Skip to content

Instantly share code, notes, and snippets.

@ichiban
Last active December 21, 2015 06:18
Show Gist options
  • Save ichiban/6262977 to your computer and use it in GitHub Desktop.
Save ichiban/6262977 to your computer and use it in GitHub Desktop.
Set I18N locale based on HTTP_ACCEPT_LANGUAGE header.
class ApplicationController < ActionController::Base
# ...
before_filter :set_locale
# ...
def set_locale
logger.debug "* Accept-Language: #{request.env['HTTP_ACCEPT_LANGUAGE']}"
I18n.locale = locale_string(locale) if locale
logger.debug "* Locale set to '#{I18n.locale}'"
end
private
def locale
@local ||= locale_from_param || locale_from_header
end
def locale_hash(local_string)
locale, qvalue = local_string.split(';q=')
language, territory = locale.split('-')
{
language: language.downcase,
territory: territory ? territory.upcase : nil,
qvalue: qvalue ? qvalue.to_f : 1.0
}
end
def locale_string(locale_hash)
language = locale_hash[:language].downcase
territory = locale_hash[:territory].upcase if locale_hash[:territory]
territory ? "#{language}-#{territory}" : language
end
# convert a locale hash into an available locale hash.
# if this app supports the given locale, returns the locale.
# if this app supports not the exact locale but an alternate locale with the same language,
# returns the alternate locale.
# otherwise, returns nil.
def available_locale(locale)
@@available_locales ||= ['en', 'ja'].map{|l| locale_hash(l) }
same_languages = @@available_locales.select{|l| l[:language] == locale[:language] }
exact_sames = same_languages.select{|l| l[:territory] == locale[:territory] }
exact_sames.empty? ? same_languages.first : exact_sames.first
end
def locale_from_param
return nil unless params[:locale]
locale = locale_hash(params[:locale])
available_locale(locale)
end
def locale_from_header
http_accept_language = request.env['HTTP_ACCEPT_LANGUAGE']
return nil unless http_accept_language
locales = http_accept_language.gsub(/\s+/, '').split(/,/).map{|l| locale_hash(l) }
# sort locale hashes by qvalue. to make it descending order, reverse it.
sorted_locales = locales.sort{|a, b| a[:qvalue] <=> b[:qvalue] }.reverse!
filtered_locales = sorted_locales.map{|l| available_locale(l) }
filtered_locales.first
rescue => e
nil
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment