I am seeing a strange issue about I18n. When i call my endpoint locally i am able to see all the available list of locales and the endpoint loads successfully.
(byebug) I18n.available_locales
[:en, :bg, :"ca-CAT", :ca, :"da-DK", :"de-AT", :"de-CH", :de, :"en-au-ocker", :"en-AU", :"en-BORK", :"en-CA", :"en-GB", :"en-IND", :"en-MS", :nep, :"en-NG", :"en-NZ", :"en-PAK", :"en-SG", :"en-UG", :"en-US", :"en-ZA", :"es-MX", :es, :fa, :"fi-FI", :fr, :he, :id, :it, :ja, :ko, :"nb-NO", :nl, :pl, :"pt-BR", :pt, :ru, :sk, :sv, :tr, :uk, :vi, :"zh-CN", :"zh-TW"]
We deployed our project to dev but we seeing the error en-US is not a valid locale so looks like its not loading all the locales on dev server.
It happens for other locales too e.g for de de is not a valid locale.
I searched online but i cant find the solution why this is happening.
Does anyone has any idea?
Try adding this to your application.rb
config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '*.{rb,yml}').to_s]
Have a look at this issue, it may help with this issue.
Related
Per the Rails 3.2 API Docs, to use different locales for number_to_currency, I need to do the following:
<%= number_to_currency(1234567890.506, :locale => :fr) %>
I was expecting the following output:
# => 1 234 567 890,51 €
Even though I literally use that exact thing within my app and it keeps outputting the following:
$1,234,567,890.51
When I check for the available_locales within my app I get the following:
> I18n.available_locales
=> [:en, :de, :es, :fr, :ja, :pl, :"pt-BR", :ru, :sv, :"zh-CN"]
So it SHOULD work, but it doesn't.
What am I missing?
Update 1
Per #s3tjan's comment, I did some digging in that linked Rails issue and that led me to my application.rb where I discovered I18n.enforce_available_locales = false. I changed that to true and restarted the server.
When I tried the above again, I am now getting this error:
ActionView::Template::Error (:fr is not a valid locale):
Not sure how to fix this.
Update 2
So I just realize that I never had a locale file in my config/locales. What I really want is to use the GBP Pounds for currency, so I added an en-GB.yml file in my config/locales, then I restarted my server and console.
In my application.rb, I have the following:
I18n.enforce_available_locales = true
Then I checked my console and got this:
[1] pry(main)> I18n.available_locales
=> [:en, :de, :es, :fr, :ja, :pl, :"pt-BR", :ru, :sv, :"zh-CN", :"en-GB"]
[2] pry(main)>
So the :"en-GB" was added successfully to my app's load path.
But when I do this in my view:
<%= number_to_currency(1234567890.506, :locale => :"en-GB") %>
This is the error I get:
:"en-GB" is not a valid locale excluded from capture due to environment or should_capture callback
ActionView::Template::Error (:"en-GB" is not a valid locale):
So still not working.
Update 3
My en-GB.yml file was taken directly from https://github.com/svenfuchs/rails-i18n/blob/master/rails/locale/en-GB.yml
So it looks exactly like that. Yet I am still getting the same error:
ActionView::Template::Error (:"en-GB" is not a valid locale):
Synopsis:
Remove custom language ymls and add the correct version of the i18n-rails gem. This resolved this special issue.
Original answer:
Ok my guess is that your en-GB.yml is empty. So it actually finds the file and adds the locale in I18n.available_locales BUT this does not include that all translations are available.
When you look at the format of such a yml file you will recognize they all start with
---
language-code
some_keys: ...
This is what actually is loaded into memory and therefore provides all the available translations. Available locale is just defined by found files in config/locales.
When you check the source of number_to_currency It takes the locale from the options and passes it along the key it looks for to I18n.
I18n.translate(:'number.format', :locale => options[:locale], :default => {})
Since you just say that en-GB is available but don't have the actual keys along the locale in memory you get the missing translation issue.
What I suggest is you either use the content of the linked yml file and paste it into your en-GB.yml or you remove your en-GB.yml and find a 3.2 working i18n-rails version and use it. i18n-rails provides plenty of default translations which are utilized all over default rails.
Addition:
Before you added the en-GB.yml file it actually worked like expected.
When no locale is found it defaults to dollar in here since the currency variable will be just and empty {}.
Somehow, I found the solution that worked for me.
First of all, you need to have a locale file with your requirements in it.
Here is the example of fr.yml file
For an instance, copy and paste this file in app/config/locales/
then restart your console,
then try, number_to_currency(1000.51, locale: :fr)
for sure, you will get '1 000,51 €'
Here is the full list of all supported countries' locale file.
Until and unless you don't have locale file with your format required in it, you won't get the desired result.
my rails version is 3.2.22.5, ruby is 2.4.2(I didnt install below 2.x.x)
I use locale yml from
https://github.com/svenfuchs/rails-i18n/blob/rails-3-x/rails/locale/en-GB.yml
This is work well
<%= number_to_currency(1234567890.506, :locale => :"en-GB") %>
<%= number_to_currency(1234567890.506, :locale => "en-GB") %>
to result
£1,234,567,890.51
and I add fr.yml too like
fr:
...
number:
currency:
format:
...
unit: €
And then this is work too
<%= number_to_currency(1234567890.506, :locale => :fr) %>
to result
€1,234,567,890.51
I didn't change or add configuration. I add only controller, view and locale file. And test it.
You could translate directly like, so test this
I18n.translate(:'number.currency.format', :locale => "en-GB", :default => {})
if it occur a same error, then check out you file's name, extension, path.
and you must restart server
I'm using https://rubygems.org/gems/countries in a project and trying to get all countries names using a locale string for translations.
The locale 'DE', 'NO' or others are coming from the Google OCR API. The gem also has a method: ISO3166::Country.translations, which will return all the locale strings and the matching country, like: "AL"=>"Albania".
In this list, there is also featured the translation "NO"=>"Norway", but when using ISO3166::Country.all_translated('NO'), an error is thrown: I18nData::NoTranslationAvailable: I18nData::NoTranslationAvailable -- countries-NO.
Is there any workaround or fix to use all languages and get all translations? Or at least how is Norway not in the locales? The gem I think uses I18n as it's mentioned in the error, and the :no locale is not valid into I18n:
I18n.locale = :no => I18n::InvalidLocale: :no is not a valid locale
I18n.locale = :de => :de
Norwegian i18n locales are :nn (Nynorsk) and :nb (Bokmål), not :no.
i18n uses countries-NN.txt and countries-NB.txt
So need to use ISO3166::Country.all_translated('NN') and ISO3166::Country.all_translated('NB')
I have the following configured in my application.rb
config.i18n.available_locales = [:at, :de, :ch_de, :ch_fr, :fr, :int_en, :int_fr]
config.i18n.default_locale = :at
My default locale is set to :at (Austria). Which I require for Route Translation. Rails server won't start without it and to be fair it makes sense.
I now created a fallback map, which works just fine:
config.i18n.fallbacks = {'de' => 'at', 'ch_de' => 'at', 'ch_fr' => 'fr', 'int_fr' => 'fr', 'fr' => 'fr', 'int_en' => 'int_en'}
So basically I want all German speaking countries to fallback on :at, whilst all French speaking countries fall back to :fr.
However, I do NOT under any circumstances want :fr to fallback on :at. This is for SEO purposes as some french pages do not have metadata configured. So now the french pages would display the Austrian :at metadata entry. Which is wrong.
If I turn of fallbacks completely:
config.i18n.fallbacks = false
the following works fine in my views:
t('.metatitle', :default => "")
In that case if there is no translation available then nothing is displayed. However, the rest of the site that already exists relies on fallbacks - so this is not an option, considering the effort to implement the change.
Is there a way turn off fallbacks for individual translations?
Or can I implement the fallback map and make sure that the map doesn't fallback to it's default locale if for example no french :fr translation exists?
PS: The route translating gem that requires the default locale is this one here.
Thank you for your help !
Figured it out - and thought of sharing it with you:
If you wish to avoid fallback to the default locale on individual translation you simply have to send a empty fallback array like this:
t('.metatitle', :default => "", :fallback => [])
Et Voila !
This is tricky in Rails up to 6.1 because you need to beat the logic in the Railtie initializer which desperately wants to fallback to the default_locale.
To set the default fallback locale to nil you need to use the following code:
config.i18n.default_locale = "de-AT"
config.i18n.fallbacks.defaults = [[]] # If you just write [], then default_locale is used
config.i18n.fallbacks.map = {
:de => "de-AT",
"de-CH" => "de-AT",
}
Let's check:
$ rails console
2.7.2 :001 > I18n.fallbacks["de"]
=> [:de, :"de-AT"]
2.7.2 :002 > I18n.fallbacks["fr"]
=> [:fr]
2.7.2 :003 > I18n.fallbacks["de-CH"]
=> [:"de-CH", :de, :"de-AT"]
2.7.2 :004 > I18n.fallbacks["de-AT"]
=> [:"de-AT", :de]
2.7.2 :005 >
Not 100% what you want, but there just seems to be no way to prevent the fallbacks to go from country specific locale to generic language locale, when fallbacks are enabled.
Note #1: Your locales are a bit non-standard. AFAIK there is no 'at' locale, but only "de-AT".
Note #2: Some more subtleties and notes in this answer.
I asked a previous question regarding locale-setting. I am trying to set up fallbacks of various Norwegian languages to Norwegian Bokmal (:nb). The desired behaviour is that if a browser passes nn or no as locale requests, the I18n.locale will be set to either :nn or :no, and then in the absence of translations for these locales, :nb will be served to the browser.
Based on the answer to my previous question, I have this line in my application initialiser:
config.i18n.default_locale = :en
config.i18n.fallbacks = {:nn => [:nb], :no => [:nb]}
In rails console, this gives me the following results:
> I18n.fallbacks
=> {:en=>[:en]}
> I18n.fallbacks[:nn]
=> [:nn, :nb, :en]
> I18n.fallbacks[:no]
=> [:no, :nb, :en]
Using a browser that has only nn & no in the language list, this does not work- it falls back to the default locale of :en instead. Here's the request headers:
Accept-Language: "nn,no;q=0.5"
If I add :nb to the browser language stack, I am correctly served Norwegian content.
Is there something I am missing in this process?
You need to set I18n.locale based on the browser setting.
def set_locale
I18n.locale = extract_locale_from_accept_language_header
end
private
def extract_locale_from_accept_language_header
request.env['HTTP_ACCEPT_LANGUAGE'].scan(/^[a-z]{2}/).first
end
Taken from: http://guides.rubyonrails.org/i18n.html#setting-the-locale-from-the-client-supplied-information
We often stumble over untranslated model attributes in our application. They most often come because an attribute was renamed or something like this.
It would be really helpful to have I18n raise an error when Model.human_attribute_name :field doesn't find a translation. Is there a way to achieve this?
Update:
It seems there's some other problem. here are my I18n settings:
I18n.enforce_available_locales = false
config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}')]
config.i18n.default_locale = 'de-CH'
config.i18n.available_locales = ['de', 'de-CH', 'en']
config.i18n.locale = 'de-CH'
config.i18n.fallbacks = {'de-CH' => 'de', 'en-GB' => 'en'}
I can't set fallbacks = false because I want missing translations of de-CH to gracefully delegate to de, which in general seems to work fine. But for my state machine attribute human_to_state method it doesn't seem to work. Here's the view code causing the problem:
= f.input :state_event, collection: f.object.state_transitions,
label_method: :human_to_name # This causes the problem!
This is printed out as "State event" in the view, and when I add the following I18n key, it's translated successfully to "Status":
de:
mongoid:
attributes:
activity:
state_event: Status
So there really is a missing translation, but I18n doesn't complain in any way. I also tried to catch the exception using a custom exception handler, but this doesn't seem to be raised:
I18n.exception_handler = lambda do |exception, locale, key, options|
binding.pry # This is never reached!
end
Any idea what's going on? Is it a problem with state machine?
The problem lies in the fact that human_attribute_name falls back to
defaults << attribute.to_s.humanize
when nothing else found. In other words, human_attribute_name will never raise an error.
I "fixed" this by overriding human_attribute_name, patching the above mentioned line:
(put this in an initializer)
require 'active_support/core_ext/hash/reverse_merge'
module ActiveModel
module Translation
include ActiveModel::Naming
def human_attribute_name(attribute, options = {})
defaults = lookup_ancestors.map do |klass|
[:"#{self.i18n_scope}.attributes.#{klass.model_name.i18n_key}.#{attribute}",
:"#{self.i18n_scope}.attributes.#{klass.model_name.i18n_key.to_s.tr('.', '/')}.#{attribute}"]
end.flatten
defaults << :"attributes.#{attribute}"
defaults << options.delete(:default) if options[:default]
defaults << attribute.to_s.humanize if Rails.env.production? # Monkey patch
options.reverse_merge! :count => 1, :default => defaults
I18n.translate(defaults.shift, options)
end
end
end
Possible duplicate of : How to enable Rails I18n translation errors in views?
The accepted answer is:
config.i18n.fallbacks = false
#BettySt 's answer is pretty cool too, you should take a look at her solution.
Doc about how to handle I18n translation errors:
http://guides.rubyonrails.org/i18n.html#using-different-exception-handlers