Локаль по-умолчанию в Rails

Mkdev article

Если ваше приложение поддерживает несколько языков, то вам понадобится способ определять язык пользователя. Русским — русский интерфейс, немцам — немецкий, всем остальным — английский, например. Есть два способа это сделать: плохой и хороший.

Геолокация

До недавнего времени в FJMoney использовался плохой способ. Работает он так: при помощи геолокации определяется страна пользователя, а затем используя страну и гем I18nData определяется непосредственно локаль:

     I18n.locale = I18nData.country_code(request.location.try(:country)).try(:downcase) if request.location.present?

request.location становится доступным благодаря гему geocoder.

Чем этот метод плох:

  • на определение местоположения пользователя уходит время, если не ошибаюсь, то по-умолчанию geocoder для этого использует Google Maps API.
  • так как используется сторонний API, то вы обязательно уткнётесь в ограничение на количество запросов к этому API
  • если пользователь со своим ноутбуком поедет отдыхать в Германию, то он получит немецкий интерфейс

Accept-Language Header

Каждый приличный браузер с каждым запросом отправляет заголовок Accept-Language, в котором хранится список предпочитаемых пользователем языков. По-умолчанию это язык операционной системы. Зная это, мы можем всегда точно определить нужный пользователю язык. Если его браузер использует немецкий, то скорее всего и веб-приложение он захочет использовать на немецком.

Для парсинга Accept-Language есть небольшой гем http_accept_language. По сути, всё что он делает это разбирает headers запроса, находит там Accept-Language, а потом разбирает эту строку и определяет предпочитаемые пользователем языки. После, используя полученный массив языков, можно легко определить доступную в Rails приложении локаль.

Полный код определения и хранения локали пользователя в FJMoney:

class ApplicationController < ActionController::Base
  before_filter :set_locale

  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

Чиним тесты

Мне дополнительно пришлось чинить тесты, так как после внесённых изменений локаль в тестах стала английской по-умолчанию. Что бы задать заголовки запроса по-умолчанию в capybara + cucumber нужно добавить следующее в env.rb

Capybara.default_driver = :poltergeist # Драйвер на ваш выбор

Before do
  Capybara.current_session.driver.headers = { 'Accept-Language' => 'ru' }
end

Хочешь узнать больше?

Записывайся на курсы по изучению программирования вместе с опытным наставником! Мы учим и новичков, и уже опытных разработчиков. С чего начнём?

Выбрать курс Nastavnik po veb razrabotke