Pluralización i18n

88

Quiero poder traducir cadenas pluralizadas en i18n en rieles. Una cadena puede ser:

You have 2 kids

o

You have 1 kid

Sé que puedo usar el método auxiliar de pluralizar, pero quiero incrustar esto en las traducciones de i18n para no tener que estropear mis puntos de vista en ningún momento en el futuro. Leí que de :countalguna manera se usa en traducciones para plural, pero no puedo encontrar ningún recurso real sobre cómo se implementa.

Observe que sé que puedo pasar una variable en una cadena de traducción. También probé algo como:

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

Lo cual funciona bien, pero tiene un problema fundamental de la misma idea. Necesito especificar la cadena 'kid'en el auxiliar pluralizado. No quiero hacer eso porque generará problemas de visualización en el futuro. En cambio, quiero mantener todo en la traducción y nada en la vista.

Cómo puedo hacer eso ?

Spyros
fuente
2
Tenga en cuenta que el "interpolador" y las comillas "#{....}"no son necesarios en el código anterior.
Zabba
1
tiene un enfoque incorrecto porque está asumiendo que los plurales de otros idiomas funcionan como en inglés. Vea mi respuesta para un enfoque correcto.
sorin
Sorin, gracias por tu respuesta, simplemente no quiero usar gettext para este. Creo que la solución de Zabba es excelente para mis necesidades con i18n.
Spyros
Rails 3 se maneja de manera más sólida usando CLDR y la variable de interpolación 'count': guides.rubyonrails.org/i18n.html#pluralization
Luke W
Años más tarde, pero también se puede usar una traducción en la cadena 'niño' - por lo que tiene: <%= t 'misc.kids', :kids_num => pluralize(1, t('kid')) %>. Tal vez esto no funcionó en 2011 (!) Pero seguro que funciona ahora en Rails 5.2.2
Jarvis Johnson

Respuestas:

176

Prueba esto:

en.yml :

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

En una vista:

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

Respuesta actualizada para idiomas con pluralización múltiple (probado con Rails 3.0.7):

Archivo config/initializers/pluralization.rb :

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

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

Archivo config/locales/en.yml :

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

Archivo config/locales/ru.yml :

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

Prueba :

$ 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! 
Zabba
fuente
Lo siento, pero esto simplemente no funciona con muchos idiomas. La pluralización es realmente compleja, ver translate.sourceforge.net/wiki/l10n/pluralforms Debido a esto, creo que mi respuesta es más apropiada.
sorin
1
@sorin, actualicé mi respuesta para usar múltiples reglas de pluralización.
Zabba
5
Está bien, pero ahora tienes un nuevo trabajo a tiempo completo, ¡para mantener el diccionario de pluralización !.
sorin
¡Esto es genial! Para que %{count}funcione, tuve que usar comillas en todo el bloque, es decir. one: "%{count} kid"
firedev
1
@ThePablick, sí, ya que los archivos en el directorio '/ initializer' se cargan solo una vez, al iniciar el servidor http.
Zabba
37

Espero que los programadores de Ruby on Rails de habla rusa puedan encontrar esto. Solo quiero compartir mi propia fórmula de pluralización rusa muy precisa. Se basa en las especificaciones Unicode . Aquí está el contenido del config/locales/plurals.rbarchivo solamente, todo lo demás debe hacerse igual que en la respuesta anterior.

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

Los hablantes nativos pueden disfrutar de casos como 111y 121. Y aquí los resultados de la prueba:

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

¡Gracias por la respuesta inicial!

Sashaegorov
fuente
1
La otra respuesta a la que se refirió la colocó en un archivo diferente. Entonces, con ese enfoque, su contenido debería ir a en config/locales/plurals.rblugar deconfig/initializers/pluralization.rb
silverdr
@silverdr He arreglado el nombre del archivo en respuesta. ¡Gracias por el consejo!
Sashaegorov
11

Primero, recuerde que el número de formas plurales depende del idioma , para el inglés hay dos, para el rumano hay 3 y para el árabe hay 6.

Si desea poder usar correctamente las formas plurales, debe usar gettext.

Para Ruby y rieles, debe consultar este http://www.yotabanana.com/hiki/ruby-gettext-howto-rails.html

sorin
fuente
4
Sorin, esto es lo que también estaba pensando, pero parece que se resuelve siguiendo el formato CLDR ( unicode.org/repos/cldr-tmp/trunk/diff/supplemental/… ). ¿Me equivoco?
Nikos D
También hay 1º, 2º, 3º, 4º, 11º, 12º y 13º pero 21º, 22º, 23º y así sucesivamente.
gnasher729
8

Rails 3 maneja esto de manera robusta con la consideración CLDR y la variable de interpolación de conteo. Ver 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
Luke W
fuente
5

Inglés

Simplemente funciona fuera de la caja

en.yml :

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

Uso (puede omitir I18n en un archivo de vista, por supuesto):

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

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

Ruso (y otros idiomas con múltiples formas plurales)

Instale la gema rails-18n y agregue traducciones a sus .ymlarchivos como en el ejemplo :

ru.yml :

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

Uso:

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

En realidad, existe una alternativa al engorroso enfoque i18n. La solución se llama Tr8n.

Su código anterior simplemente sería:

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

Eso es. No es necesario extraer sus claves de su código y mantenerlas en paquetes de recursos, no es necesario implementar reglas de pluralización para cada idioma. Tr8n viene con reglas de contexto numéricas para todos los idiomas. También viene con reglas de género, reglas de lista y casos de idioma.

La definición completa de la clave de traducción anterior se vería así:

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

Pero como queremos ahorrar espacio y tiempo, num se asigna automáticamente a las reglas numéricas y no es necesario proporcionar todas las opciones para los valores de las reglas. Tr8n viene con pluralizadores e inflectores que harán el trabajo por usted sobre la marcha.

La traducción de su clave en ruso sería simplemente:

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

Por cierto, su traducción sería inexacta en idiomas que tienen reglas específicas de género. Por ejemplo, en hebreo, en realidad tendría que especificar al menos 2 traducciones para su ejemplo, ya que "Usted" sería diferente según el género del usuario que lo ve. Tr8n lo maneja muy bien. Aquí hay una transliteración de traducciones hebreas:

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

Entonces, su clave única en inglés, en este caso, necesita 4 traducciones. Todas las traducciones se realizan en contexto, no es necesario romper la oración. Tr8n tiene un mecanismo para asignar una clave a múltiples traducciones según el idioma y el contexto, todo hecho sobre la marcha.

Una última cosa. ¿Y si tuvieras que poner la parte del recuento en negrita? Simplemente sería:

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

En caso de que desee redefinir su "negrita" más adelante, sería muy fácil, no tendrá que revisar todos sus archivos YAML y cambiarlos, simplemente hágalo en un solo lugar.

Para obtener más información, eche un vistazo aquí:

https://github.com/tr8n/tr8n_rails_clientsdk

Divulgación: Soy el desarrollador y mantenedor del marco Tr8n y todas sus bibliotecas.

Michael Berkovich
fuente
1
Ojalá supiera para qué fueron los votos negativos, la respuesta parece estar bien.
doug65536
0

Sobre Redmine. Si copia las reglas del archivo de pluralización en config / locales / como plurals.rb y otro que no sea el mismo que el nombre del entorno local (ru.rb, pl.rb .. etc), estos no funcionan. Debe cambiar el nombre de las reglas del archivo a 'locale'.rb o cambiar el método en el archivo /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

y si tiene una redmine más antigua, agregue

module Implementation
        include ::I18n::Backend::Base
        **include ::I18n::Backend::Pluralization**
Vladimir Kovalev
fuente