How to configure locale aliases using i18n & rails? - ruby-on-rails

I am working on a rails app (3.2.13) that is being translated into several languages, including (one of the 3 available flavours of) Norwegian. On public pages, the app uses the browser's language settings to set locale.
Most browsers offer 3 separate Norwegian shortcodes: no, nb & nn. The translations we have are in nb, but I think it would be best if no & nn also defaulted to nb. That way, if a user's browser language preferences were set to no then en, the app would try to supply nb Norwegian first, instead of skipping straight to English.
Is it possible to configure a list of "language aliases" for the i18n gem, something like this?
config.i18n.available_locales = [:sv, :en, :nb, :da, :fi]
config.i18n.aliased_locales = [:nb <= :no, :nb <= :nn]

Short answer
Take a look to the fallbacks
Create a file in initializers like i18n_fallbacks.rb
config.i18n.fallbacks = {:no => [:nb], :nn => [:nb]}
Here the reference
Things related
You can even set multiple fallbacks, and they will be taken in the same order as specified:
for instance:
config.i18n.default_locale = :de
config.i18n.fallbacks = {:de => [:en,:es]}
de.yml
:de:
greeting: Hallo
en.yml
:en:
foo: bar
es.yml
:es:
bar: baz
You get the following:
I18n.t :greeting # found in de.yml, no fallback
# => 'Hallo'
I18n.t :foo # not in :de, try in :en and found
# => "bar"
I18n.t :bar # not in :de, try in :en and in :es
# => "baz"
I81n.t :other # not found anywhere, note the message delivers not found for the current locale:
# => "translation missing: de.other"

In latest i18n gem (0.7.0) I have found it necessary to define fallback locales like this (in config/application.rb):
# Custom I18n fallbacks
config.after_initialize do
I18n.fallbacks = I18n::Locale::Fallbacks.new(at: :"de-DE", ch: :"de-DE", gb: :"en-US")
end
You also need to set config.i18n.fallbacks = true in all config/environments/*.rb files.

Related

I18n.t falls back to key instead to default locale

In my frontend non-translated strings are replaced with word form of their key instead of the translation of base language.
That means that changing locale to :en or :tr both shows Summaries Header for t('activerecord.misc.badge.summaries_header') instead of Auswertungen from German locale. So it's obviously build from the last part of the key. Summaries Header does not appear as Label in any locale.
Other in :en/:tr translated strings are shown correctly.
# config/application.rb
config.i18n.default_locale = :de
config.i18n.available_locales = [
:de, # Deutsch
:pt, # Portugiesisch
:en, # Englisch
:tr, # Türkisch
]
config.i18n.fallbacks = true
# Versions
ruby 2.7.2
rails 5.2.4.4
i18n 1.8.6
rails-i18n 5.1.3
I can't find the reason for that behavior and I can't figure out which update at which time broke this.
How can I fix this?
TL;DR: Update to i18n v1.8.7 or higher with bundle update i18n
i18n v1.8.6 was broken regarding getting fallbacks from config.i18n.* into Thread variables.
See i18n issue #546 and changelog for v1.8.7

Unclear how to use "config.i18n.fallbacks" in Rails 5

I want the translations on my website to fallback to English when a translation isn't found. How to do that?
There're 2 ways I know of, but it's unclear which should be used with Rails 5 and which has already become deprecated:
## config/appplication.rb
# 1
config.i18n.fallbacks = [:de, :fr, :en]
# 2
config.i18n.fallbacks = true
There's nothing about that in the documentation either.
config.i18n.default_locale = :de
config.i18n.available_locales = [:de, :en, :fr]
config.i18n.fallbacks = [:en, :de]
That means. If someone uses French, and a translation is missing, the fallback is English, when the English translation is also blank, then i18n returns German.
If you're not sure, I always recommend to look into the source code.
def self.init_fallbacks(fallbacks)
include_fallbacks_module
args = \
case fallbacks
when ActiveSupport::OrderedOptions
[*(fallbacks[:defaults] || []) << fallbacks[:map]].compact
when Hash, Array
Array.wrap(fallbacks)
else # TrueClass
[I18n.default_locale]
end
I18n.fallbacks = I18n::Locale::Fallbacks.new(*args)
end
With this in mind, we know now
# sets the fallback to the default local
config.i18n.fallbacks = true
# sets several fallbacks
config.i18n.fallbacks = [:en, :de]
https://github.com/rails/rails/blob/master/activesupport/lib/active_support/i18n_railtie.rb#L92-L106
https://github.com/ruby-i18n/i18n/blob/master/lib/i18n/locale/fallbacks.rb#L27-L51

How to add a region specific Locale to Rails?

I am trying to add a US region specific locale to rails, however tells me that :en_locale is not a valid code for a locale. How can I include this specific region?
In app/config/locales, I have en.yml and en-US.yml.
My application.rb, I have the following:
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
# config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '*.{rb,yml}').to_s]
config.i18n.available_locales = [:en, :'en-US']
config.i18n.default_locale = :en
config.i18n.fallbacks = [:en]
# config.i18n.fallbacks = {:'zh-MY' => :'zh-CN'} # If we want to designate a lang to fallback to
Error Message:
I18n::InvalidLocale - :en_us is not a valid locale:
i18n (0.6.9) lib/i18n.rb:288:in `enforce_available_locales!'
i18n (0.6.9) lib/i18n/config.rb:11:in `locale='
actionview (4.1.14.2) lib/action_view/lookup_context.rb:239:in `locale='
actionview (4.1.14.2) lib/action_view/rendering.rb:19:in `locale='
i18n (0.6.9) lib/i18n.rb:35:in `locale='
The i18n library takes a pragmatic approach to locale keys (after some
discussion), including only the locale ("language") part, like :en,
:pl, not the region part, like :en-US or :en-GB, which are
traditionally used for separating "languages" and "regional setting"
or "dialects". Many international applications use only the "language"
element of a locale such as :cs, :th or :es (for Czech, Thai and
Spanish). However, there are also regional differences within
different language groups that may be important. For instance, in the
:en-US locale you would have $ as a currency symbol, while in :en-GB,
you would have £. Nothing stops you from separating regional and other
settings in this way: you just have to provide full "English - United
Kingdom" locale in a :en-GB dictionary. Few gems such as Globalize3
may help you implement it.
~Rails Guides

Is it possible to make rails i18n locales fallback to each other?

I'm using Rails 3 with Globalize3 0.2.0.beta4
Ideally I need :fr to fallback to :en and vice versa.
There are cases when only a French translation is available and I need to show it even if the locale is :en.
I tried
config.i18n.fallbacks = { :fr => :en, :en => :fr }
but somewhat unsurprisingly it causes a stack level too deep error.
I'm changing my answer.
To enable fallbacks, add the following to your environment.rb file:
#support for locale fallbacks
require "i18n/backend/fallbacks"
I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks)
Then, you can enable circular fallbacks like you were trying to, eg:
config.i18n.fallbacks = {'en' => 'fr', 'fr' => 'en'}
In this case, if something is missing in the en locale, it'll check the fr locale, and then the other way around. I don't get any errors running this.
Source: http://batsov.com/articles/2012/09/12/setting-up-fallback-locale-s-in-rails-3/
If you pass an array of locales they will be set as default fallbacks for all locales.
config.i18n.fallbacks = [:en, :fr]
Unfortunately, I haven't found a way to set up just two locales to fall back to each other.
In the end I monkey patched Globalize3. Not great as I have to update the patch whenever the site needs a new locale, but hey, it worked.
module Globalize
class << self
def fallbacks(locale = self.locale)
case locale
when :en then [:en, :fr]
when :fr then [:fr, :en]
end
end
end
end
This seems to have changed to this:
Globalize.fallbacks = {:en => [:en, :fr], :fr => [:fr, :en]}
Got from the official docs:
https://github.com/globalize/globalize#fallback-locales-to-each-other
In latest i18n gem (0.7.0) I have found it necessary to define fallback locales like this (in config/application.rb):
# Custom I18n fallbacks
config.after_initialize do
I18n.fallbacks = I18n::Locale::Fallbacks.new(at: :"de-DE", ch: :"de-DE", gb: :"en-US")
end
You also need to set config.i18n.fallbacks = true in all config/environments/*.rb files.

How to use the I18n fallback features in Rails 3

I am getting an "translation missing" error message from Rails 3:
activerecord:
notices:
messages:
success:
create: "Something was created"
models:
user:
success:
create: "Thanks for registration"
I18n.t("activerecord.notices.models.user.success.create")
# => "Thanks for registration"
I18n.t("activerecord.notices.models.book.success.create")
# => "translation missing: de, activerecord, notices, models, book, success, create"
I don't know why the book model doesn't get the fallback massage. I have set config.i18n.fallbacks = true.
I set in config/application.rb usually
config.i18n.fallbacks = [:de, :fr, :en]
So you can declare the order of the fallback.
But keep attention in some environments/*.rb the configuration is overwritten.
When a :default option is given, its value will be returned if the translation is missing:
I18n.t :missing, :default => 'Not here'
# => 'Not here'
More info here
In rails 3+, this is set in the config/environments files :
# Enable locale fallbacks for I18n (makes lookups for any locale fall back to
# the I18n.default_locale when a translation can not be found)
config.i18n.fallbacks = true
[Answer is for Rails 2]
Have you enabled fallbacks for your backend? Assuming it's Simple(based on yml in example):
Put this in an initializer:
require "i18n/backend/fallbacks"
I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks)
https://github.com/svenfuchs/i18n/wiki/Fallbacks
I believe the best way to handle a missing string, is to display a default locale, rather than an error message.
Add this line in application.rb to fallback to the english locale.
config.i18n.fallbacks = [:en]
In case you want to specify locale-specific fallbacks, you can use the following:
config.i18n.fallbacks = {:de => [:de,:en], :en => [:en,:de]}
Also, note that you can enable and disable fallbacks based on your environment.
So while on development it might make sense to have an error displayed, you can instead enable fallbacks in your environments/production.rb with the following:
config.i18n.fallbacks = true
There is a misunderstanding with the I18n Fallback feature.
This feature causes that when there is a missing translation exception (in this case, it happens when I18n fails to find the value associated with the "activerecord.notices.models.book.success.create" key in the locale files of your current language) I18n will lookup in the predefined list of fallbacks languages the value of the key that generated the missing translation exception, if it's found I18n will returned that value, but if it's not found in any of those other locale files I18n will return the missing translation exception.
So when you defined config.i18n.fallbacks = true, that doesn't mean that when a missing translation exception occurs, in this case:
I18n.t("activerecord.models.book.success.create")
# => "translation missing: de, activerecord, notices, models, book, success, create"
I18n will lookup a similar key in your locale files to return his value, could be:
I18n.t("activerecord.models.user.success.create")
# => "Thanks for registration"
What will happens it's that I18n will lookup in yours defaults fallback languages for the specific language where the missing translation exception has occurred.
A good example of usage will be:
# using :"en-US" as a default locale:
I18n.default_locale = :"en-US"
I18n.fallbacks[:es] # => [:es, :"en-US", :en]
Locales files:
es:
activerecord:
notices:
messages:
success:
create: "Algo fue creado"
models:
user:
success:
create: "Gracias por registrarte"
en-US:
activerecord:
...
models:
books:
success:
create: "The model was created"
Call in English site:
I18n.t("activerecord.models.books.success.create")
# => "The model was created"
Call in Spanish site:
#with config.i18n.fallbacks = false
I18n.t("activerecord.models.books.success.create")
# => "translation missing: es, activerecord, models, book, success, create"
#with config.i18n.fallbacks = true
I18n.t("activerecord.models.books.success.create")
# => "The model was created"
For more information check: https://github.com/ruby-i18n/i18n

Resources