http_accept_language-2.0.5/0000755000004100000410000000000012461445747015725 5ustar www-datawww-datahttp_accept_language-2.0.5/Rakefile0000644000004100000410000000045212461445746017372 0ustar www-datawww-datarequire "bundler/gem_tasks" require 'rspec/core/rake_task' RSpec::Core::RakeTask.new(:spec) require 'cucumber/rake/task' Cucumber::Rake::Task.new(:cucumber) Cucumber::Rake::Task.new(:wip, "Run features tagged with @wip") do |t| t.profile = "wip" end task :default => [:spec, :cucumber, :wip] http_accept_language-2.0.5/Gemfile0000644000004100000410000000004712461445746017220 0ustar www-datawww-datasource "https://rubygems.org" gemspec http_accept_language-2.0.5/features/0000755000004100000410000000000012461445746017542 5ustar www-datawww-datahttp_accept_language-2.0.5/features/steps/0000755000004100000410000000000012461445746020700 5ustar www-datawww-datahttp_accept_language-2.0.5/features/steps/rails.rb0000644000004100000410000000160012461445746022334 0ustar www-datawww-dataBefore "@rails" do @rails = RailsDriver.new end When /^I generate a new Rails app$/ do @rails.generate_rails end When /^I add http_accept_language to my Gemfile$/ do @rails.append_gemfile end Given /^I have installed http_accept_language$/ do @rails.install_gem end When /^I generate the following controller:$/ do |string| @rails.generate_controller "languages", string end When /^I access that action with the HTTP_ACCEPT_LANGUAGE header "(.*?)"$/ do |header| @rails.with_rails_running do @rails.request_with_http_accept_language_header(header, "/languages") end end Then /^the response should contain "(.*?)"$/ do |output| @rails.output_should_contain(output) end When /^I run `rake middleware`$/ do @rails.bundle_exec("rake middleware") end Then /^the output should contain "(.*?)"$/ do |expected| @rails.assert_partial_output(expected, @rails.all_output) end http_accept_language-2.0.5/features/rails_integration.feature0000644000004100000410000000165312461445746024641 0ustar www-datawww-data@rails Feature: Rails Integration To use http_accept_language inside a Rails application, just add it to your Gemfile and run `bundle install`. It is automatically added to your middleware. Scenario: Installing When I generate a new Rails app And I add http_accept_language to my Gemfile And I run `rake middleware` Then the output should contain "use HttpAcceptLanguage::Middleware" Scenario: Using Given I have installed http_accept_language When I generate the following controller: """ class LanguagesController < ApplicationController def index languages = http_accept_language.user_preferred_languages render :text => "Languages: #{languages.join(' : ')}" end end """ When I access that action with the HTTP_ACCEPT_LANGUAGE header "en-us,en-gb;q=0.8,en;q=0.6,es-419" Then the response should contain "Languages: en-US : es-419 : en-GB : en" http_accept_language-2.0.5/features/support/0000755000004100000410000000000012461445746021256 5ustar www-datawww-datahttp_accept_language-2.0.5/features/support/rails_driver.rb0000644000004100000410000000366312461445746024300 0ustar www-datawww-datarequire 'aruba/api' class RailsDriver include Aruba::Api def initialize @aruba_io_wait_seconds = 10 # @announce_stdout = true # @announce_stderr = true # @announce_cmd = true # @announce_dir = true # @announce_env = true end def app_name "foobar" end def install_gem if app_exists? cd app_name else generate_rails append_gemfile end end def app_exists? in_current_dir do File.exist?("#{app_name}/Gemfile") end end def bundle_exec(cmd) run_simple "bundle exec #{cmd}" end def generate_rails # install rails with as few things as possible, for speed! bundle_exec "rails new #{app_name} --force --skip-git --skip-active-record --skip-sprockets --skip-javascript --skip-test-unit --old-style-hash" cd app_name end def append_gemfile # Specifiy a path so cucumber will use the unreleased version of the gem append_to_file "Gemfile", "gem 'http_accept_language', :path => '#{gem_path}'" end def gem_path File.expand_path('../../../', __FILE__) end def generate_controller(name, content) bundle_exec "rails generate resource #{name} --force" write_file "app/controllers/#{name}_controller.rb", content end def request_with_http_accept_language_header(header, path) run_simple "curl --retry 10 -H 'Accept-language: #{header}' #{File.join(host, path)} -o #{response}" run_simple "cat out.html" end def host "http://localhost:13000" end def with_rails_running start_rails yield ensure stop_rails end def start_rails bundle_exec "rails server -p 13000 -d" end def stop_rails in_current_dir do `cat tmp/pids/server.pid | xargs kill -9` end end def response File.expand_path(File.join(current_dir, 'out.html')) end def output_should_contain(expected) actual = File.open(response, 'r:utf-8').read actual.should include expected end end http_accept_language-2.0.5/.rspec0000644000004100000410000000003212461445746017034 0ustar www-datawww-data--color --format progress http_accept_language-2.0.5/spec/0000755000004100000410000000000012461445746016656 5ustar www-datawww-datahttp_accept_language-2.0.5/spec/parser_spec.rb0000644000004100000410000000417412461445746021517 0ustar www-datawww-datarequire 'http_accept_language/parser' describe HttpAcceptLanguage::Parser do def parser @parser ||= HttpAcceptLanguage::Parser.new('en-us,en-gb;q=0.8,en;q=0.6,es-419') end it "should return empty array" do parser.header = nil expect(parser.user_preferred_languages).to eq [] end it "should properly split" do expect(parser.user_preferred_languages).to eq %w{en-US es-419 en-GB en} end it "should ignore jambled header" do parser.header = 'odkhjf89fioma098jq .,.,' expect(parser.user_preferred_languages).to eq [] end it "should properly respect whitespace" do parser.header = 'en-us, en-gb; q=0.8,en;q = 0.6,es-419' expect(parser.user_preferred_languages).to eq %w{en-US es-419 en-GB en} end it "should find first available language" do expect(parser.preferred_language_from(%w{en en-GB})).to eq "en-GB" end it "should find first compatible language" do expect(parser.compatible_language_from(%w{en-hk})).to eq "en-hk" expect(parser.compatible_language_from(%w{en})).to eq "en" end it "should find first compatible from user preferred" do parser.header = 'en-us,de-de' expect(parser.compatible_language_from(%w{de en})).to eq 'en' end it "should accept symbols as available languages" do parser.header = 'en-us' expect(parser.compatible_language_from([:"en-HK"])).to eq :"en-HK" end it "should accept and ignore wildcards" do parser.header = 'en-US,en,*' expect(parser.compatible_language_from([:"en-US"])).to eq :"en-US" end it "should sanitize available language names" do expect(parser.sanitize_available_locales(%w{en_UK-x3 en-US-x1 ja_JP-x2 pt-BR-x5 es-419-x4})).to eq ["en-UK", "en-US", "ja-JP", "pt-BR", "es-419"] end it "should accept available language names as symbols and return them as strings" do expect(parser.sanitize_available_locales([:en, :"en-US", :ca, :"ca-ES"])).to eq ["en", "en-US", "ca", "ca-ES"] end it "should find most compatible language from user preferred" do parser.header = 'ja,en-gb,en-us,fr-fr' expect(parser.language_region_compatible_from(%w{en-UK en-US ja-JP})).to eq "ja-JP" end end http_accept_language-2.0.5/spec/auto_locale_spec.rb0000644000004100000410000000137212461445746022507 0ustar www-datawww-datarequire 'i18n' require 'http_accept_language/auto_locale' require 'http_accept_language/parser' require 'http_accept_language/middleware' describe HttpAcceptLanguage::AutoLocale do let(:controller_class) do Class.new do def self.before_filter(dummy) # dummy method end def http_accept_language HttpAcceptLanguage::Parser.new("ja,en-us;q=0.7,en;q=0.3") end include HttpAcceptLanguage::AutoLocale end end let(:controller) { controller_class.new } context "available languages includes accept_languages" do before do I18n.available_locales = [:en, :ja] end it "take a suitable locale" do controller.send(:set_locale) expect(I18n.locale).to eq(:ja) end end end http_accept_language-2.0.5/spec/middleware_spec.rb0000644000004100000410000000317712461445746022342 0ustar www-datawww-datarequire 'http_accept_language' require 'rack/test' require 'json' class TestRackApp def call(env) request = Rack::Request.new(env) http_accept_language = env.http_accept_language result = { :user_preferred_languages => http_accept_language.user_preferred_languages, } if request.params['preferred'] result[:preferred_language_from] = http_accept_language.preferred_language_from(request.params['preferred']) end [ 200, {}, [ JSON.generate(result) ]] end end describe "Rack integration" do include Rack::Test::Methods def app Rack::Builder.new do use HttpAcceptLanguage::Middleware run TestRackApp.new end.to_app end it "handles reuse of the env instance" do env = { "HTTP_ACCEPT_LANGUAGE" => "en" } app = lambda { |env| env } middleware = HttpAcceptLanguage::Middleware.new(app) middleware.call(env) expect(env.http_accept_language.user_preferred_languages).to eq %w{en} env["HTTP_ACCEPT_LANGUAGE"] = "de" middleware.call(env) expect(env.http_accept_language.user_preferred_languages).to eq %w{de} end it "decodes the HTTP_ACCEPT_LANGUAGE header" do request_with_header 'en-us,en-gb;q=0.8,en;q=0.6,es-419' expect(r['user_preferred_languages']).to eq %w{en-US es-419 en-GB en} end it "finds the first available language" do request_with_header 'en-us,en-gb;q=0.8,en;q=0.6,es-419', :preferred => %w(en en-GB) expect(r['preferred_language_from']).to eq 'en-GB' end def request_with_header(header, params = {}) get "/", params, 'HTTP_ACCEPT_LANGUAGE' => header end def r JSON.parse(last_response.body) end end http_accept_language-2.0.5/lib/0000755000004100000410000000000012461445746016472 5ustar www-datawww-datahttp_accept_language-2.0.5/lib/http_accept_language/0000755000004100000410000000000012461445746022633 5ustar www-datawww-datahttp_accept_language-2.0.5/lib/http_accept_language/parser.rb0000644000004100000410000000717212461445746024463 0ustar www-datawww-datamodule HttpAcceptLanguage class Parser attr_accessor :header def initialize(header) @header = header 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 ||= begin header.to_s.gsub(/\s+/, '').split(',').map do |language| locale, quality = language.split(';q=') raise ArgumentError, 'Not correctly formatted' unless locale =~ /^[a-z\-0-9]+|\*$/i locale = locale.downcase.gsub(/-[a-z0-9]+$/i, &:upcase) # Uppercase territory locale = nil if locale == '*' # Ignore wildcards quality = quality ? quality.to_f : 1.0 [locale, quality] end.sort do |(_, left), (_, right)| right <=> left end.map(&:first).compact rescue ArgumentError # Just rescue anything if the browser messed up badly. [] end end # Sets the user languages preference, overriding 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.map(&: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 |preferred| #en-US preferred = preferred.downcase preferred_language = preferred.split('-', 2).first available_languages.find do |available| # en available = available.to_s.downcase preferred == available || preferred_language == available.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 |available| available.to_s.split(/[_-]/).reject { |part| part.start_with?("x") }.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 |preferred| #en-US preferred = preferred.downcase preferred_language = preferred.split('-', 2).first lang_group = available_languages.select do |available| # en preferred_language == available.downcase.split('-', 2).first end lang_group.find { |lang| lang.downcase == preferred } || lang_group.first #en-US, en-UK end.compact.first end end end http_accept_language-2.0.5/lib/http_accept_language/version.rb0000644000004100000410000000006212461445746024643 0ustar www-datawww-datamodule HttpAcceptLanguage VERSION = '2.0.5' end http_accept_language-2.0.5/lib/http_accept_language/middleware.rb0000644000004100000410000000052212461445746025274 0ustar www-datawww-datamodule HttpAcceptLanguage class Middleware def initialize(app) @app = app end def call(env) env["http_accept_language.parser"] = Parser.new(env["HTTP_ACCEPT_LANGUAGE"]) def env.http_accept_language self["http_accept_language.parser"] end @app.call(env) end end end http_accept_language-2.0.5/lib/http_accept_language/auto_locale.rb0000644000004100000410000000047012461445746025450 0ustar www-datawww-datarequire 'active_support/concern' module HttpAcceptLanguage module AutoLocale extend ActiveSupport::Concern included do before_filter :set_locale end private def set_locale I18n.locale = http_accept_language.compatible_language_from(I18n.available_locales) end end end http_accept_language-2.0.5/lib/http_accept_language/railtie.rb0000644000004100000410000000071012461445746024607 0ustar www-datawww-datamodule HttpAcceptLanguage class Railtie < ::Rails::Railtie initializer "http_accept_language.add_middleware" do |app| app.middleware.use Middleware ActiveSupport.on_load :action_controller do include EasyAccess end end end module EasyAccess def http_accept_language @http_accept_language ||= request.env["http_accept_language.parser"] || Parser.new(request.env["HTTP_ACCEPT_LANGUAGE"]) end end end http_accept_language-2.0.5/lib/http_accept_language.rb0000644000004100000410000000027612461445746023165 0ustar www-datawww-datarequire 'http_accept_language/auto_locale' require 'http_accept_language/parser' require 'http_accept_language/middleware' require 'http_accept_language/railtie' if defined?(Rails::Railtie) http_accept_language-2.0.5/cucumber.yml0000644000004100000410000000013012461445746020246 0ustar www-datawww-datadefault: --format progress --strict --tags ~@wip wip: --format pretty --wip --tags @wip http_accept_language-2.0.5/metadata.yml0000644000004100000410000001031212461445746020224 0ustar www-datawww-data--- !ruby/object:Gem::Specification name: http_accept_language version: !ruby/object:Gem::Version version: 2.0.5 platform: ruby authors: - iain autorequire: bindir: bin cert_chain: [] date: 2015-01-25 00:00:00.000000000 Z dependencies: - !ruby/object:Gem::Dependency name: rake requirement: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' - !ruby/object:Gem::Dependency name: rspec requirement: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' - !ruby/object:Gem::Dependency name: rack-test requirement: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' - !ruby/object:Gem::Dependency name: guard-rspec requirement: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' - !ruby/object:Gem::Dependency name: rails requirement: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: 3.2.6 type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: 3.2.6 - !ruby/object:Gem::Dependency name: cucumber requirement: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' - !ruby/object:Gem::Dependency name: aruba requirement: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' description: Find out which locale the user preferes by reading the languages they specified in their browser email: - iain@iain.nl executables: [] extensions: [] extra_rdoc_files: [] files: - ".gitignore" - ".rspec" - Gemfile - Guardfile - README.md - Rakefile - cucumber.yml - features/rails_integration.feature - features/steps/rails.rb - features/support/rails_driver.rb - http_accept_language.gemspec - lib/http_accept_language.rb - lib/http_accept_language/auto_locale.rb - lib/http_accept_language/middleware.rb - lib/http_accept_language/parser.rb - lib/http_accept_language/railtie.rb - lib/http_accept_language/version.rb - spec/auto_locale_spec.rb - spec/middleware_spec.rb - spec/parser_spec.rb homepage: https://github.com/iain/http_accept_language licenses: - MIT metadata: {} post_install_message: rdoc_options: [] require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' required_rubygems_version: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' requirements: [] rubyforge_project: http_accept_language rubygems_version: 2.2.2 signing_key: specification_version: 4 summary: Find out which locale the user preferes by reading the languages they specified in their browser test_files: - features/rails_integration.feature - features/steps/rails.rb - features/support/rails_driver.rb - spec/auto_locale_spec.rb - spec/middleware_spec.rb - spec/parser_spec.rb has_rdoc: http_accept_language-2.0.5/.gitignore0000644000004100000410000000006712461445746017717 0ustar www-datawww-data*.gem .bundle Gemfile.lock pkg/* .rvmrc log/*.log tmp/ http_accept_language-2.0.5/http_accept_language.gemspec0000644000004100000410000000226012461445746023432 0ustar www-datawww-data# -*- encoding: utf-8 -*- $:.push File.expand_path("../lib", __FILE__) require "http_accept_language/version" Gem::Specification.new do |s| s.name = "http_accept_language" s.version = HttpAcceptLanguage::VERSION s.authors = ["iain"] s.email = ["iain@iain.nl"] s.homepage = "https://github.com/iain/http_accept_language" s.summary = %q{Find out which locale the user preferes by reading the languages they specified in their browser} s.description = %q{Find out which locale the user preferes by reading the languages they specified in their browser} s.license = "MIT" s.rubyforge_project = "http_accept_language" s.files = `git ls-files`.split("\n") s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } s.require_paths = ["lib"] s.add_development_dependency 'rake' s.add_development_dependency 'rspec' s.add_development_dependency 'rack-test' s.add_development_dependency 'guard-rspec' s.add_development_dependency 'rails', '>= 3.2.6' s.add_development_dependency 'cucumber' s.add_development_dependency 'aruba' end http_accept_language-2.0.5/README.md0000644000004100000410000000706512461445746017213 0ustar www-datawww-data# HttpAcceptLanguage A gem which helps you detect the users preferred language, as sent by the "Accept-Language" HTTP header. The algorithm is based on [RFC 2616](http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html), with one exception: when a user requests "en-US" and "en" is an available language, "en" is deemed compatible with "en-US". The RFC specifies that the requested language must either exactly match the available language or must exactly match a prefix of the available language. This means that when the user requests "en" and "en-US" is available, "en-US" would be compatible, but not the other way around. This is usually not what you're looking for. Since version 2.0, this gem is Rack middleware. ## Example The `http_accept_language` method is available in any controller: ```ruby class SomeController < ApplicationController def some_action http_accept_language.user_preferred_languages # => %w(nl-NL nl-BE nl en-US en) available = %w(en en-US nl-BE) http_accept_language.preferred_language_from(available) # => 'nl-BE' http_accept_language.user_preferred_languages # => %w(en-GB) available = %w(en-US) http_accept_language.compatible_language_from(available) # => 'en-US' http_accept_language.user_preferred_languages # => %w(nl-NL nl-BE nl en-US en) available = %w(en nl de) # This could be from I18n.available_locales http_accept_language.preferred_language_from(available) # => 'nl' end end ``` You can easily set the locale used for i18n in a before-filter: ```ruby class SomeController < ApplicationController before_filter :set_locale private def set_locale I18n.locale = http_accept_language.compatible_language_from(I18n.available_locales) end end ``` If you want to enable this behavior by default in your controllers, you can just include the provided concern: ```ruby class ApplicationController < ActionController::Base include HttpAcceptLanguage::AutoLocale #... end ``` To use the middleware in any Rack application, simply add the middleware: ``` ruby require 'http_accept_language' use HttpAcceptLanguage::Middleware run YourAwesomeApp ``` Then you can access it from `env`: ``` ruby class YourAwesomeApp def initialize(app) @app = app end def call(env) available = %w(en en-US nl-BE) language = env.http_accept_language.preferred_language_from(available) [200, {}, ["Oh, you speak #{language}!"]] end end ``` ## Available methods * **user_preferred_languages**: Returns a sorted array based on user preference in HTTP_ACCEPT_LANGUAGE, sanitized and all. * **preferred_language_from(languages)**: Finds the locale specifically requested by the browser * **compatible_language_from(languages)**: Returns the first of the user_preferred_languages that is compatible with the available locales. Ignores region. * **sanitize_available_locales(languages)**: Returns a supplied list of available locals without any extra application info that may be attached to the locale for storage in the application. * **language_region_compatible_from(languages)**: 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. ## Installation ### Without Bundler Install the gem `http_accept_language` ### With Bundler Add the gem to your Gemfile: ``` ruby gem 'http_accept_language' ``` Run `bundle install` to install it. --- Released under the MIT license http_accept_language-2.0.5/Guardfile0000644000004100000410000000027712461445746017557 0ustar www-datawww-data#!/usr/bin/env ruby guard 'rspec', :cli => "-fd", :version => 2 do watch(%r{^spec/.+_spec\.rb$}) watch(%r{^lib/(.+)\.rb$}) { "spec" } watch('spec/spec_helper.rb') { "spec" } end