Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save masasakano/37216b570845549166b74bf17fc07d50 to your computer and use it in GitHub Desktop.
Save masasakano/37216b570845549166b74bf17fc07d50 to your computer and use it in GitHub Desktop.
How to set up path-based Ruby-on-Rails I18n environment

Goals

  • Languages are :en and :ja and :fr, where :en is the default.
  • It is path-based, like /ja/articles is for Index of Article model.
  • Allow access without the locale parameter in the path like http://example.com/articles
    • in which case the locale parameter I18n.locale should be set according to the browser's request, falling back to :en

Install i18n default translations

gem 'rails-i18n', '~> 6.0' # For 6.0 or higher
gem 'i18n-timezones'
gem 'devise-i18n'

Config

In /config/application.rb

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

You may or may not set I18n.default_locale = :en

Environment-dependent setup

  # /config/environments/production.rb
  config.i18n.fallbacks = [:en, :ja, :fr]

(c.f., Stackoverflow)

Set this only in production.rb so that developers would be more likely to notice missing Translations in the Development and Test environments.

Inflection

 # /config/initializers/inflections.rb
ActiveSupport::Inflector.inflections(:ja) do |inflect|
end

This prevents the fallback (usually active only in Production) from Japanese (:ja) in inflection (pluralize, singularize) to English.

routes

 # /config/routes.rb
 # should be placed at the top(!)
  filter :locale
  default_url_options(locale: I18n.locale) if Rails.env.test?

The reason the latter is necessary for the Test environment is complicated. See my question at Stackoverflow

Rails I18n Guide tells the following is better to allow the access without the local parameter in the path and also the root directory with a locale parameter. However, it is working in my environment without these (perhaps because I am using routing-filter Gem?

 # config/routes.rb
scope "(:locale)", locale: /en|ja|fr/ do
  resources :books
end

 # To take care of the root path, place immediately before: root to: "home#index"
get '/:locale' => 'home#index'

ApplicationController

  # /app/controllers/application_controller.rb
  # This should come AFTER the Devise authentication(?)
  around_action :switch_locale

  def default_url_options(options={})
    #Rails.application.default_url_options = Rails.application.routes.default_url_options = { locale: I18n.locale }
    { locale: I18n.locale }.merge options
  end

  protected
    # From https://guides.rubyonrails.org/i18n.html#managing-the-locale-across-requests
    def switch_locale(&action)
      locale = (params[:locale].blank? ? I18n.default_locale : params[:locale])
      I18n.with_locale(locale, &action)
    end

Gem routing-filter

routing-filter Gem

  # /test/test_helper.rb
  RoutingFilter.active = false

Get the current locale

Get the current locale with I18n.locale To temporary set a locale in a block, do (Stackoverflow):

I18n.with_locale(:nl) do
  link_to('nl', params.merge(id: category.name))
end

Prepare translations and how to call them

 # `config/locales/fr.yml`
fr:
  Ta: Merci
  common:
    hello: "Bonjour %{name}"

Then call

I18n.translate :Ta
I18n.t('common.hello', name: "Mary", default: [:"common.hi", "Hello, Mary"]) %>

The latter means

  1. Try common.hello with the local variable name
  2. Failing it, it tries common.hi
  3. Failing it, the final default fallback is "Hello, Mary".

Use from Views (and helpers)

Note: In Views and helpers, t() is the short-form of I18n.translate

Also, .keyword is available in Views; for example,

es:
  books:
    index:
      title: "Título"

then it can be called from the corresponding view like:

<%# app/views/books/index.html.erb %>
<%= t '.title' %>

References

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment