Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
188 additions
and
193 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,6 @@ | ||
require "bundler/gem_tasks" | ||
|
||
require 'rake/testtask' | ||
desc 'Test the http_accept_language plugin.' | ||
Rake::TestTask.new(:test) do |t| | ||
t.pattern = 'test/**/*_test.rb' | ||
end | ||
require 'rspec/core/rake_task' | ||
RSpec::Core::RakeTask.new(:spec) | ||
|
||
desc 'Default: run unit tests.' | ||
task :default => :test | ||
task :default => :spec |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,96 +1,3 @@ | ||
module HttpAcceptLanguage | ||
|
||
# Returns a sorted array based on user preference in HTTP_ACCEPT_LANGUAGE. | ||
# Browsers send this HTTP header, so don't think this is holy. | ||
# | ||
# Example: | ||
# | ||
# request.user_preferred_languages | ||
# # => [ 'nl-NL', 'nl-BE', 'nl', 'en-US', 'en' ] | ||
# | ||
def user_preferred_languages | ||
@user_preferred_languages ||= env['HTTP_ACCEPT_LANGUAGE'].split(/\s*,\s*/).collect do |l| | ||
l += ';q=1.0' unless l =~ /;q=\d+\.\d+$/ | ||
l.split(';q=') | ||
end.sort do |x,y| | ||
raise "Not correctly formatted" unless x.first =~ /^[a-z\-0-9]+$/i | ||
y.last.to_f <=> x.last.to_f | ||
end.collect do |l| | ||
l.first.downcase.gsub(/-[a-z0-9]+$/i) { |x| x.upcase } | ||
end | ||
rescue # Just rescue anything if the browser messed up badly. | ||
[] | ||
end | ||
|
||
# Sets the user languages preference, overiding the browser | ||
# | ||
def user_preferred_languages=(languages) | ||
@user_preferred_languages = languages | ||
end | ||
|
||
# Finds the locale specifically requested by the browser. | ||
# | ||
# Example: | ||
# | ||
# request.preferred_language_from I18n.available_locales | ||
# # => 'nl' | ||
# | ||
def preferred_language_from(array) | ||
(user_preferred_languages & array.collect { |i| i.to_s }).first | ||
end | ||
|
||
# Returns the first of the user_preferred_languages that is compatible | ||
# with the available locales. Ignores region. | ||
# | ||
# Example: | ||
# | ||
# request.compatible_language_from I18n.available_locales | ||
# | ||
def compatible_language_from(available_languages) | ||
user_preferred_languages.map do |x| #en-US | ||
available_languages.find do |y| # en | ||
y = y.to_s | ||
x == y || x.split('-', 2).first == y.split('-', 2).first | ||
end | ||
end.compact.first | ||
end | ||
|
||
# Returns a supplied list of available locals without any extra application info | ||
# that may be attached to the locale for storage in the application. | ||
# | ||
# Example: | ||
# [ja_JP-x1, en-US-x4, en_UK-x5, fr-FR-x3] => [ja-JP, en-US, en-UK, fr-FR] | ||
# | ||
def sanitize_available_locales(available_languages) | ||
available_languages.map do |avail| | ||
split_locale = avail.split(/[_-]/) | ||
|
||
split_locale.map do |e| | ||
e unless e.match(/x|[0-9*]/) | ||
end.compact.join("-") | ||
end | ||
end | ||
|
||
# Returns the first of the user preferred languages that is | ||
# also found in available languages. Finds best fit by matching on | ||
# primary language first and secondarily on region. If no matching region is | ||
# found, return the first language in the group matching that primary language. | ||
# | ||
# Example: | ||
# | ||
# request.language_region_compatible(available_languages) | ||
# | ||
def language_region_compatible_from(available_languages) | ||
available_languages = sanitize_available_locales(available_languages) | ||
user_preferred_languages.map do |x| #en-US | ||
lang_group = available_languages.select do |y| # en | ||
y = y.to_s | ||
x.split('-', 2).first == y.split('-', 2).first | ||
end | ||
lang_group.find{|l| l == x} || lang_group.first #en-US, en-UK | ||
end.compact.first | ||
end | ||
|
||
end | ||
|
||
require 'http_accept_language/parser' | ||
require 'http_accept_language/rack' | ||
require 'http_accept_language/rails' if defined?(ActionPack) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
module HttpAcceptLanguage | ||
|
||
class Parser | ||
|
||
attr_reader :env | ||
|
||
def initialize(env) | ||
@env = env | ||
end | ||
|
||
# Returns a sorted array based on user preference in HTTP_ACCEPT_LANGUAGE. | ||
# Browsers send this HTTP header, so don't think this is holy. | ||
# | ||
# Example: | ||
# | ||
# request.user_preferred_languages | ||
# # => [ 'nl-NL', 'nl-BE', 'nl', 'en-US', 'en' ] | ||
# | ||
def user_preferred_languages | ||
@user_preferred_languages ||= env['HTTP_ACCEPT_LANGUAGE'].split(/\s*,\s*/).collect do |l| | ||
l += ';q=1.0' unless l =~ /;q=\d+\.\d+$/ | ||
l.split(';q=') | ||
end.sort do |x,y| | ||
raise "Not correctly formatted" unless x.first =~ /^[a-z\-0-9]+$/i | ||
y.last.to_f <=> x.last.to_f | ||
end.collect do |l| | ||
l.first.downcase.gsub(/-[a-z0-9]+$/i) { |x| x.upcase } | ||
end | ||
rescue # Just rescue anything if the browser messed up badly. | ||
[] | ||
end | ||
|
||
# Sets the user languages preference, overiding the browser | ||
# | ||
def user_preferred_languages=(languages) | ||
@user_preferred_languages = languages | ||
end | ||
|
||
# Finds the locale specifically requested by the browser. | ||
# | ||
# Example: | ||
# | ||
# request.preferred_language_from I18n.available_locales | ||
# # => 'nl' | ||
# | ||
def preferred_language_from(array) | ||
(user_preferred_languages & array.collect { |i| i.to_s }).first | ||
end | ||
|
||
# Returns the first of the user_preferred_languages that is compatible | ||
# with the available locales. Ignores region. | ||
# | ||
# Example: | ||
# | ||
# request.compatible_language_from I18n.available_locales | ||
# | ||
def compatible_language_from(available_languages) | ||
user_preferred_languages.map do |x| #en-US | ||
available_languages.find do |y| # en | ||
y = y.to_s | ||
x == y || x.split('-', 2).first == y.split('-', 2).first | ||
end | ||
end.compact.first | ||
end | ||
|
||
# Returns a supplied list of available locals without any extra application info | ||
# that may be attached to the locale for storage in the application. | ||
# | ||
# Example: | ||
# [ja_JP-x1, en-US-x4, en_UK-x5, fr-FR-x3] => [ja-JP, en-US, en-UK, fr-FR] | ||
# | ||
def sanitize_available_locales(available_languages) | ||
available_languages.map do |avail| | ||
split_locale = avail.split(/[_-]/) | ||
|
||
split_locale.map do |e| | ||
e unless e.match(/x|[0-9*]/) | ||
end.compact.join("-") | ||
end | ||
end | ||
|
||
# Returns the first of the user preferred languages that is | ||
# also found in available languages. Finds best fit by matching on | ||
# primary language first and secondarily on region. If no matching region is | ||
# found, return the first language in the group matching that primary language. | ||
# | ||
# Example: | ||
# | ||
# request.language_region_compatible(available_languages) | ||
# | ||
def language_region_compatible_from(available_languages) | ||
available_languages = sanitize_available_locales(available_languages) | ||
user_preferred_languages.map do |x| #en-US | ||
lang_group = available_languages.select do |y| # en | ||
y = y.to_s | ||
x.split('-', 2).first == y.split('-', 2).first | ||
end | ||
lang_group.find{|l| l == x} || lang_group.first #en-US, en-UK | ||
end.compact.first | ||
end | ||
|
||
end | ||
|
||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,27 @@ | ||
require 'forwardable' | ||
|
||
module HttpAcceptLanguage | ||
module Rails | ||
|
||
extend Forwardable | ||
|
||
def http_accept_language_parser | ||
@http_accept_language_parser ||= Parser.new(env) | ||
end | ||
|
||
def_delegators :http_accept_language_parser, | ||
:user_preferred_languages, :user_preferred_languages=, | ||
:preferred_language_from, :compatible_language_from, | ||
:sanitize_available_locales, :language_region_compatible_from | ||
|
||
end | ||
|
||
end | ||
|
||
classes = if ActionPack::VERSION::MAJOR == 2 | ||
[ActionController::Request, ActionController::CgiRequest] | ||
else | ||
[ActionDispatch::Request] | ||
end | ||
|
||
classes.each { |c| c.send :include, HttpAcceptLanguage } | ||
classes.each { |c| c.send :include, HttpAcceptLanguage::Rails } |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
require 'http_accept_language/parser' | ||
|
||
describe HttpAcceptLanguage::Parser do | ||
|
||
def parser | ||
@parser ||= HttpAcceptLanguage::Parser.new('HTTP_ACCEPT_LANGUAGE' => 'en-us,en-gb;q=0.8,en;q=0.6,es-419') | ||
end | ||
|
||
it "should return empty array" do | ||
parser.env['HTTP_ACCEPT_LANGUAGE'] = nil | ||
parser.user_preferred_languages.should eq [] | ||
end | ||
|
||
it "should properly split" do | ||
parser.user_preferred_languages.should eq %w{en-US es-419 en-GB en} | ||
end | ||
|
||
it "should ignore jambled header" do | ||
parser.env['HTTP_ACCEPT_LANGUAGE'] = 'odkhjf89fioma098jq .,.,' | ||
parser.user_preferred_languages.should eq [] | ||
end | ||
|
||
it "should find first available language" do | ||
parser.preferred_language_from(%w{en en-GB}).should eq "en-GB" | ||
end | ||
|
||
it "should find first compatible language" do | ||
parser.compatible_language_from(%w{en-hk}).should eq "en-hk" | ||
parser.compatible_language_from(%w{en}).should eq "en" | ||
end | ||
|
||
it "should find first compatible from user preferred" do | ||
parser.env['HTTP_ACCEPT_LANGUAGE'] = 'en-us,de-de' | ||
parser.compatible_language_from(%w{de en}).should eq 'en' | ||
end | ||
|
||
it "should accept symbols as available languages" do | ||
parser.env['HTTP_ACCEPT_LANGUAGE'] = 'en-us' | ||
parser.compatible_language_from([:"en-HK"]).should eq :"en-HK" | ||
end | ||
|
||
it "should sanitize available language names" do | ||
parser.sanitize_available_locales(%w{en_UK-x3 en-US-x1 ja_JP-x2 pt-BR-x5}).should eq ["en-UK", "en-US", "ja-JP", "pt-BR"] | ||
end | ||
|
||
it "should find most compatible language from user preferred" do | ||
parser.env['HTTP_ACCEPT_LANGUAGE'] = 'ja,en-gb,en-us,fr-fr' | ||
parser.language_region_compatible_from(%w{en-UK en-US ja-JP}).should eq "ja-JP" | ||
end | ||
|
||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
require 'http_accept_language/rack' | ||
require 'http_accept_language' | ||
require 'rack/test' | ||
require 'json' | ||
|
||
|
Oops, something went wrong.