i18n Pluralizacja


88

Chcę mieć możliwość tłumaczenia ciągów w liczbie mnogiej w i18n na szynach. Ciąg może być:

You have 2 kids

lub

You have 1 kid

Wiem, że mogę użyć metody pomocnika liczby mnogiej, ale chcę osadzić to w tłumaczeniach i18n, aby nie musieć mieszać moich poglądów w żadnym momencie w przyszłości. Czytałem, że :countjest to w jakiś sposób używane w tłumaczeniach na liczbę mnogą, ale nie mogę znaleźć żadnych prawdziwych zasobów na temat tego, jak jest wdrażany.

Zauważ, że wiem, że mogę przekazać zmienną w ciągu tłumaczenia. Spróbowałem też czegoś takiego:

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

Co działa dobrze, ale ma podstawowy problem związany z tym samym pomysłem. Muszę określić ciąg 'kid'w pomocniku liczby mnogiej. Nie chcę tego robić, ponieważ doprowadzi to do spojrzenia na problemy w przyszłości. Zamiast tego chcę zachować wszystko w tłumaczeniu i nic na widoku.

Jak mogę to zrobić ?


2
Zauważ, że „interpolator” i cudzysłowy "#{....}"nie są konieczne w powyższym kodzie.
Zabba

1
masz złe podejście, ponieważ zakładasz, że liczba mnoga dla innych języków działa tak, jak w języku angielskim. Zobacz moją odpowiedź na prawidłowe podejście.
sorin

Sorin, dziękuję za odpowiedź, po prostu nie chcę używać gettext do tego. Myślę, że rozwiązanie Zabby jest świetne dla moich potrzeb z i18n.
Spyros

Rails 3 radzi sobie lepiej, używając CLDR i zmiennej interpolacji „count”: guide.rubyonrails.org/i18n.html#pluralization
Luke W

Wiele lat później, ale można też użyć tłumaczenie na „dziecko” string - więc masz: <%= t 'misc.kids', :kids_num => pluralize(1, t('kid')) %>. Może to nie zadziałało w 2011 (!), Ale na pewno działa teraz na Railsach 5.2.2
Jarvis Johnson

Odpowiedzi:


176

Spróbuj tego:

en.yml :

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

W widoku:

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

Zaktualizowana odpowiedź dla języków z wieloma liczbami mnogimi (testowane w Railsach 3.0.7):

Plik config/initializers/pluralization.rb :

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

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

Plik config/locales/en.yml :

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

Plik 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! 

Przepraszamy, ale to po prostu nie działa w przypadku wielu języków. Pluralizacja jest naprawdę złożona, patrz translate.sourceforge.net/wiki/l10n/pluralforms Z tego powodu uważam, że moja odpowiedź jest bardziej odpowiednia.
sorin

1
@sorin, zaktualizowałem moją odpowiedź, aby używała wielu reguł liczby mnogiej.
Zabba

5
W porządku, ale teraz masz nową pracę na pełny etat, aby utrzymać słownik liczby mnogiej !.
sorin

To jest świetne! Aby %{count}zadziałało, musiałem używać cudzysłowów wokół całego bloku, tj. one: "%{count} kid"
firedev

1
@ThePablick, tak, ponieważ pliki w katalogu '/ initializer' są ładowane tylko raz - przy starcie serwera http.
Zabba,

37

Mam nadzieję, że rosyjskojęzyczni programiści Ruby on Rails mogliby to znaleźć. Chcę tylko podzielić się moją własną, bardzo precyzyjną formułą liczby mnogiej w języku rosyjskim. Jest oparty na specyfikacjach Unicode . Tutaj jest tylko zawartość config/locales/plurals.rbpliku, wszystko inne należy zrobić tak samo jak w odpowiedzi powyżej.

{: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 speakerzy mogą korzystać z przypadków takich jak 111i 121. A tutaj wyniki testów:

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

Dzięki za wstępną odpowiedź!


1
Druga odpowiedź, o której mówiłeś, umieściła to w innym pliku. Przy takim podejściu zawartość powinna config/locales/plurals.rbconfig/initializers/pluralization.rb
trafiać

@silverdr Poprawiłem nazwę pliku w odpowiedzi. Dzięki za wskazówkę!
sashaegorov

11

Po pierwsze, pamiętaj, że liczba form w liczbie mnogiej zależy od języka , dla angielskiego są dwa, dla rumuńskiego są 3, a dla arabskiego - 6!

Jeśli chcesz poprawnie używać form liczby mnogiej, musisz użyć gettext .

W przypadku Rubiego i szyn powinieneś sprawdzić to http://www.yotabanana.com/hiki/ruby-gettext-howto-rails.html


4
Sorin, o tym też myślałem, ale wydaje się, że można to rozwiązać, postępując zgodnie z formatem CLDR ( unicode.org/repos/cldr-tmp/trunk/diff/supplemental/… ). Czy się mylę?
Nikos D

Jest też 1, 2, 3, 4, 11, 12 i 13, ale 21, 22, 23 i tak dalej.
gnasher729


5

język angielski

Po prostu działa po wyjęciu z pudełka

en.yml :

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

Użycie (oczywiście można pominąć I18n w pliku widoku):

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

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

Rosyjski (i inne języki z wieloma formami liczby mnogiej)

Zainstaluj rails-18n gem i dodaj tłumaczenia do swoich .ymlplików jak w przykładzie :

ru.yml :

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

Stosowanie:

> 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

W rzeczywistości istnieje alternatywa dla uciążliwego podejścia i18n. Rozwiązanie nosi nazwę Tr8n.

Twój powyższy kod byłby po prostu:

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

Otóż ​​to. Nie ma potrzeby wyodrębniania kluczy z kodu i utrzymywania ich w pakietach zasobów, nie ma potrzeby wdrażania reguł liczby mnogiej dla każdego języka. Tr8n zawiera numeryczne reguły kontekstu dla wszystkich języków. Zawiera również zasady dotyczące płci, reguły listy i przypadki językowe.

Pełna definicja powyższego klucza tłumaczenia faktycznie wyglądałaby tak:

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

Ale ponieważ chcemy zaoszczędzić miejsce i czas, num jest automatycznie odwzorowywany na reguły numeryczne i nie ma potrzeby podawania wszystkich opcji dla wartości reguł. Tr8n jest wyposażony w pluralizery i inflektory, które wykonają pracę za Ciebie w locie.

Tłumaczenie twojego klucza w języku rosyjskim byłoby po prostu:

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

Nawiasem mówiąc, twoje tłumaczenie byłoby niedokładne w językach, w których obowiązują zasady dotyczące płci. Na przykład w języku hebrajskim należałoby w rzeczywistości określić co najmniej 2 tłumaczenia swojego przykładu, ponieważ „Ty” będzie się różnić w zależności od płci przeglądającego użytkownika. Tr8n radzi sobie z tym bardzo dobrze. Oto transliteracja tłumaczeń hebrajskich:

 "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}}

Zatem Twój pojedynczy klucz angielski wymaga w tym przypadku 4 tłumaczeń. Wszystkie tłumaczenia są wykonywane w kontekście - nie musisz przerywać zdania. Tr8n ma mechanizm mapowania jednego klucza do wielu tłumaczeń w oparciu o język i kontekst - wszystko odbywa się w locie.

Ostatnia rzecz. A co by było, gdybyś musiał pogrubić liczenie? Byłoby po prostu:

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

Na wypadek, gdybyś chciał później przedefiniować „pogrubienie” - byłoby to bardzo proste - nie będziesz musiał przeglądać wszystkich swoich plików YAML i ich zmieniać - po prostu zrób to w jednym miejscu.

Aby dowiedzieć się więcej, zajrzyj tutaj:

https://github.com/tr8n/tr8n_rails_clientsdk

Ujawnienie: Jestem programistą i opiekunem frameworka Tr8n i wszystkich jego bibliotek.


1
Żałuję, że nie wiem, po co są głosy przeciw, odpowiedź wydaje się w porządku.
doug65536

0

O Redmine. Jeśli skopiujesz reguły pliku liczby mnogiej w config / locales / jako plurals.rb i inne, różniące się od nazwy locale (ru.rb, pl.rb .. itd.), To nie zadziała. Musisz zmienić nazwę reguł plików na „locale ”.rb lub zmienić metodę w pliku /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

a jeśli masz starszą redmine, dodaj

module Implementation
        include ::I18n::Backend::Base
        **include ::I18n::Backend::Pluralization**
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.