
Security News
New Website “Is It Really FOSS?” Tracks Transparency in Open Source Distribution Models
A new site reviews software projects to reveal if they’re truly FOSS, making complex licensing and distribution models easy to understand.
Web applications often need to cater to users from around the world. One of the ways they can provide a better user experience is by presenting the content in the user's preferred language. This is where the Accept-Language
HTTP header comes into play. Sent by the client (usually a web browser), this header tells the server the list of languages the user understands, and the user's preference order.
Parsing the Accept-Language
header can be complex due to its flexible format defined in RFC 2616. For instance, it can specify languages, countries, and scripts with varying degrees of preference (quality values).
Accept Language
is a lightweight, thread-safe Ruby library designed to parse the Accept-Language
header, making it easier for your application to determine the best language to respond with. It calculates the intersection of the languages the user prefers and the languages your application supports, handling all the complexity of quality values and wildcards.
Whether you're building a multilingual web application or just trying to make your service more accessible to users worldwide, Accept Language
offers a reliable, simple solution.
There are a myriad of tools out there, so why should you consider Accept Language for your next project? Here's why:
Add this line to your application's Gemfile:
gem "accept_language"
And then execute:
bundle install
Or install it yourself as:
gem install accept_language
The Accept Language
library helps web applications serve content in the user's preferred language by parsing the Accept-Language
HTTP header. This header indicates the user's language preferences and their priority order.
The library has two main methods:
AcceptLanguage.parse(header)
: Parses the Accept-Language headermatch(*available_languages)
: Matches against the languages your application supportsAcceptLanguage.parse("fr-CH, fr;q=0.9").match(:fr, :"fr-CH") # => :"fr-CH"
# Header: "da" (Danish is the preferred language)
# Available: :en and :da
AcceptLanguage.parse("da").match(:en, :da) # => :da
# No match available - returns nil
AcceptLanguage.parse("da").match(:fr, :en) # => nil
Q-values range from 0 to 1 and indicate preference order:
# Header: "da, en-GB;q=0.8, en;q=0.7"
# Means:
# - Danish (da): q=1.0 (highest priority)
# - British English (en-GB): q=0.8 (second choice)
# - Generic English (en): q=0.7 (third choice)
AcceptLanguage.parse("da, en-GB;q=0.8, en;q=0.7").match(:en, :da) # => :da
AcceptLanguage.parse("da, en-GB;q=0.8, en;q=0.7").match(:en, :"en-GB") # => :"en-GB"
The library handles specific language variants (regional or script variations):
# Specific variants must match exactly
AcceptLanguage.parse("fr-CH").match(:fr) # => nil (Swiss French ≠ Generic French)
# But generic variants can match specific ones
AcceptLanguage.parse("fr").match(:"fr-CH") # => :"fr-CH"
# Script variants are also supported
AcceptLanguage.parse("uz-Latn-UZ").match("uz-Latn-UZ") # => "uz-Latn-UZ"
The *
wildcard matches any language, and q=0
excludes languages:
# Accept any language but prefer German
AcceptLanguage.parse("de-DE, *;q=0.5").match(:fr) # => :fr (matched by wildcard)
# Accept any language EXCEPT English
AcceptLanguage.parse("*, en;q=0").match(:en) # => nil (explicitly excluded)
AcceptLanguage.parse("*, en;q=0").match(:fr) # => :fr (matched by wildcard)
# Header: "de-LU, fr;q=0.9, en;q=0.7, *;q=0.5"
# Means:
# - Luxembourg German: q=1.0 (highest priority)
# - French: q=0.9 (second choice)
# - English: q=0.7 (third choice)
# - Any other language: q=0.5 (lowest priority)
header = "de-LU, fr;q=0.9, en;q=0.7, *;q=0.5"
parser = AcceptLanguage.parse(header)
parser.match(:de, :"de-LU") # => :"de-LU" (exact match)
parser.match(:fr, :en) # => :fr (higher q-value)
parser.match(:es, :it) # => :es (matched by wildcard)
The matching is case-insensitive but preserves the case of the returned value:
AcceptLanguage.parse("en-GB").match("en-gb") # => "en-gb"
AcceptLanguage.parse("en-gb").match("en-GB") # => "en-GB"
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
before_action :best_locale_from_request!
def best_locale_from_request!
I18n.locale = best_locale_from_request
end
def best_locale_from_request
# HTTP_ACCEPT_LANGUAGE is the standardized key for the Accept-Language header in Rack/Rails
return I18n.default_locale unless request.headers.key?("HTTP_ACCEPT_LANGUAGE")
string = request.headers.fetch("HTTP_ACCEPT_LANGUAGE")
locale = AcceptLanguage.parse(string).match(*I18n.available_locales)
# If the server cannot serve any matching language,
# it can theoretically send back a 406 (Not Acceptable) error code.
# But, for a better user experience, this is rarely done and more
# common way is to ignore the Accept-Language header in this case.
return I18n.default_locale if locale.nil?
locale
end
end
AcceptLanguage uses Semantic Versioning 2.0.0
The gem is available as open source under the terms of the MIT License.
FAQs
Unknown package
We found that accept_language demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
A new site reviews software projects to reveal if they’re truly FOSS, making complex licensing and distribution models easy to understand.
Security News
Astral unveils pyx, a Python-native package registry in beta, designed to speed installs, enhance security, and integrate deeply with uv.
Security News
The Latio podcast explores how static and runtime reachability help teams prioritize exploitable vulnerabilities and streamline AppSec workflows.