Reputation: 587
I am creating a multilingual app and I want to make the app switch to the language of the visitors browser language settings. I have noticed that it works perfectly if the language settings matches one of the available locales. But unfortunately as soon as the browser language does not match one of the locales I will get an I18n::InvalidLocale Error... ("es" is not a valid locale) eventhough I set up an default locale...
What am I missing? How can I make this work? Any hints?
application.rb
require File.expand_path('../boot', __FILE__)
require 'rails/all'
Bundler.require(*Rails.groups)
module Testapp
class Application < Rails::Application
config.i18n.default_locale = :en
config.i18n.enforce_available_locales = true
config.active_record.raise_in_transactional_callbacks = true
end
end
application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
before_action :set_locale
private
def extract_locale_from_accept_language_header
request.env['HTTP_ACCEPT_LANGUAGE'].scan(/^[a-z]{2}/).first
end
def set_locale
I18n.locale = extract_locale_from_accept_language_header || I18n.default_locale
end
end
In my locales I have de.yml, en.yml and a devise.en.yml file.
routes.rb
Rails.application.routes.draw do
scope "(:locale)", locale: /en|de/ do
root 'welcomes#index'
devise_for :users
get "language" => "welcomes#language"
get "welcomes/download_pdf"
resources :welcomes do
get :download, on: :member
end
resources :resumes do
get :download, on: :member
end
get '*path' => redirect('/')
end
end
index.html.erb
<p><%= link_to "EN", root_path(locale: 'en') %></p>
<p><%= link_to "DE", root_path(locale: 'de') %></p>
UPDATE
I have noticed when I run the rails console and check the I18n.available_locales it gives me [:en, :fr, :"zh-CN", :"zh-TW", :de] very strange?! Because I have not set those locales and I have not those in my apps are those settings the default settings? So I guess the config.i18n.available_locales = [:de, :en] settings is necessary.
UPDATE
I have noticed that if use: config.i18n.enforce_available_locales = false No translations are working but I will not get an error. If I update addtionally on environments/development.rb: config.i18n.fallbacks = true Then only the default value is shown in my case english but I can not change it to german.
Upvotes: 1
Views: 2471
Reputation: 2880
Maybe try this as the before_action in the application controller.
def set_locale
browser_locale = extract_locale_from_accept_language_header.to_sym
if I18n.available_locales.include?(browser_locale)
I18n.locale = browser_locale
else
I18n.locale = I18n.default_locale
end
end
Then it should only try to set the locale if its available.
Upvotes: 0
Reputation: 326
Since you're setting the locale via the locale
placeholder in the routes, in your application.rb
you should also resolve it using the value of params[:locale]
not the header. So in application.rb
the set_locale should be
def set_locale
I18n.locale = params[:locale] || I18n.default_locale
end
See the section on setting locale from URL params here http://guides.rubyonrails.org/i18n.html#configure-the-i18n-module
Upvotes: 0
Reputation: 1
Something like this?
def extract_locale_from_accept_language_header
available_locales = {'de' => 'de', 'en' => 'en'}
available_locales[request.env['HTTP_ACCEPT_LANGUAGE'].scan(/^[a-z]{2}/).first]
end
Upvotes: 0
Reputation: 166
config.i18n.enforce_available_locales = true
This might be overriding the default locale behavior. Try Turning it off so the default locale can kick in.
And provide a whitelist of available locales like this:
config.i18n.available_locales = [:de, :en]
Edit Try doing this in your application controller:
def default_url_options(options = {})
{ locale: I18n.locale }
end
Upvotes: 2