Маршрутизация i18n к установленному двигателю — игнорирование локали

У меня есть приложение (my_test_app) с работающей поддержкой i18n. В настоящее время доступны два языковых файла, FR и EN, и если я переключаюсь между ними, все работает так, как я ожидаю увидеть для не-двигательных функций, таких как пользовательский индекс/показать/редактировать/удалить (ISED) опции.

В my_test_app у меня установлен Rails Engine (my_engine), который имеет набор контроллера и модели (engine_job). Таким образом, рабочий URL должен быть

http://0.0.0.0:3000/fr/my_engine/engine_job

Однако независимо от того, какой язык я выберу, он всегда отображается на EN. Изучение параметров показывает:

--- !ruby/hash:ActiveSupport::HashWithIndifferentAccess
locale: fr
action: index
controller: my_engine/engine_job

И все же выбран перевод EN.

маршрут my_test_app.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

рейк маршруты:

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

Кроме того, для любых ссылок, нажимаемых в движке, устанавливается английский язык. Несколько поисковых запросов в Интернете не пролили реального света на то, что здесь может происходить, поскольку все примеры i18n, которые я смог найти, не связаны с установленными двигателями.

РЕДАКТИРОВАТЬ: показать код для установки локали по умолчанию 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

/РЕДАКТИРОВАТЬ

EDIT2 (Карта маршрута после изменений, предложенных Пьером 9 августа в 15:59):

Маршрут приложения дает http://0.0.0.0:3000/en/users с "locale"=>"en". Маршрут двигателя, созданный помощником, выглядит как http://0.0.0.0:3000/my_engine?locale=en/engine_jobs и дает 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 (Карта маршрута после изменений, предложенных Пьером, 9 августа, 15:59)

Итак, вопрос в том, какие изменения мне нужно внести в мои маршруты или движок, чтобы заставить это работать должным образом?

Заранее спасибо за ваше время и предложения!


person MichelV69    schedule 01.08.2013    source источник
comment
Не могли бы вы показать мне место, где вы установили локаль I18n по умолчанию?   -  person Pierre-Louis Gottfrois    schedule 08.08.2013
comment
@Pierre-LouisGottfrois: Готово. См. выше.   -  person MichelV69    schedule 09.08.2013
comment
Я пытаюсь ответить на ваш вопрос, вам помогло?   -  person Pierre-Louis Gottfrois    schedule 12.08.2013


Ответы (1)


Я использую Engine с I18n, и он отлично работает. Я создал фиктивное приложение Rails, чтобы попробовать ваш сценарий. Насколько мне известно, изменение локали внутри URL-адреса отлично работает с маршрутами, определенными в вашем приложении Rails:

Мои маршруты:

Bar::Application.routes.draw do
  root 'posts#index'

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

Я могу изменить локаль I18n с помощью:

http://localhost:3000/fr/posts
http://localhost:3000/en/posts

Я думаю, что ваша проблема заключается в том, что вы хотите перейти на любой из маршрутов вашего движка, поскольку вы не установили переключатель локали I18n. Смотрите ниже:

engine_jobs GET    /engine_jobs(.:format)

Затем при переходе к /engine_jobs, даже если вы указали локаль в URL-адресе, будет установлена ​​локаль I18n по умолчанию (en):

def set_locale
  I18n.locale = params[:locale] || I18n.default_locale
  # ...
end

При использовании маршрутов Engine params[:locale] равно nil

Решение

Добавьте ту же логику к маршрутам вашего движка:

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" только указывает рельсам «загружать» все маршруты двигателей. Если вам нужно добавить ограничения, области, пространство имен или что-то еще, вы должны использовать обычный способ rails, но в файле маршрутов вашего движка.

Наконец, вам нужно обновить оба ваших application_controller.rb (основное приложение + движок) следующим образом:

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
person Pierre-Louis Gottfrois    schedule 09.08.2013
comment
Здравствуйте, Пьер-Луи. Однако все еще не работает, мы изменили условие ошибки: Для URL-адреса: 0.0.0.0:3000/fr/my_engine/engine_job я получаю: ActionController::RoutingError (Нет совпадений маршрута [GET] /fr/my_engine/engine_job) : - person MichelV69; 12.08.2013
comment
Можете ли вы обновить свой вопрос, если новые маршруты? Кроме того, как получить доступ к странице, набрав URL-адрес напрямую или через UrlHelpers? Если да, не забудьте добавить use_route :your_engine - person Pierre-Louis Gottfrois; 12.08.2013
comment
Привет, Пьер, извините, я не получил уведомление о том, что вы ответили. Я собираюсь присудить вам награду, так как вы были так готовы помочь, и мы можем продолжить разбираться с этим. Я добавлю больше информации сегодня днем, когда у меня будет шанс между клиентами. - person MichelV69; 15.08.2013
comment
Отлично, я буду рад помочь вам понять, что здесь не так. - person Pierre-Louis Gottfrois; 15.08.2013
comment
Пьер, я добавил обновленную карту маршрутов. Я нигде не использую use_route :your_engine... Я не смог найти в Google хорошего примера того, как/где это должно быть реализовано, поэтому, если бы вы могли привести пример, это было бы огромной помощью. Еще раз спасибо. - person MichelV69; 16.08.2013
comment
Плохо, use_route для спецификаций контроллера. Я имел в виду, что при использовании UrlHelpers с двигателем: MyEngine.engine_jobs_path. Посмотрите здесь edgeguides.rubyonrails.org/engines.html - person Pierre-Louis Gottfrois; 16.08.2013
comment
Пьер: Я использую UrlHelpers в стиле MyEngine.engine_jobs_path для всех своих ссылок. Ничего не делается руками. - person MichelV69; 17.08.2013
comment
Попробуйте распечатать параметры локали на ApplicationController при нажатии на один из путей вашего движка. Локаль должна быть хорошей, будь то fr или en. - person Pierre-Louis Gottfrois; 18.08.2013
comment
Я удалил свой последний комментарий, потому что обнаружил, что неправильно реализовал ваше решение. Маршрут приложения дает http://0.0.0.0:3000/en/users с "locale"=>"en". Маршрут двигателя, созданный помощником, выглядит как http://0.0.0.0:3000/my_engine?locale=en/engine_jobs и дает No route matches [GET] "/my_engine". - person MichelV69; 19.08.2013
comment
Да, я думаю, что рельсы не могут найти маршруты, так как им нужна локаль не как параметры, а внутри URL-адреса... Попробуйте добавить этот код в свой метод set_locale в application_controller.rb: Rails.application.routes.default_url_options[:locale] = I18n.locale. Затем определите метод url_options в контроллере. См. здесь для более подробной информации "> stackoverflow.com/questions/14875404/ и здесь stackoverflow.com/questions/17207104/ - person Pierre-Louis Gottfrois; 19.08.2013
comment
Что ж, это шаг в правильном направлении. http://0.0.0.0:3000/en/my_engine/engine_jobs теперь рабочий URL, а Parameters: {"locale"=>"en"}. Так что это хорошо. Однако это дает No route matches, и содержимое локали теперь включает другие данные параметров. - person MichelV69; 19.08.2013
comment
В порядке. Продвигается. Проблема в том, что помощники URL-адресов в движке, похоже, не создают действительные URL-адреса. Таким образом, ошибка, которая возникает, не является попыткой добраться до содержимого движка; это работает. Ошибка вызывается командой link_to в файле engine_job/index.html.erb. - person MichelV69; 19.08.2013
comment
Добавление того же кода в файл контроллера приложения Engine решило проблему. Теперь все работает так, как я ожидаю. Браво, @Pierre-Louis Gottfrois ... еще раз спасибо за отличную и постоянную помощь. - person MichelV69; 19.08.2013
comment
Я рад это слышать ! Я добавлю вышеуказанный элемент в свой ответ. Отличная работа ;) - person Pierre-Louis Gottfrois; 19.08.2013
comment
У меня не работает (или я не понимаю ответа). Я монтирую свой движок внутри дополнительной области действия локали, например, op. НЕ прямо в корне, как подразумевается в ответе. Это не дало бы мне правильных маршрутов. Мне нужен locale/my_engine/engine_controller... не my_engine/locale/engine_controller. Или я что-то здесь не понимаю? Совет? Спасибо. - person Nico; 23.09.2015
comment
Исправлено это с помощью этого решения: stackoverflow .com/questions/14875404/ - person Nico; 23.09.2015