I have been writing software for almost 15 years now. My current weapon of choice is Ruby, Rails and everything related to it.I ran Crowd Interactive, a Software Development consultancy, for almost 5 years. While doing so I sent more than a few websites to production and helped keeping them operational when traffic really picked up.I am now running another consulting company: michelada.io from the ground up using all those lessons learned from previous endeavors.I enjoy sharing the word by organizing local community events and speaking at conferences all around the world.View the profile
About the talk
RailsConf 2019 - Localize your Rails application like a pro by David Padilla
If you have ever worked in a Rails applications that needs to be available in more than one language you probably know how hard to maintain it can become over time, specially if more than one developer is involved in the process.
If you have never worked with localizations you probably will at some point in the future.
I want to share with you my experience. As a Spanish speaking developer I have worked in many multi-language apps, I have advice and a list of good practices that can help you in future localized projects.
Highway 164 coming my name is David or wise now on on a year did as debit you can find me on Twitter and Instagram everywhere David and I work for a company named michelada like the drink you probably had one of those and we are real steam that we can hire to work from Mexico more specifically a small town on the west coast that you probably never heard of name Colima. But even though we're headquarter in Mexico, most of our clients are in the US and at such we've we've been asked to work with a multilingual apps several times in the past.
And even though if it would build an app for a company Mexico, we probably will in Spanish for pretty actual code with a probably use the internationalization engine and entrails to do that because it will just make we're looking cold if you mix English and Spanish for language, like let's say we're building a hotel reservation system. Then you can have like a Vitas Jonas controller or preservation of controllers, that would be weird. So we actually even if the opposite in Spanish, we actually use English
so I mean you could you could do everything in Spanish, but you probably you probably shouldn't know if you're just stand up with some Multicultural mix right? So So let's just stick to English. That's what we do. Even if the office in Spanish. So we've done a fair share of internationally station, which is a pretty weird. So it's often abbreviated as i18n. And the reason it's cold at is because someone was coming trouble pronouncing it like myself asking turn out to you and all the Stations of the SAS crew at it tonight 18 characters and then and then at the very end and believe or not.
That's why it's cool. I ATM so if we go back to let's let's talk a little bit about the basics. You probably heard the basic stuff regarding International station on your on your else applications. And it goes like this function that's used as the core of translating application. And you got the function you pass a key. And additionally if you want you can pass a scope which can be either as a parameter or just pretended to the actual key separated by dots and then you keep jamming files with this
same structure and in different languages where you actually store Dexter. Do you want translated into different languages that you have but you will have something like this. So everywhere you call a the key function and you pass the key and the scope depending on the local that's currently set. It's going to return the text that you have on your on your files. Right? So, like I said, it doesn't matter if it's a scope as a tribute or just pretended as a part of the key. It works the same but depending on your purpose you might need to buy tickets
tonight reviews or just like that. So on an actual application you will have something at this time. If you have a page that has text that you want to localize some different languages. So interview instead of using the whole text or like straight text that you will replace that with kulstad at e function and then you will pass the the key of the desire text that you want to do. Do you want to display you just Define Giordano's files with the different translations for English Spanish Japanese, whatever you want and then
somewhere on the code. You just said that the Locale maybe it's comes from the database because the user City that's a preference. Maybe it comes from a query parameter. Like I'm doing right here. And that's that's all you need to do to set it up and your application automatically does once you switch that local in in in iatn object and it just works right? So the basics of how internationalisation work. So now I'm going to dive into things that I don't see often. Like I've been included in teams that are already in place and then there's things that they're
doing that that's good because her life will take to become better that say it right so maybe you know them maybe don't if you do my help refresh your memory. So let's start with the first one which is you should bleed. Your camo files right by default rails. It only reads the pillow case files from the config local folder. And then you are as you may assume that you have to just bash everything in their separate about if I look at their name and then development continues you end up
with an ugly very very ugly things jumbo file with thousands and thousands of lines that no one can read no one can maintain so it's better if you organize your translations, you know, maybe separating folders for a folder for active record in a folder for the admin translations your folder for you by I don't know. How are you want but a little bit more organized by folders even in the case of active record, you can for some people have more folders separated by a language and then each model and how it's on file
and that way if you are actually working on developing this application, you will know exactly where to go to change the Like the translation for a specific model a fight if I want to change something on the address model. I will know that there's an address that he has. Jama file. So if you use the eye or whatever else you use you can use cumin tea and you'll know exactly what to type and go there really quick to the what are you looking for? So be nice and be organized about your general files. This is not a default entrails. You have to do
something on the application or B or a neutralizer to actually tell it to be recursive about reading those files on on the lookout folder. And to be honest. I don't know why they haven't changed it. I saw some discussions around their DHHS that it's already a very small minority of apps that they look Ali station, so doesn't matter that, you know, I don't know. It's just a single line. So not a lot of not a big problem just at that line and you'll be fine to go. The second thing that you should do when you are translating
a or using a real stuff that's in multiple languages use that I 80/90 box gem, which is, you know, just something that you can throw in their attitude or gemfile and what this team does is let's say that you have a form like this, right? What it's going to do is when you love what that page you will start seeing all of this it's going to chill a trace of how it's wearing the the back end for the translation and then he's going to try to a blue screen. I know what's going on there.
And you will see them in the order as they're being loaded. So there's let's say that you're showing that page and there's a lot of things loading from from the back end that you don't even know because because where else do some translation by default soap soap what it was saying, is that even though even if you're not explicitly using translations most of the help we're seeing trails are trying to translate liked the labels on on the forms and things like that. So by using this gem do
you will be able to see what's happening in the order that it's happening. So there's a default what it's called a deeper look up tree which is what rails will use to figure out a translation on your views. So If we take a look at what's Happening Here for temple, this is just a regular phone with the label and some feels there if we focus a little bit on the on the name. We'll see what's happening here on the on the background is that you can see how it's wearing. Okay, it's wearing for a translation for helpers label out their name.
And if you can find. Then he's going to try active record attributes out their name. And if you can't find that it's going to try attributes name. So this means that you can have a global translation for all the attributes in your application that are called name because that's pretty useful right. It's probably name is going to be normal brain Spanish for all the models so you can have that but then if you have something more specific Alexei here on this form, I don't want it to show number about something a little bit larger like normal adult or
4 for this particular model 10. can do that by setting active record attributes out for name on my translation file and then it will find it first and that's what it it will use and if that's not enough it's if you need something more fine grain and just for the labels on the form, then you can use the other the other translation which is helpers label alter named so This gem helps you in not trying to make up names for translations. There's already something going on in place. So maybe you just need to figure out what that is and
then just put it on channel Fox and like I said, there's nothing special that you need to do. As you are using the the regular rails helpers. It's going to do this by default. So very helpful. The only thing that you want to do as much as you can it's use Lacie look up so let's say for example, it's difficult. And in your application to have like this flash message that shows at the top when something is graded order dated or what not and you pass it us notice to respond. So if you replace that
by a translation because you wanted to show up in different messages. Do I need to come up with a with a name like author created. Flash notice or something. You can just use. Flash on the controller when you called Tootsie function and buy starting that with a with a. What it's going to do. It's real safe going to figure out what the scope of the translation is automatically and it's going to like sort of propose something with just in this case Spanish authors because it's the other controller create because it's a great action and Flash because that's the name that
I've given so they just sort of cat. Elated that for me and I don't have to come up with a weird name and something interesting that happened here in the background. He's got their soul. So a flash translation for simple that I could use for the elders controller in general that could be used if it's with a message for all the actions in the controller for sample, or if there's some text that can be used in all of the actions. It's so it's so as you can see there's a lot of things happening in the background that we don't know about that particular jammies helping figuring that out
and Lacey look up can also be used on forms. Sorry home use which is this is this is seeing for seeing you can just like I said prepend a pretty simple. Page title and automatically it's going to show up as authors new page title at the Aquarius scope for that translation because you can have partials And they can be using different controllers or different views and by using that Lacy look up depending on where it is. It's going to come up with a whole different horoscope for a presentation. So you can
have the same view used for different controllers. But if the text changes or like like the title in the page or what not you can just change it using using the translation. And speaking of beus. You can actually localized Vuze. This is this the one that I've seen that I don't see often in real life applications and it's the one that I like the most so sometimes you just have a lot of texts that needs to be localized are translated and I've seen people, you know, just adding a lot of Keith on the on The View and
and then adding all that text and on the jungle fowl and this makes you know just it's just a lot of texts and pics that can be broken and whatnot. So you can actually look like buse just buy a pending a local 220 extension file. And if you do that, it will just load the whole thing depending on the location of jurong so you can have like a Japanese view for for your terms and conditions page and instead of having anything different camo files. You can just hop the whole view translate it right and and have the same thing in Spanish and rails automatically with Triton.
The View for the current currently set Locale depending on the file extension and it is also useful because as you have you use more languages, maybe the layout itself with the date need to change right maybe for the Japanese version you wanted to show us a table instead of just straight or for Arabic languages. Do you need to show it from right to left? Whatever it is. So you can look like the whole view instead of just the two text strings. So it. You just need to have like different views and that's it. So that's that's pretty nice and
It actually works with partials. So even if you don't have to look like the hold of you if there's just one little piece of Dexter needs to be localized then you can use it just with a partial and it works with male abuse, of course. So if I don't know your newsletter needs to be in different languages, you just create the views for for each of the actions and depending on the tail. That's the view just going to use so there's a lot of fuses for. Instead of using like if around interviews you can do you can actually do this so
Fullbacks even if some languages are you know similar there's always variations depending on the Region's right? There's some words on the Spanish that is so can I do in Spain versus at the one that spoken in Mexico? That's totally different. That's a dachshund body issue with the words and even in English, for example, if you have the British English, there's some words that are different than the American English R. I like soccer football the football tackle football
bill. It's a note in the shower is the bath so you don't want to keep translations for both languages, you know for all the words, right? Because there's a lot of things that they share. So what you do is you come for you or you can come here and drop the keishin. Rb5 translation fallbacks which in which you will tell real To use a 100 KL and then if you can't find the key for that then try the next one, right? So in this case, I'm telling it to use the
British English and then if it can fall back at sorry, if you can't find the the key that it's looking for it and try on the regular English and as you can see it's an array so he can be several other other languages that can work as as fall back. So I know you have a paycheck this way. We have to think that they showing coming at the top and then three words in common at the bottom so that you can switch between the two locals you you will see the differences that are Define of your own Bojana pause, but the words in common for Campbell you only to find them on the English on the
regular English file and you don't need them anymore on the British English file, so If we take a look at what's happening on the background, it's happening exactly the way we'd expect which is it squaring first for all the words on the British English pile because that's our current look at you. But then if you can find those words it will just fall back to the American English file. So like I said, I'm in British English and American English. It's just one example, but in Spanish, that's a lot a lot of variation between
you know, what seemed Venezuela Argentina and Mexico. So if you're trying to actually be like really Global you need to change those the little variation sentence is very useful for that until you don't have to repeat yourself too much. Now let's talk a little bit about pluralization because I don't want that. I don't see often or anyone recently, like maybe a couple months ago. I saw I saw this being misused in an application. So sometimes you just need to show numbers
and then some text right? And when it's when you see her you need you need to use the word in plural when there's just one you need to use the singular and then if there's more than one then you need to use the plural again of the word, right or maybe the Texas just different if it's here or you want a child. There's nothing here or no points and I don't know if there's there's many ways that this can work and sometimes you think the right way to do this is to just usin Destructor like this and depending on what's the what's the value on the point Fire Bowl? You just use
different keys different translation keys. Did you think going to find some Joe Jama files and that's it. Right and it actually works. It's not that it doesn't work. But there's actually a better way to do this which which include a tinga translation in the whole i-89 and you no frills. So instead of having this what you can do is just actually Define the keys for points and then you use the 3D work which has zero and that's the way you tell her I was what to do when there's zero points or whatever you're counting what you do when you
have one and what you do when you have anything else right and you can Interpol 18 in the three of them can interpellate the count which will be what you will pass us at the parameter to the function to determine how many how many objects we're we're we're having right now. So instead of having this weird structure, you will have something like that is what you call Daddy. And then you passed the account payable and it will do exactly the same that he does with the weird obstructor, but it will automatically handled the whole thing for you. So you
can see the police much much cleaner and easier to to maintain and understand. So what's the time? So we've been talking about using jamo to store your translations, but it's not the only way to store them there's different, you know strategies or what they call back ends to actually store your translations and then pull them and and display them on your app. And all you have to do is just created and defined what back-end you want to use for this particular
application. So let's say for example that you want to use the active record back and you wouldn't eat you out again because they're not his back in so I'm not part of the real score but that's a lot of gems to handle different different Atkins. And would you use this Gem of what it wants to do is to have a migration or a table that will look something like this where you will store until OKO the key that you're looking for and the value. Which is exactly what what's being translated on a natural active record database. So
you set it up at the back end and let's say that we have a form like this instead of instead of having all those channels perlu cups that we had when you use the people back in now you have a bunch of queries to the to the database which is as you can imagine not very good if you're not using proper cashing but it still works right. So it's an option. So the way you actually create the translations it's you know plain active record. You just insert those records in the database and it doesn't have to be constantly can bibia
and ask me a tool that you can feel for someone that actually needs to be actively changing dose of relations, right and instead of deploying that change on the demo file then they can do it on the Fly by changing the axle database though. That's one of the use cases that I that I seen for that one. So. There's like I said, there's several backens. The simple one is the one that comes by default with rails which uses jamo and some Eternal catching to not overwhelmed your your application thirsty active record back in that we talked about a little bit
but there's a red is back-end. If you want to use redis and helps you then why not use red as if you like mongodb for some reason that I don't know you can use Mongo for that. If it's up and if it doesn't breaks or you can use I think that's called that text. I don't know if you've used up in the past I did for us application and it was not quite a good experience. So I wouldn't recommend that the either. So bad, but you can you use any any Ol Dirty to find back in and even if there's nothing for you and maybe you store your translations using butterfly
communication vibration of what I'd you control your own translation back and it's pretty simple. So let's say we want to actually do a hold or translator. We can just define a class that's high 18 and back and holder and there's a helper class from rails that you can just include which is the back and base and and dad back and base will just add everything that they will make this class and behave as a back-end and then you just need to implement the Luke up method that will receive that look real the key to
scope and some options and then you can do with that whatever you want and whatever you want it start snowing in Disguise. We just want to return to holler string for 4. Everything that's trying to be translated and then it will just work right everything will be harder. So that's pretty flexible. However, you want to start your your translations. It's up to you and it's a 302 know that you can do something with it. And then complimenting that there's a special back in that accept which she scolded chain back in
which is part of the of the Rails to set and we talked about having all this old all of his back in options. But what happens if you want to mix them you can do that by using the chain back in so you declared at the at the translation back in on your initializer and then you tell it which beckons you wanted to use and it's going to go through them. In order to write this case is going to go through a lookout for a translation in active record first and then if it doesn't find it there it's going to go to the channel back end
and as you can see if we go back to this after using that The the chain back in if we go back to the space that we already had we will see you on the log file that what's happening is that it's creating the query first to try and find it on the database and if it doesn't find it, then it falls back to the original translation that we had in the past. So I did mention that you could one of four use cases for those with that. There may be some tax on your application that marketing needs to change and you don't want to be deploying every time marketing
wants to change that text and you can create real quick. I like a small interface for them that we're taking go in and change out the text directly on on the database. It will probably be the other way around will you have the jumbo back in first and then try to find it on the database interpret performance to get the area right when you can have maybe if it's not in the day, but if you can read it for some reason and then fall back to the Gamo whatever you want. That's that's the purpose of the Pacific. chain back on
and then we need to talk about how to translate in localized. I'm times dates and numbers. There's a function that says that's used to localize at least your date and you can Define different date formats on your gamma files or on your database of whatever you're storing your translations and just have different ways to show timestamps right instead of using sdrf time and then you know, what pattern you can use this even if it's if you're not translating the app you can use it to do use different date formats in your app. So let's say that you have
defined it default in the formal informal and whatnot formats. Would you can do what you will do is go to the interview UCL function and then when you pass the time stamp, it will obviously use the default one if you don't pass. What format do you want to use? But if you pass it one, then it will just go to that translation file and it will format the date as I do to find are so very useful instead of like I said instead of having to use instead of thyme everywhere or what not. You can keep your performance in in any place if you used to what what's an iatn already.
And then there's a bunch of very useful functions that you know see a lot of using the wild like in Center of time in words to now which is a long name for a function, but it helps you it will figure out the whole thing about how much time is between here and the timestamp I'm passing and probably 5 past 3 seconds. It will return that's less than a minute if I passed three days. It's going to just translate three days and three months and so on and they put a tickets that it's all translated ride. If
you can find it for different languages just going to work for all General chaos. If not, just somewhere Fizz ball Salisbury men's and you can come up for English if you need a different languages than it's all taken care of you for you. So it's it's pretty useful same thing for numbers with precision. And this actually includes a little bit more options, like for example, maybe in Mexico we use to decimals for number but I'm Samara country. It's usual to use a five decimals when you round a number
or different separator delimiter don't know but those are different country. So you can use this function to normalize all that and just change it depending on the look at that. You're at with your jaw move files. You can Define the separator that is used for the numbers to the Limit are the default position if you don't want to specify it and it would just work for all different languages. So very useful instead of using rounds or whatever. And then there's a number to currency to instead of having like if returning different
symbols. You can just use the number to currency function that does the same thing but also had like it gives it a more money kind of format to do the to the number that you're passing and include somewhere around there that the unit like that dollar symbol that can be different depending on on the country you're at so you can use that function to get bad normalized and just changes depending on the on the scale you are you're on. Laughing at least he's the number to human function in case you want to chill with
the number as text, you know 3000 maybe you're the three million whatever and you want to throw that in different languages and you can just use that helped her and just to find all those words Towson meal is however, do you want it on your translation files and just keep your vehicle clean and it will just it we just use internal to translate the whole that text for you. And oh, I almost forgot about this one. This is one that's not but actually know it except for the stock. I didn't know it existed. I think I'll
try to find a good you said number to human size which will just turn the numbers into kilobytes megabytes terabytes, whatever you need. So Pretty useful leave for some reason it's called different on a different country see how that's the case, but you never know and that's it. That's all I have for you. I'll give you a little free capital of what we saw here. Remember be nice play. Jordano files used to use that jam to figure out what translations are already being calculated for you instead of making up weird names. You just
try to go with the convention that gross already have to accommodate your your local stations. Remember that you can look alike buse. You can look alikes partials and is very useful when there's a lot of texts on the views that you're trying to show use fallbacks for small language variations instead of creating whole language files for for all the other languages. Just try not to use a tractor. Play for you. Remember that you can have many back and so if you want that you can't even roll your home and you still Sinclair method to look ice
Buy this talk
Access to all the recordings of the event
Buy this video
With ConferenceCast.tv, you get access to our library of the world's best conference talks.