Giter Site home page Giter Site logo

http_accept_language's Introduction

HttpAcceptLanguage Build Status

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, 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:

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:

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:

class ApplicationController < ActionController::Base
  include HttpAcceptLanguage::AutoLocale

#...
end

Then set available locales in config/application.rb:

config.i18n.available_locales = %w(en nl de fr)

To use the middleware in any Rack application, simply add the middleware:

require 'http_accept_language'
use HttpAcceptLanguage::Middleware
run YourAwesomeApp

Then you can access it from env:

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:

gem 'http_accept_language'

Run bundle install to install it.


Released under the MIT license

http_accept_language's People

Contributors

bahanix avatar bquorning avatar carcols avatar coneybeare avatar dergutemoritz avatar douwem avatar frisoft avatar grosser avatar iain avatar jordimassaguerpla avatar knu avatar kostyantyn avatar phene avatar pinkvelociraptor avatar shin1higo avatar tomhughes avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

http_accept_language's Issues

Problems with Latin American Spanish encoding

Hello, in your code you make the assumption that all "correct" language codes are composed only of alphabetic characters and hyphens. That is not correct: the encoding for Latin American Spanish is "es-419" (which is weird, but true).

Hence your code have problems when the browser asks for latin american spanish.
Cheers.

does not work with RSpec

I'm using RSpec to test my controller and I think the request object is stubbed (or whatever) and then the railtie is not applied to the right instance (it's too complicated for my limited knowledge of rails)...
That's working in dev mode
thanks

my controller :

class HomeController < ApplicationController
  def choose_language
    locale = http_accept_language.compatible_language_from(I18n.available_locales)
    redirect_to root_path(locale)
  end
end

my test :

it "should redirect to home in the specified language" do
  request.env['HTTP_ACCEPT_LANGUAGE'] = 'fr'
  get :choose_language
  response.should redirect_to('/fr')
end

the result :

2) HomeController GET choose_language should redirect to home in the specified language
 Failure/Error: get :choose_language
 NoMethodError:
   undefined method `http_accept_language' for {}:Hash
 # ./app/controllers/home/home_controller.rb:14:in `choose_language'
 # ./app/controllers/application_controller.rb:73:in `block in wrap_in_transaction'
 # ./app/controllers/application_controller.rb:72:in `wrap_in_transaction'
 # ./spec/controllers/home/home_controller_spec.rb:31:in `block (3 levels) in <top (required)>'

Release new version of gem

The version of the master branch seems to work in my Rails 3.2.13 application. The middleware of the gem at rubygems doesn't load. Are you planning to release a new gem?

Thanks!

Consider to extract HttpAcceptLanguage::Parser into separate gem?

@iain Hi, I noticed the repo is not actively maintained, and most pending pull requests (#56 #58 #61) are related to Rails upgrades.

Have you considered to extract HttpAcceptLanguage::Parser into its own gem? Because by doing that, the new parser gem will have no dependency, and anyone who needs the parser can simply install the parser gem and don't have to wait for the Rails-related upgrades.

What do you think?

Does not work with RoR 4

Hi,

seems that gem does not work with RoR 4.0.2.

I've added it to Gemfile, seems that middleware is added:

$ rake middleware
[deprecated] I18n.enforce_available_locales will default to true in the future. If you really want to skip validation of your locale you can set I18n.enforce_available_locales = false to avoid this message.
use Rack::Sendfile
use ActionDispatch::Static
use Rack::Lock
use #<ActiveSupport::Cache::Strategy::LocalCache::Middleware:0x00000005455b28>
use Rack::Runtime
use Rack::MethodOverride
use ActionDispatch::RequestId
use Rails::Rack::Logger
use ActionDispatch::ShowExceptions
use ActionDispatch::DebugExceptions
use ActionDispatch::RemoteIp
use ActionDispatch::Reloader
use ActionDispatch::Callbacks
use ActiveRecord::Migration::CheckPending
use ActiveRecord::ConnectionAdapters::ConnectionManagement
use ActiveRecord::QueryCache
use ActionDispatch::Cookies
use ActionDispatch::Session::CookieStore
use ActionDispatch::Flash
use ActionDispatch::ParamsParser
use Rack::Head
use Rack::ConditionalGet
use Rack::ETag
use Warden::Manager
use HttpAcceptLanguage::Middleware
run Impressario::Application.routes

but

http_accept_language.language_region_compatible_from(available_locales_strings)

always return nil while this

HttpAcceptLanguage::Parser.new(request.headers["Accept-Language"]).language_region_compatible_from(available_locales_strings)

works properly.

NameError Exception in controller when calling methods included from EasyAccess

Hi, I'm trying to use the methods in the controller but getting no_method_error.

Here's what it looks like from inside the controller

>> Listening on 0.0.0.0:3000, CTRL+C to stop
[51, 60] in /Users/lovebob/src/cardagin-web/app/controllers/application_controller.rb
   51  
   52    protected
   53  
   54    def set_locale
   55      debugger
=> 56      available = sanitize_available_locales #I18n.available_locales
   57  
   58      http_accept_language.preferred_language_from(available)
   59  
   60      debugger
/Users/lovebob/src/cardagin-web/app/controllers/application_controller.rb:56
available = sanitize_available_locales #I18n.available_locales
(rdb:1) http_accept_language
NameError Exception: undefined local variable or method `http_accept_language' for <ApplicationController:0x007fe2b28c91e0>
(rdb:1) env.http_accept_language
NoMethodError Exception: undefined method `http_accept_language' for <Hash:0x007fe2b2e11670>
(rdb:1) http_accept_language.user_preferred_languages
NameError Exception: undefined local variable or method `http_accept_language' for #<ApplicationController:0x007fe2b28c91e0>
(rdb:1) HttpAcceptLanguage
HttpAcceptLanguage
(rdb:1) HttpAcceptLanguage::Middleware
NameError Exception: uninitialized constant HttpAcceptLanguage::Middleware
(rdb:1) HttpAcceptLanguage::EasyAccess
NameError Exception: uninitialized constant HttpAcceptLanguage::EasyAccess

Really not sure what's going on here, it's like it's not being required correctly?

I just added it to my gemfile and did bundle install.
Ruby can find the top level constant just fine, but when I try and access any of the classes underneath it it blows up.

Any ideas what I could be doing wrong ?

cardagin-web git:spike/i18n ❯ irb                                                                                                                                                                  
1.9.3p194 :001 > require 'http_accept_language'
 => true 
1.9.3p194 :002 > HttpAcceptLanguage
 => HttpAcceptLanguage 
1.9.3p194 :003 > HttpAcceptLanguage::Middleware
NameError: uninitialized constant HttpAcceptLanguage::Middleware
    from (irb):3
    from /Users/lovebob/.rvm/rubies/ruby-1.9.3-p194/bin/irb:16:in `<main>'
1.9.3p194 :004 > HttpAcceptLanguage::EasyAccess
NameError: uninitialized constant HttpAcceptLanguage::EasyAccess
    from (irb):4
    from /Users/lovebob/.rvm/rubies/ruby-1.9.3-p194/bin/irb:16:in `<main>'

Tried adding it to my config.ru and that blew up too, with similar results

cardagin-web git:spike/i18n ❯ be rails server                                                                                                                                                      
=> Booting Thin
=> Rails 3.2.8 application starting in development on http://0.0.0.0:3000
=> Call with -d to detach
=> Ctrl-C to shutdown server
Exiting
/Users/lovebob/.rvm/gems/ruby-1.9.3-p194@global/gems/rake-0.9.2.2/lib/rake/ext/module.rb:36:in `const_missing': uninitialized constant HttpAcceptLanguage::Middleware (NameError)

Does not work with traditonal vs simplified Chinese

The way that this gem throws out everything after a dash means that it is broken for Chinese locales. Typically, the languages codes are zh-hant, zh-hans, zh-CN, zh-TW, etc.

With the default methods, this gem always serves the first zh available zh variant. But almost any internationalized site that supports Chinese will have two or more variants, and getting simplified Chinese when you read traditional Chinese is not a usable situation.

Here's how I worked around it in my app: WikiEducationFoundation/WikiEduDashboard@cea14bc

I suggest that this gem would be a much more robust solution if it followed the RFC spec, rather than the current behavior described in the readme.

Request for maintainer status

Hello @iain,

I'm requesting that I be granted "maintainer" status over http_accept_language.

I'm hoping to exercise more control over the codebase than I feel I can as an outside contributor.

As part of my full-time work at Shopify, I develop and maintain i18n libraries within the Ruby/Rails ecosystem.

For example, I am the maintainer of ruby-i18n/ruby-cldr, and am currently the #7 contributor to ruby-i18n/i18n. I've also contributed minor fixes to rails-i18n and Rails itself. I also maintain shopify-i18n, Shopify's (currently internal) i18n/l10n library.

Of course, I would continue to accept and appreciate any collaboration from you, and will treat your previous contributions with respect.

I'm hoping that you'll allow me this control over the project, or at the very least, start a discussion around how I can gain such control over time.

The rest of this issue gives some more details about who I am, and what I hope to do with more control over the future of http_accept_language.


My vision for http_accept_language

I want http_accept_language to be a solid foundational library upon the Ruby/Rails ecosystem can depend to provide easy and accurate locale resolution.

Note that I do not wish to expand the scope of http_accept_language.

Some examples of changes I want to make

http_accept_language-specific changes:

  • Fix #55, so that http_accept_language can be used correctly with Chinese locales
  • [Long term] Transfer the repo to the ruby-i18n organization (i.e., ruby-i18n/http_accept_language) to ensure that it has more consistent maintenance going forward.

General repos changes:

  • Add GitHub PR and Issue templates
  • Add a CHANGELOG and LICENSE file
  • Introduce RuboCop to CI, and fix all linting issues
  • Change the default branch from master to main
  • Migrate from TravisCI to GitHub Actions, and test against all versions of Ruby
  • Add a CONTRIBUTING guide

My open source CV

I'm not new to the world of open-source maintainership. Beyond those already mentioned, I'm a maintainer/contributor of several well-used libraries in other ecosystems, including:

  • ciso8601 a foundational Python library for parsing ISO 8601 timestamps quickly.
    • It's in the top-1000 most downloaded Python libraries 📈

I also regularly contribute bug reports and bug fixes to all FOSS software I use.

Beyond that, I've been working as a Software Developer for 12 years now. For the past 4, I've been working on i18n systems at Shopify.

My open source values

  • Users should have extreme confidence when upgrading:
    • Maintain backwards compatibility.
      • Breaking changes should be avoided whenever possible.
      • If necessary, should only happen alongside major version bumps, and should have trivial, (preferably automatable) migration paths
    • Keep libraries small in scope, and provide strong invariants that users can always rely on going into the future
    • Follow [the spirit of] SemVer and Keep a Changelog
  • Document and support the path to contribution
  • Prefer permissive FOSS licenses, but any FOSS license is 👌 (http_accept_language is MIT 👍)
    • I include this to express my commitment to "open source", which doesn't include licenses with restrictions on who can use the code

What I'm asking for

  • To be added as a "Collaborator" on iain/http_accept_language
  • Eventually (when you're comfortable):
    • To have you transfer iain/http_accept_language to the ruby-i18n GitHub organization (i.e., ruby-i18n/http_accept_language)
    • To have you give me whatever keys are needed to be able to publish a new version to RubyGems

I'm hoping that you'll allow me this control over the project, or at the very least, start a discussion around how I can gain such control over time.

Is this gem maintained?

I see that there aren't any commits since 2017... but the official Rails guide still suggests to use this gem.

Is this gem still working / maintained?

Is there a new gem somewhere else?

Missing changelog

It would be really helpful for us users if you maintain a changelog. http://keepachangelog.com/en/0.3.0/
I updated from 2.0.5 to 2.1.0:

2.1.0

* Fix `nil is not a valid locale` error when the Accept-Language header is missing
* Add setting `available_locales` documentation

available_locales incorrectly set

although my application.rb features : config.I18n.available_locales = %w(en fr de)

when I request I18n.available_locales, I retrieve only [:fr]

In my initializers/locale.rb, I have : I18n.default_locale = :en

Returning wrong locale sometimes

I have the following code in my Rails app's ApplicationController:

before_filter :set_locale

And the method definition:

  def set_locale
  logger.warn("*** Available locales: #{I18n.available_locales}")
    logger.warn("*** Preferred language:  #{http_accept_language.preferred_language_from(I18n.available_locales)}")
    I18n.locale = (params[:locale] || http_accept_language.preferred_language_from(I18n.available_locales) || I18n.default_locale)
  end

I have two locales in the app as of now: :en and :pt. If I setup Portuguese to take precedence in my user agent (Chrome) and reload the page, sometimes it still returns english, even though the it's set to Portuguese.

It looks as if some of the unicorn workers still have the I18n.locale cached somehow. Would that be possible?

Any insights would be greatly appreciated!

Language detection fails with whitespaces

Hi,

It seems that language detection fails when there is some whitespace in the http header :
Using whitespacing like those on the linked RFC : http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html section#14.4 in the test file has all tests failling (string used : 'en-us, en-gb;q=0.8, en;q=0.6')

it can be fixed using (added gsub) file: lib/http_accept_language.rb:12
@user_preferred_languages ||= env['HTTP_ACCEPT_LANGUAGE'].gsub(/\s/,'').split(',').collect do |l|
instead of :
@user_preferred_languages ||= env['HTTP_ACCEPT_LANGUAGE'].split(',').collect do |l|

Not working in Rails 4.0.0.rc1

class ApplicationController < ActionController::Base
  before_filter :set_locale
private
  def set_locale
  I18n.locale = http_accept_language.preferred_language_from(%w{en de})

leads to: NameError (undefined local variable or method `http_accept_language' for

tried 1.0.2 and 2.0.0.pre

Rails 3 compatibility?

Hi, it seems like it's not yet compatible for Rails 3, do you plan a new release anytime soon?
Thanks a lot,
X

Change default branch name to `main`

The Git ecosystem is moving away from the default branch name of master, towards the name main.

e.g. All new repos on GitHub/GitLab/Bitbucket now use main as the default branch name for new repositories.

Change the default branch of iain/http_accept_language to use main.

How is this done?

  1. Rename the default branch in the GitHub UI (Requires Administrator rights on the repo)
  2. Use git grep master and update mentions of the outdated branch name in documentation and URLs.

Developers with local clones will have to perform a one-time update of the local clones by running:

git branch -m master main
git fetch origin
git branch -u origin/main main
git symbolic-ref refs/remotes/origin/HEAD refs/remotes/origin/main

These commands are also shown to developers who visit the repo in the GitHub interface, so it doesn't require additional advertising work from our end.

The version has not changed since february

Hi,

I've installed the gem and got the 1.0.1 that is not Rails 3 compatible. I fixed locally, then, forked the project and saw that it was already fixed in master. What a surprise ;-)

Maybe you could bump the version number to release a new version of the gem.

Thanks.

Update to 2.0.2?

Could you please release 2.0.2? There are some commits after 2.0.1 which would be nice-to-have!

Thanks 👍

Not working at all with Safari

The gem works on all browsers I've tried except for Safari (10.1). The following line http_accept_language.preferred_language_from(I18n.available_locales) works as expected everywhere but returns null with Safari. I'm guessing that's because it handles the Accept-Language diferently.

strange side effect on helper

No problem with the 1.0 version, but with the 2.0 version :

I have a NavigationHelper with methods used in my views.
When I add the gem to the Gemfile, my views do not find the methods anymore.

ActionView::Template::Error:
   undefined local variable or method `set_menu_key_from_path' for #<#<Class:0x007f3bc00cec90>:0x007f3bc1f99058>
 # ./app/views/home/index.html.erb:2:in `_app_views_home_index_html_erb__3961088009347108917_45244120'
 # ...

user_preferred_languages does not work as expected

Hi,

According to the comments for user_preferred_languages in http_accept_language.rb, this function should ignore regions and return languages compatible with available locales.

It is my understanding that if the user requests en-US while only en is available, en will be used instead of nothing.

Here are my results, tested in several browsers with one and multiple languages:

request.user_preferred_languages
# => ["en-US"]

I18n.available_locales
# => [:en, :no, :de]

request.compatible_language_from(I18n.available_locales)
# => nil

Have I misunderstood something?

Missing license file

The readme states the gem is licensed under MIT. Can you please add a LICENSE with the MIT license terms to the repo?

Not working with Rails 4.0.2

I have a before action set as

def set_locale
    logger.info "* Accept-Language: #{request.env['HTTP_ACCEPT_LANGUAGE']}"
    logger.info "* Available locales: #{I18n.available_locales.to_sentence}"
    logger.info "* Compatible language: #{http_accept_language.compatible_language_from(I18n.available_locales)}"
    logger.info "* Preferred language: #{http_accept_language.preferred_language_from(I18n.available_locales)}"
    logger.info "* User Preferred Languages: #{http_accept_language.user_preferred_languages}"
    I18n.locale = http_accept_language.compatible_language_from(I18n.available_locales)
    logger.info "* Locale set to '#{I18n.locale}'"
end

And have been testing out using RSpec controller tests, but the locale is not properly detected:

* Accept-Language: es
* Available locales: en, de-ch, de, en-au, en-bork, en-ca, en-gb, en-ind, en-us, es, fr, ja, nb-no, nl, pl, pt-br, sk, and vi
* Compatible language: 
* Preferred language: 
* User Preferred Languages: []
* Locale set to 'en'

I am passing in es and it is an available locale as you can see, yet it is not matched as a compatible language, preferred language or as a user preferred language. Am I doing something wrong here, have a misunderstanding of how it works, or is this a bug in Rails 4.0.2 with http_accept_language?

Wrong language occasionally - potential threading issue?

We're seeing a frustrating issue where this gem works as expected most the time but sometimes in production we end up translating to the wrong language. This is on a very high volume web app where each server runs 16-32 threads of the Rails app under Unicorn.

With settings like

config.i18n.enforce_available_locales = true
config.i18n.default_locale = :en
config.i18n.fallbacks = [:en]
config.i18n.available_locales = [:en, :ja, :ko, :ru]

(note I think that fallbacks is deprecated so I plan to remove it but its been there for a long time)

99.9% of the time we will get the behavior we want but users habitually complain that they somehow get Russian despite having an accept language string like en-US,en;q=0.5 that we can see in our logs.

We previously experienced this issue more frequently before updating the gem to include this fix: 47b02be

My best idea for why this is going awry is that there is another threading issue similar to the one I linked above. Perhaps the memoization at https://github.com/iain/http_accept_language/blob/master/lib/http_accept_language/railtie.rb#L14

Does this seem reasonable?

The only deviation from a normal install of your gem that we have is we do the following in an initializer to ensure engines also get the locale set in lieu of using the HttpAcceptLanguage::AutoLocale concern.

# The locale is set this way so that ALL ActionController::Base instances (ie                                                                                                                                             
# parent app + any engines) set the locale properly                                                                                                                                                                       
ActiveSupport.on_load :action_controller do
  prepend_before_filter { I18n.locale = http_accept_language.compatible_language_from(I18n.available_locales) || I18n.default_locale }
end

It almost always works (I can't reproduce the issue but it has been reported by multiple users) so threading does seem like a likely candidate.

Any ideas?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.