i18n basics. Change current app language.
Previously I wrote about managing translations with gem i18n-tasks
Here’s how you can let users manually switch the current language.
First, be sure to have your application i18n defaults set:
# config/application.rb
config.i18n.default_locale = :en
config.i18n.available_locales = %i[en fr nl es de it pl pt ro ua]
config.i18n.raise_on_missing_translations = true
Now you need to override the default_locale
by setting I18n.locale = :de
in application_controller
.
🔔 Install gem rails-i18n
to auto-translate stuff like time_ago_in_words
.
Rubocop #
The Rails/I18nLocaleTexts
helps you find untranslated strings. An error can look like this:
app/controllers/stripe/checkout_controller.rb:40:49: C: Rails/I18nLocaleTexts: Move locale texts to the locale files in the config/locales directory.
redirect_to user_url(current_user), notice: "foo"
Set locale from URL #
Namespace ALL the translatable routes:
# config/routes.rb
# scope "(:locale)", locale: /en|es/ do
scope "(:locale)", locale: /#{I18n.available_locales.join("|")}/ do
resources :tags, only: %i[index show]
resources :playlists, only: %i[index show]
end
This way, the below routes are equivalent, and both respond to params[:locale]
:
https://localhost:3000/en/posts
https://localhost:3000/posts?locale=en
default_url_options
will append the current locale to all links in your app, so that the user is redirected properly:
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
before_action :set_locale
def set_locale
I18n.locale = params[:locale] || I18n.default_locale
end
def default_url_options
{ locale: I18n.locale }
end
end
Finally, add links to open page in a different locale:
# switch locales & redirect to root
<%= link_to 'English', root_path(locale: :en) %>
<%= link_to 'Spanish', root_path(locale: :es) %>
# switch locales & redirect to current path
<%= link_to 'English', url_for(locale: :en) %>
<%= link_to 'Spanish', url_for(locale: :es) %>
# switch locales & redirect to current path with params
<%= link_to 'English', url_for(request.parameters.merge(locale: :en)) %>
<%= link_to 'Spanish', url_for(request.parameters.merge(locale: :es)) %>
My current best approach:
<% I18n.available_locales.each do |locale| %>
<%= link_to locale_to_flag(locale), url_for(locale:), class: (locale == I18n.locale ? "border-b" : "") %>
<% end %>
Set locale from session/cookies, or User preferences #
The official Rails Guides do not store locale in session/cookie.
Add language
attribute to User
model:
# terminal
rails g migration add_language_to_users language:string
# migration
add_column :users, :language, :string, default: 'en'
Create a concern to set locale based on
# /app/controllers/application_controller.rb
include SetLocale
# /app/controllers/concerns/set_locale.rb
module SetLocale
extend ActiveSupport::Concern
included do
before_action :set_locale
private
def set_locale
if params["locale"].present?
language = params["locale"].to_sym
session["locale"] = language
if user_signed_in?
current_user.update(language: language)
end
redirect_to(request.referrer || root_path)
elsif session["locale"].present?
language = session["locale"]
else
language = I18n.default_locale
end
if user_signed_in? && current_user.language.present?
language = current_user.language
end
I18n.locale = if I18n.available_locales.map(&:to_s).include?(language)
language
else
I18n.default_locale
end
end
end
end
Finally, show the User links to set current locale:
<%#= @user.language %>
<%#= I18n.locale %>
<% I18n.available_locales.excluding(I18n.locale).each do |language| %>
<%= link_to language, root_path(locale: language) %>
<% end %>
Did you like this article? Did it save you some time?