Pluralisation i18n

88

Je veux pouvoir traduire des chaînes plurielles dans i18n en rails. Une chaîne peut être:

You have 2 kids

ou

You have 1 kid

Je sais que je peux utiliser la méthode d'assistance pluralize, mais je veux l'intégrer dans les traductions i18n afin de ne pas avoir à gâcher mes vues à tout moment dans le futur. J'ai lu que :countc'est en quelque sorte utilisé dans les traductions pour le pluriel, mais je ne trouve pas de ressources réelles sur la façon dont il est mis en œuvre.

Notez que je sais que je peux passer une variable dans une chaîne de traduction. J'ai aussi essayé quelque chose comme:

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

Ce qui fonctionne bien, mais a un problème fondamental de la même idée. Je dois spécifier la chaîne 'kid'dans l'assistant de pluralisation. Je ne veux pas faire cela parce que cela mènera à voir des problèmes dans le futur. Au lieu de cela, je veux garder tout dans la traduction et rien dans la vue.

Comment puis je faire ça ?

Spyros
la source
2
Notez que "l'interpolateur" et les guillemets "#{....}"ne sont pas nécessaires dans le code ci-dessus.
Zabba
1
vous avez une mauvaise approche parce que vous supposez que les pluriels des autres langues fonctionnent comme en anglais. Voir ma réponse pour une approche correcte.
sorin
Sorin, merci pour votre réponse, je ne veux tout simplement pas utiliser gettext pour celui-ci. Je pense que la solution de Zabba répond parfaitement à mes besoins avec i18n.
Spyros
Rails 3 gère plus robuste en utilisant CLDR et la variable d'interpolation 'count': guides.rubyonrails.org/i18n.html#pluralization
Luke W
Des années plus tard, mais vous pouvez aussi utiliser une traduction sur la chaîne « kid » - donc vous avez: <%= t 'misc.kids', :kids_num => pluralize(1, t('kid')) %>. Peut-être que cela n'a pas fonctionné en 2011 (!) Mais c'est sûr maintenant sur Rails 5.2.2
Jarvis Johnson

Réponses:

176

Essaye ça:

en.yml :

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

Dans une vue:

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

Réponse mise à jour pour les langues à pluralisation multiple (testée avec Rails 3.0.7):

Fichier config/initializers/pluralization.rb :

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

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

Fichier config/locales/en.yml :

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

Fichier 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! 
Zabba
la source
Désolé, mais cela ne fonctionne pas avec beaucoup de langues. La pluralisation est vraiment complexe, voir translate.sourceforge.net/wiki/l10n/pluralforms Pour cette raison, je pense que ma réponse est plus appropriée.
sorin
1
@sorin, a mis à jour ma réponse pour utiliser plusieurs règles de pluralisation.
Zabba
5
C'est ok, mais maintenant vous avez un nouveau travail à plein temps, pour maintenir le dictionnaire de pluralisation !.
sorin
C'est bien! Pour faire %{count}fonctionner, j'ai dû utiliser des citations autour de tout le bloc, c'est-à-dire. one: "%{count} kid"
firedev le
1
@ThePablick, oui, puisque les fichiers du répertoire '/ initializer' ne sont chargés qu'une seule fois - au démarrage du serveur http.
Zabba
37

J'espère que les programmeurs de Ruby on Rails russophones pourront le trouver. Je veux juste partager ma propre formule de pluralisation russe très précise. Il est basé sur les spécifications Unicode . Voici le contenu du config/locales/plurals.rbfichier uniquement, tout le reste doit être fait comme dans la réponse ci-dessus.

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

Les locuteurs natifs peuvent apprécier des cas tels que 111et 121. Et voici les résultats du test:

  • zéro: 0 запросов / куриц / яблок
  • un: 1 запрос / курица / яблоко
  • peu: 3 запроса / курицы / яблока
  • beaucoup: 5 запросов / куриц / яблок
  • un: 101 запрос / курица / яблоко
  • peu: 102 запроса / курицы / яблока
  • beaucoup: 105 запросов / куриц / яблок
  • beaucoup: 111 запросов / куриц / яблок
  • beaucoup: 119 запросов / куриц / яблок
  • un: 121 запрос / курица / яблоко
  • peu: 122 запроса / курицы / яблока
  • beaucoup: 125 запросов / куриц / яблок

Merci pour la réponse initiale!

Sashaegorov
la source
1
L'autre réponse à laquelle vous avez fait allusion a placé cela dans un autre fichier. Donc, avec cette approche, votre contenu devrait aller config/locales/plurals.rbplutôt queconfig/initializers/pluralization.rb
silverdr
@silverdr J'ai corrigé le nom du fichier dans la réponse. Merci pour le conseil!
sashaegorov
11

Tout d'abord, rappelez-vous que le nombre de formes plurielles dépend de la langue , pour l'anglais il y en a deux, pour le roumain il y en a 3 et pour l'arabe il y en a 6!

Si vous voulez pouvoir utiliser correctement les formes plurielles, vous devez utiliser gettext.

Pour Ruby et les rails, vous devriez vérifier ceci http://www.yotabanana.com/hiki/ruby-gettext-howto-rails.html

Sorin
la source
4
Sorin, c'est ce à quoi je pensais aussi mais cela semble être résolu en suivant le format CLDR ( unicode.org/repos/cldr-tmp/trunk/diff/supplemental/… ). Ai-je tort?
Nikos D
Il y a aussi les 1er, 2ème, 3ème, 4ème, 11ème, 12ème et 13ème mais 21ème, 22ème, 23ème et ainsi de suite.
gnasher729
8

Rails 3 gère cela de manière robuste avec la considération CLDR et la variable d'interpolation de compte. Voir 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
la source
5

Anglais

Cela fonctionne juste hors de la boîte

en.yml :

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

Utilisation (vous pouvez ignorer I18n dans un fichier de vue, bien sûr):

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

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

Russe (et autres langues avec plusieurs formes plurielles)

Installez le gem rails-18n et ajoutez des traductions à vos .ymlfichiers comme dans l' exemple :

ru.yml :

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

Usage:

> 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
la source
4

Il existe en fait une alternative à la lourde approche i18n. La solution s'appelle Tr8n.

Votre code ci-dessus serait simplement:

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

C'est ça. Pas besoin d'extraire vos clés de votre code et de les maintenir dans des ensembles de ressources, pas besoin d'implémenter des règles de pluralisation pour chaque langue. Tr8n est livré avec des règles de contexte numériques pour toutes les langues. Il est également livré avec des règles de genre, des règles de liste et des cas de langue.

La définition complète de la clé de traduction ci-dessus ressemblerait en fait à ceci:

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

Mais puisque nous voulons économiser de l'espace et du temps, num est automatiquement mappé sur des règles numériques et il n'est pas nécessaire de fournir toutes les options pour les valeurs de règle. Tr8n est livré avec des pluraliseurs et des inflecteurs qui feront le travail pour vous à la volée.

La traduction de votre clé en russe serait simplement:

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

En passant, votre traduction serait inexacte dans les langues qui ont des règles spécifiques au genre. Par exemple, en hébreu, vous devrez en fait spécifier au moins 2 traductions pour votre exemple, car «Vous» serait différent en fonction du sexe de l'utilisateur qui regarde. Tr8n le gère très bien. Voici une translittération des traductions hébraïques:

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

Donc, votre clé anglaise unique, dans ce cas, nécessite 4 traductions. Toutes les traductions sont effectuées en contexte - vous n'avez pas à casser la phrase. Tr8n a un mécanisme pour mapper une clé à plusieurs traductions en fonction de la langue et du contexte - le tout à la volée.

Une dernière chose. Et si vous deviez rendre la partie comptage en gras? Ce serait simplement:

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

Juste au cas où vous voudriez redéfinir votre "gras" plus tard - ce serait très facile - vous n'aurez pas à parcourir tous vos fichiers YAML et à les modifier - vous le faites simplement en un seul endroit.

Pour en savoir plus, jetez un œil ici:

https://github.com/tr8n/tr8n_rails_clientsdk

Divulgation: Je suis le développeur et le mainteneur du framework Tr8n et de toutes ses bibliothèques.

Michael Berkovich
la source
1
J'aurais aimé savoir à quoi servaient les votes négatifs, la réponse semble bien.
doug65536
0

À propos de Redmine. Si vous copiez les règles de fichier de pluralisation dans config / locales / en tant que plurals.rb et autres pas les mêmes que le nom de locale (ru.rb, pl.rb .. etc.), cela ne fonctionne pas. Vous devez renommer les règles de fichier en 'locale'.rb ou changer de méthode dans le fichier /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

et si vous avez une ancienne redmine, ajoutez

module Implementation
        include ::I18n::Backend::Base
        **include ::I18n::Backend::Pluralization**
Vladimir Kovalev
la source