WordCamp Rhode Island 2015 : Introduction to i18n / l10n
Internationalization and Localization for WordPress developers. An introduction to why i18n is important, and how to get started making your plugin or theme translation-ready
Matt Mullenweg reported that WordPress had more non-English downloads than English downloads in that year - http://ma.tt/2014/10/sotw-2014/ • That is a BIG deal. Non-English growing quickly! • 7.2 Million non-English downloads versus 6.5 Million English
sites are English, 29% are non-English https://wordpress.com/activity/ • 74.4% of WordPress 4.3 downloads are US English, and 25.6% in non-English – Additional language packs are not counted in these numbers
24% of the internet • If we use the WordPress.com usage percentages, “only” 29% of that market share == 6.96% of the internet is running a non-English WordPress install
Facebook, Twitter and others experienced 30% growth in their first year after localizing • What's helped? Numerous factors, but rising global usage is an "easy" place to gain market share • Continued improvements to i18n process only continue to make the platform more accessible https://speakerdeck.com/petya/wordpress-is- growing-globally-are-you
• Most basic, but fits most needs • Based on the _() (single underscore) gettext function, but specifically for WordPress in order to load translation files “In computing, gettext is an internationalization and localization (i18n) system commonly used for writing multilingual programs on Unix-like computer operating systems. The most commonly used implementation of gettext is GNU gettext, released by the GNU Project in 1995.” - https://en.wikipedia.org/wiki/Gettext
text domain which you have defined for your plugin or theme /* Plugin Name: Hello Dolly Plugin URI: http://wordpress.org/plugins/hello-dolly/ Author: Matt Mullenweg … Text Domain: hello-dolly */
. ' the planet!', 'my-text-domain'); echo __('Hack the planet!', $my_text_domain); • Variables will not get parsed properly inside double quotes • Using string concatenation will not help • Translation tools cannot interpret text domain dynamically
$noun . __('! Hack the planet!', 'my-text-domain'); • Translators lose reference points when you break apart your strings in this way • We need to use a different method to use variables in an intelligent manner
translate the strings in your code into another language • Once translation is complete, two files are created – .po and .mo files • These files are named for the language scheme they apply to – es_ES.po and es_ES.mo for Spanish – pl_PL.po and pl_PL.mo for Polish – etc • Those files are added to the /languages subfolder of your code
/i18n-test.php:17 msgid "Hack the planet!" msgstr "" echo __("Hack the $noun!", 'my-text-domain'); echo __($verb . ' the planet!', 'my-text-domain'); • No results. The parser skips these entirely
gives us the ability to use variables in our translation strings echo sprintf( __(‘Your mom goes to %s', 'my-text-domain'), $noun ); • The inner part of the function leaves us only translating ‘Your mom goes to %s’ (or its foreign-language equivalent) • sprintf() will replace the %s with $noun • %s is the symbol for strings, but there are a number of type specifiers that can be used - http://php.net/manual/en/function.sprintf.php
than one variable? echo sprintf( __('Your %s goes to %s', 'my-text-domain'), $relative_title, $noun ); • Percent variables are used as placeholders in the string we want to be translated • Their order in the original string will match the order of our variable parameters passed to sprintf()
to change? • In the translation, the noun may need to precede the verb echo sprintf( __('Your %1$s goes to %2$s', 'my-text-domain'), $relative_title, $noun ); • This is another really good reason not to break up your phrases into multiple gettext functions
variables, we can identify which variable goes with which placeholder. • %2$s will always match to $noun, no matter where %2$s goes in the translation string echo sprintf( __(‘Your %1$s goes to %2$s! Because %2$s is a bad thing!', 'my-text-domain'), $relative_title, $noun );
to %2$s', 'my-text-domain'), $relative_title, $noun ); #: /i18n-test.php:16 #, php-format msgid "Your %1$s goes to %2$s" msgstr "" echo sprintf( __(‘Your %1$s goes to %2$s! Because %2$s is a bad thing!', 'my-text-domain'), $relative_title, $noun ); #: /i18n-test.php:17 #, php-format msgid "Your %1$s goes to %2$s! Because %2$s is a bad thing!" msgstr ""
name is Inigo Montoya.', 'my-text-domain'); echo sprintf( __('Hello. My name is %1$s.', 'my-text-domain'), $my_name ); echo sprintf( __('%2$s. My name is %1$s.', 'my-text-domain'), $my_name, $greeting_text );
you can combine “echo” and “__()” into the _e() function _e(‘Hello. My name is Inigo Montoya.', 'my-text-domain'); • While sprintf() returns a string, which can be used however you like, you can alternatively call printf() to just echo the result of whatever is inside the function printf( __('You killed my %s. Prepare to die.', 'my-text-domain'), $relative );
my %d dollar!', 'I want my %d dollars!', $int_dollars_owed, 'my-text-domain'), $int_dollars_owed ); • _n() takes 4 parameters – Singular string, Plural string, Numeric value, and Text Domain • In this example, $int_dollars_owed is first used inside of _n(), then used for replacement as part of sprintf() • %d is our placeholder in this example because we’re using digits
your own explicit conditionals for special cases if ($int_dollars_owed === 0) { echo __(‘You don't owe me any money!’); } else { echo sprintf( _n('I want my %d dollar!', 'I want my %d dollars!', $int_dollars_owed, 'my-text-domain'), $int_dollars_owed ); } https://codex.wordpress.org/I18n_for_WordPress_Developers
pronunciation – “A bear can bear very cold temperatures” • Homograph: same spelling, different pronunciation – “The violin player held his bow while taking a bow” • In text, it can be difficult to convey our meaning with our words • #polyglots, “ […] in Jetpack: “Set the primary account holder”. Does anyone know if it is the holder of the primary account, or is it the primary holder of the account?”
girls of that... caliber', 'by caliber I mean the high quality of their characters', 'my-text-domain' ); • _x() takes the string to be translated, the context for the person doing the translation, and the text domain Dr. Evil: I like to see girls of that... caliber. [pause] Dr. Evil: By "caliber," of course, I refer to both the size of their gun barrels and the high quality of their characters... Two meanings... caliber... it's a homonym... Forget it. ” – Doctor Evil http://www.imdb.com/character/ch0026630/quotes
girls of that... caliber', 'by caliber I mean the high quality of their characters', 'my-text-domain' ); #: /i18n-test.php:15 msgctxt "by caliber I mean the high quality of their characters" msgid "I like to see girls of that... caliber" msgstr ""
need for adding a specific note for translators, which could be different than simply providing context of a single word or phrase using _n() • You can do this with the /* translators: comment notation • Your note will be added to the pot file for translators as long as it is the last comment before the gettext function call /* translators: draft saved date format, see http://php.net/date */ $draft_saved_date_format = __( 'g:i:s a' );
format, see http://php.net/date */ $draft_saved_date_format = __( 'g:i:s a' ); #. translators: draft saved date format, see http://php.net/date #: /i18n-test.php:15 /i18n-test.php:72 msgid "g:i:s a" msgstr ""
_x() • /* translators: • What .pot, .po, and .mo files are and how they work together • Not covered: – Escaping content, more _n() love, dates, number formatting, and more!
– HTML in translations – URLs in translations • Unless it’s translatable – Empty strings • Notes – Many sentences at once is okay, but don’t translate War and Peace. Use paragraphs, at least. • More Good Stuff – Many exciting changes are coming to GlotPress soon – http://translate.wordpress.org – Localized versions of the plugin & theme repositories exist – Language Packs in the repo! – Streamlining the author/translator relationship right in the repository, similar to contributors (proposal)
onalization/ – https://developer.wordpress.org/themes/function ality/localization/ – https://make.wordpress.org/polyglots/handbook/ • Otto’s Blog - http://ottopress.com/tag/i18n/ • Slack – #meta-i18n and #polyglots • WP Repository – https://wordpress.org/plugins/ – https://wordpress.org/themes/ • Google! Contact • [email protected][email protected] • @thedavetheory on Twitter • @dmchale on Slack • http://www.binarytemplar.com All images are the property and copyright of their original owners. No ownership is claimed by their use in this presentation