This document provides an introduction to internationalization (i18n) and localization (l10n) in WordPress. It covers functions like __() and _e() for translating text, sprintf() for variables, _n() for pluralization, and _x() for providing context. It also discusses the .pot, .po and .mo files used in the translation process and including notes for translators. The goal is to prepare WordPress plugins and themes for translation into other languages to facilitate the growth of an increasingly global user base.
1 of 42
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
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
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
I know .com != .org, that¡¯s why we compare them differently
Don¡¯t take these numbers as gospel!!!
Petya Raykovska
polyglots leadership team
WC Sofia (Bulgaria) & WCEU Organizer