22

我怎样才能让我的路线识别一个可选的前缀参数,如下所示:

/*lang/controller/id

其中 lang 部分是可选的,如果 URL 中未指定,则具有默认值:

/en/posts/1   => lang = en
/fr/posts/1   => lang = fr
/posts/1      => lang = en

编辑

理想情况下,我希望通过映射命名空间来跨许多控制器和操作执行此操作:

map.namespace "*lang" do |lang|
  lang.resources :posts
  lang.resources :stories
end
4

5 回答 5

19

好的,我已经设法解决了这个问题:

默认情况下,在 Rails 中没有办法做到这一点(至少目前还没有)。我需要安装Sven Fuchs 的路由过滤器,而不是使用命名空间和默认值。

安装插件后,我将以下文件添加到我的 lib 目录:

require 'routing_filter/base'

module RoutingFilter
  class Locale < Base

    # remove the locale from the beginning of the path, pass the path
    # to the given block and set it to the resulting params hash
    def around_recognize(path, env, &block)
      locale = nil
      path.sub! %r(^/([a-zA-Z]{2})(?=/|$)) do locale = $1; '' end
      returning yield do |params|
        params[:locale] = locale || 'en'
      end
    end

    def around_generate(*args, &block)
      locale = args.extract_options!.delete(:locale) || 'en'
      returning yield do |result|
        if locale != 'en'
          result.sub!(%r(^(http.?://[^/]*)?(.*))){ "#{$1}/#{locale}#{$2}" }
        end 
      end
    end

  end
end

我将此行添加到 routes.rb:

map.filter 'locale'

这基本上填写了一个由插件生成的前后钩子,它包装了rails路由。

当一个 url 被识别时,在 Rails 对其进行任何操作之前,将调用 around_recognize 方法。这将提取表示区域设置的两个字母代码,并将其传递到参数中,如果未指定区域设置,则默认为“en”。

同样,当生成 url 时,locale 参数将被推送到左侧的 URL 中。

这给了我以下网址和映射:

/   => :locale => 'en'
/en => :locale => 'en'
/fr => :locale => 'fr'

所有现有的 url 助手都像以前一样工作,唯一的区别是除非指定了语言环境,否则它会被保留:

home_path                  => /
home_path(:locale => 'en') => /
home_path(:locale => 'fr') => /fr
于 2008-10-21T08:13:04.643 回答
2

:defaults您可以使用键在路由中定义默认值。试试这个:

map.connect ':lang/posts/:id', :controller => 'posts', :action => 'show',
                               :defaults => { :lang => 'en' }
于 2008-10-17T17:42:13.360 回答
2

我理解这个老问题,但它可能有用。

  map.with_options(:path_prefix => ":locale") do |m|
    m.resources :posts
    m.resources :stories        
  end

并且您必须在过滤器之前添加到应用程序控制器以定义语言环境,例如

before_filter :define_locale

def define_locale
  if params[:locale] == nil
    I18n.locale = 'en'
  else
    I18n.locale = params[:locale]
  end
end
于 2010-01-30T09:23:17.237 回答
1

我猜(现在没有时间测试)这可能有效:

map.connect ':language/posts/:id', :controller => 'posts', :action => 'show'
map.connect 'posts/:id', :controller => 'posts', :action => 'show'

好的,试过了——至少在 Rails 2.1.1 上有效。所以这很好。但是,无法使 :defaults 想法起作用,这很遗憾,因为它是 DRYer。

于 2008-10-17T16:37:55.860 回答
1

以为您可以一次使用 [key] => nil 来指定可选参数。就像是:

map.connect ':lang/posts/:id', :controller => 'posts', :action => 'show', :lang => nil
于 2008-10-17T21:09:19.337 回答