Top 6 Secrets to Successful Internationalization

WordPress

Do you want to drive more traffic to your web? So do I! That's why we created Nelio Content, a new plugin that automates content promotion in social networks. Want to know more?

Nelson Mandela once said:

If you talk to a man in a language he understands, that goes to his head. If you talk to him in his language, that goes to his heart.

A couple of weeks ago we talked about internationalizing your WordPress website聽so that you can offer your content in multiple languages. Keep in mind that your website is the first thing most prospects will know about you, so the most intimate you can talk to them, the better. And, as Mandela said, native languages play a key role!

If you’re a WordPress plugin or theme developer, you should consider to translate and internationalize not only your website, but also your plugins and themes.聽This way, your users will be able to use them in their own language, and your plugin or theme will seamlessly integrate in a Dashboard that’s already in a foreign language. Besides, making your work accessible to everyone by translating it will increase your opportunities, because you’ll be able to attract customers that wouldn’t even consider you if you didn’t offer your plugin or theme in their language.

Unfortunately, this is easier said than done, isn’t it? If you don’t know how to do any of this or if you think it’s too complicated, don’t worry! We have your back聽馃聽In this post I’ll share with you the top-6 secrets for translating plugins and themes I wish I had known when I started.

Secret #1. Write Your Code (and Strings) in English

If you’re an English-speaker, then you can skip this step. But if your native language isn’t English and you feel more comfortable writing in other languages than English, then, please, don’t. If you’re creating a new theme or plugin, you should avoid using your own language:

Most developers are used to English. Actually, language constructs and keywords are already in English (think about the keywords function, if, or聽while), so it just makes sense to stick to this language. If you do so, you’ll make the life of other people easier:

  1. The WordPress ecosystem is, by definition, open-sourced. Plugins and themes are written in PHP and JavaScript. Therefore, people will want and/or will be able to read (and hopefully understand) your code.
  2. Remember we’re talking about internationalizing your plugin or theme鈥攖hat’s our goal today鈥攁nd you won’t be the one translating it to most of the languages. It’s easier to find translators from English to another language than any other combination, so don’t limit your options by using different “source” languages.
  3. Internationalization functions (we’ll talk about them in just a few minutes) assume you’ll write your strings in English.

The previous example is written in Catalan鈥攁 romance language similar to Spanish, French, and Italian. If you know any of these, you might be able to understand most of the code. But if you don’t, you probably don’t have a clue about what that code is supposed to do. But if it were written in English…

then it’d be so much easier for everybody!聽馃槑

Secret #2. Know Your Tools鈥擨nternationalization Functions in聽WordPress

Plugin and theme internationalization in WordPress uses gettext, an old and respectable聽piece of software, widely used in the open-source world.聽As described in the Codex, this is how it works:

  1. Developers wrap translatable strings in special gettext functions.
  2. Special tools parse the source code files and extract the translatable strings into .pot聽(Portable Objects Template) files.
  3. In the WordPress world, .pot聽files are often fed to GlotPress, which is a collaboration tool for translators.
  4. Translators translate and the result is a .po聽file (i.e., a聽.pot file, but with translations inside).
  5. .po聽files are compiled to binary .mo聽files, which give faster access to the strings at run-time.

If you need to remember one thing: translatable strings are parsed from special function calls in the source-code, they are not obtained at run-time.

So, what does it all mean? How does gettext look like? Well, it’s as easy as follows鈥攊f you want to聽make the following snippet translatable:

You need to write it as follows:

Instead of聽echoing the string directly, we first wrap it within the聽gettext function聽聽__(),聽one of the multiple functions included in the library.聽This function simply returns the translated equivalent of input string it’s given. If there isn’t a translation available, the original (English) version is returned.聽By simply applying this step in all your plugin/theme strings, it’ll be ready for translation.

Once all the strings are wrapped, you need to extract them from your source code and generate a .pot file. In order to do this, you can use a WordPress tool called聽makepot.php聽(you can download it from this聽Subversion repository). Then, from a terminal, you simply need to execute the following statement:

Finally, you simply need to tell WordPress that your plugin is actually translatable, so that it uses the proper translations when required (and available). Just edit your plugin‘s main file (usually,聽plugin-name/plugin-name.php) so that it looks like this:

Line 15 is the聽Text Domain, whose聽value is the second parameter you add in all聽gettext functions,聽which聽usually corresponds to the name of the plugin. Line 16 is聽the聽Domain Path鈥攖hat is, the folder in which WordPress will find your .pot file. Finally, in line 27 we define a simple function named聽聽plugin_name_i18n聽that’s responsible of actually loading the translations. If any of these three elements was missing, internationalization wouldn’t work.

Secret #3. Write Translatable Strings

Now that you know how to make a string translatable, it’s time to talk about how to guarantee that said string can be聽properly translated. If you’re an English speaker and you don’t know any other language, pay special attention, because we’ll discuss important stuff!

More than once, I’ve come around snippets聽like these:

I know it’s a silly example but, believe me, this happens too often. The problem with the previous snippet is that the translator is supposed to translate fragments of the final string (“The”, “user”, “post”, and聽“has been deleted”) as if they were independent building blocks, and it’s the developer who then concatenates all blocks and builds the actual final string. Sure, this works in English鈥攖he resulting sentences make perfect sense:

  • The user聽has been deleted.
  • The post聽has been deleted.

But this doesn’t work in all languages. For instance, in Spanish nouns have gender鈥攖hey’re either masculine or feminine. Articles and adjectives are also declined, and they must agree with the noun they complement. So, the previous two sentences in Spanish should look like this:

  • El usuario ha sido borrado. (masculine)
  • La entrada ha sido borrada. (feminine)

The problem? A translator can only translate the word聽“The” as either聽El” or聽La”, but not both at the same time. And the same applies to the last fragment鈥攊t’s either聽“ha sido borrado” or聽“ha sido borrada“.聽As a result, following the previous approach, the translated strings will probably look like this:

  • El usuario ha sido borrado.聽馃憤
  • El entrada ha sido borrado.聽馃槰馃槺

Another thing that developers usually get wrong is plurals. There’s plenty of ways to internationalize a plural string badly, but I’ll give you just a couple of examples. There’s plenty of developers that use an聽if/else clause for printing the singular and plural versions of their string:

Others try to be more “concise” and use the same root string, dynamically appending a final “s” when required:

Again, this obviously works in English, but when we try to translate those into other languages… well, things go very, very wrong.

How can you fix this and other issues with your translations? Just follow these three simple rules:

1. Write Full Sentences

Never, ever build a sentence by concatenating fragments. Instead, write the full sentence as many times as needed, make each sentence translatable, and let the translator do their work. Sure, this means slightly more work (there’s more sentences to code and translate), but the final result looks far better. If we followed this simple rule, the previous example we discussed would look like this:

and now their translations in Spanish could look like they’re supposed to:

  • El usuario ha sido borrado.聽馃憦馃帀
  • La entrada ha sido borrada.聽馃憦馃帀

2. Use Placeholders in Your Sentences

Sometimes, your strings need to contain a variable piece of text. For instance, a welcome text might look like this: “Hello, David” or “Hello, Ruth”. Obviously, you can’t generate all the possible sentences for all the names… so you might think that, in this particular case, concatenating the greeting and the name is the right way to go:

隆Wrong! You can’t do it!聽Just remember rule #1鈥攚rite full sentences. In these cases, use聽printf‘s placeholders to indicate where the variable text should be located:

Now, a聽Spanish translator can provide the following translation:

  • Hola, %s

so that printf聽gets the translated string with a placeholder in the right location, ready to be replaced with the actual value.

3. Use Plural Functions

English has one singular form, which you use when there’s only “one” of “something” (“one post”, “one user”, “one page”), and one plural form you use in all other cases (“zero posts”, “three users”, “500 pages”). And, truth is, most languages I know also follow this rule. So, if we apply rules #1 and #2, we can easily create translatable plural strings as follows:

But, again, that’s not how you do it. There聽are other languages that have multiple plurals, and each version of the plural is used depending on the “amount of things” we’re counting. For instance,聽in Polish, plik聽(file) is used as follows:

  • 1 plik
  • 2, 3, 4 pliki
  • 5-21 plik贸w
  • 22-24 pliki
  • 25-31 plik贸w
  • etc.

which means that you can’t create an聽if/else block considering just one string for “1 element” and another for “n elements”鈥攜ou need something more powerful. Luckily,聽gettext聽also includes a function to overcome this issue::

Using a function named聽_n(), you can specify the singular and the plural sentence (in English, there’s only two versions, remember?). When this “string” is translated to a different language, the translator will have to offer as many translations as their language requires.聽That is, Spanish translators only needs to produce two translated strings (“%d fichero” and “%d ficheros”), but a Polish translator needs to聽produce three (“%d plik”, “%d pliki”, and “%d plik贸w”)

Finally, just one聽thing that’s worth discussing. If you look at the previous snippet, you’ll see that the variable $count appears twice. The first time it appears, it’s a parameter of gettext‘s聽_n()聽function, and it simply “tells”聽gettext how many elements we have, so that聽gettext can load the appropriate translation string. The second time it appears it’s a parameter of聽printf, so that the placeholder聽%d can be replaced with the actual value.

Secret #4. Use聽Contexts…

One problem with languages (and especially with聽English) is polysemous words鈥攖hat is, a single word might have multiple definitions. For instance, “comment” can be a verb (“My mum always comments on what I’m wearing”) or a noun (“He made negative comments to the press”). But the fact that in English both words look exactly the same doesn’t imply that they also look exactly the same in other languages. How should a translator translate the word? Is it a verb or is it a noun?聽Clearly, the answer to these questions depends on the context we’re in. Sometimes it’s a noun, sometimes it’s a verb:

As you can see, you can add a third parameter to all聽gettext聽functions, making the context explicit.聽Based on my own experience, there are three types of context that聽disambiguate most cases:

  1. command. The users asks the computer to perform a certain action. For instance, “Delete post”, “Create user”, and so on.
  2. user. Sometimes, it’s the other way around鈥攖he computer tells the user what they are supposed to do. For instance, “Type in a valid e-mail address” or “Please, try again later”.
  3. text. If it’s neither of the previous two, then it’s just a text informing or notifying of something. For example, “There was an error during…”, “Payments are processed by a secure platform”, or “Akismet has protected your site from 6,861 spam comments already”.

I strongly suggest you use contexts throughout all your code.聽In my opinion, it’s a good practice to explicitly state the intention of a certain string using one of the aforementioned contexts, for they ensure that translators will perfectly understand what the message is and how to translate them.聽There might be some cases in which none of these three fully capture your intention or the appropriate meaning of a given word/sentence鈥攊f that’s the case, use a different context and make sure it serves your needs.

Secret #5. …and Help Translators (as much as you can)

As I just said, contexts help translators do their job. But sometimes, it’s not about the context鈥攖he string they’re supposed to translate is just cryptic:

the previous string makes absolutely no sense, so it’s hard to believe that any translator will get it right. Best case scenario? They won’t translate it and leave it as it is. In these cases, just聽add a small description聽to the string so that the translator can understand what’s going on. Descriptions are added by inserting a comment with the translators: keyword on it:

Thanks to the previous comment, now we know that the string聽g:i:sa聽is a PHP date formatter.

Secret #6.聽Follow the Rules

Finally, if you want to get involved with translations (either by translating your own plugin to a language you know or contributing to third-party plugins), just go to WordPress.org and join聽the language team you’re interested in. But聽before you translate anything, make sure you talk to someone in聽that community and know how they work. Most translation teams have their own guidelines on how to translate (formal vs informal, verb tenses, specific words, and so on), so you need to聽be familiar with them and adhere to them.

Remember聽that all translations are produced and maintained by聽the community. If we want a coherent and good-looking聽translation, we all need to follow the same rules鈥攊f we don’t, it’ll end up looking quite messy.

Are you interested in translating your plugin or theme? Have you already started? Do you want to contribute and don’t know how? Talk to us in the comments section and we’ll help you!

Featured image by聽Mark Rasmuson.

PoorMehGoodVery GoodAwesome! (1 votes, average: 5.00 out of 5)
Loading...

by

He obtained his PhD in Computer Science at UPC. David leads the analysis and design of our services and the user support area. He's interested in a variety of areas, including conceptual modeling, virtual reality, and 3D digital printing. He contributes to the WordPress community by participating in meetups, seminars, and the WCEU.

2 thoughts on “Top 6 Secrets to Successful Internationalization

Leave a Reply

Your email address will not be published. Required fields are marked *

I have read and agree to the Nelio Software Privacy Policy

Your personal data will be located on SiteGround and will be treated by Nelio Software with the sole purpose of publishing this comment here. The legitimation is carried out through your express consent. Contact us to access, rectify, limit, or delete your data.