diff --git a/README.md b/README.md index 46c6cbb5..53102baf 100644 --- a/README.md +++ b/README.md @@ -124,7 +124,7 @@ LC_ALL=pl ./vendor/bin/lint-query --query "SELECT 1" ```php require __DIR__ . '/vendor/autoload.php'; -$GLOBALS['lang'] = 'pl'; +PhpMyAdmin\SqlParser\Translator::setLocale('pl'); $query1 = 'select * from a'; $parser = new PhpMyAdmin\SqlParser\Parser($query1); diff --git a/src/Translator.php b/src/Translator.php index b0a9ebc5..1b527cc6 100644 --- a/src/Translator.php +++ b/src/Translator.php @@ -5,7 +5,10 @@ namespace PhpMyAdmin\SqlParser; use PhpMyAdmin\MoTranslator\Loader; +use PhpMyAdmin\MoTranslator\Translator as MoTranslator; +use RuntimeException; +use function assert; use function class_exists; /** @@ -16,32 +19,42 @@ class Translator /** * The MoTranslator loader object. * - * @var Loader + * @var Loader|null */ private static $loader; /** * The MoTranslator translator object. * - * @var \PhpMyAdmin\MoTranslator\Translator + * @var MoTranslator|null */ private static $translator; + /** @var string */ + private static $locale = ''; + /** * Loads translator. * + * @internal This method is not covered by the backward compatibility promise for SQL-Parser + * * @return void */ public static function load() { + if (! class_exists(Loader::class)) { + throw new RuntimeException('The phpmyadmin/motranslator package is missing.'); + } + if (self::$loader === null) { // Create loader object self::$loader = new Loader(); - // Set locale - self::$loader->setlocale( - self::$loader->detectlocale() - ); + if (self::$locale === '') { + self::$locale = self::$loader->detectlocale(); + } + + self::$loader->setlocale(self::$locale); // Set default text domain self::$loader->textdomain('sqlparser'); @@ -67,12 +80,23 @@ public static function load() */ public static function gettext($msgid) { - if (! class_exists('\PhpMyAdmin\MoTranslator\Loader', true)) { + if (! class_exists(Loader::class)) { return $msgid; } self::load(); + assert(self::$translator instanceof MoTranslator); return self::$translator->gettext($msgid); } + + public static function setLocale(string $locale): void + { + self::$locale = $locale; + } + + public static function getLocale(): string + { + return self::$locale; + } } diff --git a/tests/Misc/TranslatorTest.php b/tests/Misc/TranslatorTest.php new file mode 100644 index 00000000..ff46d538 --- /dev/null +++ b/tests/Misc/TranslatorTest.php @@ -0,0 +1,107 @@ +setAccessible(true); + $loaderProperty->setValue(null, null); + $translatorProperty = new ReflectionProperty(Translator::class, 'translator'); + $translatorProperty->setAccessible(true); + $translatorProperty->setValue(null, null); + Translator::setLocale('en'); + } + + public function testLocale(): void + { + Translator::setLocale('en'); + self::assertSame('en', Translator::getLocale()); + Translator::setLocale('fr'); + self::assertSame('fr', Translator::getLocale()); + Translator::setLocale(''); + self::assertSame('', Translator::getLocale()); + } + + /** + * @testWith [null, "en", "en"] + * [null, "fr", "fr"] + * ["en", "", "en"] + * ["fr", "", "fr"] + */ + public function testLoad(?string $globalLang, string $locale, string $expectedLocale): void + { + $loaderProperty = new ReflectionProperty(Translator::class, 'loader'); + $loaderProperty->setAccessible(true); + $loaderProperty->setValue(null, null); + $translatorProperty = new ReflectionProperty(Translator::class, 'translator'); + $translatorProperty->setAccessible(true); + $translatorProperty->setValue(null, null); + $GLOBALS['lang'] = $globalLang; + Translator::setLocale($locale); + + Translator::load(); + + self::assertSame($expectedLocale, Translator::getLocale()); + self::assertInstanceOf(MoTranslator::class, $translatorProperty->getValue()); + $loader = $loaderProperty->getValue(); + self::assertInstanceOf(Loader::class, $loader); + $loaderClass = new ReflectionClass(Loader::class); + $localeProperty = $loaderClass->getProperty('locale'); + $localeProperty->setAccessible(true); + self::assertSame($expectedLocale, $localeProperty->getValue($loader)); + // Compatibility with MoTranslator < 5 + $defaultDomainProperty = $loaderClass->hasProperty('default_domain') + ? $loaderClass->getProperty('default_domain') + : $loaderClass->getProperty('defaultDomain'); + $defaultDomainProperty->setAccessible(true); + self::assertSame('sqlparser', $defaultDomainProperty->getValue($loader)); + $pathsProperty = $loaderClass->getProperty('paths'); + $pathsProperty->setAccessible(true); + self::assertSame( + ['' => './', 'sqlparser' => realpath(__DIR__ . '/../../src/') . '/../locale/'], + $pathsProperty->getValue($loader) + ); + } + + public function testGettext(): void + { + $loaderProperty = new ReflectionProperty(Translator::class, 'loader'); + $loaderProperty->setAccessible(true); + $loaderProperty->setValue(null, null); + $translatorProperty = new ReflectionProperty(Translator::class, 'translator'); + $translatorProperty->setAccessible(true); + $translatorProperty->setValue(null, null); + Translator::setLocale('pt_BR'); + self::assertSame( + 'Início de declaração inesperado.', + Translator::gettext('Unexpected beginning of statement.') + ); + + $loaderProperty = new ReflectionProperty(Translator::class, 'loader'); + $loaderProperty->setAccessible(true); + $loaderProperty->setValue(null, null); + $translatorProperty = new ReflectionProperty(Translator::class, 'translator'); + $translatorProperty->setAccessible(true); + $translatorProperty->setValue(null, null); + Translator::setLocale('en'); + self::assertSame( + 'Unexpected beginning of statement.', + Translator::gettext('Unexpected beginning of statement.') + ); + } +} diff --git a/tests/TestCase.php b/tests/TestCase.php index 8351a84b..766a90a4 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -12,6 +12,7 @@ use PhpMyAdmin\SqlParser\Token; use PhpMyAdmin\SqlParser\TokensList; use PhpMyAdmin\SqlParser\Tools\CustomJsonSerializer; +use PhpMyAdmin\SqlParser\Translator; use PHPUnit\Framework\TestCase as BaseTestCase; use function file_get_contents; @@ -26,13 +27,12 @@ abstract class TestCase extends BaseTestCase { public function setUp(): void { - global $lang; // This line makes sure the test suite uses English so we can assert // on the error messages, if it is not here you will need to use // LC_ALL=C ./vendor/bin/phpunit // Users can have French language as default on their OS // That would make the assertions fail - $lang = 'en'; + Translator::setLocale('en'); Context::load(); }