Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to configure Rails routes to accommodate i18n

I'm in the process of adding internationalization to a Rails app, and have more-or-less followed the relevant Rails Guide and Railscast.

I've run into two issues:

  1. How can I add a "home" link that redirects to the current locale. Currently I have root_path links, but these are failing due to the line in routes.rb designed to pick up unscoped roots. This means that root_path always directs to default locale, not current locale.
  2. I have everything set up and working locally (except the issue above) but deploying to Heroku all urls appear to be dropping through my routes file and getting caught by one of the catch alls. They are redirecting to '/' under the defulat locale.

My set up is as follows

application_controller.rb

before_filter :set_locale
def default_url_options(options = {})
  {locale: I18n.locale}
end

private
def set_locale
  I18n.locale = params[:locale] if params[:locale].present?
end

routes.rb

scope ":locale", locale: /#{I18n.available_locales.join("|")}/  do
  all_my_routes

  # handles /valid-locale
  root to: 'home#index', as: "localized_root"
  # handles /valid-locale/fake-path
  match '*path', to: redirect { |params, request| "/#{params[:locale]}" }
end

# handles /
root to: redirect("/#{I18n.default_locale}")

# handles /bad-locale|anything/valid-path
match '/*locale/*path', to: redirect("/#{I18n.default_locale}/%{path}")

# handles /anything|valid-path-but-no-locale
match '/*path', to: redirect("/#{I18n.default_locale}/%{path}")

My home link:

<%= link_to "Home", root_path %>
like image 600
Andy Harvey Avatar asked Dec 20 '12 15:12

Andy Harvey


2 Answers

I eventually got this working after some back and forth. The issue was that the catch all routes were a) catching more than I anticipated, and b) apparently behaving differently in development versus deployment (why this should be I'm not sure).

Anyway, first I changed the scope to make it optional (note parentheses):

scope "(:locale)", .....

This ensure that scoped routes are valid even if no locale is set (this is mainly to handle some issues I was experiencing with callbacks, etc).

This allowed me to drop the two root to lines, keeping only

root to "home#index"

I dropped the "handles /valid-locale/fake-path" line, this was causing problems with '/' paths.

Then kept the following catch alls after the scope (note the final one).

# handles /bad-locale|anything/valid-path
match '/*locale/*path', to: redirect("/#{I18n.default_locale}/%{path}")

# handles /anything|valid-path-but-no-locale
match '/*path', to: redirect("/#{I18n.default_locale}/%{path}"), constraints: lambda { |req| !req.path.starts_with? "/#{I18n.default_locale}/" }

# handles /
match '', to: redirect("/#{I18n.locale}")

As a point of interest, I also had to update action_mailer to handle the new localized urls.

config.action_mailer.default_url_options = { :host => 'path.to.my.app.com', :locale => I18n.locale }

And now all appears to be working!

like image 117
Andy Harvey Avatar answered Sep 28 '22 12:09

Andy Harvey


There is a gem which does this job wonderfully. (https://github.com/svenfuchs/routing-filter) You should add the following code to your Gemfile :

gem 'routing-filter'

And add the following to your routes.rb file

Rails.application.routes.draw do
  filter :locale
  ...
end

Hope it helps...

like image 39
Kzu Avatar answered Sep 28 '22 11:09

Kzu