i18n พหูพจน์


89

ฉันต้องการแปลสตริงที่เป็นพหูพจน์ใน i18n ในราง สตริงสามารถ:

You have 2 kids

หรือ

You have 1 kid

ฉันรู้ว่าฉันสามารถใช้เมธอดตัวช่วยพหูพจน์ได้ แต่ฉันต้องการฝังสิ่งนี้ในการแปล i18n เพื่อที่ฉันจะได้ไม่ต้องวุ่นวายกับมุมมองของฉันในอนาคต ฉันอ่านว่า:countมีการใช้คำแปลของพหูพจน์ แต่ฉันไม่พบแหล่งข้อมูลที่แท้จริงเกี่ยวกับวิธีการนำไปใช้

สังเกตว่าฉันรู้ว่าฉันสามารถส่งผ่านตัวแปรในสตริงการแปลได้ ฉันลองทำสิ่งต่างๆเช่น:

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

ซึ่งใช้งานได้ดี แต่มีปัญหาพื้นฐานของแนวคิดเดียวกัน ฉันต้องการระบุสตริง'kid'ในตัวช่วยพหูพจน์ ฉันไม่อยากทำอย่างนั้นเพราะมันจะนำไปสู่การมองเห็นปัญหาในอนาคต แต่ฉันต้องการเก็บทุกอย่างไว้ในคำแปลและไม่มีอะไรอยู่ในมุมมอง

ฉันจะทำเช่นนั้นได้อย่างไร?


2
โปรดทราบว่า"#{....}"ไม่จำเป็นต้องใช้ "interpolator" และเครื่องหมายคำพูดในโค้ดด้านบน
Zabba

1
คุณมีแนวทางที่ไม่ถูกต้องเนื่องจากคุณสมมติว่าพหูพจน์ของภาษาอื่น ๆ ใช้งานได้เหมือนภาษาอังกฤษ ดูคำตอบของฉันสำหรับแนวทางที่ถูกต้อง
sorin

โซรินขอบคุณสำหรับคำตอบฉันไม่อยากใช้ gettext สำหรับอันนี้ ฉันคิดว่าโซลูชันของ Zabba นั้นยอดเยี่ยมสำหรับความต้องการของฉันด้วย i18n
Spyros

Rails 3 จัดการได้อย่างมีประสิทธิภาพยิ่งขึ้นโดยใช้ตัวแปรการแก้ไข CLDR และ 'count': guide.rubyonrails.org/i18n.html#pluralization
Luke W

ปีต่อมา แต่คุณยังสามารถใช้การแปลในสตริง 'เด็ก' ที่ - <%= t 'misc.kids', :kids_num => pluralize(1, t('kid')) %>เพื่อให้คุณมี: อาจจะใช้ไม่ได้ในปี 2011 (!) แต่แน่นอนว่าตอนนี้ใช้กับ Rails 5.2.2
Jarvis Johnson

คำตอบ:


176

ลองสิ่งนี้:

en.yml :

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

ในมุมมอง:

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

คำตอบที่อัปเดตสำหรับภาษาที่มีหลายพหูพจน์ (ทดสอบด้วย Rails 3.0.7):

ไฟล์ config/initializers/pluralization.rb :

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

ไฟล์ 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`)

ไฟล์ config/locales/en.yml :

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

ไฟล์ config/locales/ru.yml :

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

ทดสอบ :

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

ขออภัย แต่นี่ใช้ไม่ได้กับหลายภาษา การทำให้เป็นพหูพจน์นั้นซับซ้อนมากโปรดดูที่translate.sourceforge.net/wiki/l10n/pluralformsเนื่องจากสิ่งนี้ฉันคิดว่าคำตอบของฉันเหมาะสมกว่า
sorin

1
@sorin อัปเดตคำตอบของฉันเพื่อใช้กฎการพหูพจน์หลายรายการ
Zabba

5
ไม่เป็นไร แต่ตอนนี้คุณมีงานประจำใหม่เพื่อรักษาพจนานุกรมพหูพจน์!
ซอริน

นี่มันเยี่ยมมาก! เพื่อให้%{count}ทำงานได้ฉันต้องใช้เครื่องหมายคำพูดรอบบล็อกทั้งหมดเช่น one: "%{count} kid"
ไล่ออก

1
@ThePablick ใช่เนื่องจากไฟล์ในไดเร็กทอรี '/ initializer' ถูกโหลดเพียงครั้งเดียว - เมื่อเริ่มต้นเซิร์ฟเวอร์ http
Zabba

37

ฉันหวังว่าโปรแกรมเมอร์ Ruby on Rails ที่พูดภาษารัสเซียจะค้นพบสิ่งนี้ แค่อยากจะแบ่งปันสูตรพหูพจน์ภาษารัสเซียที่แม่นยำมากของฉันเอง มันขึ้นอยู่กับรายละเอียด Unicode นี่คือเนื้อหาของconfig/locales/plurals.rbไฟล์เท่านั้นควรทำอย่างอื่นเช่นเดียวกับในคำตอบด้านบน

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

เจ้าของภาษาอาจชอบเคสเช่น111และ121. และนี่คือผลการทดสอบ:

  • ศูนย์: 0 запросов / куриц / яблок
  • หนึ่ง: 1 запрос / курица / яблоко
  • ไม่กี่: 3 запроса / курицы / яблока
  • หลาย: 5 запросов / куриц / яблок
  • หนึ่ง: 101 запрос / курица / яблоко
  • น้อย: 102 запроса / курицы / яблока
  • มาก: 105 запросов / куриц / яблок
  • จำนวนมาก: 111 запросов / куриц / яблок
  • หลายคน: 119 запросов / куриц / яблок
  • หนึ่ง: 121 запрос / курица / яблоко
  • น้อย: 122 запроса / курицы / яблока
  • มาก: 125 запросов / куриц / яблок

ขอบคุณสำหรับคำตอบเบื้องต้น!


1
คำตอบอื่น ๆ ที่คุณอ้างถึงวางไว้ในไฟล์อื่น ดังนั้นด้วยวิธีนี้เนื้อหาของคุณควรไปที่config/locales/plurals.rbมากกว่าconfig/initializers/pluralization.rb
silverdr

@silverdr ฉันแก้ไขชื่อไฟล์ในคำตอบแล้ว ขอบคุณสำหรับทิป!
sashaegorov

11

อันดับแรกจำไว้ว่าจำนวนของรูปพหูพจน์ขึ้นอยู่กับภาษาสำหรับภาษาอังกฤษมีสองแบบสำหรับโรมาเนียมี 3 และสำหรับอาหรับมี 6!

gettextหากคุณต้องการที่จะสามารถที่จะต้องใช้รูปพหูพจน์ที่คุณต้องใช้

สำหรับ Ruby และรางคุณควรตรวจสอบhttp://www.yotabanana.com/hiki/ruby-gettext-howto-rails.html


4
โซรินนี่คือสิ่งที่ฉันคิดเช่นกัน แต่ดูเหมือนว่าจะแก้ไขได้โดยทำตามรูปแบบCLDR ( unicode.org/repos/cldr-tmp/trunk/diff/supplemental/… ) ฉันผิดเหรอ?
Nikos D

นอกจากนี้ยังมีวันที่ 1, 2, 3, 4, 11, 12 และ 13 แต่วันที่ 21, 22, 23 และอื่น ๆ
gnasher729


5

มีทางเลือกอื่นสำหรับวิธีการ i18n ที่ยุ่งยาก โซลูชันนี้เรียกว่า Tr8n

รหัสข้างต้นของคุณจะเป็น:

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

แค่นั้นแหละ. ไม่จำเป็นต้องดึงคีย์ของคุณออกจากโค้ดของคุณและเก็บรักษาไว้ในรีซอร์สบันเดิลไม่จำเป็นต้องใช้กฎหลายภาษาสำหรับแต่ละภาษา Tr8n มาพร้อมกับกฎบริบทตัวเลขสำหรับทุกภาษา นอกจากนี้ยังมาพร้อมกับกฎทางเพศกฎรายการและกรณีภาษา

คำจำกัดความที่สมบูรณ์ของคีย์การแปลข้างต้นจะมีลักษณะดังนี้:

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

แต่เนื่องจากเราต้องการประหยัดพื้นที่และเวลา num จึงถูกจับคู่กับกฎตัวเลขโดยอัตโนมัติและไม่จำเป็นต้องระบุตัวเลือกทั้งหมดสำหรับค่ากฎ Tr8n มาพร้อมกับพหูพจน์และอินฟิลเตอร์ที่จะทำงานให้คุณได้ทันที

คำแปลสำหรับคีย์ของคุณในภาษารัสเซียจะเป็น:

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

อย่างไรก็ตามการแปลของคุณอาจไม่ถูกต้องในภาษาที่มีกฎเฉพาะทางเพศ ตัวอย่างเช่นในภาษาฮิบรูคุณจะต้องระบุคำแปลอย่างน้อย 2 คำสำหรับตัวอย่างของคุณเนื่องจาก "คุณ" จะแตกต่างกันไปตามเพศของผู้ใช้ที่ดู Tr8n จัดการได้ดีมาก นี่คือการทับศัพท์ของการแปลภาษาฮีบรู:

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

ดังนั้นในกรณีนี้คีย์ภาษาอังกฤษเดียวของคุณต้องมีการแปล 4 ครั้ง การแปลทั้งหมดเสร็จสิ้นในบริบท - คุณไม่จำเป็นต้องทำลายประโยค Tr8n มีกลไกในการแมปคีย์เดียวกับการแปลหลาย ๆ คำตามภาษาและบริบทซึ่งทำได้ทันที

สิ่งสุดท้าย. จะเกิดอะไรขึ้นถ้าคุณต้องทำให้ส่วนการนับเป็นตัวหนา? มันจะเป็น:

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

ในกรณีที่คุณต้องการกำหนด "ตัวหนา" ของคุณใหม่ในภายหลัง - มันจะง่ายมาก - คุณไม่ต้องไปถึงไฟล์ YAML ทั้งหมดของคุณและเปลี่ยนไฟล์ - คุณทำได้ในที่เดียว

หากต้องการเรียนรู้เพิ่มเติมโปรดดูที่นี่:

https://github.com/tr8n/tr8n_rails_clientsdk

การเปิดเผยข้อมูล: ฉันเป็นผู้พัฒนาและเป็นผู้ดูแล Tr8n framework และไลบรารีทั้งหมด


1
ฉันหวังว่าฉันจะรู้ว่าการโหวตลดลงคืออะไรคำตอบดูเหมือนจะดี
doug65536

5

ภาษาอังกฤษ

มันใช้งานได้นอกกรอบ

en.yml :

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

การใช้งาน (คุณสามารถข้าม I18n ในไฟล์ดูได้):

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

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

รัสเซีย (และภาษาอื่น ๆ ที่มีรูปพหูพจน์หลายรูปแบบ)

ติดตั้งrail-18n gem และเพิ่มคำแปลให้กับ.ymlไฟล์ของคุณดังตัวอย่าง :

ru.yml :

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

การใช้งาน:

> 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

เกี่ยวกับ Redmine หากคุณคัดลอกกฎไฟล์พหูพจน์ใน config / locales / เป็น plurals.rb และอื่น ๆ ที่ไม่เหมือนกับชื่อโลแคล (ru.rb, pl.rb .. ฯลฯ ) สิ่งเหล่านี้จะไม่ทำงาน คุณต้องเปลี่ยนชื่อไฟล์กฎเป็น 'locale'.rb หรือเปลี่ยนวิธีการในไฟล์ /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

และถ้าคุณมี redmine รุ่นเก่าให้เพิ่ม

module Implementation
        include ::I18n::Backend::Base
        **include ::I18n::Backend::Pluralization**
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.