12

how to set locale automatically on ruby on rails? For instance, if the web pages is opened up in Spain then the locale=es, similarly if it is in united kingdom then the locale=en and alike?

Please help me out.

RajG
  • 832
  • 2
  • 15
  • 26
  • look at 2.6.2 Using GeoIP (or Similar) Database in [this link](http://guides.rubyonrails.org/i18n.html) – piam Nov 09 '12 at 15:41
  • 1
    @NickGinanto This is quite an old post. I eventually went on with I18n gems. Using the gems enabled the app to respect the user's preferred locale based on their browser's language settings. That means they get the opportunity to look at other locale if they prefer to. – RajG Oct 18 '13 at 14:56

5 Answers5

28

You can implement it like this in your ApplicationController:

class ApplicationController < ActionController::Base
  before_filter :set_locale

  def set_locale
    I18n.locale = extract_locale_from_headers
  end

  private

  def extract_locale_from_headers
    request.env['HTTP_ACCEPT_LANGUAGE'].scan(/^[a-z]{2}/).first.presence || 'en'
  end
end

It will "inspect" the received request, find the language of the client's browser and set it as your I18n locale.

Take a look at the RubyOnRails Guide about I18n for further instructions.


I highly recommend to have a set of supported locales and fallback to a default locale. Something like this:

ALLOWED_LOCALES = %w( fr en es ).freeze
DEFAULT_LOCALE = 'en'.freeze

def extract_locale_from_headers
  browser_locale = request.env['HTTP_ACCEPT_LANGUAGE'].scan(/^[a-z]{2}/).first
  if ALLOWED_LOCALES.include?(browser_locale)
    browser_locale
  else
    DEFAULT_LOCALE
  end
end
MrYoshiji
  • 54,334
  • 13
  • 124
  • 117
  • this is works for real users but terrible for robot and search engines - all of them get 500 errors because in request haven't env['HTTP_ACCEPT_LANGUAGE'] its nill if you are still wanna use this code check: if !request.env['HTTP_ACCEPT_LANGUAGE'].blank? – r3cha Mar 25 '17 at 17:49
  • That is why I added the highly recommended fallback @RomanKlevtcov – MrYoshiji Mar 25 '17 at 19:19
  • Oh see that right now, sorry. also we can update code: – r3cha Mar 26 '17 at 21:17
9

try using gem geocoder and i18n_data gem and have a before_filter to a method which does

def checklocale
  I18n.locale =  I18nData.country_code(request.location.country) 
end
Nick Ginanto
  • 31,090
  • 47
  • 134
  • 244
  • installed both gems but, no luck :(... if i can get yours working then i can work out a better code i.e. if the browser does not reply back when doing http headers requests then i could use your idea to implement to get the location/country data and then i could set the locale based upon it. but sadly its not displaying any value. but i very much like to work on your code rather than working with 'geoip'. may be you could give me an alternative pointer. thanks – RajG Nov 16 '12 at 12:32
  • add gem 'geocoder' and gem 'i18n_data' to your gemfile. restart your app. check the above line in any view or controller. see that it works. Note, that it will not work in development since request.location.country will give you resereved since your request.ip will be 127.0.0.1 – Nick Ginanto Nov 16 '12 at 14:28
  • i ran that in production mode did not work :(. i stored the value into `@country=I18nData.country_code(request.location.country) ` and did `render :text => "country= #{@country}"` The value of the country came up null! – RajG Nov 16 '12 at 16:52
  • are you running through a proxy? – Nick Ginanto Nov 16 '12 at 17:12
  • i am running it from terminal[cmd] – RajG Nov 16 '12 at 17:21
  • @RailsNOOB is there anyway of manipulating the request.ip = 127.0.0.1 to something else ? if so, how can I do that? thanks! – RajG Nov 19 '12 at 10:52
  • if you are in development I am not aware of a way of changing you IP. You should see that request.location.country will equal "Reserved". on production/staging you could check the i18n incrementally by changing request.location.country to the country you want to check so instead of @country=I18nData.country_code(request.location.country) you would have @country=I18nData.country_code("Spain"). And see if your interface works correctly. – Nick Ginanto Nov 19 '12 at 10:58
  • in development mode it worked(did not work on production), however why does the first letter has to be in a capital? it does not work when i do **"spain"**. Similarly, it did not work for **"German"** or **"Germany"**. When we do `@country=I18nData.country_code(request.location.country)` does it only extracts the "name_of_the_country"? thanks! – RajG Nov 19 '12 at 11:39
  • **UPDATE** Germany actually works! but I am just curious that if I look up the website in German, would `request.location.country` extracts **Germany** or **German** or **german** or **germany**? – RajG Nov 19 '12 at 11:48
  • request.location.country will give you the name of the country that the request is coming from. So if a user access a website from Germany request.location.country will return "Germany". What does request.location.country give you in production? Could be that your hosting service proxy your request and changes the ip to an internal IP address – Nick Ginanto Nov 19 '12 at 11:56
  • in production mode it returns a null value. – RajG Nov 19 '12 at 11:59
  • what does request.location give? – Nick Ginanto Nov 19 '12 at 12:04
  • unfortunately, it still is a null value! in production mode :? – RajG Nov 19 '12 at 12:08
  • when i checked the terminal, the ip address is **127.0.0.1** quoting your comment again **Could be that your hosting service proxy your request and changes the ip to an internal IP address** is so true. Any chance of manipulating the internal IP address? – RajG Nov 19 '12 at 12:25
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/19759/discussion-between-railsn00b-and-rrz) – Nick Ginanto Nov 19 '12 at 12:30
  • 6
    I think a geoip-based localization is nonsense. Think about two scenarios: You are from Mexico and you went to visit Japan. You vist your most favorite app from a free WiFi in Japan and BAM: You get it in japanese and you can't read anything. The second one: a german customer of yours connects to the WiFi at her favorite Starbucks. The WiFi provider (BT WiFi) is located in the UK and so the user has a UK based IP and BAM: he gets an english version of the app. I would go for the solution with the HTTP_ACCEPT_LANGUAGE header as you can please your users with their preferred language. – Martin Röbert Nov 21 '13 at 06:34
  • @MartinRöbert BAM I got that :p BAM – RajG Jan 24 '14 at 15:16
4

Include this is ApplicationController or BaseController

before_filter :set_locale

def set_locale
  I18n.locale = params[:locale] || I18n.default_locale
end

This means set locale to default or use locale from request, priority to the one sent in request. If you want to expand this to user, session, request you can do this.

def set_locale
  I18n.locale = @user.locale || session[:locale] || params[:locale] || I18n.default_locale
end

More info here Similar question.

Community
  • 1
  • 1
Haris Krajina
  • 14,824
  • 12
  • 64
  • 81
1

If i get what u mean, u will have to work with geolocation, get the user location based on his ip, and then set the locale based on it, but u must not forgot to set some default in case u can't get nothing of the user's ip.

Im sorry to say, but i didnt worked with geolocation on ruby yet. I did a fast research on rubygems and couldnt find any gem to simplify your work. =(

Paulo Henrique
  • 1,025
  • 8
  • 12
0

From the Rails Guide, include this code in the ApplicationController

before_action :set_locale

def set_locale
  I18n.locale = extract_locale_from_tld || I18n.default_locale
end

# Get locale from top-level domain or return nil if such locale is not available
# You have to put something like:
#   127.0.0.1 application.com
#   127.0.0.1 application.it
#   127.0.0.1 application.pl
# in your /etc/hosts file to try this out locally
def extract_locale_from_tld
  parsed_locale = request.host.split('.').last
  I18n.available_locales.map(&:to_s).include?(parsed_locale) ? parsed_locale : nil
end

Essentially, this strips the final identifier (.en, .id, etc) from a url like application.co.id or example.com and sets the locale based on that. If a user comes from a locale you don't support, it returns to the default locale - English, unless set otherwise.

Jon Takagi
  • 101
  • 3