A few years ago, I wrote about the process of internationalizing WordPress-based projects. Though I think there are some times when tutorials don't necessarily need updating, refreshing, or revisiting, there are other times in which we can all benefit from revisiting the topic.
After all, software changes from year to year, and we also gain experience as we continue to work with a given piece of software. WordPress is no different.
Starting with this article and continuing to the next set of articles, we're going to take a look at the following:
- what internationalization means within the context of WordPress
- how we can internationalize our work
- how internationalization and localization differ
- tools that are available for localization
- and more
We're even going to build a small albeit functional WordPress plugin that will help us practically demonstrate the points that we've listed above.
Before we get started, though, it's important to understand what internationalization is and what WordPress offers in the way of doing it. Furthermore, there are a few gotchas that may surprise you, especially if you're an experienced programmer.
With that set out as the outline of this series, let's get started on getting a solid grasp in internationalizing our work in WordPress.
What Is Internationalization?
The WordPress Codex is always one of the best places to start when you're looking to learn more about a given topic. Here's what it offers in the way of internationalization (which we also abbreviate as i18n just in case you see it written that way):
Internationalization is the process of developing your plugin so it can easily be translated into other languages.
Furthermore, the Codex goes on to describe exactly why this is important:
Because WordPress is used all over the world, it is a good idea to prepare a WordPress plugin so that it can be easily translated into whatever language is needed. As a developer, you may not have an easy time providing localizations for all your users; You may not speak their language after all. However, any developer can successfully internationalize a theme to allow others to create a localization without the need to modify the source code itself.
It makes sense, right? WordPress powers roughly a quarter of the web, and it's being used all over the world. Why should the work that we're providing remain in the native language we speak?
This is not to say that there aren't times in which this is okay. For example, if you're building a solution for someone and you know that they along with a small-ish group are going to be using the application, then it makes sense to leave it in the native language of said client.
But if you're building something for widespread distribution, there's no doubt that you should be internationalizing your work.
In short, internationalization is the process by which we make sure our work can be translated into another language.
Forget Everything You Know About Variables
Later in this article, we're going to take a look at the functions in the WordPress API for making sure our PHP strings are properly internationalized. But there's an incredibly important caveat that you must remember.
Do you recall when you first learned about variables in whatever programming language way back when? It was awesome, right? You could define a variable one time and then reuse that variable in place of the string (or whatever other value) every other place in the code so that you didn't have to repeat yourself.
In fact, it's part of the core tenets of programming, isn't it?
The DRY principle is stated as "Every piece of knowledge must have a single, unambiguous, authoritative representation within a system."
I absolutely, nearly unequivocally agree with this definition. But when it comes to the internationalization of strings in WordPress, we must make an exception. You'll see why momentarily, but I chose to include this section here so that you can avoid any potential future mistake. I also opted to mention this so that you don't ask about trying to use variables within the context of the internationalization API in the future points of contact.
If you remember this now, you will avoid this hurdle later.
The Internationalization API
At this point, we are ready to look at the functions WordPress provides. We won't be putting them to work in this particular article, but we will be looking at the function names, how to use them, and what they are used for in a larger context.
Starting in the next article, we'll begin putting them to use. For now, let's take a look at what's available.
_e()is similar to the above function, but rather than just retrieving the translated version of the string, it will also echo the result of the translation to the screen.
_x(): unfortunately, there are times where a given string will return the wrong translation. When this happens, using this function is helpful, especially when specifying the context of how the string was translated. This will ensure the intended version of the string is returned.
_ex(), just like
_x()listed above, will make sure the proper translation of the string is echoed to the screen based on the specified context so that the incorrect version is not selected during runtime.
_n()is a neat function because it allows WordPress to select the single or plural version of the specified number based on which is being used. This means that we, as developers, have to provide strings for both the single and plural version so translators can translate it, along with the actual number. But it makes working with internationalized numbers much easier than without.
_nx()should be, at this point, clear as to how it works. It's a combination of
_n()which we just shared and
_x()which was covered above. This means that if you've properly specified the singular and plural form of the specified number along with the proper text domain, then the translation will appear as expected.
_n_noop()should sound somewhat familiar to those who are familiar with computer science or computer engineering. A NOP is short for "no operation" and, in this case, it's used to have translated, plural strings that we don't necessarily want to use at a particular time but might want to retrieve later. In short, the translator can provide the translation and we can select when to use them.
_nx_noop()is a combination of the above function and the
_x()function we've seen so many times before. This will allow us to gain access to a translation for a particular text domain without actually having to translate them.
translate_noop_plural()reads a bit differently than the functions we've examined thus far, but the implementation is quite simple: This function provides a translation of the result of
_nx_noop(). The key thing to note about this function is that it expects the first argument to be an array with the singular and plural keys that come from the aforementioned functions.
esc_html__()is very similar to
__(), but it's intended for use in HTML tags. That is, it's not meant to translate HTML tags, but it's meant to grab the translation and escape it for safe use within the context of HTML.
esc_html_e()is just like the function above it and almost exactly like the
_e()function we looked at above; however, it's meant to be used to go ahead and echo the result of the translation to the screen.
esc_html_x()should be clear at this point given how many times we've seen
_x()used in other functions. In short, this will do the same thing as
_x(), but it will provide the text in the gettext context and will prepare it for safe use in HTML.
esc_attr__()is used to take the specified string and properly escape it so that it can be used safely as an attribute such as the
titleattribute of an image.
esc_attr_e()will display the translated text with an additional encoding of any characters such as greater than, less than, ampersands, and quotes. This is another function that is intended to be used within the context of an attribute of another element.
esc_attr_x()will grab the translation, escape it, and then render it in the context of an element's attribute. If no translation has been provided, then the default string that was provided during development time will be used.
number_format_18n()is a powerful function, especially when you're working with a variety of locales. For example, if you're working with a number and you want to render "1,000" then you'd not specify a second parameter for this function; however, if you're working with currency or decimal places, then you would want to pass '2' as the second argument so that two digitals would be appended after a decimal.
date_i18n()is another powerful function that will allow you to retrieve the date in a localized format based on the specified timestamp. To learn more about this particular function, its parameters, and examples of how it's used, please review its Codex page.
Remember in the section above where I talked about avoiding the use of variables? This is where that comes in handy. As you've no doubt noticed, each of the functions above takes in two parameters:
- the string that can be translated
- the text domain of the string
The text domain refers to a unique relationship between the WordPress plugin or WordPress theme, WordPress, and the translator. Ultimately, it's to make sure that the translator is able to provide a translation of the string without overriding the translation of another string elsewhere in WordPress (or another third-party solution).
Ultimately, your best bet is to use the slug of the plugin as the text domain. Furthermore, this parameter should always be a string, not a variable. Thus, no matter how many times you end up having to type it out, do not store it in a variable. Just type the text domain as the second parameter to the function.
This has to do with how translation tools work, and we'll be looking at this in more detail in a future article.
And that's the primer on the internationalization functions. If you're still a bit confused on how to apply some of these in your work, don't worry. There's more to cover both in terms of explanation and in terms of practical demos.
All of this is going to be covered in this series. But before we get there, we needed to start with the basics. So that's what we've done. In the next article, we'll resume by talking a bit about gettext and some of the available tools.
In the meantime, if you're looking for other utilities to help you build out your growing set of tools for WordPress or for example code to study and become more well-versed in WordPress, don't forget to see what we have available in Envato Market.
If you're interested in learning more about WordPress from a development perspective, note that I exclusively work with WordPress and often write about it. You can catch all of my courses and tutorials on my profile page, and you can follow me on my blog and/or Twitter at @tommcfarlin where I talk about software development in the context of WordPress.
Don't hesitate to leave any questions or comments in the feed below, and I'll aim to respond to each of them.