i18n Pluralization

2019-01-20 21:32发布

I want to be able to translate pluralized strings in i18n in rails. A string can be :

You have 2 kids

or

You have 1 kid

I know that I can use pluralize helper method, but I want to embed this in i18n translations so that I don't have to mess up with my views at any point in the future. I read that :count is somehow used in translations for plural, but I can't find any real resources on how it gets implemented.

Notice that I know that I can pass a variable in a translation string. I also tried something like :

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

Which works fine, but has a fundamental problem of the same idea. I need to specify the string 'kid' in the pluralize helper. I don't want to do that because it will lead to view problems in the future. Instead I want to keep everything in the translation and nothing in the view.

How can I do that ?

7条回答
男人必须洒脱
2楼-- · 2019-01-20 21:49

I hope Russian-speaking Ruby on Rails programmers could find this. Just want to share my own very precise Russian pluralization formula. It based on Unicode Specs. Here is contents of config/locales/plurals.rb file only, everything else should be done as same as in answer above.

{: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
        } 
      } 
    } 
  } 
}

Native speakers may enjoy cases such as 111 and 121. And here the test results:

  • zero: 0 запросов/куриц/яблок
  • one: 1 запрос/курица/яблоко
  • few: 3 запроса/курицы/яблока
  • many: 5 запросов/куриц/яблок
  • one: 101 запрос/курица/яблоко
  • few: 102 запроса/курицы/яблока
  • many: 105 запросов/куриц/яблок
  • many: 111 запросов/куриц/яблок
  • many: 119 запросов/куриц/яблок
  • one: 121 запрос/курица/яблоко
  • few: 122 запроса/курицы/яблока
  • many: 125 запросов/куриц/яблок

Thanks for initial answer!

查看更多
萌系小妹纸
3楼-- · 2019-01-20 21:52

Try this:

en.yml :

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

In a view:

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

Updated answer for languages with multiple pluralization (tested with Rails 3.0.7):

File config/initializers/pluralization.rb:

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

File 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`)

File config/locales/en.yml:

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

File config/locales/ru.yml:

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

Test:

$ 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! 
查看更多
等我变得足够好
4楼-- · 2019-01-20 21:54

English

It just works out of the box

en.yml:

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

Usage (you can skip I18n in a view file, of course):

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

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

Russian (and other languages with multiple plural forms)

Install rails-18n gem and add translations to your .yml files as in the example:

ru.yml:

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

Usage:

> 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: ''
 => "дети"
查看更多
三岁会撩人
5楼-- · 2019-01-20 21:57

First, remember that number of plural forms depends on language, for English there are two, for Romanian there are 3 and for Arabic there are 6 !.

If you want to be able to properly use plural forms you have to use gettext.

For Ruby and rails you should check this http://www.yotabanana.com/hiki/ruby-gettext-howto-rails.html

查看更多
劫难
6楼-- · 2019-01-20 22:08

About Redmine. If you copy pluralization file rules in config/locales/ as plurals.rb and other not same as locale name (ru.rb, pl.rb .. etc) these not work. You must rename file rules to 'locale'.rb or change method in file /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

and if you have older redmine, add

module Implementation
        include ::I18n::Backend::Base
        **include ::I18n::Backend::Pluralization**
查看更多
相关推荐>>
7楼-- · 2019-01-20 22:15

Rails 3 handles this robustly with CLDR consideration and count interpolation variable. See 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
查看更多
登录 后发表回答