i18n Плюралізація


88

Я хочу мати можливість перекласти множинні рядки в i18n в рейки. Рядок може бути:

You have 2 kids

або

You have 1 kid

Я знаю, що можу використовувати допоміжний метод плюралізації, але я хочу вбудувати це в переклади i18n, щоб мені не довелося возитися зі своїми поглядами в будь-який момент у майбутньому. Я читав, що :countякимось чином використовується у перекладах множини, але я не можу знайти реальних ресурсів про те, як це реалізується.

Зверніть увагу, що я знаю, що можу передавати змінну в рядок перекладу. Я також спробував щось на зразок:

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

Що працює добре, але має фундаментальну проблему тієї ж ідеї. Мені потрібно вказати рядок 'kid'у помічнику плюралізації. Я не хочу цього робити, оскільки це призведе до появи проблем у майбутньому. Натомість я хочу залишити все в перекладі, а нічого в полі зору.

Як я можу це зробити?


2
Зверніть увагу, що "інтерполятор" та лапки "#{....}"не є необхідними у наведеному вище коді.
Забба

1
у вас неправильний підхід, оскільки ви припускаєте, що множини для інших мов працюють як в англійській мові. Дивіться мою відповідь на правильний підхід.
сорін

Сорін, дякую за вашу відповідь, я просто не хочу використовувати gettext для цього. Я думаю, що рішення Zabba чудово підходить для моїх потреб з i18n.
Spyros

Rails 3 обробляє більш надійно, використовуючи CLDR та змінну інтерполяції "count": guides.rubyonrails.org/i18n.html#pluralization
Luke W

Багато років по тому, але ви також можете використовувати переклад на рядок «дитина» - так у вас є: <%= t 'misc.kids', :kids_num => pluralize(1, t('kid')) %>. Можливо, це не спрацювало в 2011 році (!), Але зараз, звичайно, працює на Rails 5.2.2
Джарвіс Джонсон,

Відповіді:


176

Спробуйте це:

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 Завдяки цьому я вважаю, що моя відповідь є більш доречною.
сорін

1
@sorin, оновив свою відповідь, щоб використовувати кілька правил плюралізації.
Забба

5
Це нормально, але тепер у вас є нова штатна робота, щоб підтримувати словник плюралізації !.
сорін

Це чудово! Щоб змусити %{count}працювати, мені довелося використовувати лапки навколо цілого блоку, тобто. one: "%{count} kid"
firedev

1
@ThePablick, так, оскільки файли в каталозі '/ ініціалізатор' завантажуються лише один раз - під час запуску сервера http.
Забба

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

11

По-перше, пам’ятайте, що кількість форм множини залежить від мови , для англійської - дві, для румунської - 3, а для арабської - 6!.

Якщо ви хочете мати можливість правильно використовувати форми множини, ви повинні їх використовувати gettext.

Що стосується Ruby та rails, вам слід ознайомитися з цим http://www.yotabanana.com/hiki/ruby-gettext-howto-rails.html


4
Сорін, це те, про що я теж думав, але, схоже, це можна вирішити, дотримуючись формату CLDR ( unicode.org/repos/cldr-tmp/trunk/diff/supplemental/… ). Я помиляюся?
Нікос Д

Також є 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 переклади для вашого прикладу, оскільки "Ви" відрізнятиметься залежно від статі користувача, який переглядає. 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

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**
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.