Маршруты Rails с дополнительной областью ": locale"

Я работаю над приложением Rails 3.1, и я хотел бы указать конкретные маршруты для разных языков, которые приложение будет поддерживать.

/es/countries
/de/countries
…

Для языка по умолчанию ('en') я не хочу, чтобы языковой стандарт отображался в URL-адресе.

/countries

Вот определение маршрута, которое я установил.

scope "(:locale)", :locale => /es|de/ do
   resources :countries
end

Он отлично работает, пока я не попытаюсь использовать помощник пути с "en" в качестве локали.

В консоли:

app.countries_path(:locale => 'fr')
 => "/fr/countries" 

app.countries_path(:locale => 'en')
 => "/countries?locale=en" 

Я не хочу "? locale = en".

Есть ли способ сказать рельсы, что с "en" locale параметр locale не должен быть добавлен в URL?

Спасибо

Ответ 1

Наконец-то я понял, как это сделать. Вам просто нужно установить default_url_options в контроллере приложения, как показано ниже.

  def default_url_options(options={})
    { :locale => I18n.locale == I18n.default_locale ? nil : I18n.locale  }
  end

Таким образом, вы уверены, что языковой стандарт не отправляется в помощники путей.

Ответ 2

Это ДОЛЖНО быть лучшим решением:

В ваших route.rb,

scope "(:locale)", locale: /#{I18n.available_locales.join("|")}/, defaults: {locale: "en"} do

Как сказал MegaTux, установите defaults: {locale: "en"} в область видимости.

Преимущество: Решение jlfenaux работает в большинстве контекстов, но не для всех. В определенных контекстах (например, в основном что-либо вне ваших основных контроллеров и представлений), помощники путей будут запутаны и поместите объект или object.id в параметр locale, что вызовет ошибки. Вы обнаружите, что ставите locale: nil во множество помощников пути, чтобы избежать этих ошибок.

Возможная проблема: Кажется, что defaults: {locale: "en"} всегда переопределяет любое другое значение, которое вы передаете для locale. Опция называется default, поэтому я ожидаю, что она присвоит locale 'en' только тогда, когда уже нет значения, но это не то, что происходит. Кто-нибудь еще испытывает это?

Ответ 3

Если вам не нужна строка запроса, вам не нужно передавать ее помощнику:

1.9.2 (main):0 > app.countries_path(:locale=>:de)
=> "/de/countries"
1.9.2 (main):0 > app.countries_path
=> "/countries"
1.9.2 (main):0 > app.countries_path(:locale=>:en)
=> "/countries?locale=en"
1.9.2 (main):0 > app.countries_path
=> "/countries"
1.9.2 (main):0 > app.countries_path(:locale=>nil)
=> "/countries"

Ответ 4

Я делаю комбинацию того, что делают @Arcolye и @jifenaux, плюс что-то дополнительное, чтобы код был как можно сухим. Возможно, это не подходит для всех, но в моем случае, всякий раз, когда я хочу поддерживать новую локаль, мне также нужно создать новый .yml файл в config/locales/, так что это наилучшим образом для меня.

конфиг /application.rb:

locale_files = Dir["#{Rails.root}/config/locales/??.yml"]

config.i18n.available_locales = locale_files.map do |d| 
  d.split('/').last.split('.').first
end

config.i18n.default_locale = :en

конфиг /routes.rb

root_path = 'pages#welcome'

scope '(:locale)', locale: /#{I18n.available_locales.join('|')}/ do
  # ...
end

root to: root_path
get '/:locale', to: root_path

приложение/контроллеры/application_controller.rb:

private

def default_url_options(options = {})
  if I18n.default_locale != I18n.locale
    {locale: I18n.locale}.merge options
  else
    {locale: nil}.merge options
  end
end

Ответ 5

Если вы решили поместить default_url_options в application_controller для исправления ваших помощников пути, имейте в виду, что вы можете захотеть поместить его и в admin admin application_contoller.

Ответ 6

В моем случае я решил эту проблему с помощью этой техники:

class ApplicationController < ActionController::Base
  layout -> {
    if devise_controller?
      'devise'
    end
  }

  before_action :set_locale

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

  def url_options
    { :locale => I18n.locale }.merge(super)
  end

end