【问题标题】:Matching available languages to language names将可用语言与语言名称匹配
【发布时间】:2009-10-05 13:47:03
【问题描述】:

我想在站点用户编辑/创建页面中进行语言选择下拉菜单。

为此,我当然已将网站翻译成不止一种语言。 使用 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 中移出并进入 Language 模型,所以我可以缩短这个:

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

到这样的事情:

@available_languages = Language.translations_available

【问题讨论】:

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


    【解决方案1】:

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

    在 es-AR.yml 中

    es-AR:
      locale_name: "Castellano"
    

    在 en.yml 中

    en:
      locale_name: "English"
    

    【讨论】:

    • I18n.t('locale_name') 或在 erb 中简单地 t('locale_name')
    • 如果你想要一个包含所有语言环境的组合框怎么办?
    • 我会这样做:options_for_select AVAILABLE_LOCALES.map{|l| [I18n.t(l), l]}
    【解决方案2】:

    这是基于 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)
      

    懒人注意事项:如果您喜欢跳过第 2 步,那么您可以在第 3 步中使用以下单行代码: f.select :locale, options_for_select(I18n.available_locales.map{ |locale| [I18n.t('language', locale: locale), locale.to_s] } , @user.locale)

    【讨论】:

      【解决方案3】:

      在我看来,您正在做一些有趣的事情。首先有以下问题:

      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
      

      我想这就是你想要的。

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-10
      • 2015-06-20
      相关资源
      最近更新 更多