i18n Pluralisasi

89

Saya ingin bisa menerjemahkan string yang jamak di i18n di rel. String bisa berupa:

You have 2 kids

atau

You have 1 kid

Saya tahu bahwa saya dapat menggunakan metode helper pluralize, tetapi saya ingin menyematkannya dalam terjemahan i18n sehingga saya tidak perlu mengacaukan pandangan saya kapan pun di masa mendatang. Saya membaca yang :countentah bagaimana digunakan dalam terjemahan untuk jamak, tetapi saya tidak dapat menemukan sumber daya nyata tentang bagaimana penerapannya.

Perhatikan bahwa saya tahu bahwa saya dapat mengirimkan variabel dalam string terjemahan. Saya juga mencoba sesuatu seperti:

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

Yang berfungsi dengan baik, tetapi memiliki masalah mendasar dari ide yang sama. Saya perlu menentukan string 'kid'dalam helper jamak. Saya tidak ingin melakukan itu karena itu akan mengarah pada masalah pandangan di masa depan. Sebaliknya saya ingin menyimpan semuanya dalam terjemahan dan tidak ada yang terlihat.

Bagaimana saya bisa melakukan itu?

Spyros
sumber
2
Perhatikan bahwa "interpolator" dan tanda kutip "#{....}"tidak diperlukan dalam kode di atas.
Zabba
1
Anda memiliki pendekatan yang salah karena Anda berasumsi bahwa bentuk jamak untuk bahasa lain berfungsi seperti dalam bahasa Inggris. Lihat jawaban saya untuk pendekatan yang benar.
sorin
Sorin, terima kasih atas jawaban Anda, saya hanya tidak ingin menggunakan gettext untuk yang satu ini. Saya pikir solusi Zabba sangat bagus untuk kebutuhan saya dengan i18n.
Spyros
Rails 3 menangani lebih kuat menggunakan CLDR dan variabel interpolasi 'count': Guideline.rubyonrails.org/i18n.html#pluralization
Luke W
Bertahun-tahun kemudian, tetapi Anda dapat juga menggunakan terjemahan pada string 'anak' - sehingga Anda memiliki: <%= t 'misc.kids', :kids_num => pluralize(1, t('kid')) %>. Mungkin ini tidak berhasil pada tahun 2011 (!) Tetapi sekarang pasti berhasil di Rails 5.2.2
Jarvis Johnson

Jawaban:

176

Coba ini:

en.yml :

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

Dalam tampilan:

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

Jawaban yang diperbarui untuk bahasa dengan banyak pluralisasi (diuji dengan 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

Tes :

$ 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
sumber
Maaf, tapi ini tidak berfungsi dengan banyak bahasa. Pluralisasi sangat kompleks, lihat translate.sourceforge.net/wiki/l10n/pluralforms. Karena itu, menurut saya jawaban saya lebih tepat.
sorin
1
@sorin, memperbarui jawaban saya untuk menggunakan beberapa aturan pluralisasi.
Zabba
5
Tidak apa-apa, tetapi sekarang Anda memiliki pekerjaan penuh waktu baru, untuk mempertahankan kamus pluralisasi !.
sorin
Ini bagus! Untuk membuatnya %{count}bekerja saya harus menggunakan tanda kutip di seluruh blok yaitu. one: "%{count} kid"
fireev
1
@ThePablick, ya, karena file dalam direktori '/ penginisialisasi' dimuat hanya sekali - pada startup server http.
Zabba
37

Saya berharap programmer Ruby on Rails yang berbahasa Rusia dapat menemukan ini. Hanya ingin berbagi rumus pluralisasi Rusia saya yang sangat tepat. Ini berdasarkan Spesifikasi Unicode . Berikut adalah isi config/locales/plurals.rbfile saja, yang lainnya harus dilakukan seperti pada jawaban di atas.

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

Penutur asli mungkin menyukai kasus seperti 111dan 121. Dan berikut hasil tesnya:

  • nol: 0 запросов / куриц / яблок
  • satu: 1 запрос / курица / яблоко
  • sedikit: 3 запроса / курицы / яблока
  • banyak: 5 запросов / куриц / яблок
  • satu: 101 запрос / курица / яблоко
  • sedikit: 102 запроса / курицы / яблока
  • banyak: 105 запросов / куриц / яблок
  • banyak: 111 запросов / куриц / яблок
  • banyak: 119 запросов / куриц / яблок
  • satu: 121 запрос / курица / яблоко
  • sedikit: 122 запроса / курицы / яблока
  • banyak: 125 запросов / куриц / яблок

Terima kasih atas jawaban awal!

sashaegorov
sumber
1
Jawaban lain yang Anda rujuk, tempatkan ini di file lain. Jadi dengan pendekatan bahwa konten Anda harus pergi ke config/locales/plurals.rbdaripadaconfig/initializers/pluralization.rb
silverdr
@silverdr Saya telah memperbaiki nama file di jawaban. Terima kasih atas tipnya!
sashaegorov
11

Pertama, ingat bahwa bentuk jamak tergantung pada bahasanya , untuk bahasa Inggris ada dua, untuk Rumania ada 3 dan untuk bahasa Arab ada 6!.

Jika Anda ingin dapat menggunakan bentuk jamak dengan benar, Anda harus menggunakan gettext.

Untuk Ruby dan rails Anda harus memeriksa ini http://www.yotabanana.com/hiki/ruby-gettext-howto-rails.html

sorin
sumber
4
Sorin, ini yang juga saya pikirkan tetapi ini tampaknya diselesaikan dengan mengikuti format CLDR ( unicode.org/repos/cldr-tmp/trunk/diff/supplemental/… ). Apakah aku salah?
Nikos D
Ada juga yang 1, 2, 3, 4, 11, 12 dan 13 tapi 21, 22, 23 dan seterusnya.
gnasher729
8

Rails 3 menangani ini dengan kuat dengan pertimbangan CLDR dan menghitung variabel interpolasi. Lihat 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.
sumber
5

Sebenarnya ada alternatif untuk pendekatan i18n yang rumit. Solusinya disebut Tr8n.

Kode Anda di atas hanya akan menjadi:

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

Itu dia. Tidak perlu mengekstrak kunci dari kode Anda dan menyimpannya dalam paket sumber daya, tidak perlu menerapkan aturan pluralisasi untuk setiap bahasa. Tr8n hadir dengan aturan konteks numerik untuk semua bahasa. Itu juga dilengkapi dengan aturan gender, aturan daftar dan kasus bahasa.

Definisi lengkap dari kunci terjemahan di atas sebenarnya akan terlihat seperti ini:

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

Tetapi karena kami ingin menghemat ruang dan waktu, num secara otomatis dipetakan ke aturan numerik dan tidak perlu menyediakan semua opsi untuk nilai aturan. Tr8n hadir dengan pluralizer dan inflektor yang akan bekerja untuk Anda dengan cepat.

Terjemahan untuk kunci Anda dalam bahasa Rusia, sederhananya adalah:

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

Omong-omong, terjemahan Anda mungkin tidak akurat dalam bahasa yang memiliki aturan khusus gender. Misalnya, dalam bahasa Ibrani, Anda sebenarnya harus menentukan setidaknya 2 terjemahan untuk contoh Anda, karena "Anda" akan berbeda berdasarkan jenis kelamin pengguna yang melihat. Tr8n menanganinya dengan sangat baik. Berikut adalah transliterasi dari terjemahan Ibrani:

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

Jadi kunci bahasa Inggris tunggal Anda, dalam hal ini, membutuhkan 4 terjemahan. Semua terjemahan dilakukan dalam konteks - Anda tidak perlu memutuskan kalimat. Tr8n memiliki mekanisme untuk memetakan satu kunci ke beberapa terjemahan berdasarkan bahasa dan konteks - semuanya dilakukan dengan cepat.

Satu hal terakhir. Bagaimana jika Anda harus membuat bagian penghitungan menjadi tebal? Ini hanya akan menjadi:

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

Untuk berjaga-jaga jika Anda ingin mendefinisikan kembali "tebal" Anda nanti - ini akan sangat mudah - Anda tidak perlu memeriksa semua file YAML Anda dan mengubahnya - Anda cukup melakukannya di satu tempat.

Untuk mempelajari lebih lanjut, silakan lihat di sini:

https://github.com/tr8n/tr8n_rails_clientsdk

Pengungkapan: Saya adalah pengembang dan pemelihara kerangka Tr8n dan semua perpustakaannya.

Michael Berkovich
sumber
1
Saya berharap saya tahu untuk apa suara negatif itu, jawaban tampaknya baik-baik saja.
doug65536
5

Inggris

Itu hanya bekerja di luar kotak

en.yml :

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

Penggunaan (Anda dapat melewati I18n dalam file tampilan, tentu saja):

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

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

Rusia (dan bahasa lain dengan berbagai bentuk jamak)

Instal permata rails-18n dan tambahkan terjemahan ke .ymlfile Anda seperti pada contoh :

ru.yml :

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

Pemakaian:

> 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
sumber
0

Tentang Redmine. Jika Anda menyalin aturan file pluralisasi di config / locales / sebagai bentuk jamak.rb dan lainnya tidak sama dengan nama lokal (ru.rb, pl.rb .. dll) ini tidak berfungsi. Anda harus mengganti nama aturan file menjadi 'locale'.rb atau mengubah metode di 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

dan jika Anda memiliki redmine lama, tambahkan

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