From 54784df618726981536ed46a2e808c2ccc78e748 Mon Sep 17 00:00:00 2001 From: William Desportes Date: Sat, 8 Jun 2019 09:44:15 +0200 Subject: [PATCH 01/23] ci(travis): Update .travis.yml file and remove install osx --- .travis.yml | 159 +++++++++++++++++++++++++++----------- scripts/ci/install-osx.sh | 19 ----- 2 files changed, 116 insertions(+), 62 deletions(-) delete mode 100755 scripts/ci/install-osx.sh diff --git a/.travis.yml b/.travis.yml index be58e49..d6a5387 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,64 +1,137 @@ -dist: trusty - language: php -php: - - "7.1" - - "7.2" - -sudo: required - -env: - matrix: - - CI_TYPE=phpunit - before_script: - - ./scripts/ci/install-reporters.sh - - ./scripts/ci/install.sh - + - "./scripts/ci/install-reporters.sh" + - "./scripts/ci/install.sh" script: - ./scripts/ci/ci-$CI_TYPE.sh - install: - # flags to pass to install - - flags="--ansi --prefer-dist --no-interaction --optimize-autoloader --no-suggest --no-progress" - # install dependencies using system provided composer binary - - composer install $flags - -after_success: - - bash <(curl -s https://codecov.io/bash) + - if [ "$CI_COMPOSER" = "yes" ]; then composer install --ansi --prefer-dist --no-interaction --optimize-autoloader --no-suggest --no-progress; fi after_script: - - ./codacy-coverage.phar clover build/logs/clover.xml + - if [ "$TRAVIS_BUILD_STAGE_NAME" = "tests" ]; then ./codacy-coverage.phar clover build/logs/clover.xml; else echo "skipped codacy"; fi -matrix: - fast_finish: true - include: - - php: "7.2" - env: CI_TYPE=phpstan - - - php: "7.2" - env: CI_TYPE=phpcs +stages: + - name: lint + - name: tests - - os: osx - language: generic +jobs: + include: + - stage: tests + php: "7.1" + env: + - CI_TYPE=phpunit + - CI_COMPOSER=yes + name: "PHPUNIT - PHP 7.1" + after_success: + - bash <(curl -s https://codecov.io/bash) -cF php + - stage: tests php: "7.2" - env: CI_TYPE=phpunit + env: + - CI_TYPE=phpunit + - CI_COMPOSER=yes + name: "PHPUNIT - PHP 7.2" + after_success: + - bash <(curl -s https://codecov.io/bash) -cF php + - stage: tests + php: "7.3" + env: + - CI_TYPE=phpunit + - CI_COMPOSER=yes + name: "PHPUNIT - PHP 7.3" + after_success: + - bash <(curl -s https://codecov.io/bash) -cF php + - stage: tests + os: osx + language: node_js + node_js: "10" + env: + - CI_TYPE=phpunit + - CI_COMPOSER=yes + name: "PHPUNIT - PHP 7.1" + addons: + homebrew: + packages: + - php@7.1 + - composer before_install: - - ./scripts/ci/install-osx.sh + - mkdir ~/.homebrew_logs + - export HOMEBREW_LOGS="~/.homebrew_logs" + - export HOMEBREW_TEMP="/tmp" + - export HOMEBREW_INSTALL_BADGE="🌻" + after_success: + - bash <(curl -s https://codecov.io/bash) -cF php + - stage: tests + os: osx + language: node_js + node_js: "10" + env: + - CI_TYPE=phpunit + - CI_COMPOSER=yes + name: "PHPUNIT - PHP 7.2" + addons: + homebrew: + packages: + - php@7.2 + - composer + before_install: + - mkdir ~/.homebrew_logs + - export HOMEBREW_LOGS="~/.homebrew_logs" + - export HOMEBREW_TEMP="/tmp" + - export HOMEBREW_INSTALL_BADGE="🌻" + after_success: + - bash <(curl -s https://codecov.io/bash) -cF php + - stage: tests + os: osx + language: node_js + node_js: "10" + env: + - CI_TYPE=phpunit + - CI_COMPOSER=yes + name: "PHPUNIT - PHP 7.3" + addons: + homebrew: + packages: + - php@7.3 + - composer + before_install: + - mkdir ~/.homebrew_logs + - export HOMEBREW_LOGS="~/.homebrew_logs" + - export HOMEBREW_TEMP="/tmp" + - export HOMEBREW_INSTALL_BADGE="🌻" + after_success: + - bash <(curl -s https://codecov.io/bash) -cF php + - stage: lint + php: "7.3" + env: + - CI_TYPE=phpstan + - CI_COMPOSER=yes + name: "PHPSTAN - PHP 7.3" + - stage: lint + php: "7.3" + env: + - CI_TYPE=phpcs + - CI_COMPOSER=yes + name: "PHPCS - PHP 7.3" + - stage: lint + language: php + php: "7.3" + env: + - CI_TYPE=lint + - CI_COMPOSER=yes + name: "LINT - PHP 7.3" + script: composer run phpcs cache: - apt: true + ccache: true directories: - $HOME/.composer/cache/ - - $HOME/.cache/bower - - $HOME/.npm - - $HOME/.cache/ci - /var/cache/apt - - ~/Library/Caches/Homebrew + - $HOME/Library/Caches/Homebrew + +before_cache: + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew cleanup; fi addons: apt: update: false - packages: - - git \ No newline at end of file diff --git a/scripts/ci/install-osx.sh b/scripts/ci/install-osx.sh deleted file mode 100755 index 310cb3e..0000000 --- a/scripts/ci/install-osx.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash -brew remove mysql -brew remove mariadb -brew uninstall mysql -sudo chown -R $(whoami):admin /usr/local - -brew cleanup -brew update -rm -Rf /usr/local/var/mysql 2>/dev/null -rm /etc/my.cnf 2>/dev/null -brew install mariadb -rm /etc/my.cnf 2>/dev/null -mysql.server start -ls /tmp - -brew install php72 -sed -i -e 's/^memory_limit = .*/memory_limit = -1/' /usr/local/etc/php/7.2/php.ini -curl https://getcomposer.org/installer | php -ln -s "$(pwd)/composer.phar" /usr/local/bin/composer From 6d8578a9f9d2bc77b7f02ba2c344d6e0a279482d Mon Sep 17 00:00:00 2001 From: William Desportes Date: Sat, 8 Jun 2019 09:51:08 +0200 Subject: [PATCH 02/23] ci(composer): Move all commands to composer scripts - Removed a ci step --- .travis.yml | 8 -------- composer.json | 6 ++++++ scripts/ci/ci-phpcs.sh | 2 +- scripts/ci/ci-phpcsbf.sh | 4 ---- scripts/ci/ci-phpstan.sh | 2 +- scripts/ci/ci-phpunit.sh | 2 +- 6 files changed, 9 insertions(+), 15 deletions(-) delete mode 100755 scripts/ci/ci-phpcsbf.sh diff --git a/.travis.yml b/.travis.yml index d6a5387..41f3309 100644 --- a/.travis.yml +++ b/.travis.yml @@ -113,14 +113,6 @@ jobs: - CI_TYPE=phpcs - CI_COMPOSER=yes name: "PHPCS - PHP 7.3" - - stage: lint - language: php - php: "7.3" - env: - - CI_TYPE=lint - - CI_COMPOSER=yes - name: "LINT - PHP 7.3" - script: composer run phpcs cache: ccache: true diff --git a/composer.json b/composer.json index fc0576d..e58197b 100644 --- a/composer.json +++ b/composer.json @@ -11,6 +11,12 @@ "issues": "https://github.com/wdes/php-I18n-l10n/issues", "source": "https://github.com/wdes/php-I18n-l10n" }, + "scripts": { + "phpcs": "phpcs --standard=phpcs.xml --no-cache --colors -p -n", + "phpcbf": "phpcbf --standard=phpcs.xml", + "phpstan": "phpstan analyse src tests --configuration=phpstan.neon --level=max", + "phpunit": "phpunit --configuration ./tests/phpunit.xml" + }, "authors": [ { "name": "William Desportes", diff --git a/scripts/ci/ci-phpcs.sh b/scripts/ci/ci-phpcs.sh index 79d8194..b197cfd 100755 --- a/scripts/ci/ci-phpcs.sh +++ b/scripts/ci/ci-phpcs.sh @@ -1,4 +1,4 @@ #!/bin/bash cd $(dirname $0)/../../ echo "Running in : $(pwd)" -./vendor/bin/phpcs --standard=phpcs.xml --no-cache --colors -p -n +composer run phpcs diff --git a/scripts/ci/ci-phpcsbf.sh b/scripts/ci/ci-phpcsbf.sh deleted file mode 100755 index 878cd80..0000000 --- a/scripts/ci/ci-phpcsbf.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash -cd $(dirname $0)/../../ -echo "Running in : $(pwd)" -./vendor/bin/phpcbf --standard=phpcs.xml diff --git a/scripts/ci/ci-phpstan.sh b/scripts/ci/ci-phpstan.sh index ed238c6..a69d006 100755 --- a/scripts/ci/ci-phpstan.sh +++ b/scripts/ci/ci-phpstan.sh @@ -1,4 +1,4 @@ #!/bin/bash cd $(dirname $0)/../../ echo "Running in : $(pwd)" -./vendor/bin/phpstan analyse src tests --configuration=phpstan.neon --level=max --memory-limit=512M +composer run phpstan diff --git a/scripts/ci/ci-phpunit.sh b/scripts/ci/ci-phpunit.sh index 82a3f08..f0c2f5b 100755 --- a/scripts/ci/ci-phpunit.sh +++ b/scripts/ci/ci-phpunit.sh @@ -1,4 +1,4 @@ #!/bin/bash cd $(dirname $0)/../../ echo "Running in : $(pwd)" -./vendor/bin/phpunit --configuration ./tests/phpunit.xml \ No newline at end of file +composer run phpunit \ No newline at end of file From 3e03f077d6bbc363f596e60d5f1724cea286c58b Mon Sep 17 00:00:00 2001 From: William Desportes Date: Sat, 8 Jun 2019 09:53:33 +0200 Subject: [PATCH 03/23] style(editorconfig): Add .editorconfig file --- .editorconfig | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..f9366fa --- /dev/null +++ b/.editorconfig @@ -0,0 +1,8 @@ +root = true + +[*] +indent_style = space +indent_size = 4 +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true From 0923f0f3b05a714f0556f9195441d3390a66ba76 Mon Sep 17 00:00:00 2001 From: William Desportes Date: Sat, 8 Jun 2019 10:45:36 +0200 Subject: [PATCH 04/23] chore(composer): Update dependencies --- composer.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/composer.json b/composer.json index e58197b..bef3181 100644 --- a/composer.json +++ b/composer.json @@ -34,14 +34,14 @@ } }, "require": { - "php": "^7.1" + "php": "^7.1", + "twig/twig": "^2.11", + "twig/extensions": "^1.5" }, "require-dev": { "phpunit/phpunit": "^7.2", "squizlabs/php_codesniffer": "^3.3", - "slevomat/coding-standard": "^4.6", - "phpstan/phpstan": "^0.9.2", - "twig/twig": "^2.0", - "twig/extensions": "^1.5" + "slevomat/coding-standard": "^5.0", + "phpstan/phpstan": "^0.11.8" } } From 835c1c7a251cdef3a69947c7eff71fa73cc6c1ef Mon Sep 17 00:00:00 2001 From: William Desportes Date: Sat, 8 Jun 2019 10:48:07 +0200 Subject: [PATCH 05/23] style(php): Use short array syntax --- src/Twig/Extension/I18n.php | 8 ++++---- src/Twig/MemoryCache.php | 2 +- src/Twig/TokenParser.php | 12 ++++++------ src/Twig/TranslationNode.php | 10 +++++----- src/plugins/MoReader.php | 6 +++--- tests/Twig/Extension/I18nTest.php | 22 +++++++++++----------- tests/plugins/MoReaderTest.php | 4 ++-- tests/utils/UtilsTest.php | 16 ++++++++-------- 8 files changed, 40 insertions(+), 40 deletions(-) diff --git a/src/Twig/Extension/I18n.php b/src/Twig/Extension/I18n.php index cfb89b5..a75ee9d 100644 --- a/src/Twig/Extension/I18n.php +++ b/src/Twig/Extension/I18n.php @@ -23,9 +23,9 @@ class I18n extends I18nExtension */ public function getFilters(): array { - return array( + return [ new TwigFilter('trans'), - ); + ]; } /** @@ -35,9 +35,9 @@ public function getFilters(): array */ public function getTokenParsers(): array { - return array( + return [ new TokenParser() - ); + ]; } } diff --git a/src/Twig/MemoryCache.php b/src/Twig/MemoryCache.php index 92c04d6..65a7567 100644 --- a/src/Twig/MemoryCache.php +++ b/src/Twig/MemoryCache.php @@ -16,7 +16,7 @@ class MemoryCache implements \Twig_CacheInterface * * @var array */ - private $memory = array(); + private $memory = []; /** * Generate a cache key diff --git a/src/Twig/TokenParser.php b/src/Twig/TokenParser.php index c3de8b7..0690780 100644 --- a/src/Twig/TokenParser.php +++ b/src/Twig/TokenParser.php @@ -35,30 +35,30 @@ public function parse(Token $token): TransNode } else { $stream->expect(Token::BLOCK_END_TYPE); $body = $this->parser->subparse( - array($this, 'decideForFork') + [$this, 'decideForFork'] ); $nextVal = $stream->next()->getValue(); if ($nextVal === 'notes') { $stream->expect(Token::BLOCK_END_TYPE); $notes = $this->parser->subparse( - array($this, 'decideForEnd'), true + [$this, 'decideForEnd'], true ); } elseif ($nextVal === 'plural') { $pluralsNbr = $this->parser->getExpressionParser()->parseExpression(); $stream->expect(Token::BLOCK_END_TYPE); $plural = $this->parser->subparse( - array($this, 'decideForFork') + [$this, 'decideForFork'] ); if ('notes' === $stream->next()->getValue()) { $stream->expect(Token::BLOCK_END_TYPE); $notes = $this->parser->subparse( - array($this, 'decideForEnd'), true + [$this, 'decideForEnd'], true ); } } elseif ($nextVal === 'context') { $stream->expect(Token::BLOCK_END_TYPE); $context = $this->parser->subparse( - array($this, 'decideForEnd'), true + [$this, 'decideForEnd'], true ); } } @@ -77,7 +77,7 @@ public function parse(Token $token): TransNode public function decideForFork(Token $token): bool { return $token->test( - array('plural', 'context', 'notes', 'endtrans') + ['plural', 'context', 'notes', 'endtrans'] ); } diff --git a/src/Twig/TranslationNode.php b/src/Twig/TranslationNode.php index 96bba85..b8b3be7 100644 --- a/src/Twig/TranslationNode.php +++ b/src/Twig/TranslationNode.php @@ -37,7 +37,7 @@ public function __construct( $lineno, $tag = null ) { - $nodes = array('body' => $body); + $nodes = ['body' => $body]; if (null !== $context) { $nodes['context'] = $context; } @@ -51,7 +51,7 @@ public function __construct( $nodes['plural'] = $plural; } - Node::__construct($nodes, array(), $lineno, $tag); + Node::__construct($nodes, [], $lineno, $tag); } /** @@ -81,7 +81,7 @@ public function compile(Compiler $compiler): void if ($this->hasNode('notes')) { $message = trim($this->getNode('notes')->getAttribute('data')); // line breaks are removed - $message = str_replace(array("\n", "\r"), ' ', $message); + $message = str_replace(["\n", "\r"], ' ', $message); $compiler->write("// l10n: {$message}\n"); } if ($vars) { @@ -89,7 +89,7 @@ public function compile(Compiler $compiler): void if ($this->hasNode('plural')) { $compiler->raw(', ')->subcompile($pMessage)->raw(', abs(')->subcompile($this->hasNode('count') ? $this->getNode('count') : null)->raw(')'); } - $compiler->raw('), array('); + $compiler->raw('), ['); foreach ($vars as $var) { $attrName = $var->getAttribute('name'); if ($attrName === 'count') { @@ -102,7 +102,7 @@ public function compile(Compiler $compiler): void $compiler->string('%'.$attrName.'%')->raw(' => ')->subcompile($var)->raw(', '); } } - $compiler->raw("));\n"); + $compiler->raw("]);\n"); } else { $compiler->write('echo '.$function.'('); if ($this->hasNode('context')) { diff --git a/src/plugins/MoReader.php b/src/plugins/MoReader.php index 65d9f88..673b2b8 100644 --- a/src/plugins/MoReader.php +++ b/src/plugins/MoReader.php @@ -109,19 +109,19 @@ public function readFile(string $file): stdClass */ public function readTranslations(): array { - $data = array(); + $data = []; for ($counter = 0; $counter < $this->data->nbrOfStrings; $counter++) { $msgId = null; $msgStr = null; try { $msgId = $this->readStringFromTable($counter, $this->data->msgIdTable); } catch(Exception $e){ - $msgId = array(''); + $msgId = ['']; } try { $msgStr = $this->readStringFromTable($counter, $this->data->msgStrTable); } catch(Exception $e){ - $msgStr = array(); + $msgStr = []; } $this->processRecord($data, $msgId, $msgStr); } diff --git a/tests/Twig/Extension/I18nTest.php b/tests/Twig/Extension/I18nTest.php index 0cabfd1..0026cb9 100644 --- a/tests/Twig/Extension/I18nTest.php +++ b/tests/Twig/Extension/I18nTest.php @@ -36,7 +36,7 @@ public function testInstance(): TwigEnv //$tmpDir = $dataDir."twig-templates".$S."tmp".$S; $moReader = new MoReader( - array("localeDir" => $dataDir) + ["localeDir" => $dataDir] ); $data = $moReader->readFile($dataDir."abc.mo"); Launcher::$plugin = $moReader; @@ -44,10 +44,10 @@ public function testInstance(): TwigEnv $loader = new \Twig_Loader_Filesystem(); $memoryCache = new \Wdes\PIL\Twig\MemoryCache(); $twig = new TwigEnv( - $loader, array( + $loader, [ 'cache' => $memoryCache,//$tmpDir | false 'debug' => true - ) + ] ); $twig->addExtension(new ExtensionI18n()); @@ -72,7 +72,7 @@ public function testSimpleTranslation(TwigEnv $Twig): void 'echo \Wdes\PIL\Launcher::getPlugin()->gettext("Translate this");', $generatedCode ); - $html = $template->render(array()); + $html = $template->render([]); $this->assertEquals("Traduis ça", $html); $this->assertNotEmpty($html); } @@ -98,7 +98,7 @@ public function testSimpleTranslationWithComment(TwigEnv $Twig): void '// l10n: And note', $generatedCode ); - $html = $template->render(array()); + $html = $template->render([]); $this->assertEquals("Traduis ça", $html); $this->assertNotEmpty($html); } @@ -121,7 +121,7 @@ public function testSimpleTranslationWithContext(TwigEnv $Twig): void 'echo \Wdes\PIL\Launcher::getPlugin()->pgettext("NayanCat", "Translate this");', $generatedCode ); - $html = $template->render(array()); + $html = $template->render([]); $this->assertEquals("Traduis ça", $html); $this->assertNotEmpty($html); } @@ -145,7 +145,7 @@ public function testPluralTranslation(TwigEnv $Twig): void ' array("%nbr%" => ($context["nbr"] ?? null), ));', $generatedCode ); - $html = $template->render(array("nbr" => 5)); + $html = $template->render(["nbr" => 5]); $this->assertEquals("One person", $html); $this->assertNotEmpty($html); } @@ -174,7 +174,7 @@ public function testPluralTranslationWithComment(TwigEnv $Twig): void '// l10n: Number of users', $generatedCode ); - $html = $template->render(array("nbr" => 5)); + $html = $template->render(["nbr" => 5]); $this->assertEquals("one user likes this.", $html); $this->assertNotEmpty($html); } @@ -196,7 +196,7 @@ public function testSimplePluralTranslation(TwigEnv $Twig): void 'echo \Wdes\PIL\Launcher::getPlugin()->ngettext("One person", "persons", abs(($context["a"] ?? null)));', $generatedCode ); - $html = $template->render(array("nbr" => 5)); + $html = $template->render(["nbr" => 5]); $this->assertEquals("One person", $html); $this->assertNotEmpty($html); } @@ -220,7 +220,7 @@ public function testSimplePluralTranslationCount(TwigEnv $Twig): void ' ($context["a"] ?? null), "count", array())));', $generatedCode ); - $html = $template->render(array("a" => array("1", "2"))); + $html = $template->render(["a" => ["1", "2"]]); $this->assertEquals("One person", $html); $this->assertNotEmpty($html); } @@ -246,7 +246,7 @@ public function testSimplePluralTranslationCountAndVars(TwigEnv $Twig): void ' $this->source, ($context["a"] ?? null), "count", array())), ));', $generatedCode ); - $html = $template->render(array("a" => array("1", "2"), "nbrdogs" => 3)); + $html = $template->render(["a" => ["1", "2"], "nbrdogs" => 3]); $this->assertEquals("One person", $html); $this->assertNotEmpty($html); } diff --git a/tests/plugins/MoReaderTest.php b/tests/plugins/MoReaderTest.php index 72d2056..2437058 100644 --- a/tests/plugins/MoReaderTest.php +++ b/tests/plugins/MoReaderTest.php @@ -27,7 +27,7 @@ class MoReaderTest extends TestCase public function testInstance(): MoReader { $moReader = new MoReader( - array("localeDir" => self::$dir) + ["localeDir" => self::$dir] ); $this->assertInstanceOf(MoReader::class, $moReader); @@ -46,7 +46,7 @@ public function testInstance(): MoReader public function testException(): void { new MoReader( - array("localeDir" => self::$dir.str_shuffle("abcdefghijklmnopqrstuv")) + ["localeDir" => self::$dir.str_shuffle("abcdefghijklmnopqrstuv")] ); } diff --git a/tests/utils/UtilsTest.php b/tests/utils/UtilsTest.php index ecee698..0788c59 100644 --- a/tests/utils/UtilsTest.php +++ b/tests/utils/UtilsTest.php @@ -25,14 +25,14 @@ class UtilsTest extends TestCase */ public function ELFHashProvider(): array { - return array( - array("0",48), - array("ABCDEFGHIJKLMN", 178683902), - array("Dashboard", 166269444), - array("ABCDEFGHIJKLMNABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz", 163039834), - array("abcdefghijklmnopqrstuvwxyz1234567890", 126631744), - array("jdfgsdhfsdfsd 6445dsfsd7fg/*/+bfjsdgf%$^", 248446350) - ); + return [ + ["0",48], + ["ABCDEFGHIJKLMN", 178683902], + ["Dashboard", 166269444], + ["ABCDEFGHIJKLMNABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz", 163039834], + ["abcdefghijklmnopqrstuvwxyz1234567890", 126631744], + ["jdfgsdhfsdfsd 6445dsfsd7fg/*/+bfjsdgf%$^", 248446350], + ]; } /** From e1803bdc4af0f96e1e319d6615ff487c20fe3db7 Mon Sep 17 00:00:00 2001 From: William Desportes Date: Sat, 8 Jun 2019 10:49:04 +0200 Subject: [PATCH 06/23] test(twig): Fix twig tests --- src/Twig/MemoryCache.php | 16 ++-- tests/Twig/Extension/I18nTest.php | 118 ++++++++++++++---------------- 2 files changed, 62 insertions(+), 72 deletions(-) diff --git a/src/Twig/MemoryCache.php b/src/Twig/MemoryCache.php index 65a7567..37e883a 100644 --- a/src/Twig/MemoryCache.php +++ b/src/Twig/MemoryCache.php @@ -5,11 +5,14 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ namespace Wdes\PIL\Twig; +use \Twig\Cache\CacheInterface; +use \Twig\TemplateWrapper; + /** * Token parser for Twig * @license MPL-2.0 */ -class MemoryCache implements \Twig_CacheInterface +class MemoryCache implements CacheInterface { /** * Contains all templates @@ -67,10 +70,10 @@ public function getTimestamp($key): int /** * Get the cached string for key * - * @param \Twig_Template $template The template + * @param TemplateWrapper $template The template * @return string */ - public function getFromCache(\Twig_Template $template): string + public function getFromCache(TemplateWrapper $template): string { return $this->memory["memcache_".$template->getTemplateName()]; } @@ -78,17 +81,16 @@ public function getFromCache(\Twig_Template $template): string /** * Extract source code from memory cache * - * @param \Twig_Template $template The template + * @param TemplateWrapper $template The template * @return string */ - public function extractDoDisplayFromCache(\Twig_Template $template): string + public function extractDoDisplayFromCache(TemplateWrapper $template): string { $content = self::getFromCache($template); // "/function ([a-z_]+)\(" preg_match_all( - '/protected function doDisplay\(([a-z\s,\$=\(\)]+)\)([\s]+){([=%\sa-z\/0-9-\>:\(\)\\\";.,\$\[\]?_-]+)/msi', $content, $output_array + '/protected function doDisplay\(([a-z\s,\$=\[\]]+)\)([\s]+){([=%\sa-z\/0-9-\>:\(\)\\\";.,\$\[\]?_-]+)/msi', $content, $output_array ); - //echo $content; return $output_array[3][0]; } diff --git a/tests/Twig/Extension/I18nTest.php b/tests/Twig/Extension/I18nTest.php index 0026cb9..cd5c180 100644 --- a/tests/Twig/Extension/I18nTest.php +++ b/tests/Twig/Extension/I18nTest.php @@ -19,15 +19,27 @@ */ class I18nTest extends TestCase { + /** + * The memory cache + * + * @var \Wdes\PIL\Twig\MemoryCache + */ + private $memoryCache = null; + + /** + * The TwigEnv object + * + * @var TwigEnv + */ + private $twig = null; /** - * testInstance + * Set up the instance * - * @return TwigEnv + * @return void */ - public function testInstance(): TwigEnv + public function setUp(): void { - global $memoryCache; $S = DIRECTORY_SEPARATOR; $dataDir = __DIR__.$S."..".$S."..".$S."data".$S; @@ -42,32 +54,27 @@ public function testInstance(): TwigEnv Launcher::$plugin = $moReader; $loader = new \Twig_Loader_Filesystem(); - $memoryCache = new \Wdes\PIL\Twig\MemoryCache(); - $twig = new TwigEnv( + $this->memoryCache = new \Wdes\PIL\Twig\MemoryCache(); + $this->twig = new TwigEnv( $loader, [ - 'cache' => $memoryCache,//$tmpDir | false - 'debug' => true + 'cache' => $this->memoryCache,//$tmpDir | false + 'debug' => true ] ); - $twig->addExtension(new ExtensionI18n()); - $this->assertInstanceOf(TwigEnv::class, $twig); - return $twig; + $this->twig->addExtension(new ExtensionI18n()); } /** * Test simple translation - * @depends testInstance - * @param TwigEnv $Twig TwigEnv instance * @return void */ - public function testSimpleTranslation(TwigEnv $Twig): void + public function testSimpleTranslation(): void { - global $memoryCache; - $template = $Twig->createTemplate( + $template = $this->twig->createTemplate( '{% trans "Translate this" %}' ); - $generatedCode = $memoryCache->extractDoDisplayFromCache($template); + $generatedCode = $this->memoryCache->extractDoDisplayFromCache($template); $this->assertContains( 'echo \Wdes\PIL\Launcher::getPlugin()->gettext("Translate this");', $generatedCode @@ -79,17 +86,14 @@ public function testSimpleTranslation(TwigEnv $Twig): void /** * Test simple translation with a comment - * @depends testInstance - * @param TwigEnv $Twig TwigEnv instance * @return void */ - public function testSimpleTranslationWithComment(TwigEnv $Twig): void + public function testSimpleTranslationWithComment(): void { - global $memoryCache; - $template = $Twig->createTemplate( + $template = $this->twig->createTemplate( '{% trans %}Translate this{% notes %}And note{% endtrans %}' ); - $generatedCode = $memoryCache->extractDoDisplayFromCache($template); + $generatedCode = $this->memoryCache->extractDoDisplayFromCache($template); $this->assertContains( 'echo \Wdes\PIL\Launcher::getPlugin()->gettext("Translate this");', $generatedCode @@ -105,17 +109,14 @@ public function testSimpleTranslationWithComment(TwigEnv $Twig): void /** * Test simple translation with context - * @depends testInstance - * @param TwigEnv $Twig TwigEnv instance * @return void */ - public function testSimpleTranslationWithContext(TwigEnv $Twig): void + public function testSimpleTranslationWithContext(): void { - global $memoryCache; - $template = $Twig->createTemplate( + $template = $this->twig->createTemplate( '{% trans %}Translate this{% context %}NayanCat{% endtrans %}' ); - $generatedCode = $memoryCache->extractDoDisplayFromCache($template); + $generatedCode = $this->memoryCache->extractDoDisplayFromCache($template); $this->assertContains( 'echo \Wdes\PIL\Launcher::getPlugin()->pgettext("NayanCat", "Translate this");', @@ -128,21 +129,18 @@ public function testSimpleTranslationWithContext(TwigEnv $Twig): void /** * Test plural translation - * @depends testInstance - * @param TwigEnv $Twig TwigEnv instance * @return void */ - public function testPluralTranslation(TwigEnv $Twig): void + public function testPluralTranslation(): void { - global $memoryCache; - $template = $Twig->createTemplate( + $template = $this->twig->createTemplate( '{% trans %}One person{% plural nbr_persons %}{{ nbr }} persons{% endtrans %}' ); - $generatedCode = $memoryCache->extractDoDisplayFromCache($template); + $generatedCode = $this->memoryCache->extractDoDisplayFromCache($template); $this->assertContains( 'echo strtr(\Wdes\PIL\Launcher::getPlugin()->ngettext("One person"'. ', "%nbr% persons", abs(($context["nbr_persons"] ?? null))),'. - ' array("%nbr%" => ($context["nbr"] ?? null), ));', + ' ["%nbr%" => ($context["nbr"] ?? null), ]);', $generatedCode ); $html = $template->render(["nbr" => 5]); @@ -152,22 +150,19 @@ public function testPluralTranslation(TwigEnv $Twig): void /** * Test plural translation with comment - * @depends testInstance - * @param TwigEnv $Twig TwigEnv instance * @return void */ - public function testPluralTranslationWithComment(TwigEnv $Twig): void + public function testPluralTranslationWithComment(): void { - global $memoryCache; - $template = $Twig->createTemplate( + $template = $this->twig->createTemplate( '{% trans %}one user likes this.{% plural nbr_persons %}{{ nbr }} users likes this.{% notes %}Number of users{% endtrans %}' ); - $generatedCode = $memoryCache->extractDoDisplayFromCache($template); + $generatedCode = $this->memoryCache->extractDoDisplayFromCache($template); $this->assertContains( 'echo strtr(\Wdes\PIL\Launcher::getPlugin()->ngettext('. '"one user likes this.", "%nbr% users likes this.",'. ' abs(($context["nbr_persons"] ?? null))),'. - ' array("%nbr%" => ($context["nbr"] ?? null), ));', + ' ["%nbr%" => ($context["nbr"] ?? null), ]);', $generatedCode ); $this->assertContains( @@ -181,17 +176,14 @@ public function testPluralTranslationWithComment(TwigEnv $Twig): void /** * Test simple plural translation - * @depends testInstance - * @param TwigEnv $Twig TwigEnv instance * @return void */ - public function testSimplePluralTranslation(TwigEnv $Twig): void + public function testSimplePluralTranslation(): void { - global $memoryCache; - $template = $Twig->createTemplate( + $template = $this->twig->createTemplate( '{% trans %}One person{% plural a %}persons{% endtrans %}' ); - $generatedCode = $memoryCache->extractDoDisplayFromCache($template); + $generatedCode = $this->memoryCache->extractDoDisplayFromCache($template); $this->assertContains( 'echo \Wdes\PIL\Launcher::getPlugin()->ngettext("One person", "persons", abs(($context["a"] ?? null)));', $generatedCode @@ -203,21 +195,20 @@ public function testSimplePluralTranslation(TwigEnv $Twig): void /** * Test simple plural translation using count - * @depends testInstance - * @param TwigEnv $Twig TwigEnv instance + + * @return void */ - public function testSimplePluralTranslationCount(TwigEnv $Twig): void + public function testSimplePluralTranslationCount(): void { - global $memoryCache; - $template = $Twig->createTemplate( + $template = $this->twig->createTemplate( '{% trans %}One person{% plural a.count %}persons{% endtrans %}' ); - $generatedCode = $memoryCache->extractDoDisplayFromCache($template); + $generatedCode = $this->memoryCache->extractDoDisplayFromCache($template); $this->assertContains( 'echo \Wdes\PIL\Launcher::getPlugin()->ngettext("One person",'. ' "persons", abs(twig_get_attribute($this->env, $this->source,'. - ' ($context["a"] ?? null), "count", array())));', + ' ($context["a"] ?? null), "count", [], "any", false, false, false, 1)));', $generatedCode ); $html = $template->render(["a" => ["1", "2"]]); @@ -227,23 +218,20 @@ public function testSimplePluralTranslationCount(TwigEnv $Twig): void /** * Test simple plural translation using count and vars - * @depends testInstance - * @param TwigEnv $Twig TwigEnv instance * @return void */ - public function testSimplePluralTranslationCountAndVars(TwigEnv $Twig): void + public function testSimplePluralTranslationCountAndVars(): void { - global $memoryCache; - $template = $Twig->createTemplate( + $template = $this->twig->createTemplate( '{% trans %}One person{% plural a.count %}persons and {{ count }} dogs{% endtrans %}' ); - $generatedCode = $memoryCache->extractDoDisplayFromCache($template); + $generatedCode = $this->memoryCache->extractDoDisplayFromCache($template); $this->assertContains( 'echo strtr(\Wdes\PIL\Launcher::getPlugin()->ngettext("One person",'. ' "persons and %count% dogs", abs(twig_get_attribute($this->env,'. - ' $this->source, ($context["a"] ?? null), "count", array()))),'. - ' array("%count%" => abs(twig_get_attribute($this->env,'. - ' $this->source, ($context["a"] ?? null), "count", array())), ));', + ' $this->source, ($context["a"] ?? null), "count", [], "any", false, false, false, 1))),'. + ' ["%count%" => abs(twig_get_attribute($this->env,'. + ' $this->source, ($context["a"] ?? null), "count", [], "any", false, false, false, 1)), ]);', $generatedCode ); $html = $template->render(["a" => ["1", "2"], "nbrdogs" => 3]); From 167d5b263142fb2a78b92d0d5a1ba074066e1d74 Mon Sep 17 00:00:00 2001 From: William Desportes Date: Sat, 8 Jun 2019 10:57:32 +0200 Subject: [PATCH 07/23] feat(twig): remove last comma in arrays See: https://stackoverflow.com/a/8780881/5155484 --- src/Twig/TranslationNode.php | 15 ++++++++++++--- tests/Twig/Extension/I18nTest.php | 6 +++--- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/Twig/TranslationNode.php b/src/Twig/TranslationNode.php index b8b3be7..789e64c 100644 --- a/src/Twig/TranslationNode.php +++ b/src/Twig/TranslationNode.php @@ -90,16 +90,25 @@ public function compile(Compiler $compiler): void $compiler->raw(', ')->subcompile($pMessage)->raw(', abs(')->subcompile($this->hasNode('count') ? $this->getNode('count') : null)->raw(')'); } $compiler->raw('), ['); - foreach ($vars as $var) { + $lastKey = array_key_last($vars); + foreach ($vars as $key => $var) { $attrName = $var->getAttribute('name'); if ($attrName === 'count') { $compiler->string('%count%')->raw(' => abs('); if ($this->hasNode('count')) { $compiler->subcompile($this->getNode('count')); } - $compiler->raw('), '); + if ($key === $lastKey) { + $compiler->raw(')'); + } else { + $compiler->raw('), '); + } } else { - $compiler->string('%'.$attrName.'%')->raw(' => ')->subcompile($var)->raw(', '); + if ($key === $lastKey) { + $compiler->string('%'.$attrName.'%')->raw(' => ')->subcompile($var); + } else { + $compiler->string('%'.$attrName.'%')->raw(' => ')->subcompile($var)->raw(', '); + } } } $compiler->raw("]);\n"); diff --git a/tests/Twig/Extension/I18nTest.php b/tests/Twig/Extension/I18nTest.php index cd5c180..50985c5 100644 --- a/tests/Twig/Extension/I18nTest.php +++ b/tests/Twig/Extension/I18nTest.php @@ -140,7 +140,7 @@ public function testPluralTranslation(): void $this->assertContains( 'echo strtr(\Wdes\PIL\Launcher::getPlugin()->ngettext("One person"'. ', "%nbr% persons", abs(($context["nbr_persons"] ?? null))),'. - ' ["%nbr%" => ($context["nbr"] ?? null), ]);', + ' ["%nbr%" => ($context["nbr"] ?? null)]);', $generatedCode ); $html = $template->render(["nbr" => 5]); @@ -162,7 +162,7 @@ public function testPluralTranslationWithComment(): void 'echo strtr(\Wdes\PIL\Launcher::getPlugin()->ngettext('. '"one user likes this.", "%nbr% users likes this.",'. ' abs(($context["nbr_persons"] ?? null))),'. - ' ["%nbr%" => ($context["nbr"] ?? null), ]);', + ' ["%nbr%" => ($context["nbr"] ?? null)]);', $generatedCode ); $this->assertContains( @@ -231,7 +231,7 @@ public function testSimplePluralTranslationCountAndVars(): void ' "persons and %count% dogs", abs(twig_get_attribute($this->env,'. ' $this->source, ($context["a"] ?? null), "count", [], "any", false, false, false, 1))),'. ' ["%count%" => abs(twig_get_attribute($this->env,'. - ' $this->source, ($context["a"] ?? null), "count", [], "any", false, false, false, 1)), ]);', + ' $this->source, ($context["a"] ?? null), "count", [], "any", false, false, false, 1))]);', $generatedCode ); $html = $template->render(["a" => ["1", "2"], "nbrdogs" => 3]); From 29756fc3ff3da22430bab0fb32bc6e2bbf7310fc Mon Sep 17 00:00:00 2001 From: William Desportes Date: Sat, 8 Jun 2019 11:05:16 +0200 Subject: [PATCH 08/23] ci(php): Add php 8.0 --- .travis.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.travis.yml b/.travis.yml index 41f3309..e3843de 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,6 +41,14 @@ jobs: name: "PHPUNIT - PHP 7.3" after_success: - bash <(curl -s https://codecov.io/bash) -cF php + - stage: tests + php: "8.0" + env: + - CI_TYPE=phpunit + - CI_COMPOSER=yes + name: "PHPUNIT - PHP 8.0" + after_success: + - bash <(curl -s https://codecov.io/bash) -cF php - stage: tests os: osx language: node_js From 8e1662c8dd4592693b15fadb93010693f0456c39 Mon Sep 17 00:00:00 2001 From: William Desportes Date: Sat, 8 Jun 2019 11:05:55 +0200 Subject: [PATCH 09/23] chore(version): Update version to 1.0.0 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index bef3181..25ab96d 100644 --- a/composer.json +++ b/composer.json @@ -5,7 +5,7 @@ "type": "library", "readme": "https://github.com/wdes/php-I18n-l10n/blob/master/README.md", "license": "MPL-2.0", - "version": "1.0.0-alpha1", + "version": "1.0.0", "support": { "email": "williamdes@wdes.fr", "issues": "https://github.com/wdes/php-I18n-l10n/issues", From 80e6891d07a1c48d7d1fee8f484873dcca75c0f5 Mon Sep 17 00:00:00 2001 From: William Desportes Date: Sat, 8 Jun 2019 11:13:54 +0200 Subject: [PATCH 10/23] chore(phpstan): Fix reported errors --- src/plugins/MoReader.php | 40 ++++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/src/plugins/MoReader.php b/src/plugins/MoReader.php index 673b2b8..6d9d2b1 100644 --- a/src/plugins/MoReader.php +++ b/src/plugins/MoReader.php @@ -56,8 +56,13 @@ public function __construct(array $options) */ public function readFile(string $file): stdClass { - $this->data = new stdClass(); - $this->fileRes = fopen($file, 'rb'); + $this->data = new stdClass(); + $res = fopen($file, 'rb'); + if (is_resource($res)) { + $this->fileRes = $res; + } else { + throw new Exception($file . " could not be open."); + } $this->data->endian = self::determineByteOrder($this->fileRes); if ($this->data->endian === -1) { fclose($this->fileRes); @@ -169,7 +174,12 @@ public function readStringFromTable(int $index, array $table): array if ($size > 0) { $offset = $table[$sizeKey + 1]; fseek($this->fileRes, $offset); - return explode("\0", fread($this->fileRes, $size)); + $read = fread($this->fileRes, $size); + if (is_string($read)) { + return explode("\0", $read); + } else { + throw new Exception("read error !"); + } } throw new Exception("size error !"); } @@ -208,10 +218,15 @@ public static function determineByteOrder($res): int */ public static function readIntegerList(int $endian, $res, int $nbr): array { - if ($endian === self::ENDIAN_LITTLE) { - return unpack('V' . $nbr, fread($res, 4 * $nbr)); + $read = fread($res, 4 * $nbr); + if (is_string($read)) { + if ($endian === self::ENDIAN_LITTLE) { + return unpack('V' . $nbr, $read); + } else { + return unpack('N' . $nbr, $read); + } } else { - return unpack('N' . $nbr, fread($res, 4 * $nbr)); + throw new Exception("read error !"); } } @@ -226,12 +241,17 @@ public static function readIntegerList(int $endian, $res, int $nbr): array */ public static function readInteger(int $endian, $res) { - if ($endian === self::ENDIAN_LITTLE) { - $result = unpack('Vint', fread($res, 4)); + $read = fread($res, 4); + if (is_string($read)) { + if ($endian === self::ENDIAN_LITTLE) { + $result = unpack('Vint', $read); + } else { + $result = unpack('Nint', $read); + } + return $result['int']; } else { - $result = unpack('Nint', fread($res, 4)); + throw new Exception("read error !"); } - return $result['int']; } /** From 65a695a12383c19292a6e795d1753cb10d015863 Mon Sep 17 00:00:00 2001 From: William Desportes Date: Sat, 8 Jun 2019 11:14:21 +0200 Subject: [PATCH 11/23] style(phpcs): Fix style errors --- tests/Twig/Extension/I18nTest.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/Twig/Extension/I18nTest.php b/tests/Twig/Extension/I18nTest.php index 50985c5..89c081e 100644 --- a/tests/Twig/Extension/I18nTest.php +++ b/tests/Twig/Extension/I18nTest.php @@ -40,7 +40,6 @@ class I18nTest extends TestCase */ public function setUp(): void { - $S = DIRECTORY_SEPARATOR; $dataDir = __DIR__.$S."..".$S."..".$S."data".$S; @@ -53,7 +52,7 @@ public function setUp(): void $data = $moReader->readFile($dataDir."abc.mo"); Launcher::$plugin = $moReader; - $loader = new \Twig_Loader_Filesystem(); + $loader = new \Twig_Loader_Filesystem(); $this->memoryCache = new \Wdes\PIL\Twig\MemoryCache(); $this->twig = new TwigEnv( $loader, [ From 2ffc810dd3210759d54e90423ae63a96b5eceb2e Mon Sep 17 00:00:00 2001 From: William Desportes Date: Sat, 8 Jun 2019 11:05:16 +0200 Subject: [PATCH 12/23] revert(ci): Revert "add php 8.0" This reverts commit 29756fc3ff3da22430bab0fb32bc6e2bbf7310fc. --- .travis.yml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index e3843de..41f3309 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,14 +41,6 @@ jobs: name: "PHPUNIT - PHP 7.3" after_success: - bash <(curl -s https://codecov.io/bash) -cF php - - stage: tests - php: "8.0" - env: - - CI_TYPE=phpunit - - CI_COMPOSER=yes - name: "PHPUNIT - PHP 8.0" - after_success: - - bash <(curl -s https://codecov.io/bash) -cF php - stage: tests os: osx language: node_js From 5b11c2623a058b2e627c7efb6383ec76f8a231ce Mon Sep 17 00:00:00 2001 From: William Desportes Date: Sat, 8 Jun 2019 11:56:59 +0200 Subject: [PATCH 13/23] chore(code): remove unused code and improve I18n test --- src/plugins/MoReader.php | 1 - tests/Twig/Extension/I18nTest.php | 17 ++++++++--------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/plugins/MoReader.php b/src/plugins/MoReader.php index 6d9d2b1..814b502 100644 --- a/src/plugins/MoReader.php +++ b/src/plugins/MoReader.php @@ -44,7 +44,6 @@ public function __construct(array $options) { if (is_dir($options['localeDir']) == false) { throw new Exception("The directory does not exist : ".$options['localeDir']); - return; } } diff --git a/tests/Twig/Extension/I18nTest.php b/tests/Twig/Extension/I18nTest.php index 89c081e..14579a0 100644 --- a/tests/Twig/Extension/I18nTest.php +++ b/tests/Twig/Extension/I18nTest.php @@ -9,8 +9,10 @@ use \PHPUnit\Framework\TestCase; use \Wdes\PIL\Twig\Extension\I18n as ExtensionI18n; use \Twig\Environment as TwigEnv; +use \Twig\Loader\FilesystemLoader as TwigLoaderFilesystem; use \Wdes\PIL\plugins\MoReader; use \Wdes\PIL\Launcher; +use \Wdes\PIL\Twig\MemoryCache; /** * Test class for Utils @@ -22,7 +24,7 @@ class I18nTest extends TestCase /** * The memory cache * - * @var \Wdes\PIL\Twig\MemoryCache + * @var MemoryCache */ private $memoryCache = null; @@ -43,20 +45,17 @@ public function setUp(): void $S = DIRECTORY_SEPARATOR; $dataDir = __DIR__.$S."..".$S."..".$S."data".$S; - $templatesDir = $dataDir."twig-templates".$S; - //$tmpDir = $dataDir."twig-templates".$S."tmp".$S; - - $moReader = new MoReader( + $moReader = new MoReader( ["localeDir" => $dataDir] ); - $data = $moReader->readFile($dataDir."abc.mo"); + $moReader->readFile($dataDir . "abc.mo"); Launcher::$plugin = $moReader; - $loader = new \Twig_Loader_Filesystem(); - $this->memoryCache = new \Wdes\PIL\Twig\MemoryCache(); + $loader = new TwigLoaderFilesystem(); + $this->memoryCache = new MemoryCache(); $this->twig = new TwigEnv( $loader, [ - 'cache' => $this->memoryCache,//$tmpDir | false + 'cache' => $this->memoryCache, 'debug' => true ] ); From 7b9c448d18aa3a1024419a053c4806bd5b2b38fe Mon Sep 17 00:00:00 2001 From: William Desportes Date: Sat, 8 Jun 2019 15:11:24 +0200 Subject: [PATCH 14/23] feat(scripts): Add scripts to generate translations Signed-off-by: William Desportes --- composer.json | 3 +- example/simple.php | 30 ++++++ example/templates/homepage.twig | 6 ++ scripts/tools/generate-pot.sh | 40 ++++++++ scripts/tools/generate-twig-cache.php | 126 ++++++++++++++++++++++++++ scripts/tools/update-po-files.php | 99 ++++++++++++++++++++ scripts/update-example.sh | 23 +++++ 7 files changed, 326 insertions(+), 1 deletion(-) create mode 100755 example/simple.php create mode 100755 example/templates/homepage.twig create mode 100755 scripts/tools/generate-pot.sh create mode 100755 scripts/tools/generate-twig-cache.php create mode 100755 scripts/tools/update-po-files.php create mode 100755 scripts/update-example.sh diff --git a/composer.json b/composer.json index 25ab96d..69e74f9 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,8 @@ "phpcs": "phpcs --standard=phpcs.xml --no-cache --colors -p -n", "phpcbf": "phpcbf --standard=phpcs.xml", "phpstan": "phpstan analyse src tests --configuration=phpstan.neon --level=max", - "phpunit": "phpunit --configuration ./tests/phpunit.xml" + "phpunit": "phpunit --configuration ./tests/phpunit.xml", + "update:example": "./scripts/update-example.sh" }, "authors": [ { diff --git a/example/simple.php b/example/simple.php new file mode 100755 index 0000000..3471fca --- /dev/null +++ b/example/simple.php @@ -0,0 +1,30 @@ + $dataDir] +); +$moReader->readFile($dataDir . "fr.mo"); // Load the file you want (a sepecific language for example) +Launcher::$plugin = $moReader; + +$loader = new TwigLoaderFilesystem([ __DIR__ . '/templates/' ]); // Load all templates from the dir +$twig = new TwigEnvironment($loader); + +$twig->addExtension(new ExtensionI18n()); +echo $twig->render( + 'homepage.twig', // Can be found in the templates directory + [ + 'keyForTwig' => 'theValue', // Just an example line ;) + 'say' => 'Hello world' + ] +); diff --git a/example/templates/homepage.twig b/example/templates/homepage.twig new file mode 100755 index 0000000..7736007 --- /dev/null +++ b/example/templates/homepage.twig @@ -0,0 +1,6 @@ + + {% trans %}Homepage{% endtrans %} + + {{ say }} + + diff --git a/scripts/tools/generate-pot.sh b/scripts/tools/generate-pot.sh new file mode 100755 index 0000000..3a026a2 --- /dev/null +++ b/scripts/tools/generate-pot.sh @@ -0,0 +1,40 @@ +#!/bin/bash +## +# @license http://unlicense.org/UNLICENSE The UNLICENSE +# @author William Desportes +## + +if [ -z "$1" ] && [ -z "$2" ]; then + echo "usage: generate-pot.sh search/dir locale/dir project.pot" + exit 1; +fi + +if [ -z "$1" ]; then + echo "Missing search dir"; + exit 1; +fi + +if [ -z "$3" ]; then + echo "Missing locale dir"; + exit 1; +fi + +if [ -z "$3" ]; then + echo "Missing .pot filename"; + exit 1; +fi + +echo "Searching into $1 for *.php, output $3 into $2"; + +xgettext \ + --force-po --from-code=UTF-8 \ + --default-domain=example \ + --copyright-holder="William Desportes" \ + --msgid-bugs-address=williamdes@wdes.fr \ + --from-code=utf-8 \ + --keyword=gettext --keyword=pgettext:1c,2 --keyword=ngettext:1,2 \ + -p $2 \ + --from-code=UTF-8 \ + --add-comments=l10n \ + --add-location -L PHP $(find "$1" \( -name "*.php" \) | sort) \ + -o "$3" diff --git a/scripts/tools/generate-twig-cache.php b/scripts/tools/generate-twig-cache.php new file mode 100755 index 0000000..2e828a9 --- /dev/null +++ b/scripts/tools/generate-twig-cache.php @@ -0,0 +1,126 @@ +#!/usr/bin/env php + + */ + +$options = getopt( + "", [ + "twig-cache-dir:", + "twig-templates-dir:", + "twig-templates-po-files:", + "json-mapping:", + "title:", + "copyright:", + "package-version:", + ] +); + +if (! (is_dir($options["twig-cache-dir"]) || is_link($options["twig-cache-dir"]) )) { + echo $options["twig-cache-dir"] . " is not a directory." . PHP_EOL; + exit(1); +} else { + $options["twig-cache-dir"] = realpath($options["twig-cache-dir"]) . DIRECTORY_SEPARATOR; +} + +if (! (is_dir($options["twig-templates-dir"]) || is_link($options["twig-templates-dir"]) )) { + echo $options["twig-templates-dir"] . " is not a directory." . PHP_EOL; + exit(1); +} + +if (empty($options['twig-templates-po-files'])) { + echo $options['twig-templates-po-files'] . " is empty." . PHP_EOL; + exit(1); +} + +if (empty($options['title'])) { + echo $options['title'] . " is empty." . PHP_EOL; + exit(1); +} + +if (empty($options['copyright'])) { + echo $options['copyright'] . " is empty." . PHP_EOL; + exit(1); +} + +if (empty($options['package-version'])) { + echo $options['package-version'] . " is empty." . PHP_EOL; + exit(1); +} + +require_once(__DIR__ . '/../../vendor/autoload.php'); + +use \Wdes\PIL\Twig\Extension\I18n as ExtensionI18n; +use \Twig\Cache\FilesystemCache; +use \Twig\Environment as TwigEnvironment; +use \Twig\Loader\FilesystemLoader as TwigLoaderFilesystem; + +$shortTempDir = $options['twig-templates-po-files']; +$jsonMaping = $options['json-mapping']; +$templateDir = realpath($options['twig-templates-dir']) . DIRECTORY_SEPARATOR; + +$loader = new TwigLoaderFilesystem([ $templateDir ]); // Load all templates from the dir +$cache = new FilesystemCache($options["twig-cache-dir"]); +$twig = new TwigEnvironment( + $loader, [ + 'cache' => $cache + ] +); +$twig->addExtension(new ExtensionI18n()); + +$mappings = new stdClass(); +$mappings->mappings = []; +$mappings->replacements = []; + +$license = new stdClass(); + +$license->from = "This file is distributed under the same"; +$license->from .= " license as the PACKAGE package."; +$license->to = "This file is distributed under the license http://unlicense.org/UNLICENSE"; +$mappings->replacements[] = $license; + +$license = new stdClass(); +$license->from = "PACKAGE VERSION"; +$license->to = $options['package-version']; +$mappings->replacements[] = $license; + +$firstauthor = new stdClass(); +$firstauthor->from = "FIRST AUTHOR , YEAR."; +$firstauthor->to = $options['copyright']; +$mappings->replacements[] = $firstauthor; + +$description = new stdClass(); +$description->from = "SOME DESCRIPTIVE TITLE"; +$description->to = $options['title']; +$mappings->replacements[] = $description; + +$year = new stdClass(); +$year->from = "YEAR"; +$year->to = date("Y");//2018 - +$mappings->replacements[] = $year; + +$templates = new stdClass(); +$templates->from = $options["twig-cache-dir"]; +$templates->to = ""; +$mappings->replacements[] = $templates; + +// iterate over all templates +foreach (new RecursiveIteratorIterator( + new RecursiveDirectoryIterator($templateDir), + RecursiveIteratorIterator::LEAVES_ONLY +) as $file) { + // force twig to generate cache + if ($file->isFile() && $file->getExtension() === 'twig') { + $shortName = str_replace($templateDir, '', $file); + $template = $twig->loadTemplate($shortName); + // Generate line map + $cacheFile = $cache->generateKey($shortName, $twig->getTemplateClass($shortName)); + $cacheFile = str_replace($options["twig-cache-dir"], '', $cacheFile); + $mappings->mappings[$cacheFile] = new stdClass(); + $mappings->mappings[$cacheFile]->fileName = $shortTempDir . $shortName; + $mappings->mappings[$cacheFile]->debugInfo = $template->getDebugInfo(); + } +} +file_put_contents($jsonMaping, json_encode($mappings, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); diff --git a/scripts/tools/update-po-files.php b/scripts/tools/update-po-files.php new file mode 100755 index 0000000..6868f65 --- /dev/null +++ b/scripts/tools/update-po-files.php @@ -0,0 +1,99 @@ +#!/usr/bin/env php + + */ + +$options = getopt( + "", [ + "po-dir:", + "po-template:", + "json-mapping::", + ] +); + +if (! isset($options["po-dir"]) && ! isset($options["po-template"])) { + echo "usage: update-po-files.php --po-dir po/directory --po-template path/to/file.pot" . PHP_EOL; + exit(1); +} + +if (! (is_dir($options["po-dir"]) || is_link($options["po-dir"]) )) { + echo $options["po-dir"] . " is not a directory." . PHP_EOL; + exit(1); +} + +if (! is_file($options["po-template"])) { + echo $options["po-template"] . " is not a file." . PHP_EOL; + exit(1); +} + +if (isset($options["json-mapping"])) { + if (! is_file($options["json-mapping"])) { + echo $options["json-mapping"] . " is not a file." . PHP_EOL; + exit(1); + } +} + +$poDirectory = realpath($options["po-dir"]) . DIRECTORY_SEPARATOR; +$poTemplate = $options["po-template"]; +$template = file_get_contents($poTemplate); + +$mappings = new stdClass(); +$mappings->mappings = array(); +$mappings->replacements = array(); + +if (isset($options["json-mapping"])) { + $mappings = json_decode(file_get_contents($options["json-mapping"])); +} + + +foreach ($mappings->replacements as $replacement) { + $template = str_replace($replacement->from, $replacement->to, $template); +} + +$parts = explode('msgid ', $template); +$license_block = str_replace(", fuzzy", "", $parts[0]); + +file_put_contents($poTemplate, $template); + +/** + * Update the copyright header of a po file + * + * @param string $po_file The po file path + * @return void + */ +function poupdate(string $po_file): void +{ + global $mappings, $license_block; + $pot_contents = file_get_contents($po_file); + + $parts = explode('msgid ', $pot_contents); + $pot_contents = str_replace($parts[0], $license_block, $pot_contents); + + // Replace filename by name + $pot_contents = preg_replace_callback( + '@([0-9a-f]{2}\/[0-9a-f]*.php):([0-9]*)@', + function ($matchs) use ($mappings) { + $line = intval($matchs[2]); + $replace = $mappings->mappings->{$matchs[1]}; + foreach ($replace->debugInfo as $cacheLineNumber => $iii) { + if ($line >= $cacheLineNumber) { + return $replace->fileName . ':' . $iii; + } + } + return $replace->fileName . ':0'; + }, + $pot_contents + ); + file_put_contents($po_file, $pot_contents); +} + +echo "PoDir: " . $poDirectory . "\r\n"; +foreach (glob($poDirectory . "*.po") as $file) { + exec("msgmerge --quiet --previous -U $file " . $poTemplate); + echo "File: $file\r\n"; + poupdate($file); +} +poupdate($poTemplate); diff --git a/scripts/update-example.sh b/scripts/update-example.sh new file mode 100755 index 0000000..f8792b0 --- /dev/null +++ b/scripts/update-example.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +ME="$(realpath $(dirname $0))" +ROOTDIR="$(realpath $(dirname $0)/../)" + +rm -rf $ROOTDIR/example/twigcache +mkdir $ROOTDIR/example/twigcache + +$ME/tools/generate-twig-cache.php \ + --twig-cache-dir="$ROOTDIR/example/twigcache" \ + --twig-templates-dir="$ROOTDIR/example/templates" \ + --twig-templates-po-files="example/templates/" \ + --json-mapping="$ROOTDIR/example/locale/replace.json" \ + --title="Wdes example" \ + --copyright="William Desportes " \ + --package-version="1.0.0" +sh $ME/tools/generate-pot.sh $ROOTDIR/example/twigcache $ROOTDIR/example/locale example.pot +$ME/tools/update-po-files.php \ + --po-dir="$ROOTDIR/example/locale" \ + --po-template="$ROOTDIR/example/locale/example.pot" \ + --json-mapping="$ROOTDIR/example/locale/replace.json" +rm -rf $ROOTDIR/example/twigcache +rm $ROOTDIR/example/locale/replace.json From d1e3243d6be4922c4a8a405311d330efd3216b53 Mon Sep 17 00:00:00 2001 From: William Desportes Date: Sat, 8 Jun 2019 15:21:20 +0200 Subject: [PATCH 15/23] chore(composer): Update composer package - Added archive - Added keywords - Added non feature branches --- composer.json | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/composer.json b/composer.json index 69e74f9..ff5360e 100644 --- a/composer.json +++ b/composer.json @@ -18,6 +18,35 @@ "phpunit": "phpunit --configuration ./tests/phpunit.xml", "update:example": "./scripts/update-example.sh" }, + "non-feature-branches": ["dev"], + "archive": { + "exclude": [ + "/tests", + "/scripts/ci", + "/.npmignore", + "/.editorconfig", + "/.gitmodules", + "/CODEOWNERS", + "/wdes-php-i18n-l10n-*.tar", + "/docs", + "/.gitignore", + "/phpcs.xml", + "/phpstan.neon", + "/.travis.yml", + "/codecov.yml", + "/.phpunit.result.cache" + ] + }, + "keywords": [ + "i18n", + "l10n", + "mo", + "gettext", + "pot-generator", + "twig", + "library", + "composer-package" + ], "authors": [ { "name": "William Desportes", From 696c2761b5ac623b140abebf063b35a030f71808 Mon Sep 17 00:00:00 2001 From: William Desportes Date: Sat, 8 Jun 2019 15:21:42 +0200 Subject: [PATCH 16/23] chore(README): Improve README.md --- README.md | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c70f14e..2f57c88 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,20 @@ PHP library/api to provide Internationalisation and Localisation [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fwdes%2Fphp-I18n-L10n.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fwdes%2Fphp-I18n-L10n?ref=badge_shield) [![HitCount](https://hits.dwyl.com/wdes/php-I18n-L10n.svg?style=flat)](https://hits.dwyl.com/wdes/php-I18n-L10n) ![Packagist](https://img.shields.io/packagist/l/wdes/php-I18n-L10n.svg) - +[![Latest Stable Version](https://poser.pugx.org/wdes/php-I18n-L10n/v/stable)](https://packagist.org/packages/wdes/php-I18n-L10n) ## License -[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fwdes%2Fphp-I18n-L10n.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fwdes%2Fphp-I18n-L10n?ref=badge_large) \ No newline at end of file +[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fwdes%2Fphp-I18n-L10n.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fwdes%2Fphp-I18n-L10n?ref=badge_large) + +## How to use + +``` +composer require wdes/php-i18n-l10n +``` + +Have a look at example file [example/simple.php](example/simple.php) + +### Scripts + +This package includes some scripts that can be usefull [scripts/tools](scripts/tools) +Here is an example to use them : [scripts/update-example.sh](scripts/update-example.sh) From c8fa5acd1ca36e9718a2a78dc263cad902639e85 Mon Sep 17 00:00:00 2001 From: William Desportes Date: Sat, 8 Jun 2019 15:58:25 +0200 Subject: [PATCH 17/23] docs(examples): Add some examples --- example/locale/example.pot | 45 ++++++++++++++++++++++++++++++++ example/locale/fr.mo | Bin 0 -> 685 bytes example/locale/fr.po | 41 +++++++++++++++++++++++++++++ example/templates/homepage.twig | 12 ++++++++- 4 files changed, 97 insertions(+), 1 deletion(-) create mode 100755 example/locale/example.pot create mode 100755 example/locale/fr.mo create mode 100755 example/locale/fr.po diff --git a/example/locale/example.pot b/example/locale/example.pot new file mode 100755 index 0000000..7450b6e --- /dev/null +++ b/example/locale/example.pot @@ -0,0 +1,45 @@ +# Wdes example. +# Copyright (C) 2019 William Desportes +# This file is distributed under the license http://unlicense.org/UNLICENSE +# William Desportes +# +# +msgid "" +msgstr "" +"Project-Id-Version: 1.0.0\n" +"Report-Msgid-Bugs-To: williamdes@wdes.fr\n" +"POT-Creation-Date: 2019-06-08 15:57+0200\n" +"PO-Revision-Date: 2019-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" + +#. l10n: The title of the page +#: example/templates/homepage.twig:2 +#: example/templates/homepage.twig:5 +msgid "Homepage" +msgstr "" + +#: example/templates/homepage.twig:6 +msgid "Another format" +msgstr "" + +#: example/templates/homepage.twig:7 +msgid "A filter" +msgstr "" + +#: example/templates/homepage.twig:8 +#, php-format +msgid "With \"%s\" apples" +msgstr "" + +#: example/templates/homepage.twig:10 +#, php-format +msgid "1 database" +msgid_plural "%count% databases" +msgstr[0] "" +msgstr[1] "" diff --git a/example/locale/fr.mo b/example/locale/fr.mo new file mode 100755 index 0000000000000000000000000000000000000000..4bc8ef329f378c7b9862732fa340edb60c0ece72 GIT binary patch literal 685 zcmY+B!EV$r5QYsD1VI9XIC2SK!E>4W;TRpa0B^#~yjkAFh2Buv_3U*avsPXVBVr(8kZeZSWJ^ z1HbH`u)<#2;uMY+V=P4%9;LLr4|p-6xh?}cF)}tR+0op(N(J%8R$QwEivt~&wBGaUr0Tk4FH&cZ zI1h5Kknh=fZB0TM`w&gJwl2ttU+6-`>hi!{keTeH>4t$=+n=vWd9=BHFelu)$HM zHI5DZDLk)BrOklyrE;FbaF&hb=HdP+#$)(|Oucgb zaAQE-@9?RimlQu6L?7fX8+KjSspUck+UUpq7@5wM?`-38-tHPmsOvz?3{yK4D)3oj yew^WPF9y^m{FThitS03cg`}F`_+nHkUWtk)D$g6%r5GJ^j!NGRt+rK#bN>S3jk>u2 literal 0 HcmV?d00001 diff --git a/example/locale/fr.po b/example/locale/fr.po new file mode 100755 index 0000000..dafcb89 --- /dev/null +++ b/example/locale/fr.po @@ -0,0 +1,41 @@ +msgid "" +msgstr "" +"Project-Id-Version: Test\n" +"Report-Msgid-Bugs-To: williamdes@wdes.fr\n" +"POT-Creation-Date: 2019-06-08 15:57+0200\n" +"PO-Revision-Date: \n" +"Last-Translator: \n" +"Language-Team: Wdes\n" +"Language: fr_FR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Poedit 2.1.1\n" +"X-Poedit-SourceCharset: UTF-8\n" + +#. l10n: The title of the page +#: example/templates/homepage.twig:2 +#: example/templates/homepage.twig:5 +msgid "Homepage" +msgstr "Page d'accueil" + +#: example/templates/homepage.twig:6 +msgid "Another format" +msgstr "Un autre format" + +#: example/templates/homepage.twig:7 +msgid "A filter" +msgstr "Un filtre" + +#: example/templates/homepage.twig:8 +#, php-format +msgid "With \"%s\" apples" +msgstr "Avec des \"%s\" pommes" + +#: example/templates/homepage.twig:10 +#, php-format +msgid "1 database" +msgid_plural "%count% databases" +msgstr[0] "Une base de données" +msgstr[1] "%count% bases de données" diff --git a/example/templates/homepage.twig b/example/templates/homepage.twig index 7736007..da68c26 100755 --- a/example/templates/homepage.twig +++ b/example/templates/homepage.twig @@ -1,6 +1,16 @@ {% trans %}Homepage{% endtrans %} - {{ say }} + {{ say }}
+ {% trans %}Homepage{% notes %}The title of the page{% endtrans %}
+ {% trans 'Another format' %}
+ {{ 'A filter'|trans }}
+ {{ 'With "%s" apples'|trans|format(3) }}
+ {% set total = 4 %} + {% trans %} + 1 database + {% plural total %} + {{ count }} databases + {% endtrans %} From 32e619d186ea1844803eb2bac41219aab8031446 Mon Sep 17 00:00:00 2001 From: William Desportes Date: Sat, 8 Jun 2019 15:58:43 +0200 Subject: [PATCH 18/23] fix(twig): Fix twig filter --- src/Launcher.php | 12 ++++++++++++ src/Twig/Extension/I18n.php | 4 +++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/Launcher.php b/src/Launcher.php index 8783924..cd36072 100644 --- a/src/Launcher.php +++ b/src/Launcher.php @@ -32,4 +32,16 @@ public static function getPlugin(): BasePlugin return Launcher::$plugin; } + /** + * Access gettext directly, not recommended + * Reserved to twig filter + * + * @param mixed $msgId Message id + * @return string + */ + public static function gettext($msgId): string + { + return Launcher::$plugin->gettext($msgId); + } + } diff --git a/src/Twig/Extension/I18n.php b/src/Twig/Extension/I18n.php index a75ee9d..c244d28 100644 --- a/src/Twig/Extension/I18n.php +++ b/src/Twig/Extension/I18n.php @@ -24,7 +24,9 @@ class I18n extends I18nExtension public function getFilters(): array { return [ - new TwigFilter('trans'), + new TwigFilter( + 'trans', '\Wdes\PIL\Launcher::gettext' + ), ]; } From 6d018bd3366bc3dcb3c87a9534837a6b264675e6 Mon Sep 17 00:00:00 2001 From: William Desportes Date: Sat, 8 Jun 2019 15:59:04 +0200 Subject: [PATCH 19/23] chore(scripts): Add generate .mo file --- scripts/update-example.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/update-example.sh b/scripts/update-example.sh index f8792b0..05e485a 100755 --- a/scripts/update-example.sh +++ b/scripts/update-example.sh @@ -21,3 +21,5 @@ $ME/tools/update-po-files.php \ --json-mapping="$ROOTDIR/example/locale/replace.json" rm -rf $ROOTDIR/example/twigcache rm $ROOTDIR/example/locale/replace.json + +msgfmt --directory="$ROOTDIR/example/locale" --check -o "$ROOTDIR/example/locale/fr.mo" "$ROOTDIR/example/locale/fr.po" From bfc12fcba4ad8b61f2474c21e1fd86debfeb967f Mon Sep 17 00:00:00 2001 From: William Desportes Date: Sat, 8 Jun 2019 15:59:19 +0200 Subject: [PATCH 20/23] fix(git): Fix .gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index bd876a3..a9a5983 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,5 @@ node_modules .env build/ \.php_cs\.cache +/wdes-php-i18n-l10n-*.tar +/.phpunit.result.cache From 1b6e5d15993ea13de12c0b5efa3d79e783817498 Mon Sep 17 00:00:00 2001 From: William Desportes Date: Sat, 8 Jun 2019 16:29:12 +0200 Subject: [PATCH 21/23] docs(examples): Updated the example --- example/locale/example.pot | 10 +++++++++- example/locale/fr.mo | Bin 685 -> 750 bytes example/locale/fr.po | 10 +++++++++- example/templates/homepage.twig | 9 +++++++++ 4 files changed, 27 insertions(+), 2 deletions(-) diff --git a/example/locale/example.pot b/example/locale/example.pot index 7450b6e..4dcb9cf 100755 --- a/example/locale/example.pot +++ b/example/locale/example.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: 1.0.0\n" "Report-Msgid-Bugs-To: williamdes@wdes.fr\n" -"POT-Creation-Date: 2019-06-08 15:57+0200\n" +"POT-Creation-Date: 2019-06-08 16:28+0200\n" "PO-Revision-Date: 2019-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -43,3 +43,11 @@ msgid "1 database" msgid_plural "%count% databases" msgstr[0] "" msgstr[1] "" + +#. l10n: The number of files +#: example/templates/homepage.twig:17 +#, php-format +msgid "1 file" +msgid_plural "%count% files" +msgstr[0] "" +msgstr[1] "" diff --git a/example/locale/fr.mo b/example/locale/fr.mo index 4bc8ef329f378c7b9862732fa340edb60c0ece72..221fcc5ccc7b9f147856b60f15f2953102adfef1 100755 GIT binary patch delta 239 zcmZ3>`i`~!o)F7a1|VPuVi_O~0b*_-?g3&D*a5^K@tr^{0>syVm;;Dk12G>Ee}VFu z85tM^fNUNh?GD7UK&%Jkr!p}xNCW99K$;UsZvfK#KzbLD2I@CsI0a;Y4894ZfqKAz z4M>6<1Oh-|Fkpt#EI^ud;!;H+Lxr@=oKyzY*gq GCI3v1fpk8Q<_FT1KpLd46G)2y=@~#8s9X)mWME(gVvqws04R From 0e5cb090d7a411663d2d99d90d3c9c8239cdcca3 Mon Sep 17 00:00:00 2001 From: William Desportes Date: Sat, 8 Jun 2019 16:38:04 +0200 Subject: [PATCH 22/23] fix(gettext): Fix implementation of plurals --- src/Launcher.php | 4 +- src/plugins/BasePlugin.php | 14 ++-- src/plugins/MoReader.php | 132 ++++++++++++++++++------------------- 3 files changed, 74 insertions(+), 76 deletions(-) diff --git a/src/Launcher.php b/src/Launcher.php index cd36072..b3c10fe 100644 --- a/src/Launcher.php +++ b/src/Launcher.php @@ -36,10 +36,10 @@ public static function getPlugin(): BasePlugin * Access gettext directly, not recommended * Reserved to twig filter * - * @param mixed $msgId Message id + * @param string $msgId Message id * @return string */ - public static function gettext($msgId): string + public static function gettext(string $msgId): string { return Launcher::$plugin->gettext($msgId); } diff --git a/src/plugins/BasePlugin.php b/src/plugins/BasePlugin.php index 7aff254..285d30b 100644 --- a/src/plugins/BasePlugin.php +++ b/src/plugins/BasePlugin.php @@ -23,10 +23,10 @@ abstract public function __construct(array $options); /** * Get translation for a message id * - * @param mixed $msgId Message id + * @param string $msgId Message id * @return string */ - abstract public function gettext($msgId): string; + abstract public function gettext(string $msgId): string; /** * Get translation for a message id @@ -71,14 +71,14 @@ abstract public function dngettext($domain, $msgId, $msgIdPlural, $number): stri abstract public function npgettext($msgctxt, $msgId, $msgIdPlural, $number): string; /** - * Get translation + * Plural version of gettext * - * @param mixed $msgId Message id - * @param mixed $msgIdPlural Plural message id - * @param mixed $number Number + * @param string $msgId Message id + * @param string $msgIdPlural Plural message id + * @param int $number Number * @return string */ - abstract public function ngettext($msgId, $msgIdPlural, $number): string; + abstract public function ngettext(string $msgId, string $msgIdPlural, int $number); /** * Get translation diff --git a/src/plugins/MoReader.php b/src/plugins/MoReader.php index 814b502..2471bb8 100644 --- a/src/plugins/MoReader.php +++ b/src/plugins/MoReader.php @@ -137,22 +137,16 @@ public function readTranslations(): array * * @copyright 2015 Max Grigorian * @license MIT - * @param array $data The record - * @param array $msgId Message ids - * @param array $msgStr Message strings + * @param array $data The record + * @param array $msgIds Message ids + * @param array $msgStrs Message strings * @return void */ - public function processRecord(array &$data, array $msgId, array $msgStr): void + public function processRecord(array &$data, array $msgIds, array $msgStrs): void { // note: Contexts are stored by storing the concatenation of the context, a EOT byte, and the original string, instead of the original string. - if (count($msgId) > 1 && count($msgStr) > 1) { - $data[$msgId[0]] = $msgStr; - array_shift($msgId); - foreach ($msgId as $string) { - $data[$string] = $msgStr; - } - } else { - $data[$msgId[0]] = $msgStr[0]; + foreach ($msgIds as $key => $msgId) { + $data[$msgId] = $msgStrs[$key]; } } @@ -282,102 +276,106 @@ public function __($msgId): string /** * Get translation for a message id * - * @param mixed $msgId Message id + * @param string $msgId Message id * @return string */ - public function gettext($msgId): string + public function gettext(string $msgId): string { return self::idOrFind($msgId); } /** - * Get translation - * - * @param mixed $domain Domain - * @param mixed $msgctxt msgctxt - * @param mixed $msgId Message id - * @param mixed $msgIdPlural Plural message id - * @param mixed $number Number - * @return string - */ + * Get translation + * + * @param mixed $domain Domain + * @param mixed $msgctxt msgctxt + * @param mixed $msgId Message id + * @param mixed $msgIdPlural Plural message id + * @param mixed $number Number + * @return string + */ public function dnpgettext($domain, $msgctxt, $msgId, $msgIdPlural, $number): string { return self::idOrFind($msgId); } /** - * Get translation - * - * @param mixed $domain Domain - * @param mixed $msgId Message id - * @param mixed $msgIdPlural Plural message id - * @param mixed $number Number - * @return string - */ + * Get translation + * + * @param mixed $domain Domain + * @param mixed $msgId Message id + * @param mixed $msgIdPlural Plural message id + * @param mixed $number Number + * @return string + */ public function dngettext($domain, $msgId, $msgIdPlural, $number): string { return self::idOrFind($msgId); } /** - * Get translation - * - * @param mixed $msgctxt msgctxt - * @param mixed $msgId Message id - * @param mixed $msgIdPlural Plural message id - * @param mixed $number Number - * @return string - */ + * Get translation + * + * @param mixed $msgctxt msgctxt + * @param mixed $msgId Message id + * @param mixed $msgIdPlural Plural message id + * @param mixed $number Number + * @return string + */ public function npgettext($msgctxt, $msgId, $msgIdPlural, $number): string { return self::idOrFind($msgId); } /** - * Get translation - * - * @param mixed $msgId Message id - * @param mixed $msgIdPlural Plural message id - * @param mixed $number Number - * @return string - */ - public function ngettext($msgId, $msgIdPlural, $number): string + * Plural version of gettext + * + * @param string $msgId Message id + * @param string $msgIdPlural Plural message id + * @param int $number Number + * @return string + */ + public function ngettext(string $msgId, string $msgIdPlural, int $number): string { - return self::idOrFind($msgId); + if ($number > 1) { + return self::idOrFind($msgIdPlural); + } else { + return self::idOrFind($msgId); + } } /** - * Get translation - * - * @param mixed $domain Domain - * @param mixed $msgctxt msgctxt - * @param mixed $msgId Message id - * @return string - */ + * Get translation + * + * @param mixed $domain Domain + * @param mixed $msgctxt msgctxt + * @param mixed $msgId Message id + * @return string + */ public function dpgettext($domain, $msgctxt, $msgId): string { return self::idOrFind($msgId); } /** - * Get translation - * - * @param mixed $domain Domain - * @param mixed $msgId Message id - * @return string - */ + * Get translation + * + * @param mixed $domain Domain + * @param mixed $msgId Message id + * @return string + */ public function dgettext($domain, $msgId): string { return self::idOrFind($msgId); } /** - * Get translation - * - * @param mixed $msgctxt msgctxt - * @param mixed $msgId Message id - * @return string - */ + * Get translation + * + * @param mixed $msgctxt msgctxt + * @param mixed $msgId Message id + * @return string + */ public function pgettext($msgctxt, $msgId): string { return self::idOrFind($msgId); From 53f38f789d0008dfdad14c7ec04470c7c3e25454 Mon Sep 17 00:00:00 2001 From: William Desportes Date: Sat, 8 Jun 2019 16:38:19 +0200 Subject: [PATCH 23/23] style(types): Add php typehints --- src/plugins/BasePlugin.php | 56 ++++++++++++++++---------------- src/plugins/MoReader.php | 66 ++++++++++++++++++++------------------ 2 files changed, 63 insertions(+), 59 deletions(-) diff --git a/src/plugins/BasePlugin.php b/src/plugins/BasePlugin.php index 285d30b..7cf2c7b 100644 --- a/src/plugins/BasePlugin.php +++ b/src/plugins/BasePlugin.php @@ -31,44 +31,44 @@ abstract public function gettext(string $msgId): string; /** * Get translation for a message id * - * @param mixed $msgId Message id + * @param string $msgId Message id * @return string */ - abstract public function __($msgId): string; + abstract public function __(string $msgId): string; /** * Get translation * - * @param mixed $domain Domain - * @param mixed $msgctxt msgctxt - * @param mixed $msgId Message id - * @param mixed $msgIdPlural Plural message id - * @param mixed $number Number + * @param string $domain Domain + * @param string $msgctxt msgctxt + * @param string $msgId Message id + * @param string $msgIdPlural Plural message id + * @param int $number Number * @return string */ - abstract public function dnpgettext($domain, $msgctxt, $msgId, $msgIdPlural, $number): string; + abstract public function dnpgettext(string $domain, string $msgctxt, string $msgId, string $msgIdPlural, int $number): string; /** * Get translation * - * @param mixed $domain Domain - * @param mixed $msgId Message id - * @param mixed $msgIdPlural Plural message id - * @param mixed $number Number + * @param string $domain Domain + * @param string $msgId Message id + * @param string $msgIdPlural Plural message id + * @param int $number Number * @return string */ - abstract public function dngettext($domain, $msgId, $msgIdPlural, $number): string; + abstract public function dngettext(string $domain, string $msgId, string $msgIdPlural, int $number): string; /** * Get translation * - * @param mixed $msgctxt msgctxt - * @param mixed $msgId Message id - * @param mixed $msgIdPlural Plural message id - * @param mixed $number Number + * @param string $msgctxt msgctxt + * @param string $msgId Message id + * @param string $msgIdPlural Plural message id + * @param int $number Number * @return string */ - abstract public function npgettext($msgctxt, $msgId, $msgIdPlural, $number): string; + abstract public function npgettext(string $msgctxt, string $msgId, string $msgIdPlural, int $number): string; /** * Plural version of gettext @@ -83,29 +83,29 @@ abstract public function ngettext(string $msgId, string $msgIdPlural, int $numbe /** * Get translation * - * @param mixed $domain Domain - * @param mixed $msgctxt msgctxt - * @param mixed $msgId Message id + * @param string $domain Domain + * @param string $msgctxt msgctxt + * @param string $msgId Message id * @return string */ - abstract public function dpgettext($domain, $msgctxt, $msgId): string; + abstract public function dpgettext(string $domain, string $msgctxt, string $msgId): string; /** * Get translation * - * @param mixed $domain Domain - * @param mixed $msgId Message id + * @param string $domain Domain + * @param string $msgId Message id * @return string */ - abstract public function dgettext($domain, $msgId): string; + abstract public function dgettext(string $domain, string $msgId): string; /** * Get translation * - * @param mixed $msgctxt msgctxt - * @param mixed $msgId Message id + * @param string $msgctxt msgctxt + * @param string $msgId Message id * @return string */ - abstract public function pgettext($msgctxt, $msgId): string; + abstract public function pgettext(string $msgctxt, string $msgId): string; } diff --git a/src/plugins/MoReader.php b/src/plugins/MoReader.php index 2471bb8..86fe791 100644 --- a/src/plugins/MoReader.php +++ b/src/plugins/MoReader.php @@ -250,10 +250,10 @@ public static function readInteger(int $endian, $res) /** * Return string id or translation * - * @param mixed $msgId The message id + * @param string $msgId The message id * @return string */ - public function idOrFind($msgId): string + public function idOrFind(string $msgId): string { if (array_key_exists($msgId, $this->data->translations)) { return $this->data->translations[$msgId]; @@ -265,10 +265,10 @@ public function idOrFind($msgId): string /** * Get translation for a message id * - * @param mixed $msgId Message id + * @param string $msgId Message id * @return string */ - public function __($msgId): string + public function __(string $msgId): string { return self::gettext($msgId); } @@ -287,14 +287,14 @@ public function gettext(string $msgId): string /** * Get translation * - * @param mixed $domain Domain - * @param mixed $msgctxt msgctxt - * @param mixed $msgId Message id - * @param mixed $msgIdPlural Plural message id - * @param mixed $number Number + * @param string $domain Domain + * @param string $msgctxt msgctxt + * @param string $msgId Message id + * @param string $msgIdPlural Plural message id + * @param int $number Number * @return string */ - public function dnpgettext($domain, $msgctxt, $msgId, $msgIdPlural, $number): string + public function dnpgettext(string $domain, string $msgctxt, string $msgId, string $msgIdPlural, int $number): string { return self::idOrFind($msgId); } @@ -302,13 +302,13 @@ public function dnpgettext($domain, $msgctxt, $msgId, $msgIdPlural, $number): st /** * Get translation * - * @param mixed $domain Domain - * @param mixed $msgId Message id - * @param mixed $msgIdPlural Plural message id - * @param mixed $number Number + * @param string $domain Domain + * @param string $msgId Message id + * @param string $msgIdPlural Plural message id + * @param int $number Number * @return string */ - public function dngettext($domain, $msgId, $msgIdPlural, $number): string + public function dngettext(string $domain, string $msgId, string $msgIdPlural, int $number): string { return self::idOrFind($msgId); } @@ -316,15 +316,19 @@ public function dngettext($domain, $msgId, $msgIdPlural, $number): string /** * Get translation * - * @param mixed $msgctxt msgctxt - * @param mixed $msgId Message id - * @param mixed $msgIdPlural Plural message id - * @param mixed $number Number + * @param string $msgctxt msgctxt + * @param string $msgId Message id + * @param string $msgIdPlural Plural message id + * @param int $number Number * @return string */ - public function npgettext($msgctxt, $msgId, $msgIdPlural, $number): string + public function npgettext(string $msgctxt, string $msgId, string $msgIdPlural, int $number): string { - return self::idOrFind($msgId); + if ($number > 1) { + return self::idOrFind($msgIdPlural); + } else { + return self::idOrFind($msgId); + } } /** @@ -347,12 +351,12 @@ public function ngettext(string $msgId, string $msgIdPlural, int $number): strin /** * Get translation * - * @param mixed $domain Domain - * @param mixed $msgctxt msgctxt - * @param mixed $msgId Message id + * @param string $domain Domain + * @param string $msgctxt msgctxt + * @param string $msgId Message id * @return string */ - public function dpgettext($domain, $msgctxt, $msgId): string + public function dpgettext(string $domain, string $msgctxt, string $msgId): string { return self::idOrFind($msgId); } @@ -360,11 +364,11 @@ public function dpgettext($domain, $msgctxt, $msgId): string /** * Get translation * - * @param mixed $domain Domain - * @param mixed $msgId Message id + * @param string $domain Domain + * @param string $msgId Message id * @return string */ - public function dgettext($domain, $msgId): string + public function dgettext(string $domain, string $msgId): string { return self::idOrFind($msgId); } @@ -372,11 +376,11 @@ public function dgettext($domain, $msgId): string /** * Get translation * - * @param mixed $msgctxt msgctxt - * @param mixed $msgId Message id + * @param string $msgctxt msgctxt + * @param string $msgId Message id * @return string */ - public function pgettext($msgctxt, $msgId): string + public function pgettext(string $msgctxt, string $msgId): string { return self::idOrFind($msgId); }