【问题标题】:Most elegant way to deal with singles/plurals?处理单/复数最优雅的方式?
【发布时间】:2009-07-21 19:53:10
【问题描述】:

假设您正在制作一个博客软件,并且想要显示一个条目获得的 cmets 数量。你可以这样做:

[Entry title]
[Content........]
[ <?php print($numComments;) ?> Comments]

这可能会导致:

[Entry title]
[Content........]
5 Comments

但如果一个条目只有 1 条评论,我希望该行显示“评论”而不是“评论”。而且内嵌的if/elses 丑陋且重复。

解决这个问题的最佳方法是什么?

【问题讨论】:

  • +1 为您的用户名,因为它告诉我。这很聪明,我很想知道您仅为此获得了多少赞成票。 :)
  • 我很想投反对票只是为了抵消投赞成票的人的影响

标签: code-readability


【解决方案1】:

请使用ngettext 函数处理此类问题。它 允许您正确处理英语和其他语言中的复数 语言,一劳永逸。你可以这样使用它:

printf(ngettext("%d Comment", "%d Comments", $numComments), $numComments);

ngettext 函数将返回第一个格式字符串 ("%d Comment") 如果只有一个注释和第二种格式 字符串 ("%d Comments") 如果还有更多。 printf 函数将 然后将数字放入字符串中。

这可能看起来需要做很多工作,但它非常强大:它有效 对于具有一种以上复数形式(!)的语言——它们 实际存在。 PHP手册给出了“window”这个词的例子 在一些异国情调中变成“1 okno”、“2 okna”和“5 oken” 我不认识的语言...

如果您因此使用ngettext,那么您未来的用户 来自遥远国家的人会非常感谢你:-)

编辑: 正如 cmets 中所建议的,有一个函数可以 执行上述操作:

function pluralize($num, $singleWord, $pluralWord) {
    return printf(ngettext($singleWord, $pluralWord, $num), $num);
}

默认情况下,xgettext 不会识别这个新功能,但你可以 使用--keyword 标志添加它。给定一个文件test.php

echo ngettext("foo", "foos", 1);
echo pluralize(2, "bar", "bars");

你可以提取字符串

xgettext --keyword=pluralize:2,3 test.php 

生成的messages.po 文件包含如下条目:

#: test.php:7
msgid "foo"
msgid_plural "foos"
msgstr[0] ""
msgstr[1] ""

#: test.php:8
msgid "bar"
msgid_plural "bars"
msgstr[0] ""
msgstr[1] ""

译者将填写每个复数形式并正确 在消息目录标题中形成“Plural-Forms”行,您将 能够支持所有语言。

【讨论】:

  • 一直将它与 printf 一起使用会重复,但也许可以编写一个包装函数来执行 printf 和 %d。也许您可以编写此函数的主体并更新您的答案? function pluralize($num,$singleWord,$pluralWord='')
  • @Click Upvote:好主意。我用三个强制参数创建了函数——复数字符串是必需的,这样 xgettext 才能识别函数调用并正确处理它。
【解决方案2】:

为什么不花点时间让事情更加人性化......

switch ($numComments)
{
    case 0:
        echo "Be the first to write a comment";
        break;
    case 1:
        echo "Just one comment so far";
        break;
    default:
        echo "There are $numComments comments";

}

【讨论】:

  • @fishlips:除非一种语言具有三个或更多复数形式。如下所述,ngettext 函数是更通用的解决方案。它允许翻译者在“.po”文件中包含他所有的复数形式,并且在运行时会选择正确的形式。
【解决方案3】:

创建一个函数,它接受一个数字和一个单词,并返回一个包含两者的字符串。当数字大于 1 时,它将附加一个“s”(或查阅您构建的字典)。

【讨论】:

  • 如果数字不是 1,我会让函数添加 s,这样 0 也会得到复数形式。
  • 这样的函数叫什么?
  • 复数似乎是最合适的名字。
  • 可能是传递给这个函数的第三个参数可以是复数词?例如,如果你这样做:pluralize($num,'Comment'); 它会返回“评论”,但如果你这样做:pluralize(($num,'Activity','Activities'); 那么它会返回活动而不是活动
  • 当软件需要本地化时,这可能(并且将会)变得复杂,因为某些语言处理复数/单数的方式与英语不同。
【解决方案4】:

令我惊讶的是,还没有人建议,但我通常做的是使用条件运算符:

string commentWord = numComments != 1 ? "Comments" : "Comment"; 

注意:字符串当然不应该像这样硬编码,而是从某个资源库中加载,其中存储有数字的格式化占位符,以便您可以处理应该出现数字的语言最后(或中间):

// should load "{0} Comments" or "{0} Comment" if we run in an English locale
string comments = string.Format(
        numComments != 1 ? GetResource("Comments") : GetResource("Comment"),
        numComments);

【讨论】:

  • 这不是进行国际化的正确方法。英语以外的语言有自己的复数形式规则;例如立陶宛语有三种不同的形式:“1 komentaras”、“2 komentarai”、“10 komentarų”。 C 程序中流行的 GNU gettext 框架对此有一个解决方案(ngettext 函数)。我不熟悉 Java/C#/PHP,所以我不能说那里的规范正确解决方案是什么。
  • @Marius:感谢您提供的信息。我不知道那些立陶宛规则。我做过一些国际软件(事件为一个大客户做了一个UI文本的翻译软件),但从来没有遇到过这样的需求。很有意思!我不会在这里详细介绍它,我只是想介绍从资源库中获取文本的概念,而不是硬编码。
  • @Fredrik:当我第一次听说有两种以上复数形式的语言时,我也感到非常惊讶……我是丹麦人,习惯了两种形式 :-) 幸运的是,ngettext 函数可以处理它,请在此页面的其他地方查看我的答案。
  • 很多语言都有两种以上的复数形式;例如,IIRC,所有斯拉夫语言都可以(俄语当然可以)。
【解决方案5】:

不是最优雅的,但最容易输出“评论”。

[Entry title]
[Content........]
1 Comment(s)

【讨论】:

  • 正如你所注意到的,这不是很优雅......当我看到这样的输出时,我总是想知道为什么计算机没有花费额外的毫秒来确定“s”是否应该存在或不是:-)
【解决方案6】:

在 C/C++ 中,您可以执行以下操作。你也许可以在 PHP 中做类似的事情。

printf("%d %s\n", numComments, numComments == 1 ? "Comment" : "Comments");

以下方法也有效,但您可能会遇到 \b(退格)在不同实现中被错误处理的问题。

printf("%d Comment%s\n", numComments, numComments == 1 ? " \b" : "s");

使用\0(空字符)不打印任何内容,而是在我的实现中打印一个空格。

【讨论】:

    【解决方案7】:

    查看Rails inflector module。这为这个问题提供了一个很好的、集中的和可配置的解决方案。

    【讨论】:

      猜你喜欢
      • 2015-04-10
      • 2016-07-12
      • 1970-01-01
      • 2013-01-04
      • 1970-01-01
      • 1970-01-01
      • 2010-10-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多