Pluralizzazione i18n


88

Voglio essere in grado di tradurre stringhe pluralizzate in i18n in rails. Una stringa può essere:

You have 2 kids

o

You have 1 kid

So che posso usare il metodo di supporto pluralizza, ma voglio incorporarlo nelle traduzioni di i18n in modo da non dover incasinare le mie opinioni in futuro. Ho letto che :countè in qualche modo usato nelle traduzioni al plurale, ma non riesco a trovare alcuna risorsa reale su come viene implementato.

Notare che so che posso passare una variabile in una stringa di traduzione. Ho anche provato qualcosa del tipo:

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

Che funziona bene, ma ha un problema fondamentale della stessa idea. Devo specificare la stringa 'kid'nell'helper pluralize. Non voglio farlo perché porterà a problemi di vista in futuro. Invece voglio mantenere tutto nella traduzione e niente nella vista.

Come posso fare ciò ?


2
Notare che l '"interpolatore" e le virgolette "#{....}"non sono necessari nel codice precedente.
Zabba

1
hai un approccio sbagliato perché stai assumendo che i plurali per altre lingue funzionino come in inglese. Vedi la mia risposta per un approccio corretto.
sorin

Sorin, grazie per la tua risposta, semplicemente non voglio usare gettext per questo. Penso che la soluzione di Zabba sia ottima per le mie esigenze con i18n.
Spyros

Rails 3 gestisce in modo più robusto utilizzando CLDR e la variabile di interpolazione "count": guides.rubyonrails.org/i18n.html#pluralization
Luke W

Anni dopo, ma è anche possibile utilizzare una traduzione sulla corda 'Kid' - in modo da avere: <%= t 'misc.kids', :kids_num => pluralize(1, t('kid')) %>. Forse questo non ha funzionato nel 2011 (!) Ma di sicuro ora funziona su Rails 5.2.2
Jarvis Johnson

Risposte:


176

Prova questo:

en.yml :

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

In una vista:

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

Risposta aggiornata per le lingue con pluralizzazione multipla (testato con 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

Prova :

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

Mi dispiace ma questo non funziona con molte lingue. La pluralizzazione è davvero complessa, vedere translate.sourceforge.net/wiki/l10n/pluralforms Per questo motivo penso che la mia risposta sia più appropriata.
sorin

1
@sorin, ho aggiornato la mia risposta per utilizzare più regole di pluralizzazione.
Zabba

5
Va bene, ma ora hai un nuovo lavoro a tempo pieno, per mantenere il dizionario di pluralizzazione !.
sorin

È fantastico! Per far %{count}funzionare ho dovuto usare le virgolette attorno all'intero blocco, ad es. one: "%{count} kid"
firedev

1
@ThePablick, sì, poiché i file nella directory "/ initializer" vengono caricati solo una volta, all'avvio del server http.
Zabba

37

Spero che i programmatori Ruby on Rails di lingua russa possano trovarlo. Voglio solo condividere la mia formula di pluralizzazione russa molto precisa. Si basa sulle specifiche Unicode . Ecco config/locales/plurals.rbsolo il contenuto del file, tutto il resto dovrebbe essere fatto come nella risposta sopra.

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

I madrelingua possono godere di casi come 111e 121. E qui i risultati del test:

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

Grazie per la risposta iniziale!


1
L'altra risposta a cui hai fatto riferimento, l'ha inserita in un file diverso. Quindi con questo approccio il tuo contenuto dovrebbe andare a config/locales/plurals.rbpiuttosto che aconfig/initializers/pluralization.rb
silverdr

@silverdr Ho corretto il nome del file in risposta. Grazie per il consiglio!
sashaegorov

11

Innanzitutto, ricorda che il numero di forme plurali dipende dalla lingua , per l'inglese ce ne sono due, per il rumeno ce ne sono 3 e per l'arabo ce ne sono 6!.

Se vuoi essere in grado di usare correttamente le forme plurali devi usare gettext.

Per Ruby e rails dovresti controllare questo http://www.yotabanana.com/hiki/ruby-gettext-howto-rails.html


4
Sorin, questo è quello che stavo pensando anche io ma questo sembra essere risolto seguendo il formato CLDR ( unicode.org/repos/cldr-tmp/trunk/diff/supplemental/… ). Ho sbagliato?
Nikos D

Ci sono anche 1 °, 2 °, 3 °, 4 °, 11 °, 12 ° e 13 ° ma 21 °, 22 °, 23 ° e così via.
gnasher729


5

inglese

Semplicemente funziona out of the box

en.yml :

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

Utilizzo (puoi saltare I18n in un file di visualizzazione, ovviamente):

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

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

Russo (e altre lingue con più forme plurali)

Installa rails-18n gem e aggiungi traduzioni ai tuoi .ymlfile come nell'esempio :

ru.yml :

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

Utilizzo:

> 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

In realtà esiste un'alternativa all'ingombrante approccio i18n. La soluzione si chiama Tr8n.

Il tuo codice sopra sarebbe semplicemente:

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

Questo è tutto. Non è necessario estrarre le chiavi dal codice e mantenerle in bundle di risorse, né implementare regole di pluralizzazione per ogni lingua. Tr8n viene fornito con regole di contesto numeriche per tutte le lingue. Viene inoltre fornito con regole di genere, regole di elenco e casi linguistici.

La definizione completa della chiave di traduzione sopra sarebbe effettivamente simile a questa:

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

Ma poiché vogliamo risparmiare spazio e tempo, num viene automaticamente mappato su regole numeriche e non è necessario fornire tutte le opzioni per i valori delle regole. Tr8n viene fornito con pluralizzatori e inflettori che faranno il lavoro per te al volo.

La traduzione della tua chiave in russo sarebbe semplicemente:

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

A proposito, la tua traduzione sarebbe imprecisa nelle lingue che hanno regole specifiche di genere. Ad esempio, in ebraico, dovresti effettivamente specificare almeno 2 traduzioni per il tuo esempio, poiché "Tu" sarebbe diverso in base al sesso dell'utente che lo visualizza. Tr8n lo gestisce molto bene. Ecco una traslitterazione delle traduzioni ebraiche:

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

Quindi la tua singola chiave inglese, in questo caso, necessita di 4 traduzioni. Tutte le traduzioni vengono eseguite nel contesto: non è necessario interrompere la frase. Tr8n ha un meccanismo per mappare una chiave a più traduzioni in base alla lingua e al contesto, tutto fatto al volo.

Un'ultima cosa. E se dovessi rendere la parte conteggio in grassetto? Sarebbe semplicemente:

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

Nel caso in cui desideri ridefinire il tuo "grassetto" in seguito - sarebbe molto facile - non dovrai esaminare tutti i tuoi file YAML e cambiarli - lo fai semplicemente in un posto.

Per saperne di più, dai un'occhiata qui:

https://github.com/tr8n/tr8n_rails_clientsdk

Divulgazione: sono lo sviluppatore e il manutentore del framework Tr8n e di tutte le sue librerie.


1
Vorrei sapere a cosa servono i voti negativi, la risposta sembra a posto.
doug65536

0

A proposito di Redmine. Se copi le regole del file di pluralizzazione in config / locales / come plurals.rb e altri non uguali al nome del locale (ru.rb, pl.rb .. ecc.) Queste non funzionano. È necessario rinominare le regole del file in 'locale'.rb o modificare il metodo nel 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

e se hai una miniera rossa più vecchia, aggiungi

module Implementation
        include ::I18n::Backend::Base
        **include ::I18n::Backend::Pluralization**
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.