I’ve written in the past about web accessibility and how to improve the accessibility of your site for people using assistive technologies. But guess what? Accessibility isn’t just limited to folks with disabilities, it also means writing code in a way that anyone can use it, regardless of their language.
Enter WordPress i18n (internationalization).
Disclosure: There are some affiliate links in this post. Here’s my full disclosure statement.
WordPress i18n in a nutshell
I’d like to give you a high-level overview of what’s involved in the process of making your plugin (or theme) translation ready and then we’ll take a look in closer detail.
Internationalization is the process of making your code ready to translate (done by the original developer). It’s abbreviated as i18n (because there are 18 letters between “i” and “n”).
Steps for the developer:
- Add “Text Domain” to headers
- Load the language file using one of these functions:
load_plugin_textdomain()
,load_theme_textdomain()
, orload_child_theme_textdomain()
- Mark up strings with gettext function calls during development
- Generate and include a POT file
- Optionally create an RTL stylesheet
WordPress l10n in a nutshell
This post is really more about how developers can make their code translation-ready, but it’s hard to have a conversation about i18n and not include the other half of the story: localization.
Localization is the process of translating strings from code. It’s abbreviated as l10n (because there are 10 letters between “l” and “n”).
Steps for the translator:
- Use the POT file as a basis for translating strings
- Save this as a PO file using the proper locale
- Generate a MO file from the PO file
- Make no jokes about MO FOs
Ready for more? Let’s go.
Making Your Code Translation Ready
i18n is the process of prepping your plugin or theme files so that they are easily translatable. You do this by marking any “front-facing” text strings in a way that makes them easy to extract later (think of it like using a highlighter in a book).
Alright developers, let’s break down each of your steps a little further.
1. Use a text domain
The first step is to highlight the text strings that “belong” to your theme by declaring a text domain in your header comment block, like this:
* Text Domain: theme-name
There are a few rules to note when adding a text domain. You can check those out here along with full documentation on how to prep your theme for internationalization.
2. Load the text domain
Once you’ve set a text domain, you need to load it into your theme via functions.php
using load_theme_textdomain()
(alternatively load_child_theme_textdomain()
or load_plugin_textdomain(), depending on your usage). This tells the theme which .mo
file (language file) to use. An example looks like this:
load_theme_textdomain( 'theme-name', get_template_directory() .'/languages');
Tip: Any included translation files should be off the root in directory called /languages. While you can use a different name for this folder, but /languages is the standard folder.
3. Wrap all translatable strings (and include your text domain!)
Use one of the translation functions and wrap your text up like a big ole present. A common one you’ll see is this function: __()
. It in turn calls the translate()
function of WordPress and retrieves whatever text needs to be translated. So, if you have a bit of text that should be translatable, be sure to wrap it within the appropriate translation function.
At this point we have a text domain ( theme-name ) and a bit of text to translate. Now we’re ready to combine the two within a translation function. For example, let’s say you’re registering a widget area and need to give it a description. You could write it like this:
'description' => __( 'This is a terribly unhelpful description.', 'theme-name' )
By the way, I made a cool poster of all of the WordPress i18n functions. You can download it for free and use it as desktop wallpaper.
4. Extract all translatable strings into a POT file
Once you wrap your all your strings in the translation function along with your text domain, you can use a tool like Poedit to automatically extract all of your “highlighted” text strings and generate a .pot*
file. This file is what enables another user to localize the code to their language without having to dig through or change source code.
Tip: If you have any users willing to translate your theme prior to public release, go ahead and bundle those with the theme – that just saves some work for another end-user requiring that language.
*If you want to know more about the differences between .pot
, .po
, and .mo
files, read this article.
5. Create an RTL stylesheet
While it’s not mandatory for internationalization, I recommend creating a secondary stylesheet for folks using a Right to Left language* so that things like image floats, are “flipped” in the opposite direction.
* Technically a language is not RTL, but uses a script that’s defined as either RTL or LTR. For the sake of ease, I’m just saying “RTL language”
Just as different countries drive on different sides of the road, so certain languages read Right-to-Left (RTL) as opposed to Left-to-Right (LTR). By creating an RTL stylesheet, you can “flip” certain elements so they appear correctly when used with an RTL language.
For example, let’s say I have this in my regular stylesheet (style.css):
float: right;
margin-left: 1em;
text-align: left;
For my RTL stylesheet (rtl.css), I’d switch it to:
float: left;
margin-left: 0;
margin-right: 1em;
text-align: right;
Adding RTL support for your theme or plugin is a really nice touch and pretty easy to do. Of course you can manually create an rtl.css file, but that could be time-consuming and tedious. If you use Grunt or Gulp in your development workflow, I’d recommend using RTLCSS, which auto-generates RTL stylesheets. You can even set up a task that triggers RTLCSS to create a new RTL stylesheet every time your regular stylesheet is compiled. Neato.
You can test out your handiwork using the RTL Tester plugin to toggle any page on your WordPress site from LTR to RTL.
6. BONUS: Properly enqueue web fonts
Let’s say you’ve created a lovely theme and it uses a particular Google font. There’s a chance that your selected font doesn’t include the character sets needed for someone using a different language. Because of this, it’s important to enqueue your web fonts in a way that enables them to be dequeued by translators.
Here’s a fantastic article on how to include Google fonts in a WordPress theme.
8/9/22 – UPDATE ON WEB FONTS: After a German court case fined a website owner for violating GDPR for using Google-hosted fonts, WordPress.org suggests theme authors switch to locally-hosted fonts.
That’s all great, Carrie, but why should I care?
According to the 2014 WordPress Survey (highlighted by Matt Mullenweg at the 2014 State of the Word), only 23% of respondents are in the U.S. That leaves an overwhelming majority of international WordPress users.
Also in 2014 the number of non-English downloads of WordPress officially surpassed English downloads. That’s a lotta non-English!
What does that mean for you? Two things immediately come to mind:
Empathy – You might find this strange point to make, but empathy falls into the broader category of accessibility. If we as developers, without much extra effort, can make our code accessible to non-English users then why not do it? What’s the downside?
Capitalism – If you’re selling plugins or themes as part of your income stream, do you really want to exclude the majority of your potential market right out of the gate? I think not.
Additional Resources
Here are a few plugins designed to help with translation issues:
- Polylang – allows you to create a bilingual or multilingual WordPress site
- WPML is fantastic if you’re wanting to run a multi-lingual site.
- LTR2RTL – online helper tool to convert LTR to RTL
Helpful articles:
- Understand WordPress internationalization and translation – Brian Krogsgard
- Automating i18n in WordPress themes – Brady Vercher
You can also take my course on WordPress and Internationalization on LinkedIn Learning.
Props
Props to Gary Jones and Nir Rosenbaum for their willingness to openly discuss language issues that exist for WordPress users outside of North America. Also, a big thank you to Frank Klein for editing this article for accuracy.
There is also http://rtlcss.com/playground/
Awesome – thank you!
Thanks Carrie 🙂
I encourage developers to contact me if they need help with testing their products for RTL support.
Nir, you’re awesome.
Great article on WordPress l10n. Somewhat light on the intricacies of i18n.
It was good to see mentions of font issues and the need for stylesheet for handling languages were bidi issues exist.
One comment though … theme developers should give some thought to the best methodology for theme users to add language specific styling to themes.
Fonts are one aspect, font face, size and leading. But other factors come into play as well, including css related to line breaking, elements that default to italic typefaces. Font families for many scripts rarely come with Italic or oblique typefaces, its not part of their typographic and typesetting traditions.
Thanks, andjc. What advice would you give for handling the typography issues? Just a matter of documentation/awareness?
I like the wallpaper 🙂
Thanks, Rami!
Thanks for this post.
Hi, nice info and which is better L10n or I18n?
I don’t understand your question. You can’t have L10n without I18n.
Pingback: WP Weekly 108 / Enlighten / Builders Fight, Fluid Typography, Restore Customizer