In this lesson you’ll learn how to enable internationalization for your application. This will make it much easier to define multiple locales for it and to reach out to a broader audience.
1.Introduction2 lessons, 14:01
2.Building a Rails Application11 lessons, 2:09:35
3.Conclusion1 lesson, 02:23
In this specific lesson, we'll cover the topic of internationalization. Rails has its support built in. It takes advantage of the general i18n library. So we're going to learn about the context in which Rails uses it and how you can use it yourself in your application. For the context at hand, we're going to edit this form right here to edit the project in order for the labels, for example, and the title to have internationalized text. So how do we do that? Well, there are several steps in order to include internationalization. The first one is to go to the gem file and include a new gem. I'm going to include the rails-i18n gem. This gem contains several different locales already available for you. So in case you want to switch to your own language, you can do so without any hesitation. If you were to switch to a different language without this gem, you will most likely face a lot of different errors. This gem basically fulfills that need. So all we need to do is type in the bundle command in the console, and that gem should be available. Next we need to go to the server and restart it since we have done changes in to the gemfile. Okay. If we run this back again just trying to reload the browser, you will see that nothing changes. The default locale is always English, but you might want to change this to another language. Now, let's go back to the app folder, and in this specific case, we're going to start changing the template code in order to support internationalization. Let's go to project/_form. Basically this is the place where you edit the fields and the labels and stuff like that. So right next to each label, I'm going to add a text that should be replaced with one that's already there. This has nothing to do with internationalization. We just want to update the contents of the label. Now, in specific I want to use a method that reaches out to the i18n framework. It is called T or translate. Both of them will work. So if you use T like this, it will call that translation method. So what I wanna do here is pass the string that matches a key, or a nested key in a file. I wanna have, for example, projects.name. And I'm going to do the same thing for the descriptions, so let's just add projects. Description, there you go. And the same thing for ends at. Let's change this to ends at. There you go. Now let's save this and go back to our browser. If we reload the page you will see nothing different, but this is just an illusion. If I indeed scroll the mouse back to this label, you will see title. If I inspect this element with Firebug, you will see that there's a title attribute in a span tag. Translation is missing. You can see that the key that we want is en.projects.name. Right off the bat you can see that its default locale is indeed English. So, what do we need to do in order to fulfill this need? Well, by default Rails picks up on the last key and tries to capitalize it. So if I were to change this for example to Namee with two es just to be different and I reloaded the page, you would see Namee with the two es. That's the result of Rails trying to transpose or calculate the name based off just a key. If we go to config/locales, you will see this en.yml file. Let's open it. This is the yml file that we used before for sending an email. We're gonna use this again but instead of using one key we'll use another. Just add in some content right next as long as it is inside of the en keyword. So we want projects and after that we want a name, then a description and also ends at. So for the name you just type in name, then description and then ends at. With this I can safely go to the browser and hit Reload. Let's see if this worked. I'm gonna hit F12 to open fire bug and choose to inspect each element. There you go, the label no longer has that missing span tag. So that's great. The translation for English is taken care of. So basically we have been using the yml file to create the respective translations, and in the templates we use the t method to actually translate something based off the key. Each different word in between dots matches a level of depth in the yml file. So en, and then projects, and then name or even description, whatever you specified in the template. The tricky part comes when defining new languages, new locales. Let's take care of that. I'm gonna create a new locale file called pt.yml. The same keys as with in English. So I'm just gonna copy this, and I'm going to port them straight to the PTML file. This will resemble the Portuguese language, which is Is my natural language. I'm going to change name with [FOREIGN] then description with [FOREIGN] and finally ends at with [FOREIGN]. This is the translation in Portuguese for these three keys. Now we are still not able to do anything with this Portuguese layout because if we load the page there is nowhere that the locale can be specified. My idea is to add in locale=pt like so but this won't do anything because this locale parameter is actually not being used at all. How do we solve that challenge? Well, one solution is to go to the application controller, and handle that specific scenario. So, we're going to create a before action method, that will be run before each and every action. We'll use the set locale variable. Which will be a method that we'll define right here, right next to it. This method is our own. There's nowhere in Rails where this method is already defined, basically we want to make sure that the locale is defined with this function. So the way we define the locale for the application is by using I18n.locale. We assign it to a specific variable. We want the user to be able to specify a locale perimeter like this. Or if it doesn't exist, we're going to default to i18n's default locale, which is English. So if we specify a locale perimeter, it's going to take that form. So if we do this again, try to edit the project but with the PT locale specified. Let's just type that in. You will see that we have some information that's different. You will see that the localization has changed. These are all the months of the year. In Portuguese. However the previous are still missing. For this purpose we're going to need to shut down the server again because we made changes to it. There you go. Let's just restart the server, reload this again, and this time you will see all of the names in Portuguese. That's wonderful. So from here on out, when you change the locale to be a specific one, you will see the changes. Now, this idea of passing the locale parameter as a query argument is really cool. But there's something that we can do to make it a lot better. My idea is to remove this query argument and put it at the beginning of the route. Something like /pt and then the remainder of the URL. Of course this will not work because there's no such route. We need to go to config/routes, and create that scope around the whole set of projects. So, let's do a scope method and pass a block to it. This scope will include all of the remaining resource routes, basically all of the application will be stored inside. So let's go here and pass in ::locale with a forward slash at the beginning. This will make sure that the locale is properly interpreted. And so the language will always be present in the URL. So when trying to reload this page you will see that we have an error. This error was purposely thrown because there's something that we're still missing. But first let's take a look at the error itself. You can see that there's no route with the show action in the project controller. With the locale being the project itself, well this doesn't smell good. We should have the id in here. It should be populated. As you can see the id is right there, but it's still trying to do something that's really not right. The locale is the missing key and not the id. So Rails is actually doing something wrong. It's not considering that locale option per se and because of that we're gonna need to add something in particular to the application controller. In here we'll define the default URL options method. In this method, we'll need to manipulate the hash of options in order to include the locale. This is the instruction that we'll need to type in. First of all, this method takes an array of options, or a hash of options which we'll need to merge it with a new hash that basically contains the missing variable. Locale, will always be the current locale. We're going to merge the two hashes into a single one and so the problem will be solved. Because this was complaining about the id which is indeed not the cause for the error, rather it is the locale, this variable was missing and we made sure that it would be injected properly. So when reloading the page, there you go. The PT variable is considered as the locale and because of that you can see all of the labels in Portuguese. Now if I consider the EN variable as a locale, all of the names are going to be in English. So that's great, good job. We have successfully managed to integrate internationalization into our project. If you want to know more about internationalization, check the official Ruby on Rails Guides. If you go to guides.rubyonrails.org, and then switch to the index you will see the tab just for internationalization. Under the digging deeper section click on Rails Internationalization API. There's a bunch of different topics on internationalization that you can resort to in order to fully get a grasp on the potential of using this library.