将可用语言与语言名称匹配

时间:2009-10-05 13:47:03

标签: ruby-on-rails internationalization named-scope

我想在网站用户编辑/创建页面中进行语言选择下拉列表。

为此,我当然将网站翻译成多种语言。 使用I18n.available_languages,我可以得到一个区域代码数组,如此

development environment (Rails 2.3.4)
> I18n.available_locales
   => [:en, :da]

此外,我创建了一个语言模型并将其与用户相关联:

# app/models/language.rb
class Language < ActiveRecord::Base
  has_many :users  
end

# app/models/user.rb
class User < ActiveRecord::Base
  belongs_to :language  
end

# db/schema.rb
create_table "languages", :force => true do |t|
  t.string "name"
  t.string "code"
end

create_table "users", :force => true do |t|
  t.integer  "language_id"
end

然后语言表包含本地语言中的语言环境代码和语言名称,如下所示:

| id  | name                | code |
------------------------------------
| 28  | Dansk               | da   |
| 29  | Nederlands          | nl   |
| 30  | English             | en   |
| 31  | Esperanto           | eo   |

然后,我在用户新建,编辑和编辑操作中进行以下分配:

# app/controllers/users_controller.rb (extract)
@available_languages = I18n.available_locales.collect {|language_code| Language.find_by_code(language_code.to_s)}
我在视图中使用的

('available_languages'是一个局部变量,因为来自控制器的@available_languages已传递给部分):

# app/views/users/_form.haml (extract)
= f.collection_select(:language_id, available_languages, :id, :name, {:prompt => true})

所有这一切的结果是,用户将获得区域设置选择下拉列表来定义给定用户的区域设置。

我的问题是: 是否有一种干净的方法将@available_languages赋值移出UsersController并进入语言模型,所以我可以缩短它:

@available_languages = I18n.available_locales.collect {|language_code| Language.find_by_code(language_code.to_s)}

这样的事情:

@available_languages = Language.translations_available

3 个答案:

答案 0 :(得分:13)

我为每个yml添加一个“locale_name”键,并使用它自己语言的语言名称。 例如:

在es-AR.yml

es-AR:
  locale_name: "Castellano"

在en.yml

en:
  locale_name: "English"

答案 1 :(得分:12)

根据Dwaynemac的解决方案,这是一个更完整的答案:

  1. 将具有区域设置名称的密钥添加到每个yml文件中。例如在en.yml:

    en:
      language: English
    

    和es.yml:

    es:
      language: Español
    
  2. 添加一个帮助器方法(例如在/app/helpers/application_helper.rb中),该方法创建一个区域设置和区域设置名称对的数组:

      def locale_name_pairs
        I18n.available_locales.map do |locale|
          [I18n.t('language', locale: locale), locale.to_s]
        end
      end
    
  3. 在表单中使用locale_name_pairs创建您的选择下拉列表:

    f.select :locale, options_for_select(locale_name_pairs, @user.locale)
    
  4. 注意懒惰:如果您希望跳过第2步,则可以在步骤3中使用以下单行: f.select :locale, options_for_select(I18n.available_locales.map{ |locale| [I18n.t('language', locale: locale), locale.to_s] } , @user.locale)

答案 2 :(得分:4)

在我看来,你做了几件有趣的事情。首先,以下是一些问题:

I18n.available_locales.collect {|language_code| Language.find_by_code(language_code.to_s)}

此设置使您可以为每个可用的区域设置生成一个SQL查询。此外,如果I18n.available_locales中的每个区域设置都有对应的Language对象,反之亦然,则此代码似乎有点不必要。你也可以这样做:

Language.find(:all) # or even Language.all

如果出于某种原因,他们没有直接映射,您可以改用:

Language.all(:conditions => { :code => I18n.available_locales })

以更详细的形式相当于:

Language.find(:all, :conditions => ["code IN (?)", I18n.available_locales])

这将找到代码列在I18n.available_locales中的所有语言。如果需要此方法的快捷方式,可以使用named_scopes:

class Language < ActiveRecord::Base
  has_many :users

  named_scope :translation_available, :conditions => { :code => I18n.available_locales }
end

然后,您可以致电:

Language.translation_available

我认为这就是你想要的。