Skip to content

Commit fb6cf3e

Browse files
Allow for missing whitelines.
1 parent 58b9245 commit fb6cf3e

File tree

4 files changed

+81
-17
lines changed

4 files changed

+81
-17
lines changed

src/Symfony/Component/Translation/Dumper/PoFileDumper.php

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,16 @@ public function format(MessageCatalogue $messages, $domain = 'messages')
2727
{
2828
$output = '';
2929

30+
$newLine = FALSE;
3031
foreach ($messages->all($domain) as $source => $target) {
31-
$output .= sprintf("msgid \"%s\"\n", $this->escape($source));
32-
$output .= sprintf("msgstr \"%s\"\n\n", $this->escape($target));
32+
if ($newLine) {
33+
$output .= "\n";
34+
}
35+
else {
36+
$newLine = TRUE;
37+
}
38+
$output .= sprintf('msgid "%s"' . "\n", $this->escape($source));
39+
$output .= sprintf('msgstr "%s"', $this->escape($target));
3340
}
3441

3542
return $output;

src/Symfony/Component/Translation/Loader/PoFileLoader.php

Lines changed: 70 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
/**
1717
* @copyright Copyright (c) 2010, Union of RAD http://union-of-rad.org (http://lithify.me/)
18+
* @copyright Copyright (c) 2012, Clemens Tolboom
1819
*/
1920
class PoFileLoader extends ArrayLoader implements LoaderInterface
2021
{
@@ -41,6 +42,36 @@ public function load($resource, $locale, $domain = 'messages')
4142
/**
4243
* Parses portable object (PO) format.
4344
*
45+
* From http://www.gnu.org/software/gettext/manual/gettext.html#PO-Files
46+
* we should be able to parse files having:
47+
*
48+
* white-space
49+
* # translator-comments
50+
* #. extracted-comments
51+
* #: reference...
52+
* #, flag...
53+
* #| msgid previous-untranslated-string
54+
* msgid untranslated-string
55+
* msgstr translated-string
56+
*
57+
* extra or different lines are:
58+
*
59+
* #| msgctxt previous-context
60+
* #| msgid previous-untranslated-string
61+
* msgctxt context
62+
*
63+
* #| msgid previous-untranslated-string-singular
64+
* #| msgid_plural previous-untranslated-string-plural
65+
* msgid untranslated-string-singular
66+
* msgid_plural untranslated-string-plural
67+
* msgstr[0] translated-string-case-0
68+
* ...
69+
* msgstr[N] translated-string-case-n
70+
*
71+
* The definition states:
72+
* - white-space and comments are optional.
73+
* - msgid "" that an empty singleline defines a header.
74+
*
4475
* This parser sacrifices some features of the reference implementation the
4576
* differences to that implementation are as follows.
4677
* - No support for comments spanning multiple lines.
@@ -69,20 +100,14 @@ private function parse($resource)
69100
$line = trim($line);
70101

71102
if ($line === '') {
72-
if (is_array($item['translated'])) {
73-
$messages[$item['ids']['singular']] = stripslashes($item['translated'][0]);
74-
if (isset($item['ids']['plural'])) {
75-
$plurals = array();
76-
foreach ($item['translated'] as $plural => $translated) {
77-
$plurals[] = sprintf('{%d} %s', $plural, $translated);
78-
}
79-
$messages[$item['ids']['plural']] = stripcslashes(implode('|', $plurals));
80-
}
81-
} elseif(!empty($item['ids']['singular'])) {
82-
$messages[$item['ids']['singular']] = stripslashes($item['translated']);
83-
}
103+
// Whitespace indicated current item is done
104+
$this->addMessage($messages, $item);
84105
$item = $defaults;
85106
} elseif (substr($line, 0, 7) === 'msgid "') {
107+
// We start a new msg so save previous
108+
// TODO: this fails when comments or contexts are added
109+
$this->addMessage($messages, $item);
110+
$item = $defaults;
86111
$item['ids']['singular'] = substr($line, 7, -1);
87112
} elseif (substr($line, 0, 8) === 'msgstr "') {
88113
$item['translated'] = substr($line, 8, -1);
@@ -103,8 +128,41 @@ private function parse($resource)
103128
}
104129

105130
}
131+
// save last item
132+
$this->addMessage($messages, $item);
106133
fclose($stream);
107134

108135
return array_filter($messages);
109136
}
137+
138+
/**
139+
* Save a translation item to the messeages.
140+
*
141+
* A .po file could contain by error missing plural indexes. We need to
142+
* fix these before saving them.
143+
*
144+
* @param array $messages
145+
* @param array $item
146+
*/
147+
private function addMessage(array &$messages, array $item)
148+
{
149+
if (is_array($item['translated'])) {
150+
$messages[$item['ids']['singular']] = stripslashes($item['translated'][0]);
151+
if (isset($item['ids']['plural'])) {
152+
$plurals = $item['translated'];
153+
// PO are by definition indexed so sort by index.
154+
ksort($plurals);
155+
// Make sure every index is filled.
156+
end($plurals);
157+
$count = key($plurals);
158+
// Fill missing spots with '-'.
159+
$empties = array_fill(0, $count+1, '-');
160+
$plurals += $empties;
161+
ksort($plurals);
162+
$messages[$item['ids']['plural']] = stripcslashes(implode('|', $plurals));
163+
}
164+
} elseif(!empty($item['ids']['singular'])) {
165+
$messages[$item['ids']['singular']] = stripslashes($item['translated']);
166+
}
167+
}
110168
}

src/Symfony/Component/Translation/Tests/Loader/PoFileLoaderTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public function testLoadPlurals()
3939
$resource = __DIR__.'/../fixtures/plurals.po';
4040
$catalogue = $loader->load($resource, 'en', 'domain1');
4141

42-
$this->assertEquals(array('foo' => 'bar', 'foos' => '{0} bar|{1} bars'), $catalogue->all('domain1'));
42+
$this->assertEquals(array('foo' => 'bar', 'foos' => 'bar|bars'), $catalogue->all('domain1'));
4343
$this->assertEquals('en', $catalogue->getLocale());
4444
$this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
4545
}
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
msgid "foo"
2-
msgstr "bar"
3-
2+
msgstr "bar"

0 commit comments

Comments
 (0)