91

我希望能够在 Rails 中翻译 i18n 中的复数字符串。一个字符串可以是:

You have 2 kids

或者

You have 1 kid

我知道我可以使用复数辅助方法,但我想将它嵌入到 i18n 翻译中,这样我以后不必在任何时候弄乱我的观点。我读到它:count以某种方式用于复数的翻译,但我找不到任何关于它如何实现的真正资源。

请注意,我知道我可以在翻译字符串中传递一个变量。我也尝试过类似的东西:

<%= t 'misc.kids', :kids_num => pluralize(1, 'kid') %>

哪个工作正常,但有一个相同想法的基本问题。我需要'kid'在复数助手中指定字符串。我不想这样做,因为它会导致将来出现视图问题。相反,我想保留翻译中的所有内容,而视图中没有任何内容。

我怎样才能做到这一点 ?

4

7 回答 7

183

尝试这个:

en.yml

en:
  misc:
    kids:
      zero: no kids
      one: 1 kid
      other: %{count} kids

在一个视图中:

You have <%= t('misc.kids', :count => 4) %>

更新了多复数语言的答案(使用 Rails 3.0.7 测试):

文件 config/initializers/pluralization.rb

require "i18n/backend/pluralization" 
I18n::Backend::Simple.send(:include, I18n::Backend::Pluralization)

文件 config/locales/plurals.rb

{:ru => 
  { :i18n => 
    { :plural => 
      { :keys => [:one, :few, :other],
        :rule => lambda { |n| 
          if n == 1
            :one
          else
            if [2, 3, 4].include?(n % 10) && 
               ![12, 13, 14].include?(n % 100) && 
               ![22, 23, 24].include?(n % 100)

              :few 
            else
              :other 
            end
          end
        } 
      } 
    } 
  } 
}

#More rules in this file: https://github.com/svenfuchs/i18n/blob/master/test/test_data/locales/plurals.rb
#(copy the file into `config/locales`)

文件 config/locales/en.yml

en:
  kids:
    zero: en_zero
    one: en_one
    other: en_other

文件 config/locales/ru.yml

ru:
  kids:
    zero: ru_zero
    one: ru_one
    few: ru_few
    other: ru_other

测试

$ rails c
>> I18n.translate :kids, :count => 1
=> "en_one"
>> I18n.translate :kids, :count => 3
=> "en_other"
>> I18n.locale = :ru
=> :ru
>> I18n.translate :kids, :count => 1
=> "ru_one"
>> I18n.translate :kids, :count => 3
=> "ru_few"  #works! yay! 
>> I18n.translate :kids, :count => 5
=> "ru_other"  #works! yay! 
于 2011-05-29T05:13:55.393 回答
39

我希望讲俄语的 Ruby on Rails 程序员能找到这个。只是想分享我自己非常精确的俄语复数公式。它基于Unicode 规范。这里只是config/locales/plurals.rb文件的内容,其他的都应该和上面的回答一样。

{:ru => 
  { :i18n => 
    { :plural => 
      { :keys => [:zero, :one, :few, :many],
        :rule => lambda { |n| 
          if n == 0
            :zero
          elsif
            ( ( n % 10 ) == 1 ) && ( ( n % 100 != 11 ) )
            # 1, 21, 31, 41, 51, 61...
            :one
          elsif
            ( [2, 3, 4].include?(n % 10) \
            && ![12, 13, 14].include?(n % 100) )
            # 2-4, 22-24, 32-34...
            :few
          elsif ( (n % 10) == 0 || \
            ![5, 6, 7, 8, 9].include?(n % 10) || \
            ![11, 12, 13, 14].include?(n % 100) )
            # 0, 5-20, 25-30, 35-40...
            :many
          end
        } 
      } 
    } 
  } 
}

母语人士可能会喜欢 和 等111情况121。这里是测试结果:

  • 零:0 запросов/куриц/яблок
  • 一:1 запрос/курица/яблоко
  • 少数:3 запроса/курицы/яблока
  • 许多:5 запросов/куриц/яблок
  • 一:101 запрос/курица/яблоко
  • 少数:102 запроса/курицы/яблока
  • 许多:105 запросов/куриц/яблок
  • 许多:111 запросов/куриц/яблок
  • 许多:119 запросов/куриц/яблок
  • 一:121 запрос/курица/яблоко
  • 少数:122 запроса/курицы/яблока
  • 许多:125 запросов/куриц/яблок

感谢您的初步回答!

于 2014-11-17T18:55:20.540 回答
11

首先,请记住复数形式的数量取决于语言,英语有两种,罗马尼亚语有 3 种,阿拉伯语有 6 种!

如果您希望能够正确使用复数形式,您必须使用gettext.

对于 Ruby 和 rails,你应该检查这个http://www.yotabanana.com/hiki/ruby-gettext-howto-rails.html

于 2011-05-29T06:07:16.920 回答
8

Rails 3 通过 CLDR 考虑和计数插值变量稳健地处理了这个问题。见http://guides.rubyonrails.org/i18n.html#pluralization

# in view
t('actors', :count => @movie.actors.size)

# locales file, i.e. config/locales/en.yml
en:
  actors:
    one: Actor
    other: Actors
于 2012-05-23T19:06:26.520 回答
7

英语

开箱即用

en.yml

en:
  kid:
    one: '1 kid'
    other: '%{count} kids'

用法(当然,您可以在视图文件中跳过 I18n):

> I18n.t :kid, count: 1
 => "1 kid"

> I18n.t :kid, count: 3
 => "3 kids"

俄语(和其他具有多种复数形式的语言)

安装rails-18n gem 并将翻译添加到您的.yml文件中,如示例中所示:

ru.yml

ru:
  kid:
    zero: 'нет детей'
    one: '%{count} ребенок'
    few: '%{count} ребенка'
    many: '%{count} детей'
    other: 'дети'

用法:

> I18n.t :kid, count: 0
 => "нет детей"

> I18n.t :kid, count: 1
 => "1 ребенок"

> I18n.t :kid, count: 3
 => "3 ребенка"

> I18n.t :kid, count: 5
 => "5 детей"

> I18n.t :kid, count: 21
 => "21 ребенок"

> I18n.t :kid, count: 114
 => "114 детей"

> I18n.t :kid, count: ''
 => "дети"
于 2017-03-05T10:40:12.927 回答
5

实际上有一个替代繁琐的 i18n 方法的方法。该解决方案称为 Tr8n。

您上面的代码只是:

 <%= tr("You have {num || kid}", num: 1) %>

而已。无需从代码中提取密钥并将其保存在资源包中,无需为每种语言实现复数规则。Tr8n 带有适用于所有语言的数字上下文规则。它还带有性别规则、列表规则和语言案例。

上述翻译键的完整定义实际上如下所示:

 <%= tr("You have {num:number || one: kid, other: kids}", num: 1) %>

但由于我们想节省空间和时间,num 会自动映射到数字规则,无需为规则值提供所有选项。Tr8n 带有复数词和变形词,可以即时为您完成工作。

您的俄语密钥的翻译就是:

 "У вас есть {num || ребенок, ребенка, детей}"

顺便说一句,您的翻译在具有特定性别规则的语言中会不准确。例如,在希伯来语中,您实际上必须为您的示例指定至少 2 个翻译,因为“您”会根据查看用户的性别而有所不同。Tr8n 处理得很好。这是希伯来语翻译的音译:

 "Yesh leha yeled ahad" with {context: {viewing_user: male, num: one}}
 "Yesh leha {num} yeladim" with {context: {viewing_user: male, num: other}}
 "Yesh lah yeled ahad" with {context: {viewing_user: female, num: one}}
 "Yesh lah {num} yeladim" with {context: {viewing_user: female, num: other}}

因此,在这种情况下,您的单个英文键需要 4 个翻译。所有的翻译都是在上下文中完成的——你不必打断句子。Tr8n 有一种机制,可以根据语言和上下文将一个键映射到多个翻译——所有这些都是即时完成的。

最后一件事。如果您必须将计数部分加粗怎么办?它只是:

<%= tr("You have [bold: {num || kid}]", num: 1, bold: "<strong>{$0}</strong>") %>

以防万一您想稍后重新定义“粗体” - 这将非常容易 - 您不必检查所有 YAML 文件并更改它们 - 您只需在一个地方完成。

要了解更多信息,请查看此处:

https://github.com/tr8n/tr8n_rails_clientsdk

披露:我是 Tr8n 框架及其所有库的开发者和维护者。

于 2014-05-24T22:25:55.470 回答
0

关于Redmine。如果您将 config/locales/ 中的复数文件规则复制为复数.rb 和其他与语言环境名称(ru.rb、pl.rb .. 等)不同的文件,则这些规则不起作用。您必须将文件规则重命名为 'locale'.rb 或更改文件 /lib/redmine/i18n.rb 中的方法

def init_translations(locale)
  locale = locale.to_s
  paths = ::I18n.load_path.select {|path| File.basename(path, '.*') == locale}
  load_translations(paths)
  translations[locale] ||= {}
end

如果您有较旧的 redmine,请添加

module Implementation
        include ::I18n::Backend::Base
        **include ::I18n::Backend::Pluralization**
于 2018-08-30T09:44:34.013 回答