Rails 5:你能将一个字符串中的两个单词按不同数量转为复数吗?

8
我将为商店构建一个视图,列出产品评论的摘要。我将按分数对评论进行分组,并希望在每个组的顶部放置一个字符串,形式为“5星级10条评论”。我知道如果只想将“review”变成复数形式,可以在en.rb中这样做:
en: {
  reviews_header: {
    one: "%{count} review",
    other: "%{count} reviews"
  }
}

是否有一种格式可以用于reviews_header哈希表,让我能够同时指定“review”和“star”的计数,以便在需要时将它们都变成复数形式?在伪代码中,我想象了以下的方式:

en: {
    reviews_header: {
        counts: [ :review_count, :star_count ],
        review_count: {
            one: {
                star_count: {
                    one: "%{review_count} review with %{star_count} star",
                    other: "%{review_count} review with %{star_count} stars"
                }
            },
            other: {
                star_count: {
                    one: "%{review_count} reviews with %{star_count} star",
                    other: "%{review_count} reviews with %{star_count} stars"
                }
            }        
        }
    }
}

我会使用t(:reviews_header, review_count: 10, star_count: 5)获取字符串。

目前我的做法是将字符串改成"10个5星评价"的形式,这可以避免复数形式中 "star" 的问题,但是这种方法在其他语言中可能不适用。


嘿,迈克尔,你找到了解决这个问题的好方法吗?还是只能重新构建文本位? - Andrew
1
我只是改了一下文字。然后这个项目被取消了,所以我从未寻找更好的解决方案。 - Michael Dunn
1个回答

2
你在这里有一个嵌套复数的情况。虽然我对Ruby的熟悉程度很基础,但我找不到任何文档提供通过Ruby内置的i18n功能解决这个嵌套复数情况的解决方案。然而,在支持ICU库的编程语言中,可以从MessageFormat中受益。
使用Ruby的此库进行MessageFormat解析和格式化,可以手工制作一个嵌套的MessageFormat来覆盖所有这个字符串的变化,以涵盖任何语言中的嵌套复数规则的复杂性。请记住,大多数语言都不需要这些规则,但有一些语言(如阿拉伯语和俄语)需要许多这些情况;阿拉伯语有特殊的两个情况,俄语有特殊的单数情况(1、21、31、1001,但不包括11)。Unicode CLDR项目的图表列出了所有语言的复数规则,可以在这里找到。
通常情况下,我会指导翻译人员使用这个在线工具(它来自于message-format-rb的同一开发者),并根据其所需语言的需要进行MessageFormat翻译。

MessageFormat for Translators tool

这是一个完整的、最大化的MessageFormat,下面是一个Ruby代码片段:
{review_count, plural, 
=0 {
    {star_count, plural,
        other {no reviews}}
}
zero {
    {star_count, plural,
        zero {{review_count} reviews with {star_count} stars} 
        one {{review_count} review with {star_count} star}
        two {{review_count} reviews with {star_count} stars}
        few {{review_count} reviews with {star_count} stars}
        other {{review_count} reviews with {star_count} stars}}
}
one {
    {star_count, plural,
        zero {{review_count} review with {star_count} stars}
        one {{review_count} review with {star_count} star}
        two {{review_count} review with {star_count} stars}
        few {{review_count} review with {star_count} stars}
        other {{review_count} review with {star_count} stars}}
}
two {
    {star_count, plural,
        zero {{review_count} reviews with {star_count} stars}
        one {{review_count} review with {star_count} star}
        two {{review_count} reviews with {star_count} stars}
        few {{review_count} reviews with {star_count} stars}
        other {{review_count} reviews with {star_count} stars}}
}
 few { 
    {star_count, plural,
         zero {{review_count} reviews with {star_count} stars} 
         one {{review_count} review with {star_count} star}
         two {{review_count} reviews with {star_count} stars}
         few {{review_count} reviews with {star_count} stars}
         other {{review_count} reviews with {star_count} stars}}
}
other {
    {star_count, plural,
        zero {{review_count} reviews with {star_count} stars}
        one {{review_count} review with {star_count} star}
        two {{review_count} reviews with {star_count} stars}
        few {{review_count} reviews with {star_count} stars}
        other {{review_count} reviews with {star_count} stars}}
}
}

和 Ruby 代码片段:

require 'message_format'
require 'test/unit/assertions'
include Test::Unit::Assertions

icumf = "{review_count, plural, =0 {{star_count, plural,other {no reviews}}} zero { {star_count, plural, zero {{review_count} reviews with {star_count} stars} one {{review_count} review with {star_count} star} two {{review_count} reviews with {star_count} stars} few {{review_count} reviews with {star_count} stars} other {{review_count} reviews with {star_count} stars}}}one {{star_count, plural, zero {{review_count} review with {star_count} stars} one {{review_count} review with {star_count} star} two {{review_count} review with {star_count} stars} few {{review_count} review with {star_count} stars} other {{review_count} review with {star_count} stars}}} two {{star_count, plural, zero {{review_count} reviews with {star_count} stars} one {{review_count} review with {star_count} star} two {{review_count} reviews with {star_count} stars} few {{review_count} reviews with {star_count} stars} other {{review_count} reviews with {star_count} stars}}} few {{star_count, plural,zero {{review_count} reviews with {star_count} stars} one {{review_count} review with {star_count} star} two {{review_count} reviews with {star_count} stars} few {{review_count} reviews with {star_count} stars} other {{review_count} reviews with {star_count} stars}}} other {{star_count, plural, zero {{review_count} reviews with {star_count} stars} one {{review_count} review with {star_count} star} two {{review_count} reviews with {star_count} stars} few {{review_count} reviews with {star_count} stars}        other {{review_count} reviews with {star_count} stars}}}}"

# Set the locale to get the plural rules for that locale
message = MessageFormat.new(icumf, 'en')
assert_equal message.format({ :review_count => 0, :star_count => 0 }), 'no reviews'
assert_equal message.format({ :review_count => 0, :star_count => 100 }), 'no reviews'
assert_equal message.format({ :review_count => 1, :star_count => 2 }), '1 review with 2 stars'
assert_equal message.format({ :review_count => 2, :star_count => 5 }), '2 reviews with 5 stars'

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接