i18n đa năng


88

Tôi muốn có thể dịch các chuỗi đa nguyên trong i18n trong đường ray. Một chuỗi có thể là:

You have 2 kids

hoặc là

You have 1 kid

Tôi biết rằng tôi có thể sử dụng phương pháp trình trợ giúp đa nguyên, nhưng tôi muốn nhúng phương pháp này vào các bản dịch i18n để không phải xáo trộn các quan điểm của mình tại bất kỳ thời điểm nào trong tương lai. Tôi đọc rằng :countbằng cách nào đó được sử dụng trong các bản dịch cho số nhiều, nhưng tôi không thể tìm thấy bất kỳ tài nguyên thực sự nào về cách nó được triển khai.

Lưu ý rằng tôi biết rằng tôi có thể truyền một biến trong một chuỗi dịch. Tôi cũng đã thử một cái gì đó như:

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

Cái nào hoạt động tốt, nhưng có một vấn đề cơ bản của cùng một ý tưởng. Tôi cần chỉ định chuỗi 'kid'trong trình trợ giúp đa phương hóa. Tôi không muốn làm điều đó vì nó sẽ dẫn đến các vấn đề về view trong tương lai. Thay vào đó, tôi muốn giữ mọi thứ trong bản dịch và không có gì trong chế độ xem.

Làm thế nào tôi có thể làm điều đó ?


2
Lưu ý rằng "bộ nội suy" và dấu ngoặc kép "#{....}"không cần thiết trong đoạn mã trên.
Zabba

1
bạn có một cách tiếp cận sai vì bạn đang giả định rằng số nhiều cho các ngôn ngữ khác đang hoạt động giống như trong tiếng Anh. Xem câu trả lời của tôi để có cách tiếp cận đúng.
sorin

Sorin, cảm ơn bạn đã trả lời, tôi chỉ không muốn sử dụng gettext cho câu trả lời này. Tôi nghĩ rằng giải pháp của Zabba là tuyệt vời cho nhu cầu của tôi với i18n.
Spyros

Rails 3 xử lý mạnh mẽ hơn bằng cách sử dụng CLDR và ​​biến nội suy 'count': Guide.rubyonrails.org/i18n.html#pluification
Luke W

Nhiều năm sau, nhưng bạn cũng có thể sử dụng bản dịch trên chuỗi 'đứa trẻ' - vì vậy bạn có: <%= t 'misc.kids', :kids_num => pluralize(1, t('kid')) %>. Có lẽ điều này đã không làm việc trong năm 2011 nhưng nó chắc chắn làm tại on Rails 5.2.2 (!)
Jarvis Johnson

Câu trả lời:


176

Thử đi:

en.yml :

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

Theo quan điểm:

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

Câu trả lời cập nhật cho các ngôn ngữ có nhiều đa dạng (được thử nghiệm với Rails 3.0.7):

Tệp tin config/initializers/pluralization.rb :

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

Tệp tin 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`)

Tệp tin config/locales/en.yml :

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

Tệp tin config/locales/ru.yml :

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

Kiểm tra :

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

Xin lỗi nhưng điều này không hoạt động với nhiều ngôn ngữ. Đa dạng hóa thực sự phức tạp, hãy xem translate.sourceforge.net/wiki/l10n/pluralforms Do đó, tôi nghĩ rằng câu trả lời của tôi phù hợp hơn.
sorin

1
@sorin, đã cập nhật câu trả lời của tôi để sử dụng nhiều quy tắc đa dạng.
Zabba

5
Không sao cả, nhưng bây giờ bạn có một công việc toàn thời gian mới, để duy trì từ điển đa năng !.
sorin

Điều đó thật tuyệt! Để làm %{count}việc, tôi đã phải sử dụng dấu ngoặc kép xung quanh toàn bộ khối. one: "%{count} kid"
fireev

1
@ThePablick, vâng, vì các tệp trong thư mục '/ initializer' chỉ được tải một lần - khi khởi động máy chủ http.
Zabba

37

Tôi hy vọng các lập trình viên Ruby on Rails nói tiếng Nga có thể tìm thấy điều này. Chỉ muốn chia sẻ công thức đa nguyên hóa tiếng Nga rất chính xác của riêng tôi. Nó dựa trên Thông số Unicode . Đây chỉ là nội dung của config/locales/plurals.rbtệp, mọi thứ khác sẽ được thực hiện giống như trong câu trả lời ở trên.

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

Người bản ngữ có thể thích các trường hợp như 111121. Và đây là kết quả kiểm tra:

  • không: 0 запросов / куриц / яблок
  • một: 1 запрос / курица / яблоко
  • vài: 3 запроса / курицы / яблока
  • nhiều: 5 запросов / куриц / яблок
  • một: 101 запрос / курица / яблоко
  • vài: 102 запроса / курицы / яблока
  • nhiều: 105 запросов / куриц / яблок
  • nhiều: 111 запросов / куриц / яблок
  • nhiều: 119 запросов / куриц / яблок
  • một: 121 запрос / курица / яблоко
  • số ít: 122 запроса / курицы / яблока
  • nhiều: 125 запросов / куриц / яблок

Cảm ơn câu trả lời ban đầu!


1
Câu trả lời khác mà bạn đã tham khảo, đã đặt câu trả lời này trong một tệp khác. Vì vậy, với cách tiếp cận nội dung của bạn nên đến config/locales/plurals.rbhơnconfig/initializers/pluralization.rb
silverdr

@silverdr Tôi đã sửa tên tệp trong câu trả lời. Cảm ơn vì tiền hỗ trợ!
sashaegorov

11

Đầu tiên, hãy nhớ rằng số lượng dạng số nhiều phụ thuộc vào ngôn ngữ , đối với tiếng Anh có hai, đối với tiếng Romania có 3 và đối với tiếng Ả Rập có 6 !.

Nếu bạn muốn có thể sử dụng đúng dạng số nhiều, bạn phải sử dụng gettext .

Đối với Ruby và rails, bạn nên kiểm tra http://www.yotabanana.com/hiki/ruby-gettext-howto-rails.html này


4
Sorin, đây là điều tôi cũng đang nghĩ nhưng điều này dường như được giải quyết bằng cách làm theo định dạng CLDR ( unicode.org/repos/cldr-tmp/trunk/diff/supplemental/… ). Tôi có lầm không?
Nikos D

Cũng có 1, 2, 3, 4, 11, 12 và 13 nhưng 21, 22, 23, v.v.
gnasher729


5

Tiếng Anh

Nó chỉ hoạt động ra khỏi hộp

en.yml :

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

Cách sử dụng (tất nhiên bạn có thể bỏ qua I18n trong một tệp dạng xem):

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

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

Tiếng Nga (và các ngôn ngữ khác có nhiều dạng số nhiều)

Cài đặt gem rails-18n và thêm bản dịch vào .ymltệp của bạn như trong ví dụ :

ru.yml :

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

Sử dụng:

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

4

Thực sự có một giải pháp thay thế cho cách tiếp cận i18n rườm rà. Dung dịch được gọi là Tr8n.

Mã trên của bạn sẽ đơn giản là:

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

Đó là nó. Không cần trích xuất các khóa từ mã của bạn và duy trì chúng trong các gói tài nguyên, không cần triển khai các quy tắc đa dạng hóa cho từng ngôn ngữ. Tr8n đi kèm với các quy tắc ngữ cảnh số cho tất cả các ngôn ngữ. Nó cũng đi kèm với các quy tắc giới tính, quy tắc danh sách và các trường hợp ngôn ngữ.

Định nghĩa đầy đủ của khóa dịch ở trên thực sự sẽ như thế này:

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

Nhưng vì chúng ta muốn tiết kiệm không gian và thời gian, num tự động được ánh xạ tới các quy tắc số và không cần cung cấp tất cả các tùy chọn cho các giá trị quy tắc. Tr8n đi kèm với các bộ phân cực và bộ cảm biến sẽ làm công việc cho bạn một cách nhanh chóng.

Bản dịch cho khóa của bạn bằng tiếng Nga, sẽ đơn giản là:

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

Nhân tiện, bản dịch của bạn sẽ không chính xác bằng các ngôn ngữ có quy tắc cụ thể về giới tính. Ví dụ: bằng tiếng Do Thái, bạn thực sự sẽ phải chỉ định ít nhất 2 bản dịch cho ví dụ của mình, vì "Bạn" sẽ khác dựa trên giới tính của người dùng đang xem. Tr8n xử lý rất tốt. Đây là bản chuyển ngữ của các bản dịch tiếng Do Thái:

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

Vì vậy, khóa tiếng Anh duy nhất của bạn, trong trường hợp này, cần 4 bản dịch. Tất cả các bản dịch được thực hiện theo ngữ cảnh - bạn không cần phải ngắt câu. Tr8n có cơ chế ánh xạ một khóa cho nhiều bản dịch dựa trên ngôn ngữ và ngữ cảnh - tất cả đều được thực hiện nhanh chóng.

Một điều cuối cùng. Điều gì sẽ xảy ra nếu bạn phải làm cho phần đếm được in đậm? Nó chỉ đơn giản là:

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

Chỉ trong trường hợp bạn muốn xác định lại "chữ đậm" của mình sau này - sẽ rất dễ dàng - bạn sẽ không phải xem qua tất cả các tệp YAML của mình và thay đổi chúng - bạn chỉ cần thực hiện ở một nơi.

Để tìm hiểu thêm, vui lòng xem tại đây:

https://github.com/tr8n/tr8n_rails_clientsdk

Tiết lộ: Tôi là nhà phát triển và là người duy trì khuôn khổ Tr8n và tất cả các thư viện của nó.


1
Tôi ước tôi biết những gì các phiếu phản đối là gì, câu trả lời có vẻ ổn.
doug65536

0

Giới thiệu về Redmine. Nếu bạn sao chép các quy tắc tệp đa chức năng trong config / locales / as plurals.rb và các quy tắc khác không giống với tên miền (ru.rb, pl.rb .. vv) thì chúng không hoạt động. Bạn phải đổi tên các quy tắc tệp thành 'locale'.rb hoặc thay đổi phương thức trong tệp /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

và nếu bạn có redmine cũ hơn, hãy thêm

module Implementation
        include ::I18n::Backend::Base
        **include ::I18n::Backend::Pluralization**
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.