Подтвердить что ты не робот

Определение языка браузера в Rails

Как вы определяете язык пользователя (в RoR), заданный в браузере? У меня будет поле выбора, которое пользователь может использовать в любое время, но я бы хотел по умолчанию использовать свой язык браузера.

4b9b3361

Ответ 1

Здесь решение:

2.6 Установка локали из информации, предоставленной клиентом

В конкретных случаях было бы целесообразно установить языковой стандарт из предоставленной клиентом информации, то есть не из URL-адреса. Эта информация может быть получена, например, с предпочтительного языка пользователей (установленного в их браузере), может основываться на географическом местоположении пользователей, выведенном из их IP-адреса, или пользователи могут предоставить его просто, выбрав язык в вашем интерфейсе приложения и сохраняя его профиль. Этот подход более подходит для веб-приложений или служб, а не для веб-сайтов - см. Раздел о сеансах, куках и архитектуре RESTful выше...

Одним из источников информации, предоставленной клиентом, будет HTTP-заголовок Accept-Language. Люди могут установить это в своем браузере или других клиентов (например, завиток)...

Другим способом выбора локали из клиентской информации будет использование базы данных для сопоставления клиентского IP-адреса в регионе, например GeoIP Lite Country...

Вы также можете предоставить пользователям своего приложения средства для установки (и, возможно, чрезмерной езды) языка в вашем прикладном интерфейсе, а также...

Ответ 2

Это старый вопрос, но я наткнулся на него как на душу в поисках ответов, и единственным доступным ответом была ссылка без какого-либо контекста. Так что здесь немного больше глубины, основанной на моем последующем копании.

Доступ к заголовку языка Accept-

request объект request в соответствующем контроллере:

request.env['HTTP_ACCEPT_LANGUAGE'] #returns nil or a string, e.g.:
# => "en-AU,en-US;q=0.7,en;q=0.3"

Это легкая часть, хотя. Чтобы использовать его в Rails, вам нужно проанализировать эту строку (или, может быть, это nil?).

Боковая панель: учебник по заголовкам Accept- *

Итак, глядя на приведенный выше пример строки, некоторые языки имеют "q-значения" - относительный коэффициент качества, от 0 до 1. Более высокие значения q означают, что клиент предпочитает язык. Отсутствие q-значения действительно является самым высоким q-значением - неявным 1.0 (как с en-AU в приведенной выше строке). Небольшое осложнение - браузер может отправлять вам языки с q-значениями, скажем, 0 - и я понимаю, что вы должны отказаться от этих языков, если это возможно.

Разбор заголовка языка Accept-

Имея это в виду, вот несколько разных, но похожих подходов, которые я рассмотрел для разбора такой строки в списке языков, упорядоченных по их q-значениям. С простым Ruby:

# to_s to deal with possible nil value, since nil.to_s => ""
langs = request.env['HTTP_ACCEPT_LANGUAGE'].to_s.split(",").map do |lang| 
  l, q = lang.split(";q=")
  [l, (q || '1').to_f]
end
# => [["en-AU", 1.0], ["en-US", 0.7], ["en", 0.3]]

Или, если вы разбираетесь в регулярных выражениях, вы можете достичь того же, что и выше, и, возможно, одновременно улучшить свое усердное регулярное выражение:

rx = /([A-Za-z]{2}(?:-[A-Za-z]{2})?)(?:;q=(1|0?\.[0-9]{1,3}))?/
langs = request.env['HTTP_ACCEPT_LANGUAGE'].to_s.scan(rx).map do |lang, q|
  [lang, (q || '1').to_f]
end

В любом случае, при необходимости вы можете выполнить что-то вроде:

# return array of just languages, ordered by q-value
langs.sort_by(&:last).map(&:first).reverse
# => ["en-AU", "en-US", "en"]

Я начал свой анализ с просмотра этой сути, но в итоге изменил ее довольно значительно. Регулярное выражение особенно отбрасывало совершенно хорошие вторичные локали, например, en-AU стало en, zh-TW стало zh. Я попытался исправить это с помощью моих изменений в этом регулярном выражении.

Ответ 3

Вот хорошо протестированный Ruby gem, который делает именно то, что вы хотите: https://github.com/ioquatix/http-accept

languages = HTTP::Accept::Language.parse("da, en-gb;q=0.8, en;q=0.7")

expect(languages[0].locale).to be == "da"
expect(languages[1].locale).to be == "en-gb"
expect(languages[2].locale).to be == "en"

Он имеет 100% -ный охват тестирования на широком диапазоне входных данных. Он возвращает языки в порядке, указанном соответствующими RFC.

Кроме того, если вы пытаетесь сопоставить язык пользователя с контентом, доступным в определенном наборе локалей, вы можете сделать следующее:

available_localizations = HTTP::Accept::Languages::Locales.new(["en-nz", "en-us"])

# Given the languages that the user wants, and the localizations available, compute the set of desired localizations.
desired_localizations = available_localizations & languages

Желаемые_локализации в приведенном выше примере представляют собой подмножество доступных_локализаций в соответствии с предпочтениями пользователя, доступными локализациями и рекомендациями RFC.

Ответ 4

Это действительно старый вопрос, но я хотел бы упомянуть, что в руководстве по Rails есть описание того, как определять язык браузера пользователя.

Приведенный ниже код основан на решении из руководства по Ruby on Rails с улучшениями:

  • есть проверки HTTP_ACCEPT_LANGUAGE - иногда этот заголовок отсутствует для ботов, и вы получите ошибки в вашем инструменте отчетов об ошибках
  • проверки - это язык, поддерживаемый вашим приложением

код:

  def set_locale_based_on_browser
    locale = extract_locale_from_accept_language_header

    I18n.locale =
      if locale_valid?(locale)
        locale
      else
        :en
      end
  end

  private

  def locale_valid?(locale)
    I18n.available_locales.map(&:to_s).include?(locale)
  end

  def extract_locale_from_accept_language_header
    accept_language = request.env['HTTP_ACCEPT_LANGUAGE']
    return unless accept_language

    accept_language.scan(/^[a-z]{2}/).first
  end
end

Дополнительную информацию об обнаружении языковых стандартов можно найти в руководстве по Ruby on Rails: https://guides.rubyonrails.org/i18n.html#choosing-an-implied-locale.

Ответ 5

Прошлой ночью я сделал этот крошечный драгоценный камень: accept_language

Он может быть интегрирован в приложение Rails следующим образом:

# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  before_action :best_locale_from_request!

  def best_locale_from_request!
    I18n.locale = best_locale_from_request
  end

  def best_locale_from_request
    return I18n.default_locale unless request.headers.key?('HTTP_ACCEPT_LANGUAGE')

    string = request.headers.fetch('HTTP_ACCEPT_LANGUAGE')
    locale = AcceptLanguage.intersection(string, I18n.default_locale, *I18n.available_locales)

    # If the server cannot serve any matching language,
    # it can theoretically send back a 406 (Not Acceptable) error code.
    # But, for a better user experience, this is rarely done and more
    # common way is to ignore the Accept-Language header in this case.
    return I18n.default_locale if locale.nil?

    locale
  end
end

Я надеюсь, что это может помочь.