I have an application (my_test_app) with working i18n support built. Currently, there are two language files available, FR & EN, and if I toggle back and forth between them, everything works as I expect to see it for non-engine functions such as the User index/show/edit/delete (ISED) options.
Within my_test_app I have a Rails Engine mounted (my_engine) which has a controller & model set (engine_job). So, a workable URL should be
http://0.0.0.0:3000/fr/my_engine/engine_job
No matter what language I choose, however, it always shows up in EN. Examining the parameters shows:
--- !ruby/hash:ActiveSupport::HashWithIndifferentAccess
locale: fr
action: index
controller: my_engine/engine_job
And yet the chosen translation is EN.
my_test_app route.rb:
MyTestApp::Application.routes.draw do
scope "(:locale)", locale: /#{I18n.available_locales.join("|")}/ do
mount MyEngine::Engine, at: "/my_engine"
end # scope locale
match '*path', to: redirect("/#{I18n.default_locale}/%{path}"), constraints: lambda { |req| !req.path.starts_with? "/#{I18n.default_locale}/" and !req.path == "/#{I18n.default_locale}/"}
match '', to: redirect("/#{I18n.default_locale}/")
end
my_engine route.rb:
MyEngine::Engine.routes.draw do
resources :my_jobs
end
rake routes:
my_engine (/:locale)/my_engine MyEngine::Engine {:locale=>/en|fr/}
/*path(.:format) :controller#:action
/ :controller#:action
users GET (/:locale)/users(.:format) users#index {:locale=>/en|fr/}
POST (/:locale)/users(.:format) users#create {:locale=>/en|fr/}
new_user GET (/:locale)/users/new(.:format) users#new {:locale=>/en|fr/}
edit_user GET (/:locale)/users/:id/edit(.:format) users#edit {:locale=>/en|fr/}
user GET (/:locale)/users/:id(.:format) users#show {:locale=>/en|fr/}
PUT (/:locale)/users/:id(.:format) users#update {:locale=>/en|fr/}
DELETE (/:locale)/users/:id(.:format) users#destroy {:locale=>/en|fr/}
sessions POST (/:locale)/sessions(.:format) sessions#create {:locale=>/en|fr/}
new_session GET (/:locale)/sessions/new(.:format) sessions#new {:locale=>/en|fr/}
session DELETE (/:locale)/sessions/:id(.:format) sessions#destroy {:locale=>/en|fr/}
signup (/:locale)/signup(.:format) users#new {:locale=>/en|fr/}
signin (/:locale)/signin(.:format) sessions#new {:locale=>/en|fr/}
signout DELETE (/:locale)/signout(.:format) sessions#destroy {:locale=>/en|fr/}
help (/:locale)/help(.:format) static_pages#help {:locale=>/en|fr/}
about (/:locale)/about(.:format) static_pages#about {:locale=>/en|fr/}
root /(:locale)(.:format) static_pages#home {:locale=>/en|fr/}
Routes for MyEngine::Engine {:locale=>/en|fr/}:
engine_jobs GET /engine_jobs(.:format) my_engine/engine_jobs#index
POST /engine_jobs(.:format) my_engine/engine_jobs#create
new_engine_job GET /engine_jobs/new(.:format) my_engine/engine_jobs#new
edit_engine_job GET /engine_jobs/:id/edit(.:format) my_engine/engine_jobs#edit
engine_job GET /engine_jobs/:id(.:format) my_engine/engine_jobs#show
PUT /engine_jobs/:id(.:format) my_engine/engine_jobs#update
DELETE /engine_jobs/:id(.:format) my_engine/engine_jobs#destroy
Further, any links clicked within the Engine set the language to EN. A few web searches shed no real light as to what might be happening here, since all i18n examples I could find do not involve mounted engines.
EDIT: show code to set default locale my_test_app/app/controllers/application_controller.rb:
class ApplicationController < ActionController::Base
protect_from_forgery
helper MyEngine::Engine.helpers
ActiveRecord::Base.verify_active_connections!
before_filter :set_locale
private
def set_locale
I18n.locale = params[:locale] || I18n.default_locale
Rails.application.routes.default_url_options[:locale]= I18n.locale
logger.debug "My_Test_App: default_url_options is passed options: #{Rails.application.routes.default_url_options.inspect}\n"
# current_user.locale
# request.subdomain
# request.env["HTTP_ACCEPT_LANGUAGE"]
# request.remote_ip
end # set_locale
end # class ApplicationController
/EDIT
EDIT2 (Route Map after changes suggested by Pierre Aug 9 at 15:59):
An application route yeilds http://0.0.0.0:3000/en/users
with "locale"=>"en"
. A Helper created engine route looks like http://0.0.0.0:3000/my_engine?locale=en/engine_jobs
and yeilds No route matches [GET] "/my_engine"
.
my_engine_plugin /my_engine MyEnginePlugin::Engine
users GET (/:locale)/users(.:format) users#index {:locale=>/en|fr/}
POST (/:locale)/users(.:format) users#create {:locale=>/en|fr/}
new_user GET (/:locale)/users/new(.:format) users#new {:locale=>/en|fr/}
edit_user GET (/:locale)/users/:id/edit(.:format) users#edit {:locale=>/en|fr/}
user GET (/:locale)/users/:id(.:format) users#show {:locale=>/en|fr/}
PUT (/:locale)/users/:id(.:format) users#update {:locale=>/en|fr/}
DELETE (/:locale)/users/:id(.:format) users#destroy {:locale=>/en|fr/}
sessions POST (/:locale)/sessions(.:format) sessions#create {:locale=>/en|fr/}
new_session GET (/:locale)/sessions/new(.:format) sessions#new {:locale=>/en|fr/}
session DELETE (/:locale)/sessions/:id(.:format) sessions#destroy {:locale=>/en|fr/}
signup (/:locale)/signup(.:format) users#new {:locale=>/en|fr/}
signin (/:locale)/signin(.:format) sessions#new {:locale=>/en|fr/}
signout DELETE (/:locale)/signout(.:format) sessions#destroy {:locale=>/en|fr/}
help (/:locale)/help(.:format) static_pages#help {:locale=>/en|fr/}
about (/:locale)/about(.:format) static_pages#about {:locale=>/en|fr/}
root /(:locale)(.:format) static_pages#home {:locale=>/en|fr/}
Routes for MyEnginePlugin::Engine:
engine_jobs GET (/:locale)/engine_jobs(.:format) my_engine_plugin/engine_jobs#index {:locale=>/en|fr/}
POST (/:locale)/engine_jobs(.:format) my_engine_plugin/engine_jobs#create {:locale=>/en|fr/}
new_engine_job GET (/:locale)/engine_jobs/new(.:format) my_engine_plugin/engine_jobs#new {:locale=>/en|fr/}
edit_engine_job GET (/:locale)/engine_jobs/:id/edit(.:format) my_engine_plugin/engine_jobs#edit {:locale=>/en|fr/}
engine_job GET (/:locale)/engine_jobs/:id(.:format) my_engine_plugin/engine_jobs#show {:locale=>/en|fr/}
PUT (/:locale)/engine_jobs/:id(.:format) my_engine_plugin/engine_jobs#update {:locale=>/en|fr/}
DELETE (/:locale)/engine_jobs/:id(.:format) my_engine_plugin/engine_jobs#destroy {:locale=>/en|fr/}
/EDIT2 (Route Map after changes suggested by Pierre Aug 9 at 15:59)
So, the question is what changes do I need to make to my routes or engine to get this to work as expected?
Thanks in advance for your time and suggestions!
I am using Engine with I18n and it works fine. I created a dummy Rails application to try your scenario. As far as I know, changing the locale inside the URL works fine with routes defined in your Rails application:
My routes:
Bar::Application.routes.draw do
root 'posts#index'
scope "(:locale)", locale: /#{I18n.available_locales.join("|")}/ do
resources :posts, only: :index
end
end
I am able to change the I18n locale with:
http://localhost:3000/fr/posts
http://localhost:3000/en/posts
I think that your probleme is when you want to go to any of your engine's routes since you did not set the I18n locale switch. See bellow:
engine_jobs GET /engine_jobs(.:format)
Then, when going to /engine_jobs
even if you specified a locale in the URL, it's I18n default locale that will be set (en
):
def set_locale
I18n.locale = params[:locale] || I18n.default_locale
# ...
end
When using your Engine routes, params[:locale]
is nil
Add the same logic to your engine's routes:
config/routes.rb
MyTestApp::Application.routes.draw do
mount MyEngine::Engine, at: "/my_engine"
match '*path', to: redirect("/#{I18n.default_locale}/%{path}"), constraints: lambda { |req| !req.path.starts_with? "/#{I18n.default_locale}/" and !req.path == "/#{I18n.default_locale}/"}
match '', to: redirect("/#{I18n.default_locale}/")
end
your_engine/config/routes.rb
MyEngine::Engine.routes.draw do
scope "(:locale)", locale: /#{I18n.available_locales.join("|")}/ do
resources :my_jobs
end
end
mount MyEngine::Engine, at: "/my_engine"
only tells rails to "load" all engine routes. If you need to add constraints, scopes, namespace or anything else, you should use usual rails way to do it but in your engine's routes file.
Finally you need to update both of your application_controller.rb
(main app + engine) with the following:
class ApplicationController < ActionController::Base
def url_options
{ locale: I18n.locale }
end
def set_locale
I18n.locale = params[:locale] || I18n.default_locale
Rails.application.routes.default_url_options[:locale]= I18n.locale
end
end
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