Pluralização i18n


89

Eu quero ser capaz de traduzir strings pluralizadas em i18n em trilhos. Uma string pode ser:

You have 2 kids

ou

You have 1 kid

Eu sei que posso usar o método auxiliar pluralize, mas quero incorporar isso nas traduções i18n para que eu não tenha que bagunçar minhas visões em nenhum momento no futuro. Eu li que :counté de alguma forma usado em traduções para plural, mas não consigo encontrar nenhum recurso real sobre como ele é implementado.

Observe que eu sei que posso passar uma variável em uma string de tradução. Eu também tentei algo como:

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

O que funciona bem, mas tem um problema fundamental com a mesma ideia. Eu preciso especificar a string'kid' no auxiliar pluralize. Não quero fazer isso porque levará a ver problemas no futuro. Em vez disso, quero manter tudo na tradução e nada na visualização.

Como eu posso fazer isso ?


2
Observe que o "interpolador" e as aspas "#{....}"não são necessários no código acima.
Zabba

1
você tem uma abordagem errada porque está presumindo que os plurais para outros idiomas estão funcionando como no inglês. Veja minha resposta para uma abordagem correta.
Sorin

Sorin, obrigado por sua resposta, só não quero usar gettext para este. Acho que a solução da Zabba é ótima para minhas necessidades com o i18n.
Spyros

O Rails 3 é mais robusto usando CLDR e a variável de interpolação 'count': guias.rubyonrails.org/i18n.html#pluralization
Lucas W

Anos mais tarde, mas você também pode usar uma tradução on a string 'garoto' - assim que você tem: <%= t 'misc.kids', :kids_num => pluralize(1, t('kid')) %>. Talvez isso não tenha funcionado em 2011 (!), Mas com certeza funciona agora no Rails 5.2.2
Jarvis Johnson

Respostas:


176

Experimente isto:

en.yml :

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

Em uma vista:

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

Resposta atualizada para linguagens com pluralização múltipla (testado com Rails 3.0.7):

Arquivo config/initializers/pluralization.rb :

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

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

Arquivo config/locales/en.yml :

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

Arquivo config/locales/ru.yml :

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

Teste :

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

Desculpe, mas isso simplesmente não funciona com muitos idiomas. A pluralização é realmente complexa, veja translate.sourceforge.net/wiki/l10n/pluralforms Devido a isso eu acho que minha resposta é mais apropriada.
Sorin

1
@sorin, atualizei minha resposta para usar várias regras de pluralização.
Zabba

5
Tudo bem, mas agora você tem um novo emprego de tempo integral, para manter o dicionário de pluralização !.
Sorin

Isso é ótimo! Para fazer %{count}funcionar, eu tive que usar aspas em todo o bloco, ou seja. one: "%{count} kid"
firedev

1
@ThePablick, sim, já que os arquivos no diretório '/ initializer' são carregados apenas uma vez - na inicialização do servidor http.
Zabba

37

Espero que os programadores de Ruby on Rails que falam russo possam encontrar isso. Só quero compartilhar minha própria fórmula de pluralização russa muito precisa. É baseado nas especificações Unicode . Aqui está o conteúdo do config/locales/plurals.rbarquivo apenas, todo o resto deve ser feito da mesma forma que na resposta acima.

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

Falantes nativos podem gostar de casos como 111e 121. E aqui estão os resultados do teste:

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

Obrigado pela resposta inicial!


1
A outra resposta a que você se referiu, a colocou em um arquivo diferente. Portanto, com essa abordagem, seu conteúdo deve ir para, em config/locales/plurals.rbvez deconfig/initializers/pluralization.rb
silverdr

@silverdr Corrigi o nome do arquivo na resposta. Obrigado pela dica!
Sashaegorov

11

Primeiro, lembre-se de que o número de formas plurais depende do idioma , para o inglês existem duas, para o romeno existem 3 e para o árabe existem 6!.

Se você quiser usar as formas plurais de maneira adequada, terá que usar gettext.

Para Ruby e rails, você deve verificar este http://www.yotabanana.com/hiki/ruby-gettext-howto-rails.html


4
Sorin, isso é o que eu também estava pensando, mas isso parece ser resolvido seguindo o formato CLDR ( unicode.org/repos/cldr-tmp/trunk/diff/supplemental/… ). Estou errado?
Nikos D

Há também 1º, 2º, 3º, 4º, 11º, 12º e 13º, mas 21º, 22º, 23º e assim por diante.
gnasher729 de


5

Na verdade, existe uma alternativa para a abordagem complicada de i18n. A solução é chamada de Tr8n.

Seu código acima seria simplesmente:

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

É isso aí. Não há necessidade de extrair suas chaves de seu código e mantê-los em pacotes de recursos, sem necessidade de implementar regras de pluralização para cada idioma. Tr8n vem com regras de contexto numérico para todos os idiomas. Ele também vem com regras de gênero, regras de lista e casos de linguagem.

A definição completa da chave de tradução acima seria realmente semelhante a esta:

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

Mas, como queremos economizar espaço e tempo, num é mapeado automaticamente para regras numéricas e não há necessidade de fornecer todas as opções para os valores das regras. O Tr8n vem com pluralizadores e infletores que farão o trabalho para você na hora.

A tradução de sua chave em russo seria simplesmente:

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

A propósito, sua tradução seria imprecisa em idiomas que têm regras específicas de gênero. Por exemplo, em hebraico, você realmente teria que especificar pelo menos 2 traduções para o seu exemplo, já que "Você" seria diferente com base no sexo do usuário que está visualizando. Tr8n lida com isso muito bem. Aqui está uma transliteração das traduções hebraicas:

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

Portanto, sua única chave em inglês, neste caso, precisa de 4 traduções. Todas as traduções são feitas no contexto - você não precisa quebrar a frase. O Tr8n tem um mecanismo para mapear uma chave para várias traduções com base no idioma e no contexto - tudo feito na hora.

Uma última coisa. E se você tivesse que deixar a contagem em negrito? Seria simplesmente:

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

Apenas no caso de você querer redefinir seu "negrito" mais tarde - seria muito fácil - você não terá que passar por todos os seus arquivos YAML e alterá-los - basta fazê-lo em um só lugar.

Para saber mais, dê uma olhada aqui:

https://github.com/tr8n/tr8n_rails_clientsdk

Divulgação: Eu sou o desenvolvedor e mantenedor do framework Tr8n e de todas as suas bibliotecas.


1
Eu gostaria de saber para que servem os votos negativos, a resposta parece boa.
doug65536

5

Inglês

Simplesmente funciona fora da caixa

en.yml :

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

Uso (você pode pular I18n em um arquivo de visualização, é claro):

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

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

Russo (e outros idiomas com múltiplas formas plurais)

Instale o rails-18n gem e adicione traduções aos seus .ymlarquivos como no exemplo :

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

0

Sobre o Redmine. Se você copiar as regras do arquivo de pluralização em config / locales / as plurals.rb e outro diferente do nome do locale (ru.rb, pl.rb .. etc), isso não funcionará. Você deve renomear as regras de arquivo para 'locale'.rb ou alterar o método no arquivo /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 você tiver redmine mais antigo, adicione

module Implementation
        include ::I18n::Backend::Base
        **include ::I18n::Backend::Pluralization**
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.