In a digital world, reaching audiences on a global scale is a necessity for growth. However, there’s more to going global than simply putting your content out there; it’s about making sure your content can resonate with audiences anywhere in the world, regardless of what language they speak. Under normal circumstances, we’d simply call this translation, but it’s not so easy when we’re dealing with code. This is where internationalization and localization come into play.
What is internationalization?
Internationalization (abbreviated as i18n) is the process of developing or converting a WordPress theme so that it can be translated into other languages.
What is localization?
Localization (abbreviated as l10n) is the process of translating an internationalized theme to be viewed in other languages.
Wait, I thought this post was supposed to be about translation…
It is, but it also isn’t. Translation is the physical act of transposing a page, document, section, string of text, word, etc., to another language. It is largely a manual process, usually done by a professional translator, and not something that should/could be done by a machine-based translation service such as Google Translate.
Why not? I’ve used Google Translate plenty of times before!
While Google Translate is probably mostly fine for simple translations (i.e., finding the Spanish word for “cat” is simple to plug in), and will probably always yield the correct translation (by the way, the translation is “gato”).
Where Google Translate fails is when it’s challenged with full sentences, paragraphs, complete documents, or anything larger than a small textual snippet. This isn’t to say Google Translate isn’t intelligent, because it is. When met with homonyms, it tries to interpret context clues around the word to guess what the new phrase should be, but as you can imagine, as most things in technology are, it’s largely imperfect. A sentence like “I was feeling rotten because my watch broke” could logically be misinterpreted as something like “I was touching decomposed because my observe is impoverished”.
All this to say, a professional translator fluent in both languages they’re working with is a lot less prone to these pitfalls. Sure, they’re likely a lot more expensive and take a lot more time, but if translations need to be done, they should be done right.
I guess that makes sense. Talk more about the process.
Internationalizing and localizing are two separate processes that intertwine with each other. Internationalizing lies heavily on the developer while localizing is mostly done by a content manager through the CMS. Some form of internationalizing always needs to be done first.
I’m a developer. How do I start internationalizing my theme?
Probably the largest part of theme internationalization is string translation. Even on our more customizable sites, we always leave some kind of white text (hardcoded words or phrases) in our code. But if we’re i18n-ing our themes, those pieces of white text will not be localized unless we internationalize them.
WordPress’s core includes many i18n and l10n functions that are moderately easy to implement. The two PHP functions you’ll be using most frequently are __()
and _e()
. The only difference between these two is that the former returns and the latter echos, much like get_field()
and the_field()
, respectively. Usage:
$button_text = __( 'This text will be returned.', 'jrd' );
echo "<a href='#'>$button_text</a>";
_e( 'This text will be echoed.', 'jrd' );
Notice that second argument – it’s there to provide a text domain, which allows WordPress to differentiate between your theme and all other themes, plugins, functions, etc. Technically these functions can be used without a second argument, but you probably wouldn’t want to, since there are thousands of other l10n-able strings in our standard sites, many of which are introduced by the core of WordPress itself.
For more info, check out the WP Codex on __()
and _e()
.
Note that we’re only using simple strings for these two functions. There’s a different function for when you want to start introducing variables into strings. For that, we need to use another function…
Hold up, why can’t I just concatenate normally within the _e() function like:
echo __read( 'Read', 'jrd' ) . $first_name . __( "'s bio", 'jrd' );
This is better but also worse. English is among the only language that uses apostrophe-S to imply ownership and other languages might be structured very differently. For example, “Read Chris’s bio” in Spanish would translate roughly to “Lea la biografia de Chris”, which would translate back to English as “Read the bio of Chris”. This is just one example, but there are a lot more pitfalls like this.
Okay, then what’s the right way to do complex string localization?
For concatenation and interpolation of complex strings, we’d use a combination of __()
and PHP’s core sprintf() function. Basic usage:
echo sprintf( __( "Read %s's bio", 'jrd' ), $first_name );
This registers one single string in the text domain to be localized and translated. Localizers (the people putting translations into the CMS) would change just one string, but moving the %s
placeholder around to fit the structure of the language. For example, for Spanish, this could be localized to “Lea la biografia de %s
”. This is also prefaced with a “// translators:
” comment that describes the purpose of the placeholder(s) in the string.
This can also be done with multiple placeholders.
echo sprintf( __( "%1$s's favorite food is %2$s", 'jrd' ), $first_name, $favorite_food );
Note that in this example, an argument number was added to the placeholder. This is so we can move around placeholders as we need, to change the structure of the sentence. For example, this could be changed to something like “%2$s is %1$s’s favorite food
”
Cool, what if the sentence structure depends on a variable being singular or plural, like “Chris has 2 pets” or “Nikki has 1 pet”?
Another WP function exists called _n()
which, when coupled with sprintf()
, registers and returns two different strings to be localized and translated. Usage:
echo sprintf( _n( '%1$s has "%2$d pet"', '%1$s has "%2$d pets"", $number_of_pets, 'jrd' ), $first_name, $number_of_pets );
_n()
takes four arguments: a string for when a variable is singular, a string for when it’s plural, the variable in question, and the text domain. All the same principles of sprintf()
apply.
Unrelated: I learned about homonyms in grammar school. What a neat word!
Developers should also take into account the context of a particular word or phrase, and whether it can be misinterpreted another way. For instance, the word “post” could be interpreted as…
- (noun) an article or publication
- (noun) an upright stake in the ground
- (noun) the position that an employee is appointed
- (verb) the act of notifying, announcing, or submitting
- (prefix) after or subsequent
To differentiate between these interpretations, we use _x()
, which takes 3 arguments: the string, the context, and the text domain. To go with our above example, here’s how we’d use “Post” meaning to submit a comment
echo _x( 'Post', 'verb: send submission', 'jrd' );
There aren’t any standards on how the context should be defined; only that it’s descriptive enough to allow the context to be clear.
Great, how can I get started?
Let’s get practical. Take WPML (WordPress Multilingual, https://wpml.org/) as an example. With this plugin installed, you can take some initial steps to best configure how your pages are translated.
STEP-BY-STEP INSTRUCTIONS
- During back-end development, the developer should ensure that all text strings/white text have proper localization placeholders to support translations.
- CMS text is translated in WordPress via the ACFML add-on.
- This add-on should be installed and activated at the same time as WPML. The setup process walks you through which add-ons would be suitable for your site.
- Include
do_action( ‘wpml_add_language_selector’ );
in your header.php to display the language selector.
HOW THE ACTUAL TRANSLATIONS ARE HANDLED:
- Strings (white text)
- Any text that isn’t editable via the WordPress admin should be translatable via WPML’s String Translation, outlined above
- This includes all labels, custom post type info, etc.
- ACF
- This includes all labels, custom post type info, etc.
- ACF Pro is already WPML compatible, as demonstrated here
- It relies on another plugin to support it, called ACFML, Advanced Custom Fields Multi-Language
- This plugin is available once a WPML account is on a paid tier
- For technical details, refer to WPML’s official documentation
- Gravity Forms
- Similar to ACF, there’s a support plugin to assist these translations. Again, this can be added on during the setup wizard.
In Conclusion
Investing in these practices will not only diversify your reach but will also assist in how users engage with your content. Localization and internationalization aren’t just principles of translation, they’re avenues that open the doors to meaningful connections at a global scale.