Update website
This commit is contained in:
parent
0a686aeb9a
commit
c4ffa0f6ee
4360 changed files with 1727 additions and 718385 deletions
|
@ -1,33 +0,0 @@
|
|||
# Change Log
|
||||
|
||||
## [Unreleased] -
|
||||
|
||||
## [4.0.1] - 2021-06-10
|
||||
|
||||
* Fix TransNode constructor optional parameters
|
||||
|
||||
## [4.0.0] - 2021-02-25
|
||||
|
||||
* Add support for domain translation (#4)
|
||||
* TransNode constructor signature changed, new $domain parameter `?Node $notes, ?Node $domain = null, int $lineno` (#4)
|
||||
* TransNode constructor signature changed, new $context parameter `?AbstractExpression $count, ?Node $context = null, ?Node $notes` (#6)
|
||||
* Add support for contexts in translations (#6)
|
||||
* Add support for enabling `phpmyadmin/motranslator` or complex non php-gettext supported functions (#6)
|
||||
* Add support for custom notes labels (#6)
|
||||
* Make debug info disabled by default, `TransNode::$enableAddDebugInfo = true;` will add it back
|
||||
* Some slight performance improvements
|
||||
* Added tests for all the code
|
||||
|
||||
## [3.0.0] - 2020-06-14
|
||||
|
||||
* Add a .gitattributes file
|
||||
* Support Twig 3
|
||||
* Remove extra field from composer.json
|
||||
* Add support field in composer.json
|
||||
* Require php >= 7.1
|
||||
* Setup and apply phpmyadmin/coding-standard
|
||||
* Apply changes for php 8.0 compatibility (https://github.com/twigphp/Twig/issues/3327)
|
||||
|
||||
## [2.0.0] - 2020-01-14
|
||||
|
||||
* First release of this library.
|
|
@ -1,20 +0,0 @@
|
|||
Copyright (c) 2010-2019 Fabien Potencier
|
||||
Copyright (c) 2019-2021 phpMyAdmin contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished
|
||||
to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
|
@ -1,47 +0,0 @@
|
|||
{
|
||||
"name": "phpmyadmin/twig-i18n-extension",
|
||||
"description": "Internationalization support for Twig via the gettext library",
|
||||
"keywords": ["i18n","gettext"],
|
||||
"type": "library",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "The phpMyAdmin Team",
|
||||
"email": "developers@phpmyadmin.net",
|
||||
"homepage": "https://www.phpmyadmin.net/team/"
|
||||
}
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/phpmyadmin/twig-i18n-extension/issues",
|
||||
"source": "https://github.com/phpmyadmin/twig-i18n-extension"
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1 || ^8.0",
|
||||
"twig/twig": "^1.42.3|^2.0|^3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpmyadmin/coding-standard": "^3.0.0",
|
||||
"phpmyadmin/motranslator": "^5.2",
|
||||
"phpstan/phpstan": "^0.12.66",
|
||||
"phpunit/phpunit": "^7 || ^8 || ^9"
|
||||
},
|
||||
"scripts": {
|
||||
"phpstan": "./vendor/bin/phpstan analyse",
|
||||
"phpunit": "phpunit",
|
||||
"phpcs": "phpcs",
|
||||
"phpcbf": "phpcbf"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": { "PhpMyAdmin\\Twig\\Extensions\\": "src/" }
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": { "PhpMyAdmin\\Tests\\Twig\\Extensions\\": "test/" }
|
||||
},
|
||||
"config":{
|
||||
"sort-packages": true
|
||||
}
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of Twig I18n extension.
|
||||
*
|
||||
* (c) 2010-2019 Fabien Potencier
|
||||
* (c) 2019-2021 phpMyAdmin contributors
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PhpMyAdmin\Twig\Extensions;
|
||||
|
||||
use PhpMyAdmin\Twig\Extensions\TokenParser\TransTokenParser;
|
||||
use Twig\Extension\AbstractExtension;
|
||||
use Twig\TwigFilter;
|
||||
|
||||
use function dgettext;
|
||||
use function gettext;
|
||||
|
||||
class I18nExtension extends AbstractExtension
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getTokenParsers()
|
||||
{
|
||||
return [new TransTokenParser()];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFilters()
|
||||
{
|
||||
return [
|
||||
new TwigFilter('trans', [$this, 'translate']), /* Note, the filter does not handle plurals */
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'i18n';
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate a GetText string via filter
|
||||
*
|
||||
* @param string $message The message to translate
|
||||
* @param string|null $domain The GetText domain
|
||||
*/
|
||||
public function translate(string $message, ?string $domain = null): string
|
||||
{
|
||||
/* If we don't have a domain, assume we're just using the default */
|
||||
if ($domain === null) {
|
||||
return gettext($message);
|
||||
}
|
||||
|
||||
/* Otherwise specify where the message comes from */
|
||||
return dgettext($domain, $message);
|
||||
}
|
||||
}
|
|
@ -1,315 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of Twig I18n extension.
|
||||
*
|
||||
* (c) 2010-2019 Fabien Potencier
|
||||
* (c) 2019-2021 phpMyAdmin contributors
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PhpMyAdmin\Twig\Extensions\Node;
|
||||
|
||||
use Twig\Compiler;
|
||||
use Twig\Node\CheckToStringNode;
|
||||
use Twig\Node\Expression\AbstractExpression;
|
||||
use Twig\Node\Expression\ConstantExpression;
|
||||
use Twig\Node\Expression\FilterExpression;
|
||||
use Twig\Node\Expression\NameExpression;
|
||||
use Twig\Node\Expression\TempNameExpression;
|
||||
use Twig\Node\Node;
|
||||
use Twig\Node\PrintNode;
|
||||
|
||||
use function array_merge;
|
||||
use function count;
|
||||
use function sprintf;
|
||||
use function str_replace;
|
||||
use function trim;
|
||||
|
||||
/**
|
||||
* Represents a trans node.
|
||||
*
|
||||
* Author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*/
|
||||
class TransNode extends Node
|
||||
{
|
||||
/**
|
||||
* The label for gettext notes to be exported
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $notesLabel = '// notes: ';
|
||||
|
||||
/**
|
||||
* Enable MoTranslator functions
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public static $enableMoTranslator = false;
|
||||
|
||||
/**
|
||||
* Enable calls to addDebugInfo
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public static $enableAddDebugInfo = false;
|
||||
|
||||
/**
|
||||
* Enables context functions usage
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public static $hasContextFunctions = false;
|
||||
|
||||
public function __construct(
|
||||
Node $body,
|
||||
?Node $plural,
|
||||
?AbstractExpression $count,
|
||||
?Node $context = null,
|
||||
?Node $notes = null,
|
||||
?Node $domain = null,
|
||||
int $lineno = 0,
|
||||
?string $tag = null
|
||||
) {
|
||||
$nodes = ['body' => $body];
|
||||
if ($count !== null) {
|
||||
$nodes['count'] = $count;
|
||||
}
|
||||
|
||||
if ($plural !== null) {
|
||||
$nodes['plural'] = $plural;
|
||||
}
|
||||
|
||||
if ($notes !== null) {
|
||||
$nodes['notes'] = $notes;
|
||||
}
|
||||
|
||||
if ($domain !== null) {
|
||||
$nodes['domain'] = $domain;
|
||||
}
|
||||
|
||||
if ($context !== null) {
|
||||
$nodes['context'] = $context;
|
||||
}
|
||||
|
||||
parent::__construct($nodes, [], $lineno, $tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function compile(Compiler $compiler)
|
||||
{
|
||||
if (self::$enableAddDebugInfo) {
|
||||
$compiler->addDebugInfo($this);
|
||||
}
|
||||
|
||||
[$msg, $vars] = $this->compileString($this->getNode('body'));
|
||||
|
||||
$hasPlural = $this->hasNode('plural');
|
||||
|
||||
if ($hasPlural) {
|
||||
[$msg1, $vars1] = $this->compileString($this->getNode('plural'));
|
||||
|
||||
$vars = array_merge($vars, $vars1);
|
||||
}
|
||||
|
||||
$hasDomain = $this->hasNode('domain');
|
||||
$hasContext = $this->hasNode('context');
|
||||
|
||||
$function = $this->getTransFunction($hasPlural, $hasContext, $hasDomain);
|
||||
|
||||
if ($this->hasNode('notes')) {
|
||||
$message = trim($this->getNode('notes')->getAttribute('data'));
|
||||
|
||||
// line breaks are not allowed cause we want a single line comment
|
||||
$message = str_replace(["\n", "\r"], ' ', $message);
|
||||
$compiler->raw(static::$notesLabel . $message . "\n");
|
||||
}
|
||||
|
||||
if ($vars) {
|
||||
$compiler
|
||||
->raw('echo strtr(' . $function . '(');
|
||||
|
||||
if ($hasDomain) {
|
||||
[$domain] = $this->compileString($this->getNode('domain'));
|
||||
$compiler
|
||||
->subcompile($domain)
|
||||
->raw(', ');
|
||||
}
|
||||
|
||||
if ($hasContext && (static::$hasContextFunctions || static::$enableMoTranslator)) {
|
||||
[$context] = $this->compileString($this->getNode('context'));
|
||||
$compiler
|
||||
->subcompile($context)
|
||||
->raw(', ');
|
||||
}
|
||||
|
||||
$compiler
|
||||
->subcompile($msg);
|
||||
|
||||
if ($hasPlural) {
|
||||
$compiler
|
||||
->raw(', ')
|
||||
->subcompile($msg1)
|
||||
->raw(', abs(')
|
||||
->subcompile($this->getNode('count'))
|
||||
->raw(')');
|
||||
}
|
||||
|
||||
$compiler->raw('), array(');
|
||||
|
||||
foreach ($vars as $var) {
|
||||
$attributeName = $var->getAttribute('name');
|
||||
if ($attributeName === 'count') {
|
||||
$compiler
|
||||
->string('%count%')
|
||||
->raw(' => abs(')
|
||||
->subcompile($this->getNode('count'))
|
||||
->raw('), ');
|
||||
} else {
|
||||
$compiler
|
||||
->string('%' . $attributeName . '%')
|
||||
->raw(' => ')
|
||||
->subcompile($var)
|
||||
->raw(', ');
|
||||
}
|
||||
}
|
||||
|
||||
$compiler->raw("));\n");
|
||||
} else {
|
||||
$compiler
|
||||
->raw('echo ' . $function . '(');
|
||||
|
||||
if ($hasDomain) {
|
||||
[$domain] = $this->compileString($this->getNode('domain'));
|
||||
$compiler
|
||||
->subcompile($domain)
|
||||
->raw(', ');
|
||||
}
|
||||
|
||||
if ($hasContext) {
|
||||
if (static::$hasContextFunctions || static::$enableMoTranslator) {
|
||||
[$context] = $this->compileString($this->getNode('context'));
|
||||
$compiler
|
||||
->subcompile($context)
|
||||
->raw(', ');
|
||||
}
|
||||
}
|
||||
|
||||
$compiler
|
||||
->subcompile($msg);
|
||||
|
||||
if ($hasPlural) {
|
||||
$compiler
|
||||
->raw(', ')
|
||||
->subcompile($msg1)
|
||||
->raw(', abs(')
|
||||
->subcompile($this->getNode('count'))
|
||||
->raw(')');
|
||||
}
|
||||
|
||||
$compiler->raw(");\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Keep this method protected instead of private some implementations may use it
|
||||
*/
|
||||
protected function compileString(Node $body): array
|
||||
{
|
||||
if (
|
||||
$body instanceof NameExpression
|
||||
|| $body instanceof ConstantExpression
|
||||
|| $body instanceof TempNameExpression
|
||||
) {
|
||||
return [$body, []];
|
||||
}
|
||||
|
||||
$vars = [];
|
||||
if (count($body)) {
|
||||
$msg = '';
|
||||
|
||||
foreach ($body as $node) {
|
||||
if ($node instanceof PrintNode) {
|
||||
$n = $node->getNode('expr');
|
||||
while ($n instanceof FilterExpression) {
|
||||
$n = $n->getNode('node');
|
||||
}
|
||||
|
||||
while ($n instanceof CheckToStringNode) {
|
||||
$n = $n->getNode('expr');
|
||||
}
|
||||
|
||||
$attributeName = $n->getAttribute('name');
|
||||
$msg .= sprintf('%%%s%%', $attributeName);
|
||||
$vars[] = new NameExpression($attributeName, $n->getTemplateLine());
|
||||
} else {
|
||||
$msg .= $node->getAttribute('data');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$msg = $body->getAttribute('data');
|
||||
}
|
||||
|
||||
return [new Node([new ConstantExpression(trim($msg), $body->getTemplateLine())]), $vars];
|
||||
}
|
||||
|
||||
/**
|
||||
* Keep this protected to allow people to override it with their own logic
|
||||
*/
|
||||
protected function getTransFunction(bool $hasPlural, bool $hasContext, bool $hasDomain): string
|
||||
{
|
||||
$functionPrefix = '';
|
||||
|
||||
if (static::$enableMoTranslator) {
|
||||
// The functions are prefixed with an underscore
|
||||
$functionPrefix = '_';
|
||||
}
|
||||
|
||||
// If it has not context function support or not MoTranslator
|
||||
if (! static::$hasContextFunctions && ! static::$enableMoTranslator) {
|
||||
// Not found on native PHP: dnpgettext, npgettext, dpgettext, pgettext
|
||||
// No domain plural context support
|
||||
// No domain context support
|
||||
// No context support
|
||||
// No plural context support
|
||||
|
||||
if ($hasDomain) {
|
||||
// dngettext($domain, $msgid, $msgidPlural, $number);
|
||||
// dgettext($domain, $msgid);
|
||||
return $functionPrefix . ($hasPlural ? 'dngettext' : 'dgettext');
|
||||
}
|
||||
|
||||
// ngettext($msgid, $msgidPlural, $number);
|
||||
// gettext($msgid);
|
||||
return $functionPrefix . ($hasPlural ? 'ngettext' : 'gettext');
|
||||
}
|
||||
|
||||
if ($hasDomain) {
|
||||
if ($hasPlural) {
|
||||
// dnpgettext($domain, $msgctxt, $msgid, $msgidPlural, $number);
|
||||
// dngettext($domain, $msgid, $msgidPlural, $number);
|
||||
return $functionPrefix . ($hasContext ? 'dnpgettext' : 'dngettext');
|
||||
}
|
||||
|
||||
// dpgettext($domain, $msgctxt, $msgid);
|
||||
// dgettext($domain, $msgid);
|
||||
return $functionPrefix . ($hasContext ? 'dpgettext' : 'dgettext');
|
||||
}
|
||||
|
||||
if ($hasPlural) {
|
||||
// npgettext($msgctxt, $msgid, $msgidPlural, $number);
|
||||
// ngettext($msgid, $msgidPlural, $number);
|
||||
return $functionPrefix . ($hasContext ? 'npgettext' : 'ngettext');
|
||||
}
|
||||
|
||||
// pgettext($msgctxt, $msgid);
|
||||
// gettext($msgid);
|
||||
return $functionPrefix . ($hasContext ? 'pgettext' : 'gettext');
|
||||
}
|
||||
}
|
|
@ -1,144 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of Twig I18n extension.
|
||||
*
|
||||
* (c) 2010-2019 Fabien Potencier
|
||||
* (c) 2019-2021 phpMyAdmin contributors
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PhpMyAdmin\Twig\Extensions\TokenParser;
|
||||
|
||||
use PhpMyAdmin\Twig\Extensions\Node\TransNode;
|
||||
use Twig\Error\SyntaxError;
|
||||
use Twig\Node\Expression\NameExpression;
|
||||
use Twig\Node\Node;
|
||||
use Twig\Node\PrintNode;
|
||||
use Twig\Node\TextNode;
|
||||
use Twig\Token;
|
||||
use Twig\TokenParser\AbstractTokenParser;
|
||||
|
||||
class TransTokenParser extends AbstractTokenParser
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function parse(Token $token)
|
||||
{
|
||||
[
|
||||
$body,
|
||||
$plural,
|
||||
$count,
|
||||
$context,
|
||||
$notes,
|
||||
$domain,
|
||||
$lineno,
|
||||
$tag,
|
||||
] = $this->preParse($token);
|
||||
|
||||
return new TransNode($body, $plural, $count, $context, $notes, $domain, $lineno, $tag);
|
||||
}
|
||||
|
||||
protected function preParse(Token $token): array
|
||||
{
|
||||
$lineno = $token->getLine();
|
||||
$stream = $this->parser->getStream();
|
||||
$domain = null;
|
||||
$count = null;
|
||||
$plural = null;
|
||||
$notes = null;
|
||||
$context = null;
|
||||
|
||||
/* If we aren't closing the block, do we have a domain? */
|
||||
if ($stream->test(Token::NAME_TYPE)) {
|
||||
$stream->expect(Token::NAME_TYPE, 'from');
|
||||
$domain = $this->parser->getExpressionParser()->parseExpression();
|
||||
}
|
||||
|
||||
if (! $stream->test(Token::BLOCK_END_TYPE)) {
|
||||
$body = $this->parser->getExpressionParser()->parseExpression();
|
||||
} else {
|
||||
$stream->expect(Token::BLOCK_END_TYPE);
|
||||
$body = $this->parser->subparse([$this, 'decideForFork']);
|
||||
$next = $stream->next()->getValue();
|
||||
|
||||
if ($next === 'plural') {
|
||||
$count = $this->parser->getExpressionParser()->parseExpression();
|
||||
$stream->expect(Token::BLOCK_END_TYPE);
|
||||
$plural = $this->parser->subparse([$this, 'decideForFork']);
|
||||
$next = $stream->next()->getValue();
|
||||
if ($next === 'notes') {
|
||||
$stream->expect(Token::BLOCK_END_TYPE);
|
||||
$notes = $this->parser->subparse([$this, 'decideForEnd'], true);
|
||||
} elseif ($next === 'context') {
|
||||
$stream->expect(Token::BLOCK_END_TYPE);
|
||||
$context = $this->parser->subparse([$this, 'decideForEnd'], true);
|
||||
}
|
||||
} elseif ($next === 'context') {
|
||||
$stream->expect(Token::BLOCK_END_TYPE);
|
||||
$context = $this->parser->subparse([$this, 'decideForEnd'], true);
|
||||
} elseif ($next === 'notes') {
|
||||
$stream->expect(Token::BLOCK_END_TYPE);
|
||||
$notes = $this->parser->subparse([$this, 'decideForEnd'], true);
|
||||
}
|
||||
}
|
||||
|
||||
$stream->expect(Token::BLOCK_END_TYPE);
|
||||
|
||||
$this->checkTransString($body, $lineno);
|
||||
|
||||
return [$body, $plural, $count, $context, $notes, $domain, $lineno, $this->getTag()];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function decideForFork(Token $token)
|
||||
{
|
||||
return $token->test(['plural', 'context', 'notes', 'endtrans']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function decideForEnd(Token $token)
|
||||
{
|
||||
return $token->test('endtrans');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getTag()
|
||||
{
|
||||
return 'trans';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*
|
||||
* @throws SyntaxError
|
||||
*/
|
||||
protected function checkTransString(Node $body, int $lineno)
|
||||
{
|
||||
foreach ($body as $i => $node) {
|
||||
if (
|
||||
$node instanceof TextNode
|
||||
||
|
||||
($node instanceof PrintNode && $node->getNode('expr') instanceof NameExpression)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
throw new SyntaxError(
|
||||
'The text to be translated with "trans" can only contain references to simple variables.',
|
||||
$lineno
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue