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 %>
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...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With