Skip to content

Commit

Permalink
feature #31269 [Translator] Dump native plural formats to po files (S…
Browse files Browse the repository at this point in the history
…tadly)

This PR was submitted for the master branch but it was squashed and merged into the 4.4 branch instead (closes #31269).

Discussion
----------

[Translator] Dump native plural formats to po files

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | #29963, #10152
| License       | MIT
| Doc PR        |

Implementing support for dumping to the native po plural format.

```
'foo|foos' => 'bar|bars'
```

Before, the entry above was dumped directly:
```
msgid "foo|foos"
msgstr "bar|bars"
```

With this PR, it is dumped using the native po plural format:
```
msgid "foo"
msgid_plural "foos"
msgstr[0] "bar"
msgstr[1] "bars"
```

Strings using explicit rules or contain more than 2 pluralization forms are still dumped directly, as the po format does not support such cases:

```
'{0} no foos|one foo|%count% foos' => '{0} no bars|one bar|%count% bars'
```

```
msgid "{0} no foos|one foo|%count% foos"
msgstr "{0} no bars|one bar|%count% bars"
```

This PR complements #31266, fixing loading of native po plural formats.

Commits
-------

dc31739 [Translator] Dump native plural formats to po files
  • Loading branch information
fabpot committed Jul 8, 2019
2 parents 3c9ff1f + dc31739 commit e631806
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 3 deletions.
57 changes: 55 additions & 2 deletions src/Symfony/Component/Translation/Dumper/PoFileDumper.php
Expand Up @@ -51,13 +51,66 @@ public function formatCatalogue(MessageCatalogue $messages, $domain, array $opti
$output .= $this->formatComments(implode(' ', (array) $metadata['sources']), ':');
}

$output .= sprintf('msgid "%s"'."\n", $this->escape($source));
$output .= sprintf('msgstr "%s"'."\n", $this->escape($target));
$sourceRules = $this->getStandardRules($source);
$targetRules = $this->getStandardRules($target);
if (2 == \count($sourceRules) && $targetRules !== []) {
$output .= sprintf('msgid "%s"'."\n", $this->escape($sourceRules[0]));
$output .= sprintf('msgid_plural "%s"'."\n", $this->escape($sourceRules[1]));
foreach ($targetRules as $i => $targetRule) {
$output .= sprintf('msgstr[%d] "%s"'."\n", $i, $this->escape($targetRule));
}
} else {
$output .= sprintf('msgid "%s"'."\n", $this->escape($source));
$output .= sprintf('msgstr "%s"'."\n", $this->escape($target));
}
}

return $output;
}

private function getStandardRules(string $id)
{
// Partly copied from TranslatorTrait::trans.
$parts = [];
if (preg_match('/^\|++$/', $id)) {
$parts = explode('|', $id);
} elseif (preg_match_all('/(?:\|\||[^\|])++/', $id, $matches)) {
$parts = $matches[0];
}

$intervalRegexp = <<<'EOF'
/^(?P<interval>
({\s*
(\-?\d+(\.\d+)?[\s*,\s*\-?\d+(\.\d+)?]*)
\s*})
|
(?P<left_delimiter>[\[\]])
\s*
(?P<left>-Inf|\-?\d+(\.\d+)?)
\s*,\s*
(?P<right>\+?Inf|\-?\d+(\.\d+)?)
\s*
(?P<right_delimiter>[\[\]])
)\s*(?P<message>.*?)$/xs
EOF;

$standardRules = [];
foreach ($parts as $part) {
$part = trim(str_replace('||', '|', $part));

if (preg_match($intervalRegexp, $part)) {
// Explicit rule is not a standard rule.
return [];
} else {
$standardRules[] = $part;
}
}

return $standardRules;
}

/**
* {@inheritdoc}
*/
Expand Down
Expand Up @@ -45,4 +45,17 @@ public function testFormatCatalogue()

$this->assertStringEqualsFile(__DIR__.'/../fixtures/resources.po', $dumper->formatCatalogue($catalogue, 'messages'));
}

public function testDumpPlurals()
{
$catalogue = new MessageCatalogue('en');
$catalogue->add([
'foo|foos' => 'bar|bars',
'{0} no foos|one foo|%count% foos' => '{0} no bars|one bar|%count% bars',
]);

$dumper = new PoFileDumper();

$this->assertStringEqualsFile(__DIR__.'/../fixtures/plurals.po', $dumper->formatCatalogue($catalogue, 'messages'));
}
}
Expand Up @@ -34,7 +34,11 @@ public function testLoadPlurals()
$resource = __DIR__.'/../fixtures/plurals.po';
$catalogue = $loader->load($resource, 'en', 'domain1');

$this->assertEquals(['foo' => 'bar', 'foos' => 'bar|bars'], $catalogue->all('domain1'));
$this->assertEquals([
'foo' => 'bar',
'foos' => 'bar|bars',
'{0} no foos|one foo|%count% foos' => '{0} no bars|one bar|%count% bars',
], $catalogue->all('domain1'));
$this->assertEquals('en', $catalogue->getLocale());
$this->assertEquals([new FileResource($resource)], $catalogue->getResources());
}
Expand Down
8 changes: 8 additions & 0 deletions src/Symfony/Component/Translation/Tests/fixtures/plurals.po
@@ -1,5 +1,13 @@
msgid ""
msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: en\n"

msgid "foo"
msgid_plural "foos"
msgstr[0] "bar"
msgstr[1] "bars"

msgid "{0} no foos|one foo|%count% foos"
msgstr "{0} no bars|one bar|%count% bars"

0 comments on commit e631806

Please sign in to comment.