【问题标题】:CakePHP i18n __ function returns arrayCakePHP i18n __ 函数返回数组
【发布时间】:2016-09-11 17:56:25
【问题描述】:

我遇到了__ 函数的问题,我不确定这是否是 Cake (3.2.8)、Aura\Intl 或我的代码中的错误。我在 Cake 1.3 中尝试过同样的事情,并且它按我的预期工作,但我的期望可能就是这样,因为这就是它在 1.3 中的工作方式。 :-)

当我构建菜单时,我使用__('Teams') 之类的东西,但我也有一些页面使用__n('Team', 'Teams', count($player->teams)) 之类的东西。 i18n shell 将这些分别提取到 default.pot 中,所以当我将其翻译成法语时,是这样的:

msgid "Teams"
msgstr "Équipe"

msgid "Team"
msgid_plural "Teams"
msgstr[0] "Équipe"
msgstr[1] "Équipes"

如果我调用__('Team'),我会正确地返回“Équipe”,如果我调用__n('Team', 'Teams', $x),我会正确地返回“Équipe”或“Équipes”,具体取决于$x 的值。但是如果我打电话给__('Teams') 我会回来

Array
(
    [0] => Équipe
    [1] => Équipes
)

即使我去掉msgid "Teams" 部分,只留下复数定义,情况也是如此。

在 Cake 1.3 中,__('Teams') 将简单地返回“Équipes”。 (不知道它在 2.x 中会做什么,因为我完全跳过了。)那么,这是谁的 bug?

【问题讨论】:

  • In Cake 1.3, __('Teams') would simply return 'Équipes'. 假设这是真的,我很惊讶——解析 po 文件的内部逻辑已经重写了好几次,但是下面两个答案中解释的基本机制并没有改变。

标签: cakephp internationalization cakephp-3.0 auraphp


【解决方案1】:

您有两个 Teams 消息 ID。问题是CakePHP消息文件解析器以key => value方式存储消息,其中消息ID用作键,导致msgid_pluralTeams消息覆盖前面的Teams消息msgid.

https://github.com/cakephp/cakephp/blob/3.2.8/src/I18n/Parser/PoFileParser.php#L149 https://github.com/cakephp/cakephp/blob/3.2.8/src/I18n/Parser/PoFileParser.php#L172

https://github.com/cakephp/cakephp/blob/3.2.8/src/I18n/Parser/MoFileParser.php#L137-L140

由于gettext 似乎能够处理这个问题,我想说它至少是一个缺失的功能(这可能是故意的),但它甚至可能是一个错误,我无法确定(但我倾向于错误)。如需澄清,请通过at GitHub 提出问题。

要(临时)解决此问题,您可以使用上下文。

【讨论】:

    【解决方案2】:

    重复的消息定义

    这是有问题的:

    msgid "Teams" <- same string
    msgstr "Équipe"
    
    msgid "Team"
    msgid_plural "Teams" <- same string
    

    第一个表示您在应用程序代码中有或期望有__('Teams'),它期望返回一个字符串。

    第二个场景是在解析 po 文件时会创建不明确的数据。负责将po文件转换为数组格式的类是the PoFileParser,其中包含以下几行:

    $messages[$singular] = $translation; // <- a string
    ...
    $messages[$key] = $plurals; // <- an array
    

    其中$messages 是用于查找翻译的数组,由翻译键索引。

    所以,观察到行为的原因是因为这段代码:

    __('Teams'); 
    

    正在寻找$messages['Teams']

    这段代码:

    __n('Team', 'Teams', 2); 
    

    将查找$messages['Teams'][&lt;index&gt;]$messages 数组将仅包含来自复数翻译的解析数据,它覆盖了文件中早期字符串的“单数”版本。

    代码级解决方案是确保所有 msgid 和 msgid_plural 键都是唯一的(因为它们本质上是相同的)。

    错误的翻译定义

    您很可能在未来的某个时候发现像__('Teams') 这样的翻译非常有问题,这取决于使用松散词的方式,它们表明翻译定义不正确。

    举个例子,CakePHP 曾经在烘焙输出中有这种形式的翻译:

    ...
    sprintf(__('Invalid %s', true), 'Team');
    ...
    

    哪个was later changed to

    __('Invalid Team', true)
    

    因为Invalid %s 的翻译可以根据%s 是什么而改变-%s 的翻译也可以。

    【讨论】:

    • 在我的代码的前一个 (1.3) 版本中确实有“无效的 %s”类型的字符串,但是在新版本中实现了相同的实现并全部替换了它们,所以我没有不要指望遇到你在第二部分讨论的问题。
    • 我可以完全删除独立的“团队”翻译,只保留复数形式,除非我在 __n 函数之外使用它,我会取回数组. :-(
    • 您使用 __('Teams') 的上下文(即它周围的代码)是什么?例如,它是一个菜单项吗?
    • 主要是菜单、面包屑之类的东西。我预计,我的一些模型也会出现同样的情况;该应用程序有 100,000 行代码,所以我不期待通过所有这些来添加上下文...
    • 所有翻译函数都封装在function exists checks中。因此,您可以定义该函数来检查返回值是否为数组,如果是则调用__n 或简单地弹出最后一个值。虽然我认为这样做只会推迟查找和替换__('Teams') 的不可避免的任务__d('menu', 'Teams')__x('menu', 'Teams')- 这很费力但并不复杂或难做。
    猜你喜欢
    • 2015-10-22
    • 1970-01-01
    • 2014-04-26
    • 1970-01-01
    • 2012-06-04
    • 2012-09-26
    • 2012-03-17
    • 2012-08-17
    • 1970-01-01
    相关资源
    最近更新 更多