One way to redirect inside the rails router based on the client’s Accept-Language header.

Previously i thought i had to do this inside the proxy webserver nginx, only really possible with the lua-enhanced fork of openresty, or the selfcompiled nginx version.

Or to go into the rack middleware world and figure out how to do it there - it’s probably still the fastest, cleanest to do it there.

There are more ways above that: routes file, and of course application controller.

I went for the routes file and added this directive:

root to: redirect { |params, request|

"/#{best_locale_from_request!(request)}"

}, status: 302, as: :redirected_root

The curly braces syntax is obligatory, do/end block does not work.

The actual work is being done with the help of teh accept_language gem and these two methods, split up for easier reading i presume:

def best_locale_from_request(request)
	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

I’ve put them both into the routes file, but there might be a better place for that.

The available locales array grew a bit, in order to prevent edge cases:

# config/application.rb

config.i18n.available_locales = [:en, :"en-150", :"en-001", :"en-DE", :de, :"de-AT", :"de-CH", :"de-DE", :"de-BE", :"de-IT", :"de-LI", :"de-LU", :et, :"et-EE"]

turns out the gem always forwards the geography part as well, so in order to make sure nobody is left out, i’ve added this for now. this might become tricky later on as paths are created based on that, and the language switcher might be a bit more tricky. maybe it makes sense to cut the second part off somehow.

Resources:

Accept-Language gem: https://github.com/cyril/accept_language.rb

A rack app i did not get to work, but apparently does the i18n settings as well: https://github.com/blindsidenetworks/i18n-language-mapping

This was very helpful for the redirect syntax: https://www.paweldabrowski.com/articles/rails-routes-less-known-features