Recently, I had to know which language is preferred by someone visiting the web site I was developing for. Hopefully, HTTP is well designed enough that you should not have to ask your visitors for this preference but can elegantly guess what it is by analyzing the Accept-Language HTTP request header.
This header is seamlessly sent to the HTTP server by your browser. It's clearly defined by the HTTP 1.1 specification if you want all the details. Briefly, the value is a "set of natural languages that are preferred as a response to the request.". Each language "may be given an associated quality value which represents an estimate of the user's preference for the languages specified by that range. The quality value defaults to 1."
To leverage this header, I simply wrote a "helper" method that I made available to all the controllers. I named this method accepted_languages and put it on the ApplicationController class (RAILS_ROOT/app/models/application.rb). It takes no parameter and returns an array where each element is a pair [language tag, quality], sorted by ascending quality.
Here's the code
class ApplicationController < ActionController::Base # ... ## # Returns the languages accepted by the visitors, sorted by quality # (order of preference). ## def accepted_languages() # no language accepted return [] if request.env["HTTP_ACCEPT_LANGUAGE"].nil? # parse Accept-Language accepted = request.env["HTTP_ACCEPT_LANGUAGE"].split(",") accepted = accepted.map { |l| l.strip.split(";") } accepted = accepted.map { |l| if (l.size == 2) # quality present [ l[0].split("-")[0].downcase, l[1].sub(/^q=/, "").to_f ] else # no quality specified => quality == 1 [ l[0].split("-")[0].downcase, 1.0 ] end } # sort by quality accepted.sort { |l1, l2| l1[1] <=> l2[1] } end endLook at how you get the request header inside Rails. It's available from the environment attached to the request through a Ruby home-made key (HTTP_ACCEPT_LANGUAGE). This is due to how the HTTP headers are transmitted between the Rails framework and the HTTP server that stands upfront. This is directly derived from how the CGI standard Ruby library does for passing an HTTP request from a web server to a standalone program, here your Rails application.
Most of the time, your controllers only want to retain one language, the one presumably preferred by the visitor. Additionally, your application only supports a few languages. This is the context I had to fit into and I found useful to add a second method to the ApplicationController class.
This method, named preferred_language, takes 2 optional parameters
- an array that contains the list of language( tag)s supported by your application; it is used to filter out the set of languages accepted by the visitor.
- a default language (tag) that is returned to the caller when the browser does not expose any accepted languages or not a single language that is supported by the application; this second parameter represnts the default language of your application.
class ApplicationController < ActionController::Base # ... ## # Returns the language preferred by the user. ## def preferred_language(supported_languages=[], default_language="en") # only keep supported languages preferred_languages = accepted_languages.select {|l| (supported_languages || []).include?(l[0]) } if preferred_languages.empty? # the browser does accept any supported languages # => default to english default_language else # take the highest quality among accepted (and thus supported) languages preferred_languages.last[0] end end endIf you want to reuse this piece of code (what it's meant for), please remember that it does not take care of country codes. As explained in the HTTP spec, each language tag starts with an ISO-639 language abbreviation and may be followed by an ISO-3166 country code. The latter is simply ignored by this code.
Finally, the parsing and exposure of all the HTTP headers are worth writing a Rails plug-in or a gem. I might do it one day unless someone points me at a similar contribution.
UPDATE: This morning, I found the HTTP Accept-Language plugin that does exactly what I describe hereby, quite similarly. The methods used for accessing the preferred language(s) are bound to the request object, which I admit is better. I'm quite sure this plugin did not exist when I initiated this development (some months ago).
UPDATE (2013/05/10): Naomi Kyoto suggested a much more concise and elegant code snippet for the accepted_languages method. I recommend to use her gist. Thanks for sharing !
Unknown
May 9, 2013 at 9:04 AM
Unknown
May 9, 2013 at 9:06 AM
Unknown
May 9, 2013 at 9:13 AM
I would leave a highly superior solution to this problem but pasting code on your blog is a nightmare. I forfeit.
here's a gist instead
Laurent Farcy
May 10, 2013 at 9:27 AM
Thanks for your comment Naomi. I agree your code is much more concise and elegant. And it does the job !
I'd recommend everyone to go with your solution. And I'm about to make a second update to the post to suggest so.
I can read you're not in favor of gems. Otherwise, I'd have suggested to initiate a new one on GitHub.
Finally, it's great to see that a post written in 2008 can still get readers and, most importantly, constructive feedbacks.
j michel
May 23, 2014 at 12:04 PM
Great post and a good stuff for me to takeaway
Bobb
May 23, 2014 at 1:19 PM
Very Nice post!!thanks for sharing..
Tejuteju
June 27, 2018 at 7:31 AM
Excellent article. Keep upadating
Ruby on Rails Online Course Bangalore
cloudbeginners
August 17, 2021 at 4:30 PM
cloudtrail vs cloudwatch
cloudbeginners
August 18, 2021 at 4:00 PM
azure networking
arm templates
azure notification hub
azure bastion host
app power bi
kubernetes dashboard
terraform cheat sheet
Techystick
November 14, 2021 at 10:41 AM
cloudkeeda
cloudkeeda
cloudkeeda
cloudkeeda
cloudkeeda
cloudkeeda
cloudkeeda
what is azure
azure free account
CodeKing
March 10, 2023 at 12:04 PM
Thanks for sharing your valueable thoughts for us. I truly appreciate your efforts and I will be waiting for your further write ups thank you once again. We provide Website Design Services across the world at comfort price.
Alex Gour
April 18, 2023 at 11:41 AM
Informative blog.
click here
Anshu Dave
April 18, 2023 at 12:32 PM
Excellent article lots to learn.
click here
Anshu Dave
April 18, 2023 at 12:58 PM
Great stuff lots of takeaway from it.
click here
Robbin
April 19, 2023 at 9:13 AM
Great Share...
click here
Nate Lamaro
April 24, 2023 at 12:52 PM
Extensive information blog, as this one details and gives adequate information regarding the blog. Do follow here for more informations Find Here
Tristan Repin
April 26, 2023 at 8:44 AM
Had great time reading this blog, as its information being provided are very helpful. For additional information's Check Here
Chris
April 28, 2023 at 3:13 PM
Amazing write - Up, For more more informations Check Here
Antil Sen
May 2, 2023 at 7:21 AM
Amazing Information. For more click here
Adarsh Jain
May 5, 2023 at 8:39 AM
Excellent article .Lots to learn. For more information- Read Here
Armaan
May 15, 2023 at 2:02 PM
Great Content.For more such content-
click here
Anindya Dutta
May 16, 2023 at 11:21 AM
Ananya Dhar
May 16, 2023 at 11:25 AM
Great learning. For more click here
Mobile Game Development Company in India
May 17, 2024 at 9:08 AM
Parsing the Accept-Language header in Rails allows your app to detect and respond to the user's preferred language, enhancing localization. ChicMic’s expertise ensures seamless integration of such features in your Rails applications for a global user experience.