ºÝºÝߣ

ºÝºÝߣShare a Scribd company logo
Introduction to i18n and l10n
Dave McHale
@thedavetheory
@dmchale
dave@websolutions.com
dmchale@gmail.com
i n t e r n a t i o n a l i z a t i o n
1 + 18 +1
i18n
l o c a l i z a t i o n
1 + 10 + 1
l10n
What can be translated?
Pulp Fiction
Actually¡­ no
? In the 2014 State of the Word, 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
Why do we care
? 71% of all current
WordPress.com 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
¨C Additional language packs are
not counted in these numbers
Why do we care
? WordPress is currently running over 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
Why i18n matters for growth
? Social Media sites like 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-glo
Rush Hour
Introduction to __()
? The double-underscore function
? Most common
? 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
Hackers
Using __()
Never translate variables
Translate full phrases, NOT this
Creating the .pot file
? When our code is prepared for
translation, we will run it through a
program that generates a .pot file
? .pot = portable object template
? File contains all translatable strings
? Can be generated¡­
¨C Through the WP repository
¨C Using Loco Translate
¨C Via command-line, using the WP i18n tools
¨C Grunt
¨C GlotPress
https://codex.wordpress.org/I18n_for_WordPress_Developers
https://wordpress.org/plugins/loco-translate/
# Loco Gettext template
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: i18n testn"
"Report-Msgid-Bugs-To: n"
"POT-Creation-Date: Thu Sep 24 2015 18:38:43 GMT-0400
(Eastern Daylight Time)n"
"POT-Revision-Date: Thu Sep 24 2015 18:38:51 GMT-0400
(Eastern Daylight Time)n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONEn"
"Last-Translator: n"
"Language-Team: n"
"Language: n"
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSIONn"
"MIME-Version: 1.0n"
"Content-Type: text/plain; charset=UTF-8n"
"Content-Transfer-Encoding: 8bitn"
"X-Poedit-SourceCharset: UTF-8n"
"X-Poedit-Basepath: .n"
"X-Poedit-SearchPath-0: .n"
"X-Poedit-KeywordsList:
_:1;gettext:1;dgettext:2;ngettext:1,2;dngettext:2,3;"
"__:1;_e:1;_c:1;_n:1,2;_n_noop:1,2;_nc:1,2;__ngettext:1,2;__ngette
xt_noop:1,2;"
"_x:1,2c;_ex:1,2c;_nx:1,2,4c;_nx_noop:1,2,3c;_n_js:1,2;_nx_js:1,2,3
c;"
"esc_attr__:1;esc_html__:1;esc_attr_e:1;esc_html_e:1;esc_attr_x:1,
2c;"
"esc_html_x:1,2c;comments_number_link:2,3;t:1;st:1;trans:1;transC
hoice:1,2n"
"X-Generator: Loco - https://localise.biz/"
Translating the .pot file
? Someone (maybe even you!) will translate the strings in your code into
another language
? Once translation is complete, two files are created
¨C .po and .mo files
? These files are named for the language scheme they apply to
¨C es_ES.po and es_ES.mo for Spanish
¨C pl_PL.po and pl_PL.mo for Polish
¨C etc
? Those files are added to the /languages subfolder of your code
.pot file results
echo __('Hack the planet!', 'my-text-domain');
#: /i18n-test.php:14 /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
.pot file results
Napolean
Dynamite
Enter sprintf()
sprintf() with multiple variables
.pot file interpretations of sprint()
sprintf()
sprintf()
.pot file interpretations of sprintf()
The Princess
Bride
One last look at __() and sprintf()
echo __('Hello. My 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 );
Using _e() and printf() to echo
? As a shortcut, 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 );
Better Off Dead
Dealing with multiples for numeric values
echo sprintf( _n('I want my %d dollar!', 'I want my %d dollars!',
$int_dollars_owed, 'my-text-domain'), $int_dollars_owed );
? _n() takes 4 parameters
¨C 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
Custom conditions for numeric values
? The codex recommends writing 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
.pot interpretations of _n()
echo sprintf( _n('I want my %d
dollar!', 'I want my %d dollars!',
$int_dollars_owed, 'my-text-
domain'), $int_dollars_owed );
#: /i18n-test.php:14 /i18n-test.php:20
#, php-format
msgid "I want my %d dollar!"
msgid_plural "I want my %d dollars!"
msgstr[0] ""
msgstr[1] ""
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 );
}
#: /i18n-test.php:18
msgid "You don't owe me any money!"
msgstr "¡°
AND
Austin Powers:
International Man
of Mystery
Dealing with homonyms and homographs
? Homonym: same spelling, same pronunciation
¨C ¡°A bear can bear very cold temperatures¡±
? Homograph: same spelling, different pronunciation
¨C ¡°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?¡±
Providing context with _x()
.pot interpretation of _x()
Leaving notes for translators
? Sometimes you may have a 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' );
.pot interpretation of /* translators:
/* translators: draft saved date 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 ""
Final notes, for your i18n to DO something
? Text Domain MUST match your plugin/theme slug
? Plugins
add_action('init', 'my_plugin_init');
function my_plugin_init() {
load_plugin_textdomain('my-text-domain', false,
dirname(plugin_basename(__FILE__)) . '/languages');
}
? Themes
add_action('after_setup_theme', 'my_theme_setup');
function my_theme_setup() {
load_theme_textdomain('my-text-domain', get_template_directory() . '/languages');
}
Summary
? __(), _e()
? sprintf(), printf()
? _n()
? _x()
? /* translators:
? What .pot, .po, and .mo files are and how they work together
? Not covered:
¨C Escaping content, more _n() love, dates, number formatting, and more!
Final Warnings, ¡°Gotchas¡±, and Misc
? Avoid
¨C Newline characters
¨C HTML in translations
¨C URLs in translations
? Unless it¡¯s translatable
¨C Empty strings
? Notes
¨C Many sentences at once is
okay, but don¡¯t translate War
and Peace. Use paragraphs, at
least.
? More Good Stuff
¨C Many exciting changes are
coming to GlotPress soon
¨C http://translate.wordpress.org
¨C Localized versions of the plugin
& theme repositories exist
¨C Language Packs in the repo!
¨C Streamlining the
author/translator relationship
right in the repository, similar to
contributors (proposal)
Additional Resources
? WP Links
¨C https://codex.wordpress.org/I18n_for_WordPres
s_Developers
¨C https://developer.wordpress.org/plugins/internati
onalization/
¨C https://developer.wordpress.org/themes/function
ality/localization/
¨C https://make.wordpress.org/polyglots/handbook/
? Otto¡¯s Blog - http://ottopress.com/tag/i18n/
? Slack
¨C #meta-i18n and #polyglots
? WP Repository
¨C https://wordpress.org/plugins/
¨C https://wordpress.org/themes/
? Google!
Contact
? dmchale@gmail.com
dave@websolutions.com
? @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

More Related Content

WCRI 2015 I18N L10N

  • 1. Introduction to i18n and l10n Dave McHale @thedavetheory @dmchale dave@websolutions.com dmchale@gmail.com
  • 2. i n t e r n a t i o n a l i z a t i o n 1 + 18 +1 i18n l o c a l i z a t i o n 1 + 10 + 1 l10n
  • 3. What can be translated?
  • 5. Actually¡­ no ? In the 2014 State of the Word, 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
  • 6. Why do we care ? 71% of all current WordPress.com 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 ¨C Additional language packs are not counted in these numbers
  • 7. Why do we care ? WordPress is currently running over 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
  • 8. Why i18n matters for growth ? Social Media sites like 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-glo
  • 10. Introduction to __() ? The double-underscore function ? Most common ? 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
  • 15. Creating the .pot file ? When our code is prepared for translation, we will run it through a program that generates a .pot file ? .pot = portable object template ? File contains all translatable strings ? Can be generated¡­ ¨C Through the WP repository ¨C Using Loco Translate ¨C Via command-line, using the WP i18n tools ¨C Grunt ¨C GlotPress https://codex.wordpress.org/I18n_for_WordPress_Developers https://wordpress.org/plugins/loco-translate/ # Loco Gettext template #, fuzzy msgid "" msgstr "" "Project-Id-Version: i18n testn" "Report-Msgid-Bugs-To: n" "POT-Creation-Date: Thu Sep 24 2015 18:38:43 GMT-0400 (Eastern Daylight Time)n" "POT-Revision-Date: Thu Sep 24 2015 18:38:51 GMT-0400 (Eastern Daylight Time)n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONEn" "Last-Translator: n" "Language-Team: n" "Language: n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSIONn" "MIME-Version: 1.0n" "Content-Type: text/plain; charset=UTF-8n" "Content-Transfer-Encoding: 8bitn" "X-Poedit-SourceCharset: UTF-8n" "X-Poedit-Basepath: .n" "X-Poedit-SearchPath-0: .n" "X-Poedit-KeywordsList: _:1;gettext:1;dgettext:2;ngettext:1,2;dngettext:2,3;" "__:1;_e:1;_c:1;_n:1,2;_n_noop:1,2;_nc:1,2;__ngettext:1,2;__ngette xt_noop:1,2;" "_x:1,2c;_ex:1,2c;_nx:1,2,4c;_nx_noop:1,2,3c;_n_js:1,2;_nx_js:1,2,3 c;" "esc_attr__:1;esc_html__:1;esc_attr_e:1;esc_html_e:1;esc_attr_x:1, 2c;" "esc_html_x:1,2c;comments_number_link:2,3;t:1;st:1;trans:1;transC hoice:1,2n" "X-Generator: Loco - https://localise.biz/"
  • 16. Translating the .pot file ? Someone (maybe even you!) will translate the strings in your code into another language ? Once translation is complete, two files are created ¨C .po and .mo files ? These files are named for the language scheme they apply to ¨C es_ES.po and es_ES.mo for Spanish ¨C pl_PL.po and pl_PL.mo for Polish ¨C etc ? Those files are added to the /languages subfolder of your code
  • 17. .pot file results echo __('Hack the planet!', 'my-text-domain'); #: /i18n-test.php:14 /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
  • 27. One last look at __() and sprintf() echo __('Hello. My 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 );
  • 28. Using _e() and printf() to echo ? As a shortcut, 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 );
  • 30. Dealing with multiples for numeric values echo sprintf( _n('I want my %d dollar!', 'I want my %d dollars!', $int_dollars_owed, 'my-text-domain'), $int_dollars_owed ); ? _n() takes 4 parameters ¨C 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
  • 31. Custom conditions for numeric values ? The codex recommends writing 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
  • 32. .pot interpretations of _n() echo sprintf( _n('I want my %d dollar!', 'I want my %d dollars!', $int_dollars_owed, 'my-text- domain'), $int_dollars_owed ); #: /i18n-test.php:14 /i18n-test.php:20 #, php-format msgid "I want my %d dollar!" msgid_plural "I want my %d dollars!" msgstr[0] "" msgstr[1] "" 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 ); } #: /i18n-test.php:18 msgid "You don't owe me any money!" msgstr "¡° AND
  • 34. Dealing with homonyms and homographs ? Homonym: same spelling, same pronunciation ¨C ¡°A bear can bear very cold temperatures¡± ? Homograph: same spelling, different pronunciation ¨C ¡°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?¡±
  • 37. Leaving notes for translators ? Sometimes you may have a 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' );
  • 38. .pot interpretation of /* translators: /* translators: draft saved date 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 ""
  • 39. Final notes, for your i18n to DO something ? Text Domain MUST match your plugin/theme slug ? Plugins add_action('init', 'my_plugin_init'); function my_plugin_init() { load_plugin_textdomain('my-text-domain', false, dirname(plugin_basename(__FILE__)) . '/languages'); } ? Themes add_action('after_setup_theme', 'my_theme_setup'); function my_theme_setup() { load_theme_textdomain('my-text-domain', get_template_directory() . '/languages'); }
  • 40. Summary ? __(), _e() ? sprintf(), printf() ? _n() ? _x() ? /* translators: ? What .pot, .po, and .mo files are and how they work together ? Not covered: ¨C Escaping content, more _n() love, dates, number formatting, and more!
  • 41. Final Warnings, ¡°Gotchas¡±, and Misc ? Avoid ¨C Newline characters ¨C HTML in translations ¨C URLs in translations ? Unless it¡¯s translatable ¨C Empty strings ? Notes ¨C Many sentences at once is okay, but don¡¯t translate War and Peace. Use paragraphs, at least. ? More Good Stuff ¨C Many exciting changes are coming to GlotPress soon ¨C http://translate.wordpress.org ¨C Localized versions of the plugin & theme repositories exist ¨C Language Packs in the repo! ¨C Streamlining the author/translator relationship right in the repository, similar to contributors (proposal)
  • 42. Additional Resources ? WP Links ¨C https://codex.wordpress.org/I18n_for_WordPres s_Developers ¨C https://developer.wordpress.org/plugins/internati onalization/ ¨C https://developer.wordpress.org/themes/function ality/localization/ ¨C https://make.wordpress.org/polyglots/handbook/ ? Otto¡¯s Blog - http://ottopress.com/tag/i18n/ ? Slack ¨C #meta-i18n and #polyglots ? WP Repository ¨C https://wordpress.org/plugins/ ¨C https://wordpress.org/themes/ ? Google! Contact ? dmchale@gmail.com dave@websolutions.com ? @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

Editor's Notes

  1. This presentation is on internationalization and localization. This is TRANSLATION of code, from a developer¡¯s point of view We will be LOOKING AT CODE Beginner track has Tony Mazzarella talking about managing client expectations Business track has Vinay Raghu talking about content-first designing ------- Over 15 years of professional experience in web industry Never needed to do i18n before writing code for WordPress when I wrote my first plugin for the repo
  2. I know .com != .org, that¡¯s why we compare them differently Don¡¯t take these numbers as gospel!!!
  3. Petya Raykovska polyglots leadership team WC Sofia (Bulgaria) & WCEU Organizer