Reputation: 12653
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:
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 %>
Upvotes: 7
Views: 7326
Reputation: 11013
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.
Upvotes: 6
Reputation: 12653
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!
Upvotes: 8
Reputation: 16793
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.
Upvotes: 0
Reputation: 783
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...
Upvotes: 7