Skip to content
Browse files

feature#8534 [Translation] Added support for JSON format (both loader…

… and dumper). (singles)

This PR was merged into the master branch.

Discussion
----------

[Translation] Added support for JSON format (both loader and dumper).

Based on `IniFileLoader\Dumper`.

Q | A
--- | ---
Bug fix? |no
New feature?	| yes
BC breaks?|	no
Deprecations?	|no
Tests pass?	| yes
Fixed tickets	| -
License	| MIT
Doc | this component don't have docs

Commits
-------

fcef021 [Translation] Added support for JSON format (both loader and dumper).
  • Loading branch information...
2 parents 21bddb8 + fcef021 commit 9988475881d0e857d7c668aeb62b55da990ea32f @fabpot fabpot committed Sep 27, 2013
View
10 src/Symfony/Bundle/FrameworkBundle/Resources/config/translation.xml
@@ -18,6 +18,7 @@
<parameter key="translation.loader.res.class">Symfony\Component\Translation\Loader\IcuResFileLoader</parameter>
<parameter key="translation.loader.dat.class">Symfony\Component\Translation\Loader\IcuDatFileLoader</parameter>
<parameter key="translation.loader.ini.class">Symfony\Component\Translation\Loader\IniFileLoader</parameter>
+ <parameter key="translation.loader.json.class">Symfony\Component\Translation\Loader\JsonFileLoader</parameter>
<parameter key="translation.dumper.php.class">Symfony\Component\Translation\Dumper\PhpFileDumper</parameter>
<parameter key="translation.dumper.xliff.class">Symfony\Component\Translation\Dumper\XliffFileDumper</parameter>
<parameter key="translation.dumper.po.class">Symfony\Component\Translation\Dumper\PoFileDumper</parameter>
@@ -26,6 +27,7 @@
<parameter key="translation.dumper.qt.class">Symfony\Component\Translation\Dumper\QtFileDumper</parameter>
<parameter key="translation.dumper.csv.class">Symfony\Component\Translation\Dumper\CsvFileDumper</parameter>
<parameter key="translation.dumper.ini.class">Symfony\Component\Translation\Dumper\IniFileDumper</parameter>
+ <parameter key="translation.dumper.json.class">Symfony\Component\Translation\Dumper\JsonFileDumper</parameter>
<parameter key="translation.dumper.res.class">Symfony\Component\Translation\Dumper\IcuResFileDumper</parameter>
<parameter key="translation.extractor.php.class">Symfony\Bundle\FrameworkBundle\Translation\PhpExtractor</parameter>
<parameter key="translation.loader.class">Symfony\Bundle\FrameworkBundle\Translation\TranslationLoader</parameter>
@@ -90,6 +92,10 @@
<tag name="translation.loader" alias="ini" />
</service>
+ <service id="translation.loader.json" class="%translation.loader.json.class%">
+ <tag name="translation.loader" alias="json" />
+ </service>
+
<service id="translation.dumper.php" class="%translation.dumper.php.class%">
<tag name="translation.dumper" alias="php" />
</service>
@@ -122,6 +128,10 @@
<tag name="translation.dumper" alias="ini" />
</service>
+ <service id="translation.dumper.json" class="%translation.dumper.json.class%">
+ <tag name="translation.dumper" alias="json" />
+ </service>
+
<service id="translation.dumper.res" class="%translation.dumper.res.class%">
<tag name="translation.dumper" alias="res" />
</service>
View
42 src/Symfony/Component/Translation/Dumper/JsonFileDumper.php
@@ -0,0 +1,42 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Dumper;
+
+use Symfony\Component\Translation\MessageCatalogue;
+
+if (!defined('JSON_PRETTY_PRINT')) {
+ define('JSON_PRETTY_PRINT', 128);
+}
+
+/**
+ * JsonFileDumper generates an json formatted string representation of a message catalogue.
+ *
+ * @author singles
+ */
+class JsonFileDumper extends FileDumper
+{
+ /**
+ * {@inheritDoc}
+ */
+ public function format(MessageCatalogue $messages, $domain = 'messages')
+ {
+ return json_encode($messages->all($domain), JSON_PRETTY_PRINT);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function getExtension()
+ {
+ return 'json';
+ }
+}
View
87 src/Symfony/Component/Translation/Loader/JsonFileLoader.php
@@ -0,0 +1,87 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Loader;
+
+use Symfony\Component\Translation\Exception\InvalidResourceException;
+use Symfony\Component\Translation\Exception\NotFoundResourceException;
+use Symfony\Component\Config\Resource\FileResource;
+
+/**
+ * JsonFileLoader loads translations from an json file.
+ *
+ * @author singles
+ */
+class JsonFileLoader extends ArrayLoader implements LoaderInterface
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function load($resource, $locale, $domain = 'messages')
+ {
+ if (!stream_is_local($resource)) {
+ throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource));
+ }
+
+ if (!file_exists($resource)) {
+ throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource));
+ }
+
+ $messages = json_decode(file_get_contents($resource), true);
+
+ if (($errorCode = json_last_error()) > 0) {
+ $message = $this->getJSONErrorMessage($errorCode);
+ throw new InvalidResourceException(sprintf('Error parsing JSON - %s', $message));
+ }
+
+ if ($messages === null) {
+ $messages = array();
+ }
+
+ $catalogue = parent::load($messages, $locale, $domain);
+ $catalogue->addResource(new FileResource($resource));
+
+ return $catalogue;
+ }
+
+ /**
+ * Translates JSON_ERROR_* constant into meaningful message
+ *
+ * @param integer $errorCode Error code returned by json_last_error() call
+ * @return string Message string
+ */
+ private function getJSONErrorMessage($errorCode)
+ {
+ $errorMsg = null;
+ switch ($errorCode) {
+ case JSON_ERROR_DEPTH:
+ $errorMsg = 'Maximum stack depth exceeded';
+ break;
+ case JSON_ERROR_STATE_MISMATCH:
+ $errorMsg = 'Underflow or the modes mismatch';
+ break;
+ case JSON_ERROR_CTRL_CHAR:
+ $errorMsg = 'Unexpected control character found';
+ break;
+ case JSON_ERROR_SYNTAX:
+ $errorMsg = 'Syntax error, malformed JSON';
+ break;
+ case JSON_ERROR_UTF8:
+ $errorMsg = 'Malformed UTF-8 characters, possibly incorrectly encoded';
+ break;
+ default:
+ $errorMsg = 'Unknown error';
+ break;
+ }
+
+ return $errorMsg;
+ }
+}
View
36 src/Symfony/Component/Translation/Tests/Dumper/JsonFileDumperTest.php
@@ -0,0 +1,36 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Tests\Dumper;
+
+use Symfony\Component\Translation\MessageCatalogue;
+use Symfony\Component\Translation\Dumper\JsonFileDumper;
+
+class JsonFileDumperTest extends \PHPUnit_Framework_TestCase
+{
+ public function testDump()
+ {
+ if (version_compare(PHP_VERSION, '5.4.0', '<')) {
+ $this->markTestIncomplete('PHP below 5.4 doesn\'t support JSON pretty printing');
+ }
+
+ $catalogue = new MessageCatalogue('en');
+ $catalogue->add(array('foo' => 'bar'));
+
+ $tempDir = sys_get_temp_dir();
+ $dumper = new JsonFileDumper();
+ $dumper->dump($catalogue, array('path' => $tempDir));
+
+ $this->assertEquals(file_get_contents(__DIR__.'/../fixtures/resources.json'), file_get_contents($tempDir.'/messages.en.json'));
+
+ unlink($tempDir.'/messages.en.json');
+ }
+}
View
68 src/Symfony/Component/Translation/Tests/Loader/JsonFileLoaderTest.php
@@ -0,0 +1,68 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Tests\Loader;
+
+use Symfony\Component\Translation\Loader\JsonFileLoader;
+use Symfony\Component\Config\Resource\FileResource;
+
+class JsonFileLoaderTest extends \PHPUnit_Framework_TestCase
+{
+ protected function setUp()
+ {
+ if (!class_exists('Symfony\Component\Config\Loader\Loader')) {
+ $this->markTestSkipped('The "Config" component is not available');
+ }
+ }
+
+ public function testLoad()
+ {
+ $loader = new JsonFileLoader();
+ $resource = __DIR__.'/../fixtures/resources.json';
+ $catalogue = $loader->load($resource, 'en', 'domain1');
+
+ $this->assertEquals(array('foo' => 'bar'), $catalogue->all('domain1'));
+ $this->assertEquals('en', $catalogue->getLocale());
+ $this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
+ }
+
+ public function testLoadDoesNothingIfEmpty()
+ {
+ $loader = new JsonFileLoader();
+ $resource = __DIR__.'/../fixtures/empty.json';
+ $catalogue = $loader->load($resource, 'en', 'domain1');
+
+ $this->assertEquals(array(), $catalogue->all('domain1'));
+ $this->assertEquals('en', $catalogue->getLocale());
+ $this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Translation\Exception\NotFoundResourceException
+ */
+ public function testLoadNonExistingResource()
+ {
+ $loader = new JsonFileLoader();
+ $resource = __DIR__.'/../fixtures/non-existing.json';
+ $loader->load($resource, 'en', 'domain1');
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Translation\Exception\InvalidResourceException
+ * @expectedExceptionMessage Error parsing JSON - Syntax error, malformed JSON
+ */
+ public function testParseException()
+ {
+ $loader = new JsonFileLoader();
+ $resource = __DIR__.'/../fixtures/malformed.json';
+ $loader->load($resource, 'en', 'domain1');
+ }
+}
View
1 src/Symfony/Component/Translation/Tests/TranslatorTest.php
@@ -199,6 +199,7 @@ public function getTransFileTests()
array('ts', 'QtFileLoader'),
array('xlf', 'XliffFileLoader'),
array('yml', 'YamlFileLoader'),
+ array('json', 'JsonFileLoader'),
);
}
View
0 src/Symfony/Component/Translation/Tests/fixtures/empty.json
No changes.
View
3 src/Symfony/Component/Translation/Tests/fixtures/malformed.json
@@ -0,0 +1,3 @@
+{
+ "foo": "bar" "
+}
View
3 src/Symfony/Component/Translation/Tests/fixtures/resources.json
@@ -0,0 +1,3 @@
+{
+ "foo": "bar"
+}

0 comments on commit 9988475

Please sign in to comment.
Something went wrong with that request. Please try again.