Supporting different locale regions using Rails i18n - ruby-on-rails

I'm using the standard Rails I18n API to localise some of our views. This is working really well, but we now have a few use cases for regional changes to the en locale.
The API guide mentions that this isn't supported directly, and other plugins should be used. However, I'm wondering whether there's a simpler way to do this.
I already have en.yml, so in theory I could just create en-AU.yml and en-US.yml which are effectively clones of en.yml but with a few regional changes applied. I could then add additional English - American and English - Australian options to our configuration which would map to the new region-specific locales and allow users to use a region-specific locale.
The only problem I can think of with this is that it isn't DRY -- I would have duplicate translations for all common English words. I can't see a way around this.
Are there any other disadvantages to this approach, or should I just bite the bullet and dive into one of the plug-ins such as Globalize2 instead?

The rails-i18n-translation-inheritance-helper is getting a bit old now, so here's my approach for a Rails 3.2 project.
If you keep both en-US and en-AU in the same en.yml file you can use the yml repeated node to have a super en section:
For example:
en: &en
errors:
messages:
expired: "has expired, please request a new one"
not_found: "not found"
en-US:
<<: *en
en-AU:
<<: *en
errors:
messages:
not_found: "tis not found"

I'm using translation inheritance helper plugin for this.

In newer versions of Rails/i18n, they've added a fallback feature. Works similar to the outdated translation inheritance helper gem
see this answer for more info: Fall back to default language if translation missing

Related

How to selectively deactivate Rails I18n translation_missing spans?

In my Rails 5.2 app, almost all my UI, except the Admin area, is internationalized using t(). The "translation missing" spans often break the layout, but I figure that's a price worth paying in order to know when I may have misspelled a key or not committed a file or something. There is one place where the spans really don't work however, and that is when it comes to the self-described roles people have in my Groups. The roles can be pre-defined strings that are part of my en.yml, like "coordinator", "treasurer" and so on, but they can also be write-ins, like "minister of awesome". So doing t("groups.roles." + role) doesn't work because the "translation missing" span messes up the layout. This wasn't a problem in previous version of Rails because the "translation missing" spans were automatically disabled for the production environment and only the last part of the key was displayed, i.e. exactly the functionality I want here. In Rails 5.2 the spans also show up in production and this is a problem, at least for this part.
The functionality I'd really want, which used to be standard, is:
If the translation exists, display it.
If the translation doesn't exist, display the English string from en.yml (English is defined as a fallback language)
If the English doesn't exist either, display the final part of the key. With "translation missing" spans in development, without them in production.
I browsed all the answers on here about how to disable these error messages in production and the suggested solutions seem geared at Rails 4 or don't work. Or they have the side effect of deactivating fallback translations, which is an unacceptable trade-off for me because I need English fallbacks for much of my app. Overwriting or extending the TranslationHelper seems like a momentous task, especially since I'd only want the spans removed in production (like it used to work). So for my case and for now, I've decided against doing a complete override and I only changed the helper in the one place where I expect to have missing translations that are not a problem:
def human_role(role)
str = t("groups.roles." + role)
if str.include?("translation missing")
role
else
str
end
end
You can use :default option like this:
t("groups.roles.#{role}", default: role)
And if you want to have "translation missing" in development, without them in production (it's ugly a little):
t("groups.roles.#{role}", default: Rails.env.development? ? "#{role} translation missing" : role)

Rails language name using I18n locale

I want to match the locale code to the specific language name. Is there any build in function in I18n/rails which would return the language name to the corresponding locales. Is installing a gem is the only way?
It seems there is no method for this in I18n.
If you just need current language name, you can easily include it in corresponding locale file:
# config/locales/en.yml
en:
language_name: "English"
And get it as usual: I18n.t('language_name') or I18n.t('language_name', locale: :en).
For general purposes you could use: https://github.com/hexorx/countries or initialize your own mapping as a ruby hash: { en: 'English', ... }.
Without installing an additional gem, you could make your own key/value pairs (either store it in a json file or store it to DB) and then lookup key eg "de" and read the value (in this case, "German"). It requires a bit of manual work (or setup a rake task or something to build it for you in appropriate format from some info source) but you aren't dependent on an additional gem in that case (which, without going thoroughly through the code, might have a far greater impact on your app performance/memory wise than your custom implementation for your specific need for all you know).
I am not aware of any rails built in functions that would return the entire language name, though. You can return the language abbreviation (eg for use in html lang attribute), but I think it stops there as far as the built in functions are concerned).
Have a look the following post in google groups (Gist). I hope there is no default support for the required conversion in rails.

Multi language with Rails app to prepare YML file

I am building a car rental app with Ruby on Rails and currently I have been coding with English. Basically I have an user and car model, where user can login, sign in, log out and list their car.
I would like to implement another language allowing the user to select English or Spanish from a dropdown. I have default error messages returns from the controller actions such as "can't be blank, already used" etc. And I also have custom JS messages, such as if user successfully adds a car, jQuery returns "your car has been published". Lastly, I also have Flash messages. But I do not know how should I handle errors, custom JS and Flash messages in the YML file according to user's language selection.
It actually really depends on the structure of your YAML file, for example, for ActiveRecord error messages:
it:
errors:
format: "%{attribute} %{message}"
messages: &errors_messages
empty: "non può essere vuoto"
blank: "non può essere lasciato in bianco"
If you want to access I18n (a.k.a Internationalization) outside of views, you can use I18n.t(your_key), which is in fact the helper you have access to in your views. So for example, if you wish to translate a notice in a controller you could be doing something like:
def your_action
redirect_to other_path, notice: I18n.t("notices.successful_action")
end
And then having in your YAML the correspondent structure:
en:
notices:
successful_action: "You did it!"
Hope this helps!
I do not know how should I handle error, custom js and flash messages in yml file according to user's language selection
For Rails app-related translations in general, including error messages, the Rails i18n gem has you covered. You can see what languages have been translated in the gem's locale file.
For specifically overriding error messages or creating new ones, see The Rails Guide sections on looking up translations and translations for ActiveRecord models to see what keys in your YAML files you should be putting your translations under.
For flash messages, have a look at this StackOverflow question to see how you can use lazy lookups (eg t('.notice')) in your controllers.
For the ability to use translations in Javascript files in the same way you do in Ruby (eg I18n.t("my_translation"), and be able to manage those translations in your YAML files with the rest of your Rails translations, have a look at the i18n-js gem. Setup instructions are in the README file.

Developing a Rails app in a language other than english

So I'm building a new rails app and it's end users will all be spanish speakers. I figured I should use rails' I18n API but it feels like this is meant for translating an app that's already written in english. What I mean by that is that internally rails looks things up (models, table names, routes) with the english locale. Thus it feels weird to name your models in spanish if they are not going to be pluralized correctly when creating the schema.
Anyone has best practices for this kind of situation? Should I just name everything in english and then map the translations on the es.yml file?
Even though the application should be viewed by spanish end users, you are probably better off coding it in english. This means writing english ruby code, english routes, english models etc. The only thing that should be spanish is the text on your web sites.
Some reasons:
All reserved words in ruby are english.
Libraries/Framework use english naming.
Pluralization etc. is in english.
Better chance of getting help on StackOverflow if the code snippet is in english.
You never know, maybe someday it will turn into a collaboration project with non spanish speaking developers.
As for the i18n api, you may skip using it for now if you only should present the site content in one language.
Write your code (and translation keys) in whatever language you prefer and use your es.yml for the translated language.
Here's an example of how you'd use I18n throughout your app:
app/controllers/things_controller.rb
def create
thing = Thing.new(params[:id])
if thing.save
redirect_to thing, notice: t('cosa.crear.prosperidad')
else
flash.now.alert = t('cosa.crear.fracaso')
end
end
app/views/things/index.html.erb
<h1><%= t('cosa.texto_de_ayuda') %></h1>
config/locales/es.yml
es:
cosa:
texto_de_ayuda: "Necesita ayuda para la creación de las cosas?"
crear:
prosperidad: "Cosa fue creado con éxito"
fracaso: "Hubo un problema al crear su cosa"
There's no golden rule, but I think code should be written in English (even if you start writing in Spanish you may mix Spanish and English words and make a mess in your code).
About the i18n, you should use it not only for translating your app from a language to another, but also to specify textual elements that will be shown to the user. Hence you can have all that content organized into an unique file. It's better for maintenance and code organization and you can specify the default language (.yml file) that Rails should use.

Plugin to use Ruby on Rails Simple I18n backend with translations overridable in the database?

Hoping some learned Rails developers here can recommend an existing Ruby on Rails plugin or gem that allows you to continue using the Simple I18n backend whilst allowing you to optionally specify translations in the database.
Here's why:
I have one Rails app used for many websites. For the example I'll just use 2 websites:
Website 1: Leprechauns R Us
Website 2: Unicorns R Us
Most translations are the same for both websites, but occassionally I want to override a translation. For example, in my en-US.yml file I have the following translation:
view_all: View all
And for most websites this translation is fine, including for website 1 (Leprechauns) where I'm happy to use "View all".
However, for website 2, I'd like to use "View all Unicorns" as the view_all translation and I'd like to specify this in the database. For maintenance reasons I don't want to specify this override in a YAML file.
Many thanks,
Eliot
In the end I opted to take advantage of Rails' I18n::Backend::Simple's ability to process both .yml files and .rb files as locale dictionaries.
Artifacts created:
DB migration to create a translations table with columns: locale, key, text
Translation model to map to the translations table
Class method to_locale_hash on Translation model that returns a locale keyed hash as required by I18n::Backend::Simple.load_rb
A single-line file located at config/translations.rb with the line 'Translation.to_locale_hash'
For the source code see the Spree extension (sorry not in a Rails plugin structure, it will be easy to move over to a plugin should you require it) here:
http://github.com/eliotsykes/spree-i18n-db/tree/master

Resources