Building Your Startup With PHP: Localization With I18n

Final product image
What You'll Be Creating

This is part four of the Building Your Startup With PHP series on Tuts+. In this series, I'm guiding you through launching a startup from concept to reality using my Meeting Planner app as a real life example. Every step along the way, we'll release the Meeting Planner code as open source examples you can learn from. We'll also address startup-related business issues as they arise.

In this tutorial, I wanted to step back and add I18n internationalization support to our application before we build more and more code. According to Wikipedia, I18n is a numeronym:

18 stands for the number of letters between the first i and last n in internationalization, a usage coined at DEC in the 1970s or 80s.

With I18n, all of the text strings displayed to the user from the application are replaced by function calls which can dynamically load translated strings for any language the user selects.

All of the code for Meeting Planner is written in the Yii2 Framework for PHP, which has built-in support for I18n. If you'd like to learn more about Yii2, check out our parallel series Programming With Yii2 at Tuts+.

Just a reminder, I do participate in the comment threads below. I'm especially interested if you have different approaches, or additional ideas, or want to suggest topics for future tutorials.

The Goals of Internationalization

When building a startup, it's useful to think globally from the beginning—but not always. Alternately, it may make sense to focus only on building for your local market. Does your minimum viable product need to work in other languages for users from different countries?

In our case, the Yii Framework provides built-in support for I18n, so it's relatively easy to build support in for I18n from the beginning—and time-consuming to add it in later.

How I18n Works

I18n operates by replacing all references to text displayed to the user with function calls that provide translation when needed. 

For example, here's what the attribute field names in the Place model look like before I18n:

Providing translated versions of the code would become very complicated. Non-technical translators would have to translate code in place, likely breaking syntax.

Here's what the same code looks like with I18n:

Yii:t() is a function calls that checks what language is currently selected and displays the appropriate translated string. 'frontend' refers to a section of our application. Translations can be optionally organized according to various categories. But, where do these translated strings appear? 

The default language, in this case English, is written into the code, as shown above. Language resource files are lists of arrays of strings whose key is the default language text—e.g. 'Place Type'—and each file provides translated text values for their appropriate language.

Here's an example of our completed Spanish translation file, language code "es". The Yii:t() function uses this file to find the appropriate translation to display:

While this looks time-consuming, Yii provides scripts to automate the generation and organization of these files. 

By separating the text from the code, we make it easier for non-technical multi-lingual experts to translate our applications for us—without breaking the code.

I18n also offers specialized functions for translating time, currency, plurals et al. I won't go into the detail of these in this tutorial. 

Configuring I18n Support

Unfortunately, the Yii2 documentation for I18n is not yet very descriptive—and it was difficult to find working, step by step examples. Luckily for you, I'm going to walk you through what I've learned from scouring the docs and the web. I found The Code Ninja's I18n example and the Yii2 Definitive Guide on I18n helpful, and Yii contributor Alexander Makarov offered me some assistance as well.

Generating the I18n Configuration File

We're using the Yii2 advanced template for Meeting Planner. This creates two Yii applications in our codebase, frontend and backend. And, it creates a common area for models shared between both applications. Yii's configuration files is loaded whenever page requests are made. We'll use Yii's I18n message scripts to build out a configuration file for I18n in the common/config path.

From our codebase root, we'll run the Yii message/config script:

This generates the following file template which we can customize:

I'm customizing my file. I move messagePath up to the top and customize sourcePath and messagePath. I am also specifying the languages I want my application to support besides English—in this case Spanish and German, 'es' and 'de'. Here's a list of all the I18n language codes.

In the next step, we'll run Yii's extract script, which will scan all the code in the sourcePath tree to generate default string files for all the labels used in our code. I'm customizing sourcePath to scan the entire code tree. I'm customizing messagePath to generate the resulting files in common/messages.

You'll see Yii scanning all of your code files:

When it completes, you'll see something like this in your codebase:

Meeting Planner I18n Message Files and Paths

Activating I18n and Selecting A Language

In the common configuration file, common/config/main.php, we're going to tell Yii about our new language support. I'll make Spanish my default language:

But there's still more to do. We have to make our code I18n aware.

Using Yii's Gii Code Generator With I18n

In part two of this series, Building Your Startup With PHP: Feature Requirements and Database Design, we used Yii's awesome code generator, Gii, to generate our models, controllers and views. But, we did not activate I18n, so all of our code embedded text strings. Let's redo this.

We return to Gii, likely http://localhost:8888/mp/gii in your browser, and re-run the model and controller generators with I18n activated.

Note: If you kept up with part three of our series, you may need to make note of the differences with each file and manually move code over. Or, it may be easiest to replace your code with the Github repository for this tutorial, linked at the upper right.

Here's an example of generating the Meeting model code with I18n activated. Notice that we specify "frontend" for our Message Category. We're placing all of our frontend text strings in one frontend category file. 

Meeting Planner I18n Gii Model Generator

Let's do the same for the CRUD generation for controllers and views:

Meeting Planner I18n Message CRUD Generator with Gii

If you browse the generated code in models, controllers and views, you'll see the text strings replaced with the Yii:t('frontend',...) function:

Translating Your Message Files

Take a look at our Spanish message file, /common/messages/es/frontend.php. It's a long list of empty array values:

For the purposes of filling in our Spanish language translations for this tutorial, I'll use Google Translate. Tricky, huh?

Meeting Planner I18n Using Google Translator to Fill Message Files

Then, we'll do some cut and paste with those translations back into the message file. 

When we visit the Place index page, you'll see the Spanish version—nice, huh?

Meeting Planner I18n Spanish Places Index Page

Notice that the navigation bar remains in English—that's because the Message/Extract script didn't pick up the Bootstrap navigation array definitions and convert them to using Yii:t(). We'll do that by hand. Also, notice that Home and paging text was translated automatically—Yii's codebase includes language translations for these standard strings.

Here's the Create A Place form:

Meeting Planner I18n Spanish Create a Place Form

If I want to switch back to English, I just change the configuration file, /common/main.php, back to English:

Meeting Planner Create a Place in English

You'll also notice as you proceed that replacing strings in JavaScript has its own complexities. I haven't explored it myself, but the Yii 1.x JsTrans extension may provide a useful guideline for supporting this.

Going Further With I18n

Ultimately, we may want to translate our application into a number of languages. I've posted a Yii feature request to extend the Message/Extract script to use the Google Translate API to automate this process. I've also asked Tuts+ to let me write a tutorial about it, so stay tuned. Of course, this just provides a base translation. You may want to hire professional translators to tune the files afterwards.

Some applications allow users to select their native language so that when they log in, the user interface automatically translates for them. In Yii, setting the $app->language variable does this:

Other applications, like below, leverage the URL path to switch languages. The user just clicks the language prefix they want, e.g. "FR", and the app is automatically translated: 

JScrambler Dynamic Language Paths

Note: Watch my Tuts+ instructor page for an upcoming tutorial about JScrambler—it's a pretty useful service. It may have already appeared by the time you read this.

Yii's URL Manager can provide this type of functionaliaty as well. I will probably implement these features for Meeting Planner in a future tutorial.

What's Next?

I hope you've learned something new with this tutorial. I had used I18n with Rails before—but this was the first time I'd implemented it with PHP. Watch for upcoming tutorials in our Building Your Startup With PHP series—there are lots of fun features coming up.

Please feel free add your questions and comments below; I generally participate in the discussions. You can also reach me on Twitter @reifman or email me directly.

Related Links



Related Articles