How to Make Multilingual
Plugins and Themes
John P Bloch ● 2015-09-12 ● WordCamp DFW
About Me
John P Bloch
Lead Web Engineer at 10up
Yes 10up is hiring
Tell them I sent you
Seriously, we’re always hiring
Not a designer
Do these slides look designed?
DFW Local (Irving)
Definitions
Definitions
Internationalization
The process of making your
code translatable at all.
Abbreviated as i18n
Localization
The process of using translated
text in internationalized code.
Abbreviated as l10n
Definitions
Internationalization
The process of making your
code translatable at all.
Abbreviated as i18n
Localization
The process of using translated
text in internationalized code.
Abbreviated as l10n
Why
Why
• Empathy
• Grow your potential user-base
• Potentially make more money
• Make more of an impact in the world
How
How translation works in WordPress
English text goes into a translation function
WP looks for translations of the text in the current language
If a translation is found, the function uses that
Otherwise it uses the English text
Text Domains
A text domain is a namespace for your code’s translations
If you use the wordpress.org repositories, you must use your
plugin or theme’s slug as the text domain
Even if you’re not on the official repos it’s still a good idea
Text Domains – Loading
Plugins
load_plugin_textdomain(
)
Run on plugins_loaded
action
Arguments
• The text domain
• false // deprecated
• Location of translations
• Relative to plugins directory
Themes
load_theme_textdomain()
Run on after_setup_theme
Arguments
• The text domain
• Location of translations
• Absolute path
Plugin and Theme Headers
Plugins and themes have two
special headers:
Text Domain
Domain Path
Basic Translation Functions
__()
Basic Translation Functions
__()
_e()
Basic Translation Functions
__()
_e()
_n()
Basic Translation Functions
__()
_e()
_n()
_x()
_ex()
_nx()
Basic Translation Functions
You can leave longer comments for the translators
Advanced Translation Functions
number_format_i18n()
Advanced Translation Functions
number_format_i18n()
date_i18n()
Advanced Translation Functions
number_format_i18n()
date_i18n()
wp_localize_script()
For adding translated strings to
javascript
Translates text in PHP and
outputs as a global javascript
variable
wp_localize_script()
wp_localize_script()
wp_localize_script()
Final Steps
Final Steps
• Generate .pot file
• Official repositories provide web tools
• Generate locally with PoEdit or makepot.php
• Publish .pot file
• Usually packaged with plugin or theme in the languages directory
• Add translation files to your plugin or theme
Gotchas
• Line breaks
• Empty strings
• Formatted strings vs. interpolation
_e( "You live in $state", 'my-plugin' );
_e( "You live in $state", 'my-plugin' );
printf( __( 'You live in %s', 'my-plugin' ),
$state );
printf(
__( 'Hi %s, you live in %s', 'my-plugin' ),
$user_name, $state
);
printf(
__( 'Hi %s, you live in %s', 'my-plugin' ),
$user_name, $state
);
printf(
__( 'Hi %s, you live in %s', 'my-plugin' ),
$user_name, $state
);
printf(
__( 'Hi %1$s, you live in %2$s', 'my-plugin'
),
$user_name, $state
);
Best Practices
Best Practices
• Use decent English style
• Avoid slang and abbreviations
• Keep text together
• Break at paragraphs
• Use formatted strings instead of
concatenation
• Translate phrases not words
Best Practices
Bad:
echo __( 'Click ', 'my-plugin' ) . '<a
href="/there">' .
__( 'here', 'my-plugin' ) . '</a>' .
__( ' for stuff.', 'my-plugin' );
Better:
_e( 'Click <a href="/there">here</a> for stuff.',
'my-plugin' );
Best Practices
Best:
echo '<a href="/there">' .
__( 'Click here for stuff.', 'my-plugin' )
.
'</a>';
Best Practices
Bad:
echo __( 'Thanks for using ', 'my-plugin' ) . 'My
Plugin!';
Better:
echo sprintf( __( 'Thanks for using %s', 'my-
plugin' ),
'My Plugin' ) . '!';
Best:
printf( __( 'Thanks for using %s!', 'my-plugin'
),
'My Plugin' );
Best Practices
• Use decent English style
• Avoid slang and abbreviations
• Keep text together
• Break at paragraphs
• Use formatted strings instead of
concatenation
• Translate phrases not words
• No unnecessary HTML
• Make no assumptions about
the translated text
• Length
• Word order
• Direction
• Punctuation
• Avoid translating URLs that
don’t have alternate
languages available
Tools
• Pig Latin (http://w.org/plugins/piglatin/)
• WP i18n Tools (develop.svn.wordpress.org/trunk/tools/i18n/)
• PoEdit (https://poedit.net/)
• GlotPress (http://blog.glotpress.org/)
• Language Packs
Questions?
Twitter: @johnpbloch
Website: https://johnpbloch.com
Email: john.bloch@10up.com

How to make multilingual plugins and themes

Editor's Notes

  • #5  I18n also works for institutionalization lol Internationalization is all about potential Localization is realization of that potential
  • #7 Less than half of new WordPress installations are in English Exercise in empathy coming up
  • #10 WP community is so inclusive. Alienating that many people is contrary to the community values
  • #13 All translations need to use your text domain so that WP knows where to look for translations
  • #14 Tells WP where to find translations for your text domain
  • #15 Domain path is relative to your plugin or theme’s root directory
  • #19 Disambiguation by context
  • #21 Number format i18n has a second argument which is how many decimal points to keep Always returns a string, not an integer or float
  • #22 First argument is the date format, second is timestamp (defaults to now) third is whether to use GMT Date formats should always be run through translation! There is no standard date format across most languages.
  • #25 This can also be used to send data to the script that has nothing to do with translation, but that’s not germane right now. Can be used multiple times for the same script but not for the same js variable
  • #29 Only unix line endings Never try to translate an empty string
  • #31 Always use %s, never anything else. PHP type coercion will take care of it for you.
  • #34 You can’t depend on word order staying the same. Use positional formatting
  • #40 Sometimes HTML is unavoidable. There’s no great way to solve this. Just keep in mind that translators aren’t necessarily going to know HTML