trickydiddy
trickydiddy

Reputation: 587

I18n::InvalidLocale Error

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

Answers (4)

Andrew
Andrew

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

Oranagwa Osmond Oscar
Oranagwa Osmond Oscar

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

Vladyslav Sydorenko
Vladyslav Sydorenko

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

Sarmad Sabih
Sarmad Sabih

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

Related Questions