I found both methods to work but I don't want strange surprises: what' the difference between them? Can I use one or another without problems?
Both methods effectively do the same thing:
Record what the current locale is
Set the locale to the specified locale
Run the provided block of code
Set the locale back to the recorded locale
I18n will fetch translations from its locale files, whereas globalize will fetch translations from its database store.
Related
Is there way to get time_ago_in_words in different languages, or write locales?
Here’s my investigation:
time_ago_in_words calls distance_of_time_in_words (https://apidock.com/rails/ActionView/Helpers/DateHelper/distance_of_time_in_words)
The api docs for that method mention translations in the scope of datetime.distance_in_words.
If you look for distance_in_words in a default locale, such as this en.yml (https://github.com/svenfuchs/rails-i18n/blob/master/rails/locale/en.yml) you’ll see all the available translations in that space. You can redefine any of these in your locale file.
If, however, you’re just trying to change the language it uses, it seems I18n contains a great many default locales, you need to set the locale either as a default within your app, or from the locale defined in the browser.
To set the default for the app, you’ll need a line like this in config/application.rb
config.i18n.default_locale = :de
You can see the list of default locales here (use the part before .yml) https://github.com/svenfuchs/rails-i18n/tree/master/rails/locale
You can look at the rails i18 locale file en.yml https://github.com/svenfuchs/rails-i18n/blob/master/rails/locale/en.yml and can use their predefined translations. If you want to change the translations you can also override the en.yml file in your repository.
I am introducing a new locale to my application, and copy all existing files in config/locales/.locale1.yml to config/locales/.locale2.yml.
At first I expect that I18n.backend.send(:translations)['locale1'] would equal I18n.backend.send(:translations)['locale2'], but when I diff both hashes I realise that my new new 'locale2' is missing a bunch of translations.
I figure that for locale1 additional translations have been loaded from gems like for instance the popular rails-i18n gem.
As there is no (easy) way to find out in which .yml file a translation was defined, I want to get a list of all locale-files loaded from any gems.
Any suggestions how to get that information?
Even more interesting would be if I could actually implement a way to figure out from which file a translation was loaded, but I guess that would require writing a custom i18n backend that somehow stores where each key was loaded from.
After phrasing the question, it became quite clear what I need to search for: 'rails i18n load paths'.
By using:
Rails.configuration.i18n.load_path.select { |path| path.match('bundle/gems') }
I get close to what I need. Still not a list of what files are actually loaded or containing translations for the locale of interest, but at least a list of all gems that are considered by i18n.
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.
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
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!