Temporary disable i18n fallback in Rails - ruby-on-rails

I18n fallback is loaded:
I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks)
Any idea now to temporary disable it? I have forms, where I want to edit various language versions, and with fallback I am getting fields with default language, if given translation is yet not present.

You can pass the fallback: true option to I18n.t, which will prevent I18n from looking up other locales (see implementation here). But it's probably not part of the public API...

You can pass :fallback => 'false' on your I18n.translate calls, but this is not part of the public API.
Another way you might want to try is the following:
I18n.available_locales.each do
|al| I18n.fallbacks.merge!({al => [al]})
end
This will basically make the fallback for each available locale to include only itself. So, if the translation is not found in itself, then there is not fallback to fall back to.
However, then you need to find a way to restore to the default fallback.
You can do that for example with a statement like:
I18n.available_locales.each do
|al| I18n.fallbacks.merge!({al => [al, I18n.default_locale]})
end

if anyone is still wondering how to do that, you can change the I18n.fallbacks on the fly:
def foo
I18n.fallbacks[:at] = [:at]
# do stuff with I18n#t
ensure
I18n.fallbacks[:at] = [:at, :de] # or whatever is was before
end
Not sure how safe is that though.

Are you using globalize?
I'm using I18n fallback for my system strings, and globalize3 for my attribute translations. I want system strings to fallback, but not attributes. I simply disabled fallbacks for globalize only with a small monkey patch:
config/initializers/i18n.rb:
require "i18n/backend/fallbacks"
I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks)
# monkey patch globalize3 to not use fallbacks
module Globalize
def self.fallbacks?
false
end
end

Related

Rails I18n validation deprecation warning

I just updated to rails 4.0.2 and I'm getting this warning:
[deprecated] I18n.enforce_available_locales will default to true in the future. If you really want to skip validation of your locale you can set I18n.enforce_available_locales = false to avoid this message.
Is there any security issue in setting it to false?
Important: Make sure your app is not using I18n 0.6.8, it has a bug that prevents the configuration to be set correctly.
Short answer
In order to silence the warning edit the application.rb file and include the following line inside the Rails::Application body
config.i18n.enforce_available_locales = true
The possible values are:
false: if you
want to skip the locale validation
don't care about locales
true: if you
want the application to raise an error if an invalid locale is passed (or)
want to default to the new Rails behaviors (or)
care about locale validation
Note:
The old default behavior corresponds to false, not true.
If you are setting the config.i18n.default_locale configuration or other i18n settings, make sure to do it after setting the config.i18n.enforce_available_locales setting.
If your use third party gems that include I18n features, setting the variable through the Application config object, may not have an effect. In this case, set it directly to I18n using I18n.config.enforce_available_locales.
Caveats
Example
require File.expand_path('../boot', __FILE__)
# ...
module YouApplication
class Application < Rails::Application
# ...
config.i18n.enforce_available_locales = true
# or if one of your gem compete for pre-loading, use
I18n.config.enforce_available_locales = true
# ...
end
end
Long answer
The deprecation warning is now displayed both in Rails 4 (>= 4.0.2) and Rails 3.2 (>= 3.2.14). The reason is explained in this commit.
Enforce available locales
When I18n.config.enforce_available_locales is true we'll raise an
I18n::InvalidLocale exception if the passed locale is unavailable.
The default is set to nil which will display a deprecation error.
If set to false we'll skip enforcing available locales altogether (old behaviour).
This has been implemented in the following methods :
I18n.config.default_locale=
I18n.config.locale=
I18n.translate
I18n.localize
I18n.transliterate
Before this change, if you passed an unsupported locale, Rails would silently switch to it if the locale is valid (i.e. if there is a corresponding locale file in the /config/locales folder), otherwise the locale would default to the config.i18n.default_locale configuration (which defaults to :en).
The new version of the I18n gem, forces developers to be a little bit more conscious of the locale management.
In the future, the behavior will change and if a locale is invalid, the Rails app will raise an error.
In preparation of such change (that may potentially break several applications that until today were relying on silent defaults), the warning is forcing you to explicitly declare which validation you want to perform, during the current transition period.
To restore the previous behavior, simply set the following configuration to false
config.i18n.enforce_available_locales = false
otherwise, set it to true to match the new Rails defaults or if you want to be more rigid on domain validation and avoid switching to the default in case of invalid locale.
config.i18n.enforce_available_locales = true
Caveat
If you are setting the config.i18n.default_locale configuration or using any of the previously mentioned methods (default_locale=, locale=, translate, etc), make sure to do it after setting the config.i18n.enforce_available_locales setting. Otherwise, the deprecation warning will keep on popping up. (Thanks Fábio Batista).
If you use third party gems that include I18n features, setting the variable through may not have effect. In fact, the issue is the same as described in the previous point, just a little bit harder to debug.
This issue is a matter of precedence. When you set the config in your Rails app, the value is not immediately assigned to the I18n gem. Rails stores each config in an internal object, loads the dependencies (Railties and third party gems) and then it passes the configuration to the target classes. If you use a gem (or Rails plugin) that calls any of the I18n methods before the config is assigned to I18n, then you'll get the warning.
In this case, you need to skip the Rails stack and set the config immediately to the I18n gem by calling
I18n.config.enforce_available_locales = true
instead of
config.i18n.enforce_available_locales = true
The issue is easy to prove. Try to generate a new empty Rails app and you will see that setting config.i18n in the application.rb works fine.
If in your app it does not, there is an easy way to debug the culprit. Locate the i18n gem in your system, open the i18n.rb file and edit the method enforce_available_locales! to include the statement puts caller.inspect.
This will cause the method to print the stacktrace whenever invoked. You will be able to determine which gem is calling it by inspecting the stacktrace (in my case it was Authlogic).
["/Users/weppos/.rvm/gems/ruby-2.0.0-p247#application/gems/i18n-0.6.9/lib/i18n.rb:150:in `translate'",
"/Users/weppos/.rvm/gems/ruby-2.0.0-p247#application/gems/authlogic-3.1.0/lib/authlogic/i18n/translator.rb:8:in `translate'",
"/Users/weppos/.rvm/gems/ruby-2.0.0-p247#application/gems/authlogic-3.1.0/lib/authlogic/i18n.rb:79:in `translate'",
"/Users/weppos/.rvm/gems/ruby-2.0.0-p247#application/gems/authlogic-3.1.0/lib/authlogic/acts_as_authentic/email.rb:68:in `validates_format_of_email_field_options'",
"/Users/weppos/.rvm/gems/ruby-2.0.0-p247#application/gems/authlogic-3.1.0/lib/authlogic/acts_as_authentic/email.rb:102:in `block in included'",
"/Users/weppos/.rvm/gems/ruby-2.0.0-p247#application/gems/authlogic-3.1.0/lib/authlogic/acts_as_authentic/email.rb:99:in `class_eval'",
"/Users/weppos/.rvm/gems/ruby-2.0.0-p247#application/gems/authlogic-3.1.0/lib/authlogic/acts_as_authentic/email.rb:99:in `included'",
"/Users/weppos/.rvm/gems/ruby-2.0.0-p247#application/gems/authlogic-3.1.0/lib/authlogic/acts_as_authentic/base.rb:37:in `include'",
"/Users/weppos/.rvm/gems/ruby-2.0.0-p247#application/gems/authlogic-3.1.0/lib/authlogic/acts_as_authentic/base.rb:37:in `block in acts_as_authentic'",
"/Users/weppos/.rvm/gems/ruby-2.0.0-p247#application/gems/authlogic-3.1.0/lib/authlogic/acts_as_authentic/base.rb:37:in `each'",
"/Users/weppos/.rvm/gems/ruby-2.0.0-p247#application/gems/authlogic-3.1.0/lib/authlogic/acts_as_authentic/base.rb:37:in `acts_as_authentic'",
"/Users/weppos/Projects/application/app/models/user.rb:8:in `<class:User>'",
"/Users/weppos/Projects/application/app/models/user.rb:1:in `<top (required)>'",
Just for completeness, note that you can also get rid of the warning by setting I18n.enforce_available_locales to true (or false) in config/application.rb:
require File.expand_path('../boot', __FILE__)
.
.
.
module SampleApp
class Application < Rails::Application
.
.
.
I18n.enforce_available_locales = true
.
.
.
end
end
I18n.config.enforce_available_locales = true worked for me in Rails 3.2.16 (I put it in config/application.rb)
Doesn't seem that way - that'd be previous behavior of the way i18n works - new behavior (true) will raise an error when you ask for a locale not implemented/available.
See the commit that added this warning: https://github.com/svenfuchs/i18n/commit/3b6e56e06fd70f6e4507996b017238505e66608c
If you want to care about locales write into appilcation.rb file.
config.i18n.enforce_available_locales = true
You can write false if locale validation and do not care about that.

rails: how can I override a locale based on subdomain?

I have internationalized and localized my application using the standard rails mechanisms.
Everything is stored in en, fr, de.yml files.
My application is multi-tenant, based on the subdomain.
I would like to allow my users to override certain translations in the application (e.g. to change "Employee" to "Associate" because it matches their own terminology).
I've tried to change the load path of my yml files on a per-request basis, but to no avail.
Any idea how I could, for each request, look up first in my user-specific yaml file, and fall back to the default yaml file if the translation was not overriden?
Assuming you store the subdomain in an instance variable from a controller filter, you could override the translation helper to do a lookup with a subdomain-specific scope first, then fallback to the specified or default scope. Something like this:
module ApplicationHelper
def t(key, original_options = {})
options = original_options.dup
site_translation_scope = ['subdomain_overrides', #subdomain.name]
scope =
case options[:scope]
when nil
site_translation_scope
when Array
options[:scope] = site_translation_scope + options[:scope]
when String
[site_translation_scope, options[:scope]].join(".")
end
translate(key, options.merge(:scope => scope, :raise => true))
rescue I18n::MissingTranslationData
translate(key, original_options)
end
end
Then you add your subdomain-specific overrides likes this:
en:
customer: Customer
subdomain_overrides:
subdomain_1:
customer: Buyer
If you want to allow tenants to use specific language but fallback to the default, I have written a micro library that will get the job done:
https://github.com/ElMassimo/i18n_multitenant
It takes care of configuring I18n to fallback to the base locale, allowing you to use tenant-specific translations if available. It's designed to work with the default backend of static .yml files, but it should also work with other I18n backends.
I've recently created I18n_global_scope gem that does exactly what you are describing, please checkout the source code https://github.com/mobilityhouse/i18n_global_scope and let me know your feedback.

Any way to temporarily disable I18n fallbacks / Globalize3 translations?

I'm trying to implement fallbacks for translated attributes using Globalize3 and I18n fallbacks. To get fallbacks up and running, I added to my environment.rb file:
#support for locale fallbacks
require "i18n/backend/fallbacks"
I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks)
And then in my config file:
config.i18n.fallbacks = {'en-US' => 'zh-CN', 'zh-CN' => 'en-US'}
Now I have an app running where, if a field is not translated in the 'en-US' locale, it'll fall back on the 'zh-CN' locale, and vice versa.
However, this means that the fallback also occurs on forms on the site. This is undesired behaviour for two reasons:
Users might think that this means that this locale has this value for the input being seen (whereas it was inherited from the fallback locale).
Saving a form with these inherited values actually saves the translations as the current locale's values - so then all of a sudden you've got data on both locales, but the user may not know this (or know why).
I'd like to disable the fallbacks while on edit pages / in forms showing objects with translated attributes. Is there any way to do this?
I'm using versions of Globalize3 and I18n from svenfuchs https://github.com/svenfuchs/globalize3

Locale fallback from country to language without having to define each individually

I am localizing an app with the default rails I18n with globalize3 as the back-end.
Is it possible to set a locale with a country code (ie :fr-CA) to fallback to its specific language (:fr) before going to the default fallback automatically? I know its possible to set each locale/country manually with
config.i18n.fallbacks = {'fr-CA' => 'fr'}
But it would be nice to not have to add each fallback manually and have this behaviour automatic.
To achieve precisely this I have an initializer with
I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks)
See the source code for more info.
Edit:
This reminds me, there is an annoying bug in the ActionView LookupContext which prevents this from working for localized views (though it works correcly for locale files). I see it still hasn't been fixed. Basically, if you have any localized views (help pages for example, which are unsuitable to store in locale files due to their length) then a fr-CA locale will not fall back to a view called help.fr.html.erb. You either have to name the file help.fr-CA.html.erb or, which is what I have done, monkeypatch the LookupContext with another initializer, sort of like this:
module ActionView
class LookupContext
# Override locale= to also set the I18n.locale. If the current I18n.config object responds
# to original_config, it means that it's has a copy of the original I18n configuration and it's
# acting as proxy, which we need to skip.
def locale=(value)
if value
config = I18n.config.respond_to?(:original_config) ? I18n.config.original_config : I18n.config
config.locale = value[0,2] # only use first part of the locale in lookups
end
super(#skip_default_locale ? I18n.locale : default_locale)
end
end
end
Another edit: Note that the patch is rather crude and breaks full locale lookups, going straight for just the language. If you need to also have fully matching views (language-REGION) you'll need to improve my code!

Internationalization Best Practices / Rails App

I am new to ruby & rails and have started building an application.
My goal is to build this in a way I can easily translate the contents of the rails app and display the website contents in a locale preferred by registered user.
Appreciate any inputs on some of the best practices or references to any documentation to read, to build a web application that can be easily translated?
Thanks,
Krish.
Check out the Rails Internationalization (I18n) API. It does everything you've described.
Also check out Globalize3, it became a standard for model translations. Very useful.
You can use ready_for_i18n plugin that convert your erb to desired form.It saves some time.
You'd definetely watch this talk: http://www.youtube.com/watch?v=CTu4iHWGDyE
Here are some tips or best practices I noted while working through Internationalization of a Rails app. (It's possible that some of them are now outdated).
Before I get into a list here's some clarification between localization and translation that was helpful to me:
Definitions:
App localization and model translations are separate concerns. Figure out which one of those (or both) it is, that you need.
The way I use them here:
App localization: Localization your app to a locale.
Model translation: Translation your model/data into a language.
Example: Give me the french translation (model translation) of the resource in my Spanish site (app localization)
I use Globalize for model translations.
Helpful Tips/ Best Practices:
Some of the following are clearly just helpful tips while working in the Context of Rails + Globalize, some of them might be more than that... possibly best practices.
I18n.locale refers to and sets the locale of the app. When using Globalize, Globalize.locale refers to and sets the locale for model/data translations.
Set both I18n.locale and Globalize.locale on every request. Since these variables are set in Thread, it will avoid some hard-to-replicate bugs.
Set Globalize.locale to I18n.locale right after setting I18n.locale. This allows for model translations to default to the locale of the app. (On my Spanish site, I expect data to be in Spanish, by default).
Change Globalize.locale (and notI18n.locale) to change model translation.
Reset I18n.locale and Globalize.locale after every test. In rspec
RSpec.configure do |config|
config.after(:each) do
I18n.locale = :en
Globalize.locale = :en
end
end
Either use subdomain, or subfolder in the url to refer to the locale of the app.
Use a language parameter to specify the language of the data.
When you work on your rails app, you will probably use default_url_options to use I18n.locale as the default locale parameter for your route / path helpers. However this doesn't work in tests. I picked up a solution from this github issue on rspec-rails.
I monkey patch ActionDispatch::Routing::RouteSet like so:
class ActionDispatch::Routing::RouteSet
def url_for_with_locale_fix(options={})
url_for_without_locale_fix(options.merge(:locale => I18n.locale))
end
alias_method_chain :url_for, :locale_fix
end
Set up a translate helper t as a wrapper around the I18n.t method
module I18nHelper
def t string, options = {}
I18n.t string, options
end
end
RSpec.configure do |config|
config.include I18nHelper
end
This is mini-pattern I use. You can check it out: http://developers-note.blogspot.com/2012/01/rails-i18n-good-practice.html

Resources