ruby-on-rails - rails : Setting locale appropriately to IP address

标签 ruby-on-rails ruby internationalization locale geocoding

我正在尝试使用 request.location (geocoder gem) , 将区域设置适本地设置为客户端 IP 地址


这是我得到的:

app/controllers/application_controller.rb

before_action :set_locale

private

def set_locale
    # get location with geocoder
    location = request.location

    # set locale through URL
    if params.has_key?(:locale)
        I18n.locale = params[:locale] || I18n.default_locale
    # set locale through user preference
    elsif current_user && current_user.locale.present?
        I18n.locale = current_user.try(:locale) || I18n.default_locale
    # set locale through geocoder detection of location
    elsif location.present? && location.country_code.present? && I18n.available_locales.include?(location.country_code)
        if location.country_code.include? "-"
            I18n.locale = location.country_code
        else
            I18n.locale = location.country_code.downcase
        end
    # set locale through HTTP detection of location
    elsif (request.env["HTTP_ACCEPT_LANGUAGE"] || "en").scan(/^[a-z]{2}/).first.present? && I18n.available_locales.include?((request.env["HTTP_ACCEPT_LANGUAGE"] || "en").scan(/^[a-z]{2}/).first)
        I18n.locale = (request.env["HTTP_ACCEPT_LANGUAGE"] || "en").scan(/^[a-z]{2}/).first
    end
end


config/application.rb

# i18n Translations
## load the subfolders in the locales
config.i18n.load_path += Dir["#{Rails.root.to_s}/config/locales/**/**/**/**/**/*.{rb,yml}"]
## set default locale
config.i18n.default_locale = 'en'
## provide locale fallbacks
config.i18n.enforce_available_locales = false
config.i18n.fallbacks = {
    'de-AT' => 'de', 'de-CH' => 'de', 'de-DE' => 'de',
    'en-AU' => 'en', 'en-CA' => 'en', 'en-GB' => 'en', 'en-IE' => 'en', 'en-IN' => 'en', 'en-NZ' => 'en', 'en-US' => 'en', 'en-ZA' => 'en'
}

使用参数 params[:locale],一切正常。但是如果没有参数,它总是默认为 en

我在这里做错了什么?

最佳答案

I18n.locale 默认情况下不会在请求之间被记住 - 您需要通过将其保存到 session 中来自己实现它。 I18n.locale 设置后,您可以使用:

session[:locale] = I18n.locale

然后把它拉回来:

I18n.locale = params[:locale] || session[:locale] || I18n.default_locale
# explicit params take precedence
# otherwise use the remembered session value
# fallback to the default for new users

旁注:考虑移动您的location = request.location,这样它就不会一直运行。您对每个请求的性能影响很小(和地理编码服务查找)——即使您没有使用数据也是如此。


举例来说,这是您可以执行此操作的一种方式:

def set_locale
    # explicit param can always override existing setting
    # otherwise, make sure to allow a user preference to override any automatic detection
    # then detect by location, and header
    # if all else fails, fall back to default
    I18n.locale = params[:locale] || user_pref_locale || session[:locale] || location_detected_locale || header_detected_locale || I18n.default_locale

    # save to session
    session[:locale] = I18n.locale
end

# these could potentially do with a bit of tidying up
# remember to return `nil` to indicate no match

def user_pref_locale
    return nil unless current_user && current_user.locale.present?
    current_user.locale
end

def location_detected_locale
    location = request.location
    return nil unless location.present? && location.country_code.present? && I18n.available_locales.include?(location.country_code)
    location.country_code.include?("-") ? location.country_code : location.country_code.downcase
end

def header_detected_locale
    return nil unless (request.env["HTTP_ACCEPT_LANGUAGE"] || "en").scan(/^[a-z]{2}/).first.present? && I18n.available_locales.include?((request.env["HTTP_ACCEPT_LANGUAGE"] || "en").scan(/^[a-z]{2}/).first)
    (request.env["HTTP_ACCEPT_LANGUAGE"] || "en").scan(/^[a-z]{2}/).first
end

关于ruby-on-rails - rails : Setting locale appropriately to IP address,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42734358/

相关文章:

c - 保持 Ruby C 扩展代码干燥?

oracle - 在 oracle 数据库中搜索文本中的字符,如 'a' 以匹配以下字符 : 'a' , 'à' 、 'â' 和 'ä'

java - 在 eclipse 项目中使用西里尔字母 .properties 文件

ruby-on-rails - 按 ActiveRecord 中的多列分组

ruby-on-rails - 如何在Ruby中设置通用错误/异常处理程序回调?

ruby-on-rails - Ransacker 和 Arel 在关联领域

java - Struts 2 消息资源包的替代方案

ruby-on-rails - 如何验证至少一个嵌套对象的存在?

ruby - YAML 每个缩进有多少个空格?

ruby - 我怎样才能在 each_char 中执行此操作?