mirror of
https://github.com/alchemy-fr/Phraseanet.git
synced 2025-10-12 12:33:26 +00:00
Add cached translation loader
This commit is contained in:
@@ -110,8 +110,8 @@ use Alchemy\Phrasea\Exception\InvalidArgumentException;
|
|||||||
use Alchemy\Phrasea\Twig\JSUniqueID;
|
use Alchemy\Phrasea\Twig\JSUniqueID;
|
||||||
use Alchemy\Phrasea\Twig\Camelize;
|
use Alchemy\Phrasea\Twig\Camelize;
|
||||||
use Alchemy\Phrasea\Twig\BytesConverter;
|
use Alchemy\Phrasea\Twig\BytesConverter;
|
||||||
|
use Alchemy\Phrasea\Utilities\CachedTranslator;
|
||||||
use FFMpeg\FFMpegServiceProvider;
|
use FFMpeg\FFMpegServiceProvider;
|
||||||
use JMS\TranslationBundle\Translation\Loader\Symfony\XliffLoader;
|
|
||||||
use Neutron\Silex\Provider\ImagineServiceProvider;
|
use Neutron\Silex\Provider\ImagineServiceProvider;
|
||||||
use MediaVorus\MediaVorusServiceProvider;
|
use MediaVorus\MediaVorusServiceProvider;
|
||||||
use MediaVorus\Utils\RawImageMimeTypeGuesser;
|
use MediaVorus\Utils\RawImageMimeTypeGuesser;
|
||||||
@@ -130,7 +130,7 @@ use Silex\Application\TranslationTrait;
|
|||||||
use Silex\Provider\FormServiceProvider;
|
use Silex\Provider\FormServiceProvider;
|
||||||
use Silex\Provider\MonologServiceProvider;
|
use Silex\Provider\MonologServiceProvider;
|
||||||
use Silex\Provider\SessionServiceProvider;
|
use Silex\Provider\SessionServiceProvider;
|
||||||
use Silex\Provider\TranslationServiceProvider;
|
use Alchemy\Phrasea\Core\Provider\TranslationServiceProvider;
|
||||||
use Silex\Provider\TwigServiceProvider;
|
use Silex\Provider\TwigServiceProvider;
|
||||||
use Silex\Provider\SwiftmailerServiceProvider;
|
use Silex\Provider\SwiftmailerServiceProvider;
|
||||||
use Silex\Provider\UrlGeneratorServiceProvider;
|
use Silex\Provider\UrlGeneratorServiceProvider;
|
||||||
@@ -138,8 +138,6 @@ use Silex\Provider\ValidatorServiceProvider;
|
|||||||
use Silex\Provider\ServiceControllerServiceProvider;
|
use Silex\Provider\ServiceControllerServiceProvider;
|
||||||
use Symfony\Bridge\Twig\Extension\TranslationExtension;
|
use Symfony\Bridge\Twig\Extension\TranslationExtension;
|
||||||
use Symfony\Component\Translation\Loader\MoFileLoader;
|
use Symfony\Component\Translation\Loader\MoFileLoader;
|
||||||
use Symfony\Component\Translation\Loader\PoFileLoader;
|
|
||||||
use Symfony\Component\Translation\Translator;
|
|
||||||
use Unoconv\UnoconvServiceProvider;
|
use Unoconv\UnoconvServiceProvider;
|
||||||
use XPDF\PdfToText;
|
use XPDF\PdfToText;
|
||||||
use XPDF\XPDFServiceProvider;
|
use XPDF\XPDFServiceProvider;
|
||||||
@@ -311,18 +309,21 @@ class Application extends SilexApplication
|
|||||||
|
|
||||||
$this->register(new TranslationServiceProvider(), [
|
$this->register(new TranslationServiceProvider(), [
|
||||||
'locale_fallbacks' => ['fr'],
|
'locale_fallbacks' => ['fr'],
|
||||||
|
'translator.cache-options' => [
|
||||||
|
'debug' => $this['debug'],
|
||||||
|
'cache_dir' => $this['root.path'].'/tmp/translations'
|
||||||
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this['translator'] = $this->share($this->extend('translator', function(Translator $translator, $app) {
|
$this['translator'] = $this->share($this->extend('translator', function(CachedTranslator $translator, $app) {
|
||||||
$translator->addLoader('xliff', new XliffLoader());
|
$translator->addResource('xliff', __DIR__.'/../../../resources/locales/messages.fr.xliff', 'fr', 'messages');
|
||||||
$translator->addResource('xliff', __DIR__.'/../../../resources/locales/messages.fr.xliff', 'fr', 'messages');
|
$translator->addResource('xliff', __DIR__.'/../../../resources/locales/validators.fr.xliff', 'fr', 'validators');
|
||||||
$translator->addResource('xliff', __DIR__.'/../../../resources/locales/validators.fr.xliff', 'fr', 'validators');
|
$translator->addResource('xliff', __DIR__.'/../../../resources/locales/messages.en.xliff', 'en', 'messages');
|
||||||
$translator->addResource('xliff', __DIR__.'/../../../resources/locales/messages.en.xliff', 'en', 'messages');
|
$translator->addResource('xliff', __DIR__.'/../../../resources/locales/validators.en.xliff', 'en', 'validators');
|
||||||
$translator->addResource('xliff', __DIR__.'/../../../resources/locales/validators.en.xliff', 'en', 'validators');
|
$translator->addResource('xliff', __DIR__.'/../../../resources/locales/messages.de.xliff', 'de', 'messages');
|
||||||
$translator->addResource('xliff', __DIR__.'/../../../resources/locales/messages.de.xliff', 'de', 'messages');
|
$translator->addResource('xliff', __DIR__.'/../../../resources/locales/validators.de.xliff', 'de', 'validators');
|
||||||
$translator->addResource('xliff', __DIR__.'/../../../resources/locales/validators.de.xliff', 'de', 'validators');
|
$translator->addResource('xliff', __DIR__.'/../../../resources/locales/messages.nl.xliff', 'nl', 'messages');
|
||||||
$translator->addResource('xliff', __DIR__.'/../../../resources/locales/messages.nl.xliff', 'nl', 'messages');
|
$translator->addResource('xliff', __DIR__.'/../../../resources/locales/validators.nl.xliff', 'nl', 'validators');
|
||||||
$translator->addResource('xliff', __DIR__.'/../../../resources/locales/validators.nl.xliff', 'nl', 'validators');
|
|
||||||
|
|
||||||
return $translator;
|
return $translator;
|
||||||
}));
|
}));
|
||||||
|
@@ -53,6 +53,7 @@ class Uninstaller extends Command
|
|||||||
foreach ([
|
foreach ([
|
||||||
$root.'/tmp/serializer',
|
$root.'/tmp/serializer',
|
||||||
$root.'/tmp/cache_twig',
|
$root.'/tmp/cache_twig',
|
||||||
|
$root.'/tmp/translations',
|
||||||
$root.'/tmp/cache_minify',
|
$root.'/tmp/cache_minify',
|
||||||
$root.'/tmp/download',
|
$root.'/tmp/download',
|
||||||
$root.'/tmp/locks',
|
$root.'/tmp/locks',
|
||||||
|
@@ -0,0 +1,57 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Alchemy\Phrasea\Core\Provider;
|
||||||
|
|
||||||
|
use Alchemy\Phrasea\Utilities\CachedTranslator;
|
||||||
|
use Silex\Application;
|
||||||
|
use Silex\ServiceProviderInterface;
|
||||||
|
use Symfony\Component\Translation\MessageSelector;
|
||||||
|
use Symfony\Component\Translation\Loader\ArrayLoader;
|
||||||
|
use JMS\TranslationBundle\Translation\Loader\Symfony\XliffLoader;
|
||||||
|
|
||||||
|
class TranslationServiceProvider implements ServiceProviderInterface
|
||||||
|
{
|
||||||
|
public function register(Application $app)
|
||||||
|
{
|
||||||
|
$app['translator.cache-options'] = array();
|
||||||
|
|
||||||
|
$app['translator'] = $app->share(function ($app) {
|
||||||
|
$app['translator.cache-options'] = array_replace(
|
||||||
|
array(
|
||||||
|
'debug' => $app['debug'],
|
||||||
|
), $app['translator.cache-options']
|
||||||
|
);
|
||||||
|
|
||||||
|
$translator = new CachedTranslator($app, $app['translator.message_selector'], $app['translator.cache-options']);
|
||||||
|
|
||||||
|
// Handle deprecated 'locale_fallback'
|
||||||
|
if (isset($app['locale_fallback'])) {
|
||||||
|
$app['locale_fallbacks'] = (array) $app['locale_fallback'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$translator->setFallbackLocales($app['locale_fallbacks']);
|
||||||
|
|
||||||
|
$translator->addLoader('array', new ArrayLoader());
|
||||||
|
$translator->addLoader('xliff', new XliffLoader());
|
||||||
|
|
||||||
|
foreach ($app['translator.domains'] as $domain => $data) {
|
||||||
|
foreach ($data as $locale => $messages) {
|
||||||
|
$translator->addResource('array', $messages, $locale, $domain);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $translator;
|
||||||
|
});
|
||||||
|
|
||||||
|
$app['translator.message_selector'] = $app->share(function () {
|
||||||
|
return new MessageSelector();
|
||||||
|
});
|
||||||
|
|
||||||
|
$app['translator.domains'] = array();
|
||||||
|
$app['locale_fallbacks'] = array('en');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function boot(Application $app)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
106
lib/Alchemy/Phrasea/Utilities/CachedTranslator.php
Normal file
106
lib/Alchemy/Phrasea/Utilities/CachedTranslator.php
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Silex framework.
|
||||||
|
*
|
||||||
|
* (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 Alchemy\Phrasea\Utilities;
|
||||||
|
|
||||||
|
use Alchemy\Phrasea\Application;
|
||||||
|
use Silex\Translator;
|
||||||
|
use Symfony\Component\Config\ConfigCache;
|
||||||
|
use Symfony\Component\Translation\MessageSelector;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Translator that gets the current locale from the Silex application
|
||||||
|
* and cache the translations on filesystem.
|
||||||
|
*/
|
||||||
|
class CachedTranslator extends Translator
|
||||||
|
{
|
||||||
|
protected $app;
|
||||||
|
protected $options = array(
|
||||||
|
'cache_dir' => null,
|
||||||
|
'debug' => false,
|
||||||
|
);
|
||||||
|
|
||||||
|
public function __construct(Application $app, MessageSelector $selector, array $options = array())
|
||||||
|
{
|
||||||
|
$this->app = $app;
|
||||||
|
|
||||||
|
if ($diff = array_diff(array_keys($options), array_keys($this->options))) {
|
||||||
|
throw new \InvalidArgumentException(sprintf('The Translator does not support the following options: \'%s\'.', implode('\', \'', $diff)));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->options = array_merge($this->options, $options);
|
||||||
|
|
||||||
|
parent::__construct($app, $selector);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function loadCatalogue($locale)
|
||||||
|
{
|
||||||
|
if (isset($this->catalogues[$locale])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null === $this->options['cache_dir']) {
|
||||||
|
return parent::loadCatalogue($locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
$cache = new ConfigCache($this->options['cache_dir'].'/catalogue.'.$locale.'.php', $this->options['debug']);
|
||||||
|
if (!$cache->isFresh()) {
|
||||||
|
parent::loadCatalogue($locale);
|
||||||
|
|
||||||
|
$fallbackContent = '';
|
||||||
|
$current = '';
|
||||||
|
foreach ($this->computeFallbackLocales($locale) as $fallback) {
|
||||||
|
$fallbackSuffix = ucfirst(str_replace('-', '_', $fallback));
|
||||||
|
|
||||||
|
$fallbackContent .= sprintf(<<<EOF
|
||||||
|
\$catalogue%s = new MessageCatalogue('%s', %s);
|
||||||
|
\$catalogue%s->addFallbackCatalogue(\$catalogue%s);
|
||||||
|
|
||||||
|
|
||||||
|
EOF
|
||||||
|
,
|
||||||
|
$fallbackSuffix,
|
||||||
|
$fallback,
|
||||||
|
var_export($this->catalogues[$fallback]->all(), true),
|
||||||
|
ucfirst(str_replace('-', '_', $current)),
|
||||||
|
$fallbackSuffix
|
||||||
|
);
|
||||||
|
$current = $fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
$content = sprintf(<<<EOF
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Symfony\Component\Translation\MessageCatalogue;
|
||||||
|
|
||||||
|
\$catalogue = new MessageCatalogue('%s', %s);
|
||||||
|
|
||||||
|
%s
|
||||||
|
return \$catalogue;
|
||||||
|
|
||||||
|
EOF
|
||||||
|
,
|
||||||
|
$locale,
|
||||||
|
var_export($this->catalogues[$locale]->all(), true),
|
||||||
|
$fallbackContent
|
||||||
|
);
|
||||||
|
|
||||||
|
$cache->write($content, $this->catalogues[$locale]->getResources());
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->catalogues[$locale] = include $cache;
|
||||||
|
}
|
||||||
|
}
|
@@ -312,6 +312,7 @@ class appbox extends base
|
|||||||
$finder->in([
|
$finder->in([
|
||||||
$this->app['root.path'] . '/tmp/cache_minify/',
|
$this->app['root.path'] . '/tmp/cache_minify/',
|
||||||
$this->app['root.path'] . '/tmp/cache_twig/',
|
$this->app['root.path'] . '/tmp/cache_twig/',
|
||||||
|
$this->app['root.path'] . '/tmp/translations/',
|
||||||
$this->app['root.path'] . '/tmp/cache/profiler/',
|
$this->app['root.path'] . '/tmp/cache/profiler/',
|
||||||
$this->app['root.path'] . '/tmp/doctrine/',
|
$this->app['root.path'] . '/tmp/doctrine/',
|
||||||
$this->app['root.path'] . '/tmp/serializer/',
|
$this->app['root.path'] . '/tmp/serializer/',
|
||||||
|
@@ -37,6 +37,7 @@ class module_console_systemClearCache extends Command
|
|||||||
->in([
|
->in([
|
||||||
$this->container['root.path'] . '/tmp/cache_minify/',
|
$this->container['root.path'] . '/tmp/cache_minify/',
|
||||||
$this->container['root.path'] . '/tmp/cache_twig/',
|
$this->container['root.path'] . '/tmp/cache_twig/',
|
||||||
|
$this->container['root.path'] . '/tmp/translations/',
|
||||||
$this->container['root.path'] . '/tmp/cache/profiler/',
|
$this->container['root.path'] . '/tmp/cache/profiler/',
|
||||||
$this->container['root.path'] . '/tmp/doctrine/',
|
$this->container['root.path'] . '/tmp/doctrine/',
|
||||||
$this->container['root.path'] . '/tmp/serializer/',
|
$this->container['root.path'] . '/tmp/serializer/',
|
||||||
|
@@ -337,6 +337,76 @@ class ApplicationTest extends \PhraseanetPHPUnitAbstract
|
|||||||
$this->assertInstanceOf('MediaAlchemyst\Alchemyst', $app['media-alchemyst']);
|
$this->assertInstanceOf('MediaAlchemyst\Alchemyst', $app['media-alchemyst']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider transProvider
|
||||||
|
*/
|
||||||
|
public function testCachedTranslator($key, $locale, $expected)
|
||||||
|
{
|
||||||
|
$tempDir = __DIR__ . '/temp-trans';
|
||||||
|
$this->cleanupTempDir($tempDir);
|
||||||
|
|
||||||
|
$app = $this->getPreparedApp($tempDir);
|
||||||
|
|
||||||
|
$this->assertInstanceOf('Alchemy\Phrasea\Utilities\CachedTranslator', $app['translator']);
|
||||||
|
|
||||||
|
$result = $app['translator']->trans($key, array(), null, $locale);
|
||||||
|
|
||||||
|
$this->assertEquals($expected, $result);
|
||||||
|
$this->assertFileExists($tempDir.'/catalogue.'.($locale ?: 'en').'.php');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function transProvider()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
array('key1', 'de', 'The german translation'),
|
||||||
|
array('test.key', 'de', 'It works in german'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getPreparedApp($tempDir)
|
||||||
|
{
|
||||||
|
$app = new Application('test');
|
||||||
|
$app['translator.cache-options'] = [
|
||||||
|
'debug' => false,
|
||||||
|
'cache_dir' => $tempDir,
|
||||||
|
];
|
||||||
|
|
||||||
|
$app['translator.domains'] = array(
|
||||||
|
'messages' => array(
|
||||||
|
'en' => array (
|
||||||
|
'key1' => 'The translation',
|
||||||
|
'key_only_english' => 'Foo',
|
||||||
|
'key2' => 'One apple|%count% apples',
|
||||||
|
'test' => array(
|
||||||
|
'key' => 'It works'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'de' => array (
|
||||||
|
'key1' => 'The german translation',
|
||||||
|
'key2' => 'One german apple|%count% german apples',
|
||||||
|
'test' => array(
|
||||||
|
'key' => 'It works in german'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return $app;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function cleanupTempDir($dir)
|
||||||
|
{
|
||||||
|
if (!is_dir($dir)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (new \DirectoryIterator($dir) as $fileinfo) {
|
||||||
|
if ($fileinfo->isFile()) {
|
||||||
|
unlink($fileinfo->getPathname());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private function getAppThatReturnLocale()
|
private function getAppThatReturnLocale()
|
||||||
{
|
{
|
||||||
$app = new Application('test');
|
$app = new Application('test');
|
||||||
|
@@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Alchemy\Tests\Phrasea\Core\Provider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers Alchemy\Phrasea\Core\Provider\TranslatorServiceProvider
|
||||||
|
*/
|
||||||
|
class TranslatorServiceProvidertest extends ServiceProviderTestCase
|
||||||
|
{
|
||||||
|
public function provideServiceDescription()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['Alchemy\Phrasea\Core\Provider\TranslationServiceProvider', 'translator', 'Alchemy\Phrasea\Utilities\CachedTranslator'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user