At Spaces we’ve implemented a non-obtrusive redirection for our multi-language, multi-domain websites. Too many websites have the awful habit of forcing content to visitors that the visitor didn’t request in the first place.
Our rules are simple:
- Redirect automatically visitor if all of these applies:
- Visitor accesses root of website (e.g. https://gospaces.com/)
- Visitor has preferred language (in
http-accept-language
) that we support - If visitor hasn’t been redirected in the same session
- In all other cases show a small notice box for localized content if the content exists.
English speaking visitors going to https://gospaces.com.mx/
will be redirected. Going to that URL a second time will not cause a redirection. This works well in case it’s a shared link, and the user actually meant to get to the Spanish frontpage page.
English speaking visitors visiting https://gospaces.com.mx/contacto
won’t be forced back to https://gospaces.com
and vice-versa. Instead they’ll have a small popup notice guiding them.
Ruby on rails implementation
We’re using route_translator
and http_accept_language
gems.
First we need two helper methods to detect and generate the language urls:
# e.g. app/controllers/application_controller.rb
helper_method :preferred_language
def preferred_language
http_accept_language.compatible_language_from(I18n.available_locales)
end
helper_method :generate_preferred_language_url
def generate_preferred_language_url(opts = {})
return if cookies[:hide_localized_content_notification] or !preferred_language or preferred_language == I18n.locale.to_sym
url = localized_url(locale: preferred_language) do |localized_opts|
url_for(params.to_h.merge(localized_opts).merge(locale: preferred_language.to_s).merge(opts))
end
# Removes /es/ and ?locale=es from any strings generated. Unfortunately, route_translator doesn't work well here. The url_for doesn't see any domain specific routes where /es/ and locale=es is not needed.
if get_host_from_locale(preferred_language)
url = url.sub("/#{preferred_language}/", "/").sub("locale=#{preferred_language}", "")
# Remove ? if empty
url.sub!(/\?$/, "")
end
url
rescue ActionController::UrlGenerationError => e
Rails.logger.warn("WARN: Could not generate preferred language url. #{e.message}")
end
You’ll notice that if hide_localized_content_notification
is set, the URL isn’t generated. This cookie is set by Javascript when clicking the close button. Something simple like this will do:
document.cookie = "hide_localized_content_notification=true; max-age=" + 3*24*60*60*1000 + "; path=/"
To force redirection on index page we’ll do this:
# app/controllers/index_controller.rb
class IndexController < ApplicationController
before_filter :redirect_i18n, only: :index
protected
def redirect_i18n
if url = generate_preferred_language_url(utm_source: "website", utm_medium: "redirect").presence and cookies[:frontpage_i18n_redirected].blank?
cookies[:frontpage_i18n_redirected] = true
redirect_to url
end
end
end
This shows a small notice:
# app/views/layouts/application.rb
<% if localized_content_url = generate_preferred_language_url(utm_source: "website", utm_medium: "localized-content-notification-box").presence %>
<%= render partial: 'localized_content_notification', locals: { language: preferred_language, url: localized_content_url } %>
<% end %>