Skip to content

I18n, translations, locales

Dylan Fisher edited this page Mar 24, 2022 · 6 revisions

Configuring routes and default locales

It is helpful to include the Cache with Locale gem for automatic cache key localization.

gem 'cache_with_locale'

Example code for an Italian website with English locale:

# config/application.rb

I18n.available_locales = [:it, :en]
config.i18n.default_locale = :it
# config/routes.rb

Rails.application.routes.draw do
  get '/', to: redirect('/it')

  # PagesController routes scoped to locale
  scope constraints: lambda { |request| (request.path =~ /^\/admin(\/|$)/).nil? } do
    scope '(:locale)',
          locale: /#{I18n.available_locales.join('|')}/ do
      root to: 'pages#show'
    end
  end

  # Admin resources
  namespace :admin do
    # resources :projects
  end

  # Front-end resources and routes, scoped to the locale
  scope '/:locale', locale: /#{I18n.available_locales.join('|')}/ do
    # resources :projects, only: [:index, :show]
  end
end
# controllers/application_controller.rb

class ApplicationController < ActionController::Base
  before_action :set_locale

  def default_url_options
    { locale: I18n.locale }
  end

  private

    def set_locale
      default_locale = Proc.new { I18n.default_locale }
      I18n.locale = I18n.available_locales.detect(default_locale) { |locale| locale == params[:locale].to_s.to_sym }
    end
end

When generating additional blocks or models be sure to include attributes to store the translations, following this pattern:

bin/rails g forest:scaffold Project title:string title_en:string description:text description_en:text

Projects with existing models

If you are adding localization to an existing project you'll need to add localized fields for all attributes.

class AddLocalizationToCurrentModelsAndBlocks < ActiveRecord::Migration[6.0]
  def change
    I18n.available_locales.reject { |x| x == I18n.default_locale }.each do |locale|
      # Pages
      add_column :pages, "title_#{locale}", :string
      add_column :pages, "seo_title_#{locale}", :string
      add_column :pages, "description_#{locale}", :text

      # Media Items
      add_column :media_items, "caption_#{locale}", :text
      add_column :media_items, "alternative_text_#{locale}", :string
      add_column :media_items, "description_#{locale}", :string

      # Continue for other models
    end
  end
end

Editing localized fields in your backend views

Use the localized_inputs helper to render an input in each of the site's available locales.

<%= localized_inputs f, :title, hint: 'Additional input options are passed to the form input method.' %>

Another option for rendering localized inputs is to group the fields in a locale-panel class that will toggle when viewing a particular locale for that record. Use the localized_input helper to make it easier to display these fields.

<% I18n.available_locales.each_with_index do |locale, index| %>
  <%= content_tag :div, class: "#{'display-none' unless index.zero?} locale-panel", data: { locale: locale } do %>
    <%= localized_input f, :title, locale %>
    <%= localized_input f, :description, locale, markdown: true %>
  <% end %>
<% end %>

Displaying translated fields in your frontend views

Use the TranslationHelper methods to make it more convenient to display translated fields in your views. For example, to render markdown for a localized title field of your project record, falling back to your application's default locale in case that translation is missing:

md(ft(@project, :title, fallback: true))