国际化


87

我希望能够在i18n中的rails中转换多个字符串。字符串可以是:

You have 2 kids

要么

You have 1 kid

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

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

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

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

我怎样才能做到这一点 ?


2
请注意,"#{....}"上面的代码中不需要“插值器”和引号。
2011年

1
您采用了错误的方法,因为您假设其他语言的复数形式的工作方式与英语一样。请参阅我的答案以获取正确的方法。
索林2011年

Sorin,谢谢您的回答,我只是不想为此使用gettext。我认为Zabba的解决方案非常适合我使用i18n的需求。
斯派罗斯

Rails 3使用CLDR和'count'插值变量可以更稳健地处理:guides.rubyonrails.org/i18n.html#pluralization
Luke W

多年以后,但也可以用在字符串“孩子”翻译-所以你必须:<%= t 'misc.kids', :kids_num => pluralize(1, t('kid')) %>。也许这并没有在2011年的工作,但它肯定on Rails的5.2.2现在这样(!)
贾维斯·约翰逊

Answers:


175

试试这个:

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! 

抱歉,但这不适用于多种语言。多元化确实很复杂,请参见translate.sourceforge.net/wiki/l10n/pluralforms。因此,我认为我的回答更合适。
索林2011年

1
@sorin,更新了我的答案以使用多个复数规则。
2011年

5
可以,但是现在您有一份新的全职工作,以维护复数字典!
索林2011年

这很棒!为了%{count}正常工作,我不得不在整个块周围都使用引号,即。one: "%{count} kid"
firedev

1
@ThePablick,是的,因为“ / initializer”目录中的文件仅加载一次-在HTTP服务器启动时。
Zabba

37

我希望说俄语的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запросов/куриц/яблок

感谢您的初步回答!


1
您提到的另一个答案将其放在另一个文件中。因此,采用这种方法,您的内容应该转到config/locales/plurals.rb而不是config/initializers/pluralization.rb
silverdr

@silverdr我已经固定了文件名。谢谢你的提示!
sashaegorov '16

11

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

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

对于Ruby和Rails,您应该查看此http://www.yotabanana.com/hiki/ruby-gettext-howto-rails.html


4
Sorin,这也是我在想的,但这似乎可以通过遵循CLDR格式(unicode.org/repos/cldr-tmp/trunk/diff/supplemental/…)来解决。我错了吗?
Nikos D

还有1、2、3、4、11、12和13,但21、22、23等。
gnasher729


5

英语

这只是工作的开箱

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: ''
 => "дети"

4

实际上,还有繁琐的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个译文,因为“ You”会根据查看用户的性别而有所不同。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框架及其所有库的开发者和维护者。


1
我希望我知道反对投票的目的,答案似乎还不错。
doug65536 '16

0

关于Redmine。如果您在config / locales /中将复数文件规则复制为plurals.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**
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.