victorfink
victorfink

Reputation: 373

How to fix: i18n always translate to default locale

I'm trying out the internationalization of a Rails app with i18n. I did some small tests with 2 languages: english and french.

The problem I have is that i18n always translate to the default locale. So if it's english, everything will be in english, and the same with french.

Here is what I tried:

config/initializers/locales.rb

# Permitted locales available for the application
I18n.available_locales = [:en, :fr]

app/controllers/application_controller.rb

class ApplicationController < ActionController::Base

    def default_url_options
        { locale: I18n.locale }
    end

end

config/application.rb

module LanguageApp
  class Application < Rails::Application
    ...
    config.i18n.load_path += Dir["#{Rails.root.to_s}/config/locales/**/*.{rb,yml}"]
    config.i18n.default_locale = :en
    # I change the default locale here to :fr or :en
  end
end

config/routes.rb

root to: "home#index"

get '/:locale/about' => 'about#index'
get '/:locale' => 'home#index'

I organized my yml files like this:

config/locales/views/about/en.yml

en:
  about: "This page is about us."

config/locales/views/about/fr.yml

fr:
  about: "Cette page est à propos de nous."

config/locales/views/home/en.yml

en:
  welcome: "Hello world"

config/locales/views/home/fr.yml

fr:
  welcome: "Bonjour le monde"

And finally my views:

app/views/about/index.html.erb

About us page. <%= t(:about) %>

app/views/home/index.html.erb

This is the homepage. <%= t(:welcome) %>

I think the problem may come from the way I organized my yml files but I don't understand why i18n only translate to the default locale and 'ignore' the other language.

EDIT:

To try this out in the browser with the rails server running, I tried to visit these URL:

localhost:3000
localhost:3000/en
localhost:3000/fr

These 3 URL give me the same content, so the :fr locale doesn't actually work (it returns the same translation as :en)

Same for

localhost:3000/en/about
localhost:3000/fr/about

I also tried it in the rails console:

> I18n.t(:welcome, :en)
"Hello world"
> I18n.t(:welcome, :fr)
"Hello world"

Upvotes: 1

Views: 7391

Answers (1)

max
max

Reputation: 102250

First set the locale for the request:

class ApplicationController < ActionController::Base
    around_action :switch_locale
 
    def switch_locale(&action)
        I18n.with_locale(params[:locale] || I18n.default_locale, &action)
    end

    def default_url_options
        { locale: I18n.locale }
    end
end

Don't use I18n.locale= as many older answers / tutorials do.

I18n.locale can leak into subsequent requests served by the same thread/process if it is not consistently set in every controller. For example executing I18n.locale = :es in one POST requests will have effects for all later requests to controllers that don't set the locale, but only in that particular thread/process. For that reason, instead of I18n.locale = you can use I18n.with_locale which does not have this leak issue.

If you want to create translations for specific views you should nest the keys instead of just using flat hashes:

en:
  home:
    welcome: "Hello World"

fr:
  home:
    welcome: "Bonjour le monde"

And then use an implicit lookup in the view:

<h1><%= t('.welcome') %></h1>

This resolves the key to home.welcome.

Upvotes: 2

Related Questions