symfony 翻译系统是否支持要连接的任意长度的元素列表?

Does the symfony translation system support an arbitrary-length list of elements to be concatenated?

我需要在 Symfony 3.4 中翻译可变长度的句子。

例句:"Included: 4 breakfasts, 1 brunch and 3 dinners."

例如,我们假设以下限制条件:

  1. 我必须表达一次旅行在完整行程中可能包含的早餐、早午餐、午餐和晚餐的数量
  2. 要枚举的 "things" 列表是已知且有限的。每个关键词都有单复数翻译。
  3. 并不是所有的人都必须出现。如果有 0 个单元,将省略整个块。
  4. 列表以逗号分隔。
  5. 除了添加了 "and" 连接器的最后一个块。
  6. 如果只有 1 个方块,则没有逗号,也没有 "and" 连接符。
  7. 每个都可以singular/plural.
  8. 有多种语言,在本例中我将使用英语和西班牙语,但实际上也有加泰罗尼亚语。

关键词是英文-单数/英文-复数/西班牙-单数/西班牙-复数:

breakfast / breakfasts / desayuno / desayunos
brunch / brunches / alumerzo-desayuno / almuerzo-desayunos
lunch / lunches / almuerzo / almuerzos
dinner / dinners / cena / cenas

所以...我可以想象以下测试用例:

[
    'language' => 'en-US',
    'parameters' => [
        'breakfast' => 4,
        'dinner' => 1,
    ],
    'expectedOutput' => 'Included: 4 breakfasts and 1 dinner.'
],
[
    'language' => 'es-ES',
    'parameters' => [
        'breakfast' => 2,
        'brunch' => 1,
        'lunch' => 5,
        'dinner' => 2,
    ],
    'expectedOutput' => 'Incluido: 2 desayunos, 1 desayuno-almuerzo, 5 almuerzos y 2 cenas.'
],
[
    'language' => 'en-US',
    'parameters' => [
        'breakfast' => 1,
    ],
    'expectedOutput' => 'Included: 1 breakfast.'
],
[
    'language' => 'es-ES',
    'parameters' => [
        'dinner' => 4,
        'lunch' => 3,
    ],
    'expectedOutput' => 'Incluido: 3 almuerzos y 4 cenas.'
],

问题

翻译引擎在某种程度上可以做的就是用一个数字来切换不同的大小写(for singular/plural)。看看 transChoice for symfony 3.4 (til 4.1.x apparently). Since symfony 4.2, the ICU message format(也可以关注链接)可用于处理复数。

但是,(条件)字符串构建根本不是翻译引擎的真正任务(即使对于简单的情况,transChoice 或 ICU 消息格式可能会很好)。所以你最终可能会从点点滴滴构建字符串。

在 php

中构建字符串
// fetch translations for the itemss
$items = [];
foreach($parameters as $key => $count) {
    if($count <= 0) {
        continue;
    } 

    $items[] = $translator->transChoice($key, $count);
}

// handle 2+ items differently from 1 item
if(count($items) > 1) {
    // get last item
    $last = array_pop($items);
    // comma-separate all other items, add last item with "and"
    $itemstring = implode(', ', $items)
        . $translator->trans('included_and') 
        . $last; 
} else {
    $itemstring = $items[0] ?? ''; // if no items or something like 
                                   // $translator->trans('included_none')
}

return $translator->trans('included', ['%items%' => $itemstring]);

在翻译文件(英文)中:

'included' => 'Included: %items%.',
'included_and' => ' and ',
'breakfast' => '%count% breakfast|%count% breakfasts', // etc. for all other stuff

请注意,transChoice 应该 自动将 %count% 占位符设置为作为 transChoice 第二个参数提供的计数。

替代方法

如果您想避免使用 transChoice,您可以轻松地将可翻译字符串拆分为 breakfast_singularbreakfast_plural,您必须替换

transChoice($key, $count)

trans($key.($count > 1 ? '_plural' : '_singular'), ['%count%' => $count])

您还可以使用适当的参数和条件将 included 字符串扩展为 included_singleincluded_multiple,其中后者被翻译为 'Included: %items% and %last%'

但最终,字符串生成或更具体的语言生成并不是简单翻译引擎的真正工作。