├── Changelog.md ├── LICENSE ├── Readme.md ├── composer.json ├── src ├── Command │ └── ConvertCommand.php ├── Loader │ └── TranslationLoader.php ├── Reader │ └── JmsReader.php ├── Service │ └── Converter.php └── translation-converter └── tests ├── Fixtures ├── admin.en.yml ├── messages.en.xlf └── xliff.en.xliff └── Functional └── Service └── ConverterTest.php /Changelog.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | The change log describes what is "Added", "Removed", "Changed" or "Fixed" between each release. 4 | 5 | ## 0.1.0 6 | 7 | Init release 8 | 9 | 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) PHP Translation team 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # Convert your translation files 2 | 3 | [![Latest Version](https://img.shields.io/github/release/php-translation/converter.svg?style=flat-square)](https://github.com/php-translation/converter/releases) 4 | [![Build Status](https://img.shields.io/travis/php-translation/converter.svg?style=flat-square)](https://travis-ci.org/php-translation/converter) 5 | [![Code Coverage](https://img.shields.io/scrutinizer/coverage/g/php-translation/converter.svg?style=flat-square)](https://scrutinizer-ci.com/g/php-translation/converter) 6 | [![Quality Score](https://img.shields.io/scrutinizer/g/php-translation/converter.svg?style=flat-square)](https://scrutinizer-ci.com/g/php-translation/converter) 7 | [![Total Downloads](https://img.shields.io/packagist/dt/php-translation/converter.svg?style=flat-square)](https://packagist.org/packages/php-translation/converter) 8 | 9 | **Don't you hate all the different translations formats? Are you stuck with JMSTranslatorBundle? If so, this is the 10 | tool for you!** 11 | 12 | This little tool can convert your translation files from one format to the excellent XLIFF 2.0. A perfect use case is 13 | when you migrating from JMSTranslatorBundle to [PHP-translation](http://php-translation.readthedocs.io/). 14 | 15 | ### Install 16 | 17 | ```bash 18 | composer require php-translation/converter 19 | ``` 20 | 21 | ### Use 22 | 23 | Just run the command like below: 24 | 25 | ```bash 26 | # Example 27 | ./vendor/bin/translation-converter translation:convert [input_dir] [output_dir] [format] 28 | 29 | # Convert from JMSTranslationBundle 30 | ./vendor/bin/translation-converter translation:convert app/Resources/translations app/Resources/translations-new --format=jms 31 | 32 | # Convert from Yaml 33 | ./vendor/bin/translation-converter translation:convert app/Resources/translations app/Resources/translations-new --format=yml 34 | ``` 35 | 36 | ### Documentation 37 | 38 | Read our documentation at [http://php-translation.readthedocs.io](http://php-translation.readthedocs.io/en/latest/). 39 | 40 | ### Contribute 41 | 42 | Do you want to make a change? Pull requests are welcome. 43 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "php-translation/converter", 3 | "description": "Converts your translation files to Xliff", 4 | "license": "MIT", 5 | "authors": [ 6 | { 7 | "name": "Tobias Nyholm", 8 | "email": "tobias.nyholm@gmail.com" 9 | } 10 | ], 11 | "require": { 12 | "php": "^5.5 || ^7.0", 13 | "php-translation/symfony-storage": "^1.0.1", 14 | "symfony/console": "^2.7 || ^3.0 || ^4.0", 15 | "symfony/yaml": "^2.7 || ^3.0 || ^4.0", 16 | "symfony/finder": "^2.7 || ^3.0 || ^4.0", 17 | "symfony/config": "^2.7 || ^3.0 || ^4.0" 18 | }, 19 | "require-dev": { 20 | "symfony/phpunit-bridge": "^4.0", 21 | "php-translation/symfony-bundle": "^0.8" 22 | }, 23 | "autoload": { 24 | "psr-4": { 25 | "Translation\\Converter\\": "src/" 26 | } 27 | }, 28 | "autoload-dev": { 29 | "psr-4": { 30 | "Translation\\Converter\\Tests\\": "tests/" 31 | } 32 | }, 33 | "scripts": { 34 | "test": "vendor/bin/simple-phpunit", 35 | "test-ci": "vendor/bin/simple-phpunit --coverage-text --coverage-clover=build/coverage.xml" 36 | }, 37 | "bin": [ 38 | "src/translation-converter" 39 | ], 40 | "extra": { 41 | "branch-alias": { 42 | "dev-master": "1.0-dev" 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Command/ConvertCommand.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Translation\Converter\Command; 13 | 14 | use Symfony\Component\Console\Command\Command; 15 | use Symfony\Component\Console\Input\InputArgument; 16 | use Symfony\Component\Console\Input\InputInterface; 17 | use Symfony\Component\Console\Input\InputOption; 18 | use Symfony\Component\Console\Output\OutputInterface; 19 | use Symfony\Component\Translation\Loader; 20 | use Translation\Converter\Reader\JmsReader; 21 | use Translation\Converter\Service\Converter; 22 | 23 | /** 24 | * @author Tobias Nyholm 25 | */ 26 | class ConvertCommand extends Command 27 | { 28 | const SUPPORTED_FORMATS = ['jms', 'csv', 'ini', 'json', 'mo', 'php', 'yml', 'xlf']; 29 | 30 | protected function configure() 31 | { 32 | $this 33 | ->setName('translation:convert') 34 | ->setDescription('Convert your existing translation files to Xliff') 35 | ->addArgument('input_dir', InputArgument::REQUIRED, 'Where are your existing translations?') 36 | ->addArgument('output_dir', InputArgument::REQUIRED, 'Where should we put the new translations?') 37 | ->addOption('format', null, InputOption::VALUE_REQUIRED, 'The format to convert from. Supported formats are: '.implode(', ', self::SUPPORTED_FORMATS)) 38 | ; 39 | } 40 | 41 | protected function execute(InputInterface $input, OutputInterface $output) 42 | { 43 | $files = scandir($input->getArgument('input_dir')); 44 | 45 | $formats = []; 46 | $locales = []; 47 | foreach ($files as $file) { 48 | if (preg_match('|.+\.(.+)\.(.+)|', $file, $matches)) { 49 | $locales[] = $matches[1]; 50 | $formats[] = $matches[2]; 51 | } 52 | } 53 | 54 | if (null === $format = $input->getOption('format')) { 55 | $formats = array_unique($formats); 56 | if (1 !== count($formats)) { 57 | throw new \InvalidArgumentException('More than one format found. Please specify a format with --format=xxx'); 58 | } 59 | $format = reset($formats); 60 | } 61 | 62 | $reader = $this->getReader($format); 63 | $converter = new Converter($reader, 'jms' === $format ? ['xlf', 'xliff'] : $format); 64 | $converter->convert($input->getArgument('input_dir'), $input->getArgument('output_dir'), array_unique($locales)); 65 | } 66 | 67 | /** 68 | * @param string $format 69 | * 70 | * @return Loader\LoaderInterface 71 | */ 72 | private function getReader($format) 73 | { 74 | switch ($format) { 75 | case 'jms': 76 | return new JmsReader(); 77 | case 'csv': 78 | return new Loader\CsvFileLoader(); 79 | case 'ini': 80 | return new Loader\IniFileLoader(); 81 | case 'json': 82 | return new Loader\JsonFileLoader(); 83 | case 'mo': 84 | return new Loader\MoFileLoader(); 85 | case 'php': 86 | return new Loader\PhpFileLoader(); 87 | case 'yml': 88 | case 'yaml': 89 | return new Loader\YamlFileLoader(); 90 | case 'xlf': 91 | case 'xliff': 92 | return new Loader\XliffFileLoader(); 93 | default: 94 | throw new \InvalidArgumentException(sprintf('Format "%s" is not a valid format', $format)); 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/Loader/TranslationLoader.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Translation\Converter\Loader; 13 | 14 | use Symfony\Component\Finder\Finder; 15 | use Symfony\Component\Translation\Loader\LoaderInterface; 16 | use Symfony\Component\Translation\MessageCatalogue; 17 | use Translation\SymfonyStorage\TranslationLoader as TranslationLoaderInterface; 18 | 19 | class TranslationLoader implements TranslationLoaderInterface 20 | { 21 | /** 22 | * @var LoaderInterface 23 | */ 24 | private $loader; 25 | 26 | /** 27 | * @var string 28 | */ 29 | private $format; 30 | 31 | /** 32 | * @param LoaderInterface $loader 33 | * @param string|string[] $format 34 | */ 35 | public function __construct(LoaderInterface $loader, $format) 36 | { 37 | $this->loader = $loader; 38 | $this->format = $format; 39 | } 40 | 41 | /** 42 | * Loads translation messages from a directory to the catalogue. 43 | * 44 | * @param string $directory the directory to look into 45 | * @param MessageCatalogue $catalogue the catalogue 46 | * 47 | * @deprecated Use read instead. 48 | */ 49 | public function loadMessages($directory, MessageCatalogue $catalogue) 50 | { 51 | return $this->read($directory, $catalogue); 52 | } 53 | 54 | /** 55 | * Loads translation messages from a directory to the catalogue. 56 | * 57 | * @param string $directory the directory to look into 58 | * @param MessageCatalogue $catalogue the catalogue 59 | */ 60 | public function read($directory, MessageCatalogue $catalogue) 61 | { 62 | if (!is_dir($directory)) { 63 | return; 64 | } 65 | 66 | // load any existing translation files 67 | $patterns = $this->getTranslationFilePatterns($catalogue); 68 | $files = $this->getTranslationFiles($directory, $patterns); 69 | foreach ($files as $file) { 70 | $domain = $this->getDomainFromFilename($file->getFilename(), $patterns); 71 | $catalogue->addCatalogue($this->loader->load($file->getPathname(), $catalogue->getLocale(), $domain)); 72 | } 73 | } 74 | 75 | protected function getTranslationFiles($directory, $patterns) 76 | { 77 | $finder = new Finder(); 78 | foreach ($patterns as $pattern) { 79 | $finder->name($pattern); 80 | } 81 | 82 | return $finder 83 | ->files() 84 | ->in($directory); 85 | } 86 | 87 | protected function getDomainFromFilename($filename, $patterns) 88 | { 89 | foreach ($patterns as $pattern) { 90 | $extension = str_replace('*.', '', $pattern); 91 | $length = strlen($extension); 92 | if (substr($filename, -$length) === $extension) { 93 | return substr($filename, 0, -1 * $length - 1); 94 | } 95 | } 96 | 97 | return $filename; 98 | } 99 | 100 | protected function getTranslationFilePatterns(MessageCatalogue $catalogue) 101 | { 102 | if ($this->format && !is_array($this->format)) { 103 | $this->format = [$this->format]; 104 | } 105 | 106 | $patterns = []; 107 | foreach ($this->format as $ext) { 108 | $patterns[] = sprintf('*.%s.%s', $catalogue->getLocale(), $ext); 109 | } 110 | 111 | return $patterns; 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/Reader/JmsReader.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Translation\Converter\Reader; 13 | 14 | use Symfony\Component\Config\Resource\FileResource; 15 | use Symfony\Component\Translation\Loader\LoaderInterface; 16 | use Symfony\Component\Translation\MessageCatalogue; 17 | 18 | class JmsReader implements LoaderInterface 19 | { 20 | /** 21 | * @param mixed $resource 22 | * @param string $locale 23 | * @param string $domain 24 | * 25 | * @return MessageCatalogue 26 | */ 27 | public function load($resource, $locale, $domain = 'messages') 28 | { 29 | $previous = libxml_use_internal_errors(true); 30 | if (false === $doc = simplexml_load_file($resource)) { 31 | libxml_use_internal_errors($previous); 32 | $libxmlError = libxml_get_last_error(); 33 | 34 | throw new \RuntimeException(sprintf('Could not load XML-file "%s": %s', $resource, $libxmlError->message)); 35 | } 36 | 37 | libxml_use_internal_errors($previous); 38 | 39 | $doc->registerXPathNamespace('xliff', 'urn:oasis:names:tc:xliff:document:1.2'); 40 | $doc->registerXPathNamespace('jms', 'urn:jms:translation'); 41 | 42 | $hasReferenceFiles = in_array('urn:jms:translation', $doc->getNamespaces(true)); 43 | 44 | $catalogue = new MessageCatalogue($locale); 45 | $catalogue->addResource(new FileResource($resource)); 46 | 47 | /** @var \SimpleXMLElement $trans */ 48 | foreach ($doc->xpath('//xliff:trans-unit') as $trans) { 49 | $id = ($resName = (string) $trans->attributes()->resname) 50 | ? $resName : (string) $trans->source; 51 | 52 | if (empty($id)) { 53 | continue; 54 | } 55 | 56 | $meta = []; 57 | if ($hasReferenceFiles) { 58 | foreach ($trans->xpath('./jms:reference-file') as $file) { 59 | $line = (string) $file->attributes()->line; 60 | 61 | $meta['notes'][] = ['category' => 'file-source', 'content' => sprintf('%s:%s', (string) $file, $line ? (int) $line : 0)]; 62 | } 63 | } 64 | 65 | if ($meaning = (string) $trans->attributes()->extradata) { 66 | if (0 === strpos($meaning, 'Meaning: ')) { 67 | $meaning = substr($meaning, 9); 68 | } 69 | 70 | $meta['notes'][] = ['category' => 'meaning', 'content' => $meaning]; 71 | } 72 | if ($approved = (string) $trans->attributes()->approved) { 73 | $text = (string) $approved; 74 | $meta['notes'][] = ['category' => 'approved', 'content' => 'yes' == $text || 'true' == $text ? 'true' : 'false']; 75 | } 76 | 77 | foreach ($trans->target->attributes() as $name => $value) { 78 | if ('state' === $name) { 79 | $meta['notes'][] = ['category' => 'state', 'content' => (string) $value]; 80 | } 81 | } 82 | 83 | $catalogue->set($id, $trans->target, $domain); 84 | $catalogue->setMetadata($id, $meta, $domain); 85 | } 86 | 87 | return $catalogue; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/Service/Converter.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Translation\Converter\Service; 13 | 14 | use Symfony\Component\Config\Resource\FileResource; 15 | use Symfony\Component\Translation\Loader\LoaderInterface; 16 | use Symfony\Component\Translation\MessageCatalogue; 17 | use Symfony\Component\Translation\Writer\TranslationWriter; 18 | use Translation\Converter\Loader\TranslationLoader; 19 | use Translation\SymfonyStorage\Dumper\XliffDumper; 20 | use Translation\SymfonyStorage\FileStorage; 21 | 22 | /** 23 | * Convert any translation format to XLF. 24 | * 25 | * @author Tobias Nyholm 26 | */ 27 | class Converter 28 | { 29 | /** 30 | * @var \Translation\SymfonyStorage\TranslationLoader 31 | */ 32 | private $reader; 33 | 34 | /** 35 | * @var TranslationWriter 36 | */ 37 | private $writer; 38 | 39 | /** 40 | * @param LoaderInterface $reader 41 | * @param string|string[] $format 42 | */ 43 | public function __construct(LoaderInterface $reader, $format) 44 | { 45 | $this->reader = new TranslationLoader($reader, $format); 46 | $this->writer = new TranslationWriter(); 47 | $this->writer->disableBackup(); 48 | $this->writer->addDumper('xlf', new XliffDumper()); 49 | } 50 | 51 | /** 52 | * @param string $inputDir 53 | * @param string $outputDir 54 | * @param array $locales 55 | */ 56 | public function convert($inputDir, $outputDir, array $locales) 57 | { 58 | $inputDir = realpath($inputDir); 59 | if (false === realpath($outputDir) && false === mkdir($outputDir)) { 60 | throw new \Exception('Unable to create output directory.'.$outputDir); 61 | } 62 | $outputDir = realpath($outputDir); 63 | 64 | $inputStorage = new FileStorage($this->writer, $this->reader, [$inputDir]); 65 | $outputStorage = new FileStorage($this->writer, $this->reader, [$outputDir], ['xliff_version' => '2.0']); 66 | foreach ($locales as $locale) { 67 | $inputCatalogue = new MessageCatalogue($locale); 68 | $outputCatalogue = new MessageCatalogue($locale); 69 | 70 | $inputStorage->export($inputCatalogue); 71 | foreach ($inputCatalogue->all() as $domain => $messages) { 72 | $outputCatalogue->add($messages, $domain); 73 | foreach ($messages as $id => $message) { 74 | $outputCatalogue->setMetadata($id, $inputCatalogue->getMetadata($id, $domain), $domain); 75 | } 76 | } 77 | 78 | // rewrite the resources to new path. 79 | /** @var FileResource $resource */ 80 | foreach ($inputCatalogue->getResources() as $resource) { 81 | $path = str_replace($inputDir, $outputDir, $resource->getResource()); 82 | 83 | // rewrite $path extension to be xlf 84 | $path = substr($path, 0, strrpos($path, '.')).'.xlf'; 85 | 86 | // Make sure file exists 87 | file_put_contents($path, ''); 88 | 89 | $outputCatalogue->addResource(new FileResource($path)); 90 | } 91 | 92 | $outputStorage->import($outputCatalogue); 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/translation-converter: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | // This sucks.. we have to try to find the composer autoloader. But chances 14 | // are, we can't find it this way. So we'll do our bestest 15 | $paths = array( 16 | __DIR__ . '/../vendor/autoload.php', 17 | __DIR__ . '/../../../autoload.php', 18 | ); 19 | 20 | foreach($paths as $path) { 21 | if (file_exists($path)) { 22 | include $path; 23 | break; 24 | } 25 | } 26 | 27 | use Symfony\Component\Console\Application; 28 | 29 | $application = new Application(); 30 | 31 | $application->add(new \Translation\Converter\Command\ConvertCommand()); 32 | 33 | $application->run(); 34 | -------------------------------------------------------------------------------- /tests/Fixtures/admin.en.yml: -------------------------------------------------------------------------------- 1 | en: 2 | symbol: 3 | anonymous: "Business" 4 | bacon: 5 | one: "1 bacon" 6 | other: "%count% bacons" 7 | -------------------------------------------------------------------------------- /tests/Fixtures/messages.en.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 | The source node in most cases contains the sample message as written by the developer. If it looks like a dot-delimitted string such as "form.label.firstname", then the developer has not provided a default message. 7 |
8 | 9 | 10 | key0 11 | trans0 12 | 13 | 14 | Tests/Translation/XliffMessageUpdaterTest.php 15 | This is a bar. 16 | This is a bar. 17 | 18 | 19 | key1 20 | trans1 21 | 22 | 23 | foo.bar.baz 24 | foo.bar.baz 25 | /a/b/c/foo/bar 26 | /z/order/test 27 | bar/baz 28 | 29 | 30 | same.as.trans 31 | same.as.trans 32 | 33 | 34 |
35 |
36 | -------------------------------------------------------------------------------- /tests/Fixtures/xliff.en.xliff: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 | The source node in most cases contains the sample message as written by the developer. If it looks like a dot-delimitted string such as "form.label.firstname", then the developer has not provided a default message. 7 |
8 | 9 | 10 | key0 11 | trans0 12 | 13 | 14 | Tests/Translation/XliffMessageUpdaterTest.php 15 | This is a bar. 16 | This is a bar. 17 | 18 | 19 | key1 20 | trans1 21 | 22 | 23 | foo.bar.baz 24 | foo.bar.baz 25 | /a/b/c/foo/bar 26 | /z/order/test 27 | bar/baz 28 | 29 | 30 | same.as.trans 31 | same.as.trans 32 | 33 | 34 |
35 |
36 | -------------------------------------------------------------------------------- /tests/Functional/Service/ConverterTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Translation\Converter\Tests\Functional\Service; 13 | 14 | use PHPUnit\Framework\TestCase; 15 | use Translation\Bundle\Model\Metadata; 16 | use Translation\Converter\Reader\JmsReader; 17 | use Translation\Converter\Service\Converter; 18 | use Translation\SymfonyStorage\Loader\XliffLoader; 19 | use Symfony\Component\Translation\Loader; 20 | 21 | class ConverterTest extends TestCase 22 | { 23 | protected static $fixturesDir; 24 | 25 | protected static $outputDir; 26 | 27 | public static function setUpBeforeClass() 28 | { 29 | self::$outputDir = sys_get_temp_dir().'/translation_converter_output'; 30 | self::$fixturesDir = __DIR__.'/../../Fixtures'; 31 | parent::setUpBeforeClass(); 32 | } 33 | 34 | protected function setUp() 35 | { 36 | @mkdir(self::$outputDir, 0777, true); 37 | $files = glob(self::$outputDir.'/*'); 38 | foreach ($files as $file) { 39 | if (is_file($file)) { 40 | unlink($file); 41 | } 42 | } 43 | } 44 | 45 | public function testConvertJMS() 46 | { 47 | $reader = new JmsReader(); 48 | $converter = new Converter($reader, ['xlf', 'xliff']); 49 | $converter->convert(self::$fixturesDir, self::$outputDir, ['en']); 50 | 51 | $catalogue = (new XliffLoader())->load(self::$outputDir.'/messages.en.xlf', 'en'); 52 | $this->assertEquals('This is a bar.', $catalogue->get('bar')); 53 | $meta = new Metadata($catalogue->getMetadata('bar')); 54 | $this->assertTrue($meta->isApproved()); 55 | $this->assertEquals('new', $meta->getState()); 56 | $this->assertEquals('Tests/Translation/XliffMessageUpdaterTest.php', $meta->getSourceLocations()[0]['path']); 57 | 58 | $catalogue = (new XliffLoader())->load(self::$outputDir.'/xliff.en.xlf', 'en'); 59 | $this->assertEquals('This is a bar.', $catalogue->get('bar')); 60 | $meta = new Metadata($catalogue->getMetadata('bar')); 61 | $this->assertTrue($meta->isApproved()); 62 | $this->assertEquals('new', $meta->getState()); 63 | $this->assertEquals('Tests/Translation/XliffMessageUpdaterTest.php', $meta->getSourceLocations()[0]['path']); 64 | } 65 | 66 | public function testConvertYaml() 67 | { 68 | $reader = new Loader\YamlFileLoader(); 69 | $converter = new Converter($reader, 'yml'); 70 | $converter->convert(self::$fixturesDir, self::$outputDir, ['en']); 71 | 72 | $catalogue = (new XliffLoader())->load(self::$outputDir.'/admin.en.xlf', 'en'); 73 | $this->assertEquals('Business', $catalogue->get('en.symbol.anonymous')); 74 | } 75 | } 76 | --------------------------------------------------------------------------------