diff --git a/.travis.yml b/.travis.yml index 7f8987ce..b07fa39e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,38 +1,55 @@ language: php + sudo: false php: - - 5.5 - 5.6 - 7.0 - - hhvm + - 7.1 + - 7.2 matrix: fast_finish: true - allow_failures: - - php: hhvm + exclude: + - php: 5.6 + env: SYMFONY_VERSION=4.0.* DB=pdo_mysql DB_USER=root DB_NAME=lexik_test DEPENDENCIES=alpha + - php: 7.0 + env: SYMFONY_VERSION=4.0.* DB=pdo_mysql DB_USER=root DB_NAME=lexik_test DEPENDENCIES=alpha + - php: 7.2 + env: SYMFONY_VERSION=2.8.* DB=pdo_mysql DB_USER=root DB_NAME=lexik_test DEPENDENCIES=alpha + - php: 7.2 + env: SYMFONY_VERSION=3.0.* DB=pdo_mysql DB_USER=root DB_NAME=lexik_test DEPENDENCIES=alpha + - php: 7.2 + env: SYMFONY_VERSION=3.1.* DB=pdo_mysql DB_USER=root DB_NAME=lexik_test DEPENDENCIES=alpha + - php: 7.2 + env: SYMFONY_VERSION=3.2.* DB=pdo_mysql DB_USER=root DB_NAME=lexik_test DEPENDENCIES=alpha + - php: 7.2 + env: SYMFONY_VERSION=3.3.* DB=pdo_mysql DB_USER=root DB_NAME=lexik_test DEPENDENCIES=alpha + - php: 7.2 + env: SYMFONY_VERSION=3.4.* DB=pdo_mysql DB_USER=root DB_NAME=lexik_test DEPENDENCIES=alpha services: - mongodb env: - - SYMFONY_VERSION=2.8.* DB=pdo_mysql DB_USER=root DB_NAME=lexik_test - - SYMFONY_VERSION=3.2.* DB=pdo_mysql DB_USER=root DB_NAME=lexik_test - - SYMFONY_VERSION=3.3.* DB=pdo_mysql DB_USER=root DB_NAME=lexik_test - + - SYMFONY_VERSION=2.8.* DB=pdo_mysql DB_USER=root DB_NAME=lexik_test DEPENDENCIES=alpha + - SYMFONY_VERSION=3.0.* DB=pdo_mysql DB_USER=root DB_NAME=lexik_test DEPENDENCIES=alpha + - SYMFONY_VERSION=3.1.* DB=pdo_mysql DB_USER=root DB_NAME=lexik_test DEPENDENCIES=alpha + - SYMFONY_VERSION=3.2.* DB=pdo_mysql DB_USER=root DB_NAME=lexik_test DEPENDENCIES=alpha + - SYMFONY_VERSION=3.3.* DB=pdo_mysql DB_USER=root DB_NAME=lexik_test DEPENDENCIES=alpha + - SYMFONY_VERSION=3.4.* DB=pdo_mysql DB_USER=root DB_NAME=lexik_test DEPENDENCIES=alpha + - SYMFONY_VERSION=4.0.* DB=pdo_mysql DB_USER=root DB_NAME=lexik_test DEPENDENCIES=alpha cache: directories: - $HOME/.composer/cache before_install: - - phpenv config-add travis-php.ini - - echo "memory_limit = 2G" > /home/travis/.phpenv/versions/$(phpenv version-name)/etc/conf.d/z.ini - - sh -c "if [ '$DB' = 'pdo_mysql' ]; then mysql -e 'create database IF NOT EXISTS $DB_NAME' -u$DB_USER; fi" - - composer require symfony/framework-bundle:${SYMFONY_VERSION} --no-update - - composer require symfony/validator:${SYMFONY_VERSION} --no-update - - composer require symfony/finder:${SYMFONY_VERSION} --no-update - - composer require symfony/doctrine-bridge:${SYMFONY_VERSION} --no-update + - if [ "$DEPENDENCIES" = "beta" ]; then composer config minimum-stability beta; fi; + - if [ "$DEPENDENCIES" = "alpha" ]; then composer config minimum-stability alpha; fi; + - if [ -x .travis/before_install.sh ]; then .travis/before_install.sh; fi; -install: composer install --prefer-dist --no-interaction +install: + - if [ -x .travis/install.sh ]; then .travis/install.sh; fi; -script: phpunit +script: + - php vendor/bin/phpunit -v diff --git a/.travis/before_install.sh b/.travis/before_install.sh new file mode 100755 index 00000000..6e3658aa --- /dev/null +++ b/.travis/before_install.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env sh +set -ev + +sh -c "if [ '$DB' = 'pdo_mysql' ]; then mysql -e 'create database IF NOT EXISTS $DB_NAME' -u$DB_USER; fi" + +phpenv config-rm xdebug.ini + +if [ "${TRAVIS_PHP_VERSION}" != "hhvm" ]; then + PHP_INI_DIR="$HOME/.phpenv/versions/$(phpenv version-name)/etc/conf.d/" + TRAVIS_INI_FILE="$PHP_INI_DIR/travis.ini" + echo "memory_limit=3072M" >> "$TRAVIS_INI_FILE" + + if [ "$TRAVIS_PHP_VERSION" '<' '7.0' ]; then + echo "extension=mongo.so" >> "$TRAVIS_INI_FILE" + else + echo "extension=mongodb.so" >> "$TRAVIS_INI_FILE" + + # Backwards compatibility with old mongo extension + composer require "alcaeus/mongo-php-adapter" --no-update + fi +fi + +composer require "symfony/symfony:${SYMFONY_VERSION}" --no-update diff --git a/.travis/install.sh b/.travis/install.sh new file mode 100755 index 00000000..41ac0ee5 --- /dev/null +++ b/.travis/install.sh @@ -0,0 +1,6 @@ +# To be removed when these issues are resolved: +# https://github.com/composer/composer/issues/5355 +# https://github.com/composer/composer/issues/5030 +composer update --prefer-dist --no-interaction --prefer-stable --quiet --ignore-platform-reqs + +composer update --prefer-dist --no-interaction --prefer-stable diff --git a/Command/ImportTranslationsCommand.php b/Command/ImportTranslationsCommand.php index 473432e4..9def8d06 100644 --- a/Command/ImportTranslationsCommand.php +++ b/Command/ImportTranslationsCommand.php @@ -9,6 +9,8 @@ use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Finder\Finder; use Symfony\Component\HttpKernel\Bundle\BundleInterface; +use Symfony\Component\HttpKernel\Kernel; +use Symfony\Component\Translation\TranslatorInterface; /** * Imports translation files content in the database. @@ -19,6 +21,21 @@ */ class ImportTranslationsCommand extends ContainerAwareCommand { + /** + * @var TranslatorInterface + */ + private $translator; + + /** + * @param TranslatorInterface $translator + */ + public function __construct(TranslatorInterface $translator) + { + parent::__construct(); + + $this->translator = $translator; + } + /** * @var \Symfony\Component\Console\Input\InputInterface */ @@ -71,7 +88,7 @@ protected function execute(InputInterface $input, OutputInterface $output) if ($bundleName) { $bundle = $this->getApplication()->getKernel()->getBundle($bundleName); - if (null !== $bundle->getParent()) { + if (Kernel::VERSION_ID < 40000 && null !== $bundle->getParent()) { // due to symfony's bundle inheritance if a bundle has a parent it is fetched first. // so we tell getBundle to NOT fetch the first if a parent is present $bundles = $this->getApplication()->getKernel()->getBundle($bundle->getParent(), false); @@ -114,7 +131,7 @@ protected function execute(InputInterface $input, OutputInterface $output) if ($this->input->getOption('cache-clear')) { $this->output->writeln('Removing translations cache files ...'); - $this->getContainer()->get('translator')->removeLocalesCacheFiles($locales); + $this->translator->removeLocalesCacheFiles($locales); } } diff --git a/Controller/RestController.php b/Controller/RestController.php index 3b27e37b..1819f5c6 100644 --- a/Controller/RestController.php +++ b/Controller/RestController.php @@ -2,6 +2,7 @@ namespace Lexik\Bundle\TranslationBundle\Controller; +use Lexik\Bundle\TranslationBundle\Util\Csrf\CsrfCheckerTrait; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; @@ -11,6 +12,8 @@ */ class RestController extends Controller { + use CsrfCheckerTrait; + /** * @param Request $request * @@ -50,6 +53,8 @@ public function updateAction(Request $request, $id) throw $this->createNotFoundException(sprintf('Invalid request method %s, PUT only.', $request->getMethod())); } + $this->checkCsrf(); + $transUnit = $this->get('lexik_translation.data_grid.request_handler')->updateFromRequest($id, $request); return $this->get('lexik_translation.data_grid.formatter')->createSingleResponse($transUnit); @@ -64,6 +69,8 @@ public function updateAction(Request $request, $id) */ public function deleteAction($id) { + $this->checkCsrf(); + $transUnit = $this->get('lexik_translation.translation_storage')->getTransUnitById($id); if (!$transUnit) { @@ -85,6 +92,8 @@ public function deleteAction($id) */ public function deleteTranslationAction($id, $locale) { + $this->checkCsrf(); + $transUnit = $this->get('lexik_translation.translation_storage')->getTransUnitById($id); if (!$transUnit) { diff --git a/Controller/TranslationController.php b/Controller/TranslationController.php index b58c6db1..b908145c 100644 --- a/Controller/TranslationController.php +++ b/Controller/TranslationController.php @@ -2,7 +2,9 @@ namespace Lexik\Bundle\TranslationBundle\Controller; +use Lexik\Bundle\TranslationBundle\Form\Type\TransUnitType; use Lexik\Bundle\TranslationBundle\Storage\StorageInterface; +use Lexik\Bundle\TranslationBundle\Util\Csrf\CsrfCheckerTrait; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; @@ -12,6 +14,8 @@ */ class TranslationController extends Controller { + use CsrfCheckerTrait; + /** * Display an overview of the translation status per domain. * @@ -67,6 +71,8 @@ public function invalidateCacheAction(Request $request) $message = $this->get('translator')->trans('translations.cache_removed', array(), 'LexikTranslationBundle'); if ($request->isXmlHttpRequest()) { + $this->checkCsrf(); + return new JsonResponse(array('message' => $message)); } @@ -84,7 +90,7 @@ public function newAction(Request $request) { $handler = $this->get('lexik_translation.form.handler.trans_unit'); - $form = $this->createForm('Lexik\Bundle\TranslationBundle\Form\Type\TransUnitType', $handler->createFormData(), $handler->getFormOptions()); + $form = $this->createForm(TransUnitType::class, $handler->createFormData(), $handler->getFormOptions()); if ($handler->process($form, $request)) { $message = $this->get('translator')->trans('translations.successfully_added', array(), 'LexikTranslationBundle'); diff --git a/DependencyInjection/LexikTranslationExtension.php b/DependencyInjection/LexikTranslationExtension.php index f2e8c59b..5044e502 100644 --- a/DependencyInjection/LexikTranslationExtension.php +++ b/DependencyInjection/LexikTranslationExtension.php @@ -76,7 +76,16 @@ public function buildTranslatorDefinition(ContainerBuilder $container) $translator = new Definition(); $translator->setClass('%lexik_translation.translator.class%'); - if (Kernel::VERSION_ID >= 30300) { + if (Kernel::VERSION_ID >= 40000) { + $arguments = [ + new Reference('service_container'), // Will be replaced by service locator + new Reference('translator.formatter.default'), + new Parameter('kernel.default_locale'), + [], // translation loaders + new Parameter('lexik_translation.translator.options') + ]; + $translator->setPublic(true); + } elseif (Kernel::VERSION_ID >= 30300) { $arguments = [ new Reference('service_container'), // Will be replaced by service locator new Reference('translator.selector'), @@ -171,7 +180,7 @@ protected function buildTranslationStorageDefinition(ContainerBuilder $container ); $storageDefinition = new Definition(); - $storageDefinition->setClass(new Parameter(sprintf('lexik_translation.%s.translation_storage.class', $storage))); + $storageDefinition->setClass($container->getParameter(sprintf('lexik_translation.%s.translation_storage.class', $storage))); $storageDefinition->setArguments($args); $container->setDefinition('lexik_translation.translation_storage', $storageDefinition); @@ -206,7 +215,7 @@ protected function buildDevServicesDefinition(ContainerBuilder $container) ->addMethodCall('setProfiler', array(new Reference('profiler'))); $tokenFinderDefinition = new Definition(); - $tokenFinderDefinition->setClass(new Parameter('lexik_translation.token_finder.class')); + $tokenFinderDefinition->setClass($container->getParameter('lexik_translation.token_finder.class')); $tokenFinderDefinition->setArguments(array( new Reference('profiler'), new Parameter('lexik_translation.token_finder.limit'), @@ -224,7 +233,11 @@ protected function buildDevServicesDefinition(ContainerBuilder $container) protected function registerTranslatorConfiguration(array $config, ContainerBuilder $container) { // use the Lexik translator as default translator service - $container->setAlias('translator', 'lexik_translation.translator'); + $alias = $container->setAlias('translator', 'lexik_translation.translator'); + + if (Kernel::VERSION_ID >= 30400) { + $alias->setPublic(true); + } $translator = $container->findDefinition('lexik_translation.translator'); $translator->addMethodCall('setFallbackLocales', array($config['fallback_locale'])); diff --git a/Form/Type/TransUnitType.php b/Form/Type/TransUnitType.php index 7f67e178..5ac13d03 100644 --- a/Form/Type/TransUnitType.php +++ b/Form/Type/TransUnitType.php @@ -5,6 +5,7 @@ use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; +use Symfony\Component\Validator\Constraints\NotBlank; /** * TransUnit form type. @@ -23,12 +24,18 @@ public function buildForm(FormBuilderInterface $builder, array $options) )); $builder->add('domain', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', array( 'label' => 'translations.domain', - 'choices' => array_combine($options['domains'], $options['domains']), + 'choices' => array_merge( + array_combine($options['default_domain'], $options['default_domain']), + array_combine($options['domains'], $options['domains']) + ), )); $builder->add('translations', 'Symfony\Component\Form\Extension\Core\Type\CollectionType', array( 'entry_type' => 'Lexik\Bundle\TranslationBundle\Form\Type\TranslationType', 'label' => 'translations.page_title', - 'required' => false, + 'required' => true, + 'constraints' => array( + new NotBlank(), + ), 'entry_options' => array( 'data_class' => $options['translation_class'], ), @@ -48,7 +55,8 @@ public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults(array( 'data_class' => null, - 'domains' => array('messages'), + 'default_domain' => ['messages'], + 'domains' => [], 'translation_class' => null, 'translation_domain' => 'LexikTranslationBundle', )); diff --git a/Form/Type/TranslationType.php b/Form/Type/TranslationType.php index 499a5802..e0fa4732 100644 --- a/Form/Type/TranslationType.php +++ b/Form/Type/TranslationType.php @@ -7,6 +7,7 @@ use Symfony\Component\Form\FormView; use Symfony\Component\Form\FormInterface; use Symfony\Component\OptionsResolver\OptionsResolver; +use Symfony\Component\Validator\Constraints\NotBlank; /** * Translation form type. @@ -22,7 +23,10 @@ public function buildForm(FormBuilderInterface $builder, array $options) { $builder->add('locale', 'Symfony\Component\Form\Extension\Core\Type\HiddenType'); $builder->add('content', 'Symfony\Component\Form\Extension\Core\Type\TextareaType', array( - 'required' => false, + 'required' => true, + 'constraints' => array( + new NotBlank(), + ), )); } diff --git a/Manager/FileManager.php b/Manager/FileManager.php index 7ed5e948..64282cc7 100644 --- a/Manager/FileManager.php +++ b/Manager/FileManager.php @@ -46,11 +46,8 @@ public function getFor($name, $path = null) $hash = $this->generateHash($name, $this->getFileRelativePath($path)); $file = $this->storage->getFileByHash($hash); - if (!($file instanceof FileInterface)) { - $file = $this->create($name, $path); - } + return $file instanceof FileInterface? $file : $this->create($name, $path); - return $file; } /** diff --git a/Model/TransUnit.php b/Model/TransUnit.php index 43736000..c300355e 100644 --- a/Model/TransUnit.php +++ b/Model/TransUnit.php @@ -35,6 +35,8 @@ abstract class TransUnit /** * @var \Doctrine\Common\Collections\Collection + * + * @Assert\NotBlank() */ protected $translations; @@ -192,6 +194,22 @@ public function filterNotBlankTranslations() }); } + /** + * Return false if at least one translation without content. + * + * @return bool + */ + public function validForBlankTranslations() + { + foreach ($this->getTranslations() as $translation) { + if (empty($translation->getContent())) { + return false; + } + } + + return true; + } + /** * Get createdAt * diff --git a/Propel/File.php b/Propel/File.php index 84180457..2e8a9e1a 100644 --- a/Propel/File.php +++ b/Propel/File.php @@ -2,7 +2,7 @@ namespace Lexik\Bundle\TranslationBundle\Propel; -use Lexik\Bundle\TranslationBundle\Propel\om\BaseFile; +use Lexik\Bundle\TranslationBundle\Propel\Base\File as BaseFile; use Lexik\Bundle\TranslationBundle\Manager\FileInterface; class File extends BaseFile implements FileInterface diff --git a/Propel/FilePeer.php b/Propel/FilePeer.php deleted file mode 100644 index 0c526e39..00000000 --- a/Propel/FilePeer.php +++ /dev/null @@ -1,9 +0,0 @@ -connection = $connection; } /** - * @return PDO + * @return ConnectionWrapper */ protected function getConnection() { @@ -38,11 +41,11 @@ public function findForLocalesAndDomains(array $locales, array $domains) { return FileQuery::create() ->_if(count($locales) > 0) - ->filterByLocale($locales, \Criteria::IN) + ->filterByLocale($locales, Criteria::IN) ->_endif() ->_if(count($domains) > 0) - ->filterByDomain($domains, \Criteria::IN) + ->filterByDomain($domains, Criteria::IN) ->_endif() ->find($this->getConnection()) diff --git a/Propel/TransUnit.php b/Propel/TransUnit.php index 4f464739..7ff761b9 100644 --- a/Propel/TransUnit.php +++ b/Propel/TransUnit.php @@ -3,7 +3,7 @@ namespace Lexik\Bundle\TranslationBundle\Propel; use Lexik\Bundle\TranslationBundle\Model\Translation; -use Lexik\Bundle\TranslationBundle\Propel\om\BaseTransUnit; +use Lexik\Bundle\TranslationBundle\Propel\Base\TransUnit as BaseTransUnit; use Lexik\Bundle\TranslationBundle\Manager\TransUnitInterface; use Lexik\Bundle\TranslationBundle\Manager\TranslationInterface; diff --git a/Propel/TransUnitPeer.php b/Propel/TransUnitPeer.php deleted file mode 100644 index 33c8ff11..00000000 --- a/Propel/TransUnitPeer.php +++ /dev/null @@ -1,9 +0,0 @@ -connection = $connection; } /** - * @return PDO + * @return ConnectionWrapper */ protected function getConnection() { @@ -61,7 +66,7 @@ public function getAllByLocaleAndDomain($locale, $domain) ->useTranslationQuery() ->filterByLocale($locale) ->endUse() - ->setFormatter('PropelArrayFormatter') + ->setFormatter(ModelCriteria::FORMAT_ARRAY) ->find($this->getConnection()) ; @@ -78,7 +83,7 @@ public function getAllDomains() $domains = TransUnitQuery::create() ->select('Domain') ->setDistinct() - ->orderByDomain(\Criteria::ASC) + ->orderByDomain(Criteria::ASC) ->find($this->getConnection()) ; @@ -119,13 +124,13 @@ public function getTransUnitList(array $locales = null, $rows = 20, $page = 1, a if (count($ids) > 0) { $unitsData = TransUnitQuery::create() - ->filterById($ids, \Criteria::IN) + ->filterById($ids, Criteria::IN) ->joinWith('Translation') ->useTranslationQuery() - ->filterByLocale($locales, \Criteria::IN) + ->filterByLocale($locales, Criteria::IN) ->endUse() ->orderBy($sortColumn, $order) - ->setFormatter('PropelArrayFormatter') + ->setFormatter(ModelCriteria::FORMAT_ARRAY) ->find($this->getConnection()) ; @@ -171,12 +176,12 @@ public function getTranslationsForFile($file, $onlyUpdated) ; if ($onlyUpdated) { - $query->add(null, TranslationPeer::UPDATED_AT.'>'.TranslationPeer::CREATED_AT, \Criteria::CUSTOM); + $query->add(null, TranslationTableMap::COL_UPDATED_AT.'>'.TranslationTableMap::COL_CREATED_AT, Criteria::CUSTOM); } $results = $query ->select(array('Content', 'TransUnit.Key')) - ->orderBy(TranslationPeer::ID, \Criteria::ASC) + ->orderBy(TranslationTableMap::COL_ID, Criteria::ASC) ->find() ; @@ -198,11 +203,11 @@ protected function addTransUnitFilters(TransUnitQuery $query, array $filters = n { if (isset($filters['_search']) && $filters['_search']) { if (!empty($filters['domain'])) { - $query->filterByDomain(sprintf('%%%s%%', $filters['domain']), \Criteria::LIKE); + $query->filterByDomain(sprintf('%%%s%%', $filters['domain']), Criteria::LIKE); } if (!empty($filters['key'])) { - $query->filterByKey(sprintf('%%%s%%', $filters['key']), \Criteria::LIKE); + $query->filterByKey(sprintf('%%%s%%', $filters['key']), Criteria::LIKE); } } } @@ -220,15 +225,15 @@ protected function addTranslationFilter(TransUnitQuery $query, array $locales = $q = TransUnitQuery::create() ->select('Id') ->distinct() - ->join('Translation', \Criteria::LEFT_JOIN) + ->join('Translation', Criteria::LEFT_JOIN) ->useTranslationQuery() - ->filterByLocale($locales, \Criteria::IN) + ->filterByLocale($locales, Criteria::IN) ; foreach ($locales as $locale) { if (!empty($filters[$locale])) { $q - ->filterByContent(sprintf('%%%s%%', $filters[$locale]), \Criteria::LIKE) + ->filterByContent(sprintf('%%%s%%', $filters[$locale]), Criteria::LIKE) ->filterByLocale(sprintf('%s', $locale)) ; } @@ -240,7 +245,7 @@ protected function addTranslationFilter(TransUnitQuery $query, array $locales = ; if (count($ids) > 0) { - $query->filterById($ids, \Criteria::IN); + $query->filterById($ids, Criteria::IN); } } } diff --git a/Propel/Translation.php b/Propel/Translation.php index eb9758b5..dc1bb6d4 100644 --- a/Propel/Translation.php +++ b/Propel/Translation.php @@ -2,7 +2,7 @@ namespace Lexik\Bundle\TranslationBundle\Propel; -use Lexik\Bundle\TranslationBundle\Propel\om\BaseTranslation; +use Lexik\Bundle\TranslationBundle\Propel\Base\Translation as BaseTranslation; use Lexik\Bundle\TranslationBundle\Manager\TranslationInterface; class Translation extends BaseTranslation implements TranslationInterface diff --git a/Propel/TranslationPeer.php b/Propel/TranslationPeer.php deleted file mode 100644 index 8172d734..00000000 --- a/Propel/TranslationPeer.php +++ /dev/null @@ -1,9 +0,0 @@ -connection = $connection; } /** - * @return \PDO + * @return ConnectionWrapper */ protected function getConnection() { @@ -36,7 +39,7 @@ protected function getConnection() public function getLatestTranslationUpdatedAt() { $result = TranslationQuery::create() - ->withColumn(sprintf('MAX(%s)', TranslationPeer::UPDATED_AT), 'max_updated_at') + ->withColumn(sprintf('MAX(%s)', TranslationTableMap::COL_UPDATED_AT), 'max_updated_at') ->select(array('max_updated_at')) ->findOne($this->getConnection()) ; diff --git a/README.md b/README.md index 07bf618c..b91d80ac 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ Overview ======== -This Symfony2 bundle allows you to: +This Symfony bundle allows you to: * import translation files content into the database and provide a GUI to edit translations. * export translations from the database into files. diff --git a/Resources/config/services.xml b/Resources/config/services.xml index 97f68f69..df508911 100644 --- a/Resources/config/services.xml +++ b/Resources/config/services.xml @@ -1,8 +1,8 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> Lexik\Bundle\TranslationBundle\Translation\Translator @@ -45,6 +45,9 @@ Lexik\Bundle\TranslationBundle\Util\Profiler\TokenFinder + Lexik\Bundle\TranslationBundle\Command\ImportTranslationsCommand + Lexik\Bundle\TranslationBundle\Command\ExportTranslationsCommand + false 15 @@ -62,7 +65,7 @@ - + %kernel.root_dir% @@ -73,12 +76,12 @@ %kernel.root_dir% - + %lexik_translation.managed_locales% - + @@ -89,7 +92,7 @@ - + @@ -110,12 +113,12 @@ - + %lexik_translation.storage.type% - + @@ -129,13 +132,13 @@ - + - + @@ -150,5 +153,16 @@ + + + + + + + + + + + diff --git a/Resources/doc/index.md b/Resources/doc/index.md index 99eccb6a..b839c53b 100644 --- a/Resources/doc/index.md +++ b/Resources/doc/index.md @@ -41,7 +41,7 @@ $bundles = array( Then install the required assets: - ./app/console assets:install + ./bin/console assets:install ___________________ @@ -111,7 +111,7 @@ lexik_translation: ``` You can choose the resource's type you want to load, by default the bundle will load translations from files + database, but you can choose to use only one of these two resource types. -Note that if you use files + database, if a translation exists in both resources, the value from the database will override the files' translation because the database is loaded after. +Note that if you use files + database, if a translation exists in both resources, the value from the database will override the file's translation because the database is loaded after. By default the bundle will only load resources for managed locales. ```yml @@ -147,7 +147,7 @@ lexik_translation: If you use Doctrine ORM, you have to update your database: - ./app/console doctrine:schema:update --force + ./bin/console doctrine:schema:update --force #### Routing @@ -176,9 +176,9 @@ Import translations To import translations files content into your database just run the following command: - ./app/console lexik:translations:import [bundleName] [--cache-clear] [--force] [--globals] + ./bin/console lexik:translations:import [bundleName] [--cache-clear] [--force] [--globals] -This command will import all application and bundles translations files according to the `managed_locales` defined in configuration (it will also load tanslations from SF conponents). +This command will import all application and bundles translations files according to the `managed_locales` defined in configuration (it will also load tanslations from SF components). Command arguments: * `bundle`: Import translations for this specific bundle. @@ -199,7 +199,7 @@ Export translations To export translations from the database into files, run the following command: - ./app/console lexik:translations:export [--locales=en,de] [--domains=messages,validators] [--format=yml] [--case-insensitive] + ./bin/console lexik:translations:export [--locales=en,de] [--domains=messages,validators] [--format=yml] [--case-insensitive] This command will export all translations from the database into files. A translation is exported in the same file (and format) it was imported in, except for vendors files which are exported in `app/Resources/translations/` and in this case the command will only export translations that have changed. diff --git a/Resources/public/js/translation.js b/Resources/public/js/translation.js index 677a7283..7d9c416c 100644 --- a/Resources/public/js/translation.js +++ b/Resources/public/js/translation.js @@ -26,7 +26,7 @@ app.factory('sharedMessage', function () { /** * Api manager service. */ -app.factory('translationApiManager', ['$http', function ($http) { +app.factory('translationApiManager', ['$http', '$httpParamSerializer', function ($http, $httpParamSerializer) { return { token: null, @@ -69,19 +69,22 @@ app.factory('translationApiManager', ['$http', function ($http) { }, invalidateCache: function () { - return $http.get(translationCfg.url.invalidateCache, {headers: {'X-Requested-With': 'XMLHttpRequest'}}); + return $http.get(translationCfg.url.invalidateCache, { + headers: {'X-Requested-With': 'XMLHttpRequest'}, + params: this.initializeParametersWithCsrf() + }); }, updateTranslation: function (translation) { var url = translationCfg.url.update.replace('-id-', translation._id); - var parameters = []; + var parameters = this.initializeParametersWithCsrf(); for (var name in translation) { - parameters.push(name+'='+encodeURIComponent(translation[name])); + parameters[name] = translation[name]; } // force content type to make SF create a Request with the PUT parameters - return $http({ 'url': url, 'data': parameters.join('&'), method: 'PUT', headers: {'Content-Type': 'application/x-www-form-urlencoded'} }); + return $http({ 'url': url, 'data': $httpParamSerializer(parameters), method: 'PUT', headers: {'Content-Type': 'application/x-www-form-urlencoded'} }); }, deleteTranslationLocale: function (translation, locale) { @@ -89,11 +92,25 @@ app.factory('translationApiManager', ['$http', function ($http) { .replace('-id-', translation._id) .replace('-locale-', locale); - return $http.delete(url); + return $http.delete(url, { + params: this.initializeParametersWithCsrf() + }); }, deleteTranslation: function (translation) { - return $http.delete(translationCfg.url.delete.replace('-id-', translation._id)); + return $http.delete(translationCfg.url.delete.replace('-id-', translation._id), { + params: this.initializeParametersWithCsrf() + }); + }, + + initializeParametersWithCsrf: function(parameters) { + var parameters = {}; + + if(translationCfg.csrfToken ){ + parameters._token = translationCfg.csrfToken; + } + + return parameters; } }; }]); @@ -101,11 +118,11 @@ app.factory('translationApiManager', ['$http', function ($http) { /** * ngTable column definition and parameters builder service. */ -app.factory('tableParamsManager', ['ngTableParams', 'translationApiManager', function (ngTableParams, translationApiManager) { +app.factory('tableParamsManager', ['ngTableParams', 'translationApiManager', '$location', function (ngTableParams, translationApiManager, $location) { return { columns: [], tableParams: null, - defaultOptions: { page: 1, count: 20, filter: {}, sort: {'_id': 'asc'} }, + defaultOptions: angular.extend( { page: 1, count: 20, filter: {}, sort: {'_id': 'asc'} }, $location.search()), build: function (locales, labels) { this.columns = [ @@ -127,6 +144,8 @@ app.factory('tableParamsManager', ['ngTableParams', 'translationApiManager', fun currentSort: {}, currentFilter: {}, getData: function($defer, params) { + $location.search(params.url()); + translationApiManager .getPage(params, this) .success(function (responseData) { diff --git a/Resources/translations/LexikTranslationBundle.lv.yml b/Resources/translations/LexikTranslationBundle.lv.yml new file mode 100644 index 00000000..925c773f --- /dev/null +++ b/Resources/translations/LexikTranslationBundle.lv.yml @@ -0,0 +1,33 @@ +translations: + invalidate_cache: "Notīrīt kešatmiņu" + domain: "Domēns" + key: "Atslēga" + grid_caption: "Tulkojumu saraksts" + cache_removed: "Kešatmiņa notīrīta" + new_translation: "Jauns tulkojums" + add_translation: "Pievienot tulkojumu" + save: "Saglabāt" + save_add: "Saglabāt un pievienot vēl" + page_title: "Tulkojumi" + show_hide_columns: "Parādīt/Paslēpt kolonnas" + toggle_all_columns: "Parādīt/Paslēpt visas kolonnas" + save_row: "Saglabāt rindu" + successfully_updated: "Atslēgas #%id% tulkojumi veiksmīgi saglabāti." + successfully_added: "Tulkojumi tika veiksmīgi pievienoti." + successfully_deleted: "Tulkojumi tika veiksmīgi dzēsti." + update_failed: "Failed to update translations for key #%id%." + delete_failed: "Failed to delete translations for key #%id%." + back_to_list: "Atpakaļ" + all_translations: "Visi" + no_translations: "Tulkojumi netika atrasti" + profiler: "Profiler" + data_source: "Data source" + latest_profiles: "Latest profiles" + profile: "Profile" + +overview: + page_title: "Pārskats" + show_grid: "Tulkojumu saraksts" + msg_latest_translation: "Jaunākā tulkojuma datums: %date% UTC." + domain: "Domēns" + no_stats: "Nav datu." diff --git a/Resources/views/Translation/_ngGrid.html.twig b/Resources/views/Translation/_ngGrid.html.twig index 38e86c6c..dc69a480 100644 --- a/Resources/views/Translation/_ngGrid.html.twig +++ b/Resources/views/Translation/_ngGrid.html.twig @@ -150,7 +150,7 @@