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

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.

Related

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

Locale fallbacks in Rails 4 not working

I am building a Rails 4 site for a client in Singapore, Malaysia, Taiwan and China.
The locale code for a Chinese speaking Malaysian is zh-MY.
I would like to keep a base zh-CN (Simplified Chinese) set of locale files and for zh-MY to fallback to zh-CN.
Just having a zh is not correct as zh-TW (Traditional Chinese) is what Taiwan uses and there are big differences between that and zh-CN.
So here's my config/application.rb file as per the Rails Guide.
require File.expand_path('../boot', __FILE__)
require 'rails/all'
require "i18n/backend/fallbacks"
module MyAwesomeApp
class Application < Rails::Application
I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks)
# all translations from config/locales/**/*.rb,yml are auto loaded.
config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}')]
# The default locale is :en
config.i18n.default_locale = :en
# See http://guides.rubyonrails.org/i18n.html#localized-views for a discussion of
# how language codes fall-back.
config.i18n.available_locales = [:en, :'zh-CN', :'zh-TW', :'en-SG', :'en-MY', :'zh-MY']
I18n.fallbacks.map(:'zh-MY' => :'zh-CN')
end
end
But this simply doesn't work.
When I actually set the locale to :zh-MY it does not fall back to :zh-CN but to :en
What am I missing?
update:
If I puts "I18n.fallbacks #{I18n.fallbacks}" it says I18n.fallbacks {}. Clearly I18n.fallbacks.map is failing.
update
As per the suggestion in the comments I looked at I18n.fallbacks[:'zh-MY'] in the very next line after I checked I18n.fallbacks and it returns [:"zh-MY", :zh, :"zh-CN", :en]
update
With a binding.pry in my application controller I have checked the locale etc and observe this:
[1] pry(#<ServicesController>)> I18n.locale
=> :"zh-MY"
[2] pry(#<ServicesController>)> I18n.fallbacks
=> {:en=>[:en], :"zh-MY"=>[:"zh-MY", :zh, :en]}
So somewhere between the Rails app starting up and the controller's set_locale method being called, I18n.fallbacks is being reset to the default.
Don't ask me why but this works, despite what the official docs say.
require File.expand_path('../boot', __FILE__)
require 'rails/all'
require "i18n/backend/fallbacks"
Bundler.require(*Rails.groups)
module MyAwesomeApp
class Application < Rails::Application
# all translations from config/locales/**/*.rb,yml are auto loaded.
config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}')]
# The default locale is :en
config.i18n.default_locale = :en
# See http://guides.rubyonrails.org/i18n.html#localized-views for a
# mostly correct discussion of how language codes fall-back.
config.i18n.available_locales = [:en, :'zh-CN', :'zh-TW', :'en-SG', :'en-MY', :'zh-MY']
config.i18n.fallbacks = {:'zh-MY' => :'zh-CN'}
end
end
Removing the I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks) and setting the fallbacks via config.i18n.fallbacks = {:'zh-MY' => :'zh-CN'} rather than I18n.fallbacks.map(:'zh-MY' => :'zh-CN') makes it all work perfectly.
And now in my controller, at the same breakpoint as discussed in the 3rd question update:
[1] pry(#<ServicesController>)> I18n.fallbacks
=> {:en=>[:en], :"zh-MY"=>[:"zh-MY", :zh, :"zh-CN", :en]}
I hope this is helpful to others.

How to configure locale aliases using i18n & 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.

Rails does not permit changing locale

I'm trying to change the locale that my rails (4.1.4) application is using, but every time I try to change it in the console using commands such as
I18n.locale = :es
I18n.default_locale = :de
an I18n::InvalidLocale error is brought up. This is the case for every locale I test, including regional ones such as :en-US. This is true even if I have a *.yml file set up for that locale. The only one that works is :en, which is the default for me.
I feel like this should be something pretty basic as all the resources I find seem to skip past this as a given, but it's not working for me and I can't figure out where to look for the problem source.
Did you add the new locale in application.rb ?
config.i18n.enforce_available_locales = false
config.i18n.available_locales = [:en, :es, :de]
config.i18n.default_locale = :de
You also have to create the files en.yml , es.yml and de.yml in your config/locale folder.
Thanks! When I looked in that file, I realized that in addition to the answer you gave, Rails provides it's own solution commented out -
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
So basically it takes a translation file such as pt-br.yml and adds that to the list of valid locales.
Make sure you have added es.yml and de.yml to the config/locales folder.

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