RailsConf 2019

Localize your Rails application like a pro

Localize your Rails application like a pro

by David Padilla

In the video "Localize your Rails application like a pro" presented by David Padilla at RailsConf 2019, the speaker delves into practical strategies for effectively managing multi-language Rails applications. With a focus on internationalization (often abbreviated as i18n), Padilla shares insights garnered from his experience as a Spanish-speaking developer working with diverse clients in the U.S. and Mexico.

Key Points Discussed:

  • Basics of Internationalization: Padilla explains the core functionality of the i18n system in Rails, particularly the usage of the T function for translating text, and how localization files (in YAML format) are structured by language.
  • Best Practices for Organizing Translations: The speaker emphasizes the importance of splitting localization files into organized folders instead of lumping all translations into one massive file, which can become unwieldy over time.
  • Utilizing Gems: He recommends utilizing the i18n-debug gem to visualize how translations are fetched in Rails applications, aiding in debugging issues.
  • Lazy Lookup Feature: Padilla talks about the lazy lookup mechanism, which automatically determines translation scopes, streamlining the localization process.
  • Localized Views: A unique strategy presented is the use of localized views by appending locale information to view file extensions, enabling entire views to be translated rather than just text strings.
  • Fallback Mechanisms: Guidelines for configuring translation fallbacks to handle regional language variations are discussed, which prevents unnecessary duplication of translation keys.
  • Pluralization: The handling of pluralization within localization is addressed. Padilla suggests using a cleaner method than traditional if-statements by utilizing built-in i18n pluralization features.
  • Alternative Backends for Translations: Multiple strategies for storing translations in different backends (e.g., Redis, Active Record) are indicated, demonstrating flexibility in how translations can be managed.
  • Localization of Dates and Numbers: Techniques for localizing time formats and currency are highlighted, ensuring that user-facing content is culturally appropriate.

Conclusions and Takeaways:

Padilla concludes with a checklist of best practices to enhance localization in Rails applications:
- Splitting YAML files for maintainability.
- Utilizing the default lookup tree for automatic translations.
- Employing lazy loading to reduce manual naming assumptions.
- Localizing entire views for significant text rather than individual strings.
- Configuring fallbacks for language variations.
- Leveraging pluralization tools for clearer code.
Overall, the session provides valuable insights for Rails developers aiming to create inclusive applications that cater to multilingual users effectively.

00:00:21.510 Hi everyone, thanks for coming. My name is David, or more commonly known on the internet as Dabit. You can find me on Twitter, GitHub, Instagram, and everywhere else as Dabit. I work for a company named Michelada, like the drink you probably had one of.
00:00:35.989 We are a Rails team that you can hire from Mexico, more specifically from a small town on the west coast that you probably have never heard of called Calima. Despite being headquartered in Mexico, most of our clients are in the US. As a result, we’ve been asked to work with multilingual apps several times in the past.
00:00:52.289 Even if we built an app for a company in Mexico, we probably would use Spanish for the actual code. We opt for using the internationalization (i18n) engine in Rails to keep the code clean. If you mix English and Spanish or other languages, for example, if we're building a hotel reservation system, it could lead to a confusing situation with filenames like 'bed_siones_controller' or 'tree_service_ronas_controller.' As such, even if the app is in Spanish, we still tend to stick with English naming conventions in the code.
00:01:14.940 We have done a fair share of internationalization, which, I must admit, is a pretty weird word to pronounce. It’s often abbreviated as i18n. The reason it’s called that is because someone found it difficult to pronounce, so they coined the term i18n, which stands for 'I' plus 18 characters followed by 'n.' Believe it or not, that's where the term comes from.
00:01:38.200 Now, let’s talk a little bit about the basics of internationalization. You’ve probably heard of the core elements regarding internationalization in your Rails applications. It goes like this: there’s a 'T' function that is used as the core of translating Rails applications.
00:02:01.560 To use the 'T' function, you pass a key and, optionally, you can also pass a scope, which can be either a parameter or just prepended to the actual key, separated by dots. You keep YAML files with the same structure in different languages, where you store the text that you want to be translated. Whenever you call the 'T' function with the provided key and the current locale, it returns the corresponding text.
00:02:24.250 It does not matter if the scope is an attribute or just prepended as part of the key; it works the same way. Depending on your specific use case, you might need to pass the scope as an attribute or just like that. In an actual application, you might have a page that contains text you want to localize into different languages. So instead of using hard-coded text in the view, you replace that with calls to the 'T' function and pass the key for the desired text.
00:02:51.170 You then define your YAML files with the different translations, whether it is English, Spanish, Japanese, or any other language you require. At some point in the code, you set the locale, which may come from the database, or perhaps from a query parameter as I’m doing right here. That’s all you need to set up, and your application will work automatically.
00:03:13.020 That’s the basic functionality of internationalization. Now I'm going to dive into some common practices I've encountered when joining existing teams. Sometimes, there are things being done that could be improved.
00:03:32.220 Let's start with the first tip, which is to split your YAML files. By default, Rails only reads the locale files from the config/locales folder. You might assume you need to shove everything in there, separated by locale names. However, as development continues, this approach leads to enormous YAML files filled with thousands of lines, which nobody can read or maintain.
00:03:55.060 It's better to organize your translations by separating them into folders — maybe a folder for ActiveRecord translations and another one for admin translations. You can even go further and separate by language. Each model can have its own file, making it easier to find the translation for a specific model when working on the application. If I want to change something for the 'address' model, I will know that 'address.es.yaml' is the relevant file.
00:04:14.850 Be organized about your YAML files. However, as mentioned, this is not the default behavior in Rails. You need to add a line in the application.rb or an initializer to make Rails recursively read those files in the locales folder.
00:04:32.600 To be honest, I don’t know why this behavior hasn’t changed yet. I’ve seen discussions around it, but as DHH mentioned, it's a very small minority of apps that require localization, and in that context, it doesn't matter much.
00:04:58.760 The second best practice to keep in mind when translating or using a Rails app with multiple languages is to utilize the i18n-debug gem. This gem can be added to your Gemfile. When added, it enables you to see a trace of how your site is querying the backend for translations. This way, when you load a page, you will see a blue screen detailing what translations are being performed.
00:05:27.680 Some helpers in Rails will automatically attempt to translate labels and text, even if you don’t explicitly call translations. By using this gem, you can understand the translation order and the default lookup tree that Rails employs.
00:05:46.760 For example, if you have a standard form with labels and some fields, and you focus on the label for the author name, you’ll see Rails querying the translation for 'helpers.label.author_name.' If it can't find that key, it will look up 'active_record.attributes.author_name,' and if that fails too, it will try 'attributes.name.' This method allows for a more structured and comprehensive approach to translations.
00:06:04.680 Thus, you can set global translations for attributes that are regularly used across your application. If you require something more specific for a particular model or form, defining labels directly in your translation files will ensure those specific details are used.
00:06:24.410 Another useful practice is to utilize lazy lookup. For example, when you have flash messages that inform the user that something was created or updated, instead of using a hard-coded message, you can create a translation that shows different messages based on the context.
00:06:42.690 By prefixing the translation key with a period, Rails will automatically calculate the scope based on the controller and action context. This enhances your flexibility and ensures that related translations are grouped automatically.
00:07:05.050 Lazy lookup can also be applied to views and partials. You can easily prepend a period to utilize the context of partials in different views, ensuring that your keys match the translations needed for whichever controller or view they are in.
00:07:27.760 You can also localize entire views by appending a locale to the extension file. This means you could have a Japanese view for your terms and conditions page instead of maintaining different YAML files for translations of lengthy text.
00:07:48.320 This approach is useful because as languages vary, so too might the required layout. For instance, a Japanese version of a page may need to be formatted as a table, while Arabic languages necessitate right-to-left text.
00:08:08.210 You can use this optimization with partials, allowing small pieces of localized text to be reused across different views, especially in mailers that require translation.
00:08:28.900 There will be instances where certain languages share common words or phrases, but there are variations depending on the region. For instance, there's a distinct difference in vocabulary among Spanish spoken in Spain, Mexico, or Argentina.
00:08:48.560 To manage this, configuration fallbacks in your application.rb file allow Rails to use one locale and then search for the next, if needed. This minimizes duplication of translations across multiple language files.
00:09:07.490 For example, you could define preferred English terms and when the British English fails to find a match, it will revert to standardized English. This is equally applicable when fine-tuning language differences in Spanish.
00:09:29.580 Now, let's discuss pluralization and best practices. It’s common to require different vernacular depending on whether the count is zero, one, or multiple. For example, in some user interfaces, you need phrases that reflect these count distinctions, like 'no items,' 'one item,' or 'multiple items.'
00:09:49.360 A common mistake is to use if-else statements to determine the correct phrase to display based on the count. There’s a more effective way within i18n that allows you to define key conditions for specific counts by using pluralization keys.
00:10:10.300 Through this method, you can keep your translations organized and your code cleaner. Instead of cluttering the code with conditional logic, you pass the count variable to the 'T' function, allowing Rails to intelligently display the relevant phrase.
00:10:30.670 Next, while we’ve discussed using YAML files to store translations, it's not the sole method available. Various strategies exist for how you can store and retrieve translations depending on your application’s needs.
00:10:48.670 For instance, you can opt for an ActiveRecord back end where you will store locale keys and translations in a database table. This approach could lead to increased database queries but provides flexibility when needing to change translations dynamically.
00:11:07.709 Alternatively, you can add a gem to utilize Redis, MongoDB, or even roll your own solution to handle translation storage. However, make sure to select a backend that suits your application requirements.
00:11:24.120 Also, keep in mind that you can define chain backends in Rails to utilize multiple translation backends concurrently. By prioritizing where Rails looks for translations, you can offer flexible fallback options.
00:11:44.690 For example, if translations are not available in ActiveRecord, it may fallback to the default YAML or other defined backends, ensuring you have coverage across your application without duplicating data.
00:12:05.500 Additionally, you can localize time, dates, and numbers effectively using the built-in Rails functions. For datetimes, you can pass configurations for formatting in your translation files, which helps control how they appear across different locales.
00:12:24.310 Functions like 'time_ago_in_words' can also localize the time differences and generate appropriate strings dynamically based on the defined translations. It automatically handles the variations needed for different languages.
00:12:44.450 Similarly, number formatting can be effectively managed to ensure it complies with different regional standards for decimal points and separators, so all of your data remains user-friendly.
00:13:05.390 Keep in mind currency formatting, too! By utilizing the 'number_to_currency' function, you can dynamically modify how currency shows in your application, ensuring it aligns with locale preferences and formats.
00:13:27.340 Lastly, the 'number_to_human' function helps render large numbers as human-readable text based on your locale, which adds to the usability of your application.
00:13:50.410 As we recap, remember to split your YAML files, utilize the default lookup tree, and deploy debugging gems to improve your translation strategies. Always keep an eye on organization and don’t hesitate to roll your custom solutions to cater to unique requirements.
00:14:13.660 Thank you for your time, and I hope you can take these insights into your own Rails applications!