检测Rails中的浏览器语言

tyb*_*103 19 ruby locale ruby-on-rails ruby-on-rails-3

如何检测浏览器中设置的用户语言(在RoR中)?我将有一个用户可以随时使用的选择框,但我想默认使用他们的浏览器语言.

inn*_*ran 21

这是解决方案:

2.6从客户端提供的信息中设置区域设置

在特定情况下,从客户端提供的信息(即不是URL)设置区域设置是有意义的.此信息可以来自用户的首选语言(在其浏览器中设置),可以基于从其IP推断的用户的地理位置,或者用户可以通过选择应用程序界面中的区域设置并保存它来提供它.他们的个人资料.这种方法更适用于基于Web的应用程序或服务,而不适用于网站 - 请参阅上面有关会话,cookie和RESTful架构的方框...

客户端提供的信息的一个来源是Accept-Language HTTP标头.人们可以在他们的浏览器或其他客户端(例如curl)中设置它...

从客户端信息中选择区域设置的另一种方法是使用数据库将客户端IP映射到区域,例如GeoIP Lite Country ...

您还可以为应用程序的用户提供在应用程序界面中设置(并可能覆盖)区域设置的方法,以及...


Kim*_*all 17

这是一个古老的问题,但我发现它是寻找答案的灵魂,唯一可用的答案是没有任何背景的链接.基于我后来的挖掘,这里有一点深度.

访问Accept-Language标头

查询request相关控制器中的对象:

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

这很简单.要在Rails中充分利用它,您需要解析该字符串(或者可能是它nil?).

侧栏:Accept-*标题的入门读物

因此,查看上面的示例字符串,某些语言具有"q值" - 相对品质因数,介于0和1之间.较高的q值意味着客户首选语言.缺少q值实际上是最高的q值 - 隐含的1.0(如en-AU上面的字符串中所示).虽然有点复杂 - 浏览器可能会向您发送带有q值的语言,例如0 - 我收集这意味着您应该尽可能拒绝这些语言.

解析Accept-Language标头

考虑到这一点,这里有几种不同但相似的方法,我已经看过将这样的字符串解析为语言列表,按其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]]
Run Code Online (Sandbox Code Playgroud)

或者如果你精通正则表达式,你可以达到与上面相同的效果,并且可能同时改进我的屠宰正则表达式:

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
Run Code Online (Sandbox Code Playgroud)

无论哪种方式,您都可以根据需要跟进:

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

我通过查看这个要点开始我的解析,但最终相当显着地修改它.正则表达式特别是扔掉非常好的辅助语言环境中,例如en-AU变得en,zh-TW成为zh.我试图通过对正则表达式的修改来纠正这个问题.


Mic*_*ski 7

这是一个非常老的问题,但我想提一下 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
        I18n.default_locale
      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
Run Code Online (Sandbox Code Playgroud)

有关区域设置检测的更多信息,请参阅 Ruby on Rails 指南: https ://guides.rubyonrails.org/i18n.html#choosing-an-implied-locale


Cyr*_*ato 7

昨晚我做了这个小宝石: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.parse(string).match(*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
Run Code Online (Sandbox Code Playgroud)

我希望它能有所帮助。