Локаль по умолчанию в Rails
Когда приложение поддерживает несколько языков, может понадобится определять язык пользователя. Допустим, мы работаем с русскоязычными, которым нужен русский интерфейс, немцам — немецкий, всем остальным — английский, например. Рассмотрим способы сделать это.
Из параметров URL
Напишем такой код:
# app/controllers/application_controller.rb
def default_url_options
{ locale: I18n.locale }
end
Теперь любой хелпер, зависимый от url_for
(к примеру, root_path
, root_url
или quests_path
), будет добавлять локаль в строку запроса:
http://localhost:3000/quests?locale=de.
Чтобы получить более элегантный URL, такой как http://localhost:3000/de/quests
, необходимо добавить следующее:
# config/routes.rb
scope "/:locale" do
resources :quests
end
Если же мы хотим, чтобы работали адресы без явного указания (автоматически использовалась локаль по умолчанию), такие как http://localhost:3000/quests
, то нужно изменить предыдущий код на:
# config/routes.rb
scope "(:locale)", locale: /en|de/ do
resources :quests
end
Геолокация
Как-то в 2014 году я использовал плохой способ. Работал он так: при помощи геолокации определялась страна пользователя, а затем используя страну и гем i18n_data устанавливалась непосредственно локаль:
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
before_action :set_locale
private
def set_locale
I18n.locale = I18nData.country_code(request.location.try(:country)).try(:downcase) if request.location.present?
end
end
request.location
становится доступным благодаря гему geocoder.
Чем этот метод плох:
- на определение местоположения пользователя уходит время, по умолчанию geocoder для этого использует Google Maps API;
- так как используется сторонний API, то вы обязательно уткнётесь в ограничение на количество запросов к этому API;
- если пользователь со своим ноутбуком поедет отдыхать в Германию, то он получит немецкий интерфейс.
HTTP-заголовок Accept-Language
Любой приличный браузер с каждым запросом отправляет заголовок Accept-Language, в котором хранится список предпочитаемых пользователем языков. По умолчанию это язык операционной системы. Зная это, мы можем всегда точно определить нужный пользователю язык. Если его браузер использует немецкий, то скорее всего и веб-приложение он захочет на немецком.
Для парсинга Accept-Language
можно использовать либо промежуточное приложение locale, либо небольшой гем http_accept_language, остановимся на последнем. По сути, всё что он делает это разбирает headers
запроса, отыскивает там Accept-Language
, а потом из этой строки находит используемые пользователем языки. После, используя полученный массив языков, можно легко определить доступную в Rails приложении локаль.
Полный код определения и хранения локали пользователя:
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
before_action :set_locale
private
def set_locale
locale = if current_user
current_user.settings.locale
elsif params[:locale]
session[:locale] = params[:locale]
elsif session[:locale]
session[:locale]
else
http_accept_language.compatible_language_from(I18n.available_locales)
end
if locale && I18n.available_locales.include?(locale.to_sym)
session[:locale] = I18n.locale = locale.to_sym
end
end
end