简体   繁体   中英

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 %>

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!

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...

This blogpost explains it actually in great detail:

Just what I was looking for when nothing seems to work

http://dhampik.com/blog/rails-routes-tricks-with-locales

  scope "/:locale", locale: /#{I18n.available_locales.join("|")}/ do
    resources :posts    
    root to: "main#index"
  end

  root to: redirect("/#{I18n.default_locale}", status: 302), as: :redirected_root

  get "/*path", to: redirect("/#{I18n.default_locale}/%{path}", status: 302), constraints: {path: /(?!(#{I18n.available_locales.join("|")})\/).*/}, format: false

Redirects to default lang from root and does a lot of other things as well.

Looks like you were able to use the comment I wrote on Railscasts to help with your I18n routing. Cool!

As for your first issue, can you just re-route root to: redirect("/#{I18n.default_locale}") to redirect to I18n.locale instead?

As for your second issue, Did you use the tests in the Railscast comment as well or have your own tests, and if so, did they pass? Does Heroku provide you with any error logs? ( $ heroku logs ). I have those routes deployed to Heroku working as expected, so I think there is a chance it's not an issue with Heroku.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM