installation de motranslator

via Composer
This commit is contained in:
2024-12-13 06:44:07 +01:00
parent 3ee1a9eaf6
commit db9f05f6f6
249 changed files with 29788 additions and 0 deletions

View File

@@ -0,0 +1,98 @@
<?php
declare(strict_types=1);
namespace PhpMyAdmin\MoTranslator\Tests\Cache;
use PhpMyAdmin\MoTranslator\Cache\ApcuCache;
use PhpMyAdmin\MoTranslator\Cache\ApcuCacheFactory;
use PhpMyAdmin\MoTranslator\MoParser;
use PHPUnit\Framework\TestCase;
use function apcu_clear_cache;
use function apcu_delete;
use function apcu_enabled;
use function apcu_fetch;
use function function_exists;
use function sleep;
/**
* @covers \PhpMyAdmin\MoTranslator\Cache\ApcuCacheFactory
*/
class ApcuCacheFactoryTest extends TestCase
{
protected function setUp(): void
{
parent::setUp();
if (function_exists('apcu_enabled') && apcu_enabled()) {
return;
}
$this->markTestSkipped('ACPu extension is not installed and enabled for CLI');
}
protected function tearDown(): void
{
parent::tearDown();
apcu_clear_cache();
}
public function testGetInstanceReturnApcuCache(): void
{
$factory = new ApcuCacheFactory();
$instance = $factory->getInstance(new MoParser(null), 'foo', 'bar');
$this->assertInstanceOf(ApcuCache::class, $instance);
}
public function testConstructorSetsTtl(): void
{
$locale = 'foo';
$domain = 'bar';
$msgid = 'Column';
$ttl = 1;
$factory = new ApcuCacheFactory($ttl);
$parser = new MoParser(__DIR__ . '/../data/little.mo');
$factory->getInstance($parser, $locale, $domain);
sleep($ttl * 2);
apcu_fetch('mo_' . $locale . '.' . $domain . '.' . $msgid, $success);
$this->assertFalse($success);
}
public function testConstructorSetsReloadOnMiss(): void
{
$expected = 'Column';
$locale = 'foo';
$domain = 'bar';
$msgid = 'Column';
$factory = new ApcuCacheFactory(0, false);
$parser = new MoParser(__DIR__ . '/../data/little.mo');
$instance = $factory->getInstance($parser, $locale, $domain);
apcu_delete('mo_' . $locale . '.' . $domain . '.' . $msgid);
$actual = $instance->get($msgid);
$this->assertSame($expected, $actual);
}
public function testConstructorSetsPrefix(): void
{
$expected = 'Pole';
$locale = 'foo';
$domain = 'bar';
$msgid = 'Column';
$prefix = 'baz_';
$factory = new ApcuCacheFactory(0, true, $prefix);
$parser = new MoParser(__DIR__ . '/../data/little.mo');
$factory->getInstance($parser, $locale, $domain);
$actual = apcu_fetch($prefix . $locale . '.' . $domain . '.' . $msgid);
$this->assertSame($expected, $actual);
}
}

View File

@@ -0,0 +1,270 @@
<?php
declare(strict_types=1);
namespace PhpMyAdmin\MoTranslator\Tests\Cache;
use PhpMyAdmin\MoTranslator\Cache\ApcuCache;
use PhpMyAdmin\MoTranslator\MoParser;
use PHPUnit\Framework\TestCase;
use ReflectionMethod;
use function apcu_clear_cache;
use function apcu_delete;
use function apcu_enabled;
use function apcu_entry;
use function apcu_fetch;
use function chr;
use function explode;
use function function_exists;
use function implode;
use function sleep;
/**
* @covers \PhpMyAdmin\MoTranslator\Cache\ApcuCache
*/
class ApcuCacheTest extends TestCase
{
protected function setUp(): void
{
parent::setUp();
if (function_exists('apcu_enabled') && apcu_enabled()) {
return;
}
$this->markTestSkipped('ACPu extension is not installed and enabled for CLI');
}
protected function tearDown(): void
{
parent::tearDown();
apcu_clear_cache();
}
public function testConstructorLoadsCache(): void
{
$expected = 'Pole';
$locale = 'foo';
$domain = 'bar';
$msgid = 'Column';
new ApcuCache(new MoParser(__DIR__ . '/../data/little.mo'), $locale, $domain);
$actual = apcu_fetch('mo_' . $locale . '.' . $domain . '.' . $msgid);
$this->assertSame($expected, $actual);
}
public function testConstructorSetsTtl(): void
{
$locale = 'foo';
$domain = 'bar';
$msgid = 'Column';
$ttl = 1;
new ApcuCache(new MoParser(__DIR__ . '/../data/little.mo'), $locale, $domain, $ttl);
sleep($ttl * 2);
apcu_fetch('mo_' . $locale . '.' . $domain . '.' . $msgid, $success);
$this->assertFalse($success);
apcu_fetch('mo_' . $locale . '.' . $domain . '.' . ApcuCache::LOADED_KEY, $success);
$this->assertFalse($success);
}
public function testConstructorSetsReloadOnMiss(): void
{
$expected = 'Column';
$locale = 'foo';
$domain = 'bar';
$msgid = 'Column';
$prefix = 'baz_';
$cache = new ApcuCache(
new MoParser(__DIR__ . '/../data/little.mo'),
$locale,
$domain,
0,
false,
$prefix
);
apcu_delete($prefix . $locale . '.' . $domain . '.' . $msgid);
$actual = $cache->get($msgid);
$this->assertEquals($expected, $actual);
}
public function testConstructorSetsPrefix(): void
{
$expected = 'Pole';
$locale = 'foo';
$domain = 'bar';
$msgid = 'Column';
$prefix = 'baz_';
new ApcuCache(new MoParser(__DIR__ . '/../data/little.mo'), $locale, $domain, 0, true, $prefix);
$actual = apcu_fetch($prefix . $locale . '.' . $domain . '.' . $msgid);
$this->assertSame($expected, $actual);
}
public function testEnsureTranslationsLoadedSetsLoadedKey(): void
{
$expected = 1;
$locale = 'foo';
$domain = 'bar';
new ApcuCache(new MoParser(__DIR__ . '/../data/little.mo'), $locale, $domain);
$actual = apcu_fetch('mo_' . $locale . '.' . $domain . '.' . ApcuCache::LOADED_KEY);
$this->assertSame($expected, $actual);
}
public function testEnsureTranslationsLoadedHonorsLock(): void
{
$locale = 'foo';
$domain = 'bar';
$msgid = 'Column';
$lock = 'mo_' . $locale . '.' . $domain . '.' . ApcuCache::LOADED_KEY;
apcu_entry($lock, static function () {
sleep(1);
return 1;
});
new ApcuCache(new MoParser(__DIR__ . '/../data/little.mo'), $locale, $domain);
$actual = apcu_fetch($lock);
$this->assertSame(1, $actual);
apcu_fetch('mo_' . $locale . '.' . $domain . '.' . $msgid, $success);
$this->assertFalse($success);
}
public function testGetReturnsMsgstr(): void
{
$expected = 'Pole';
$msgid = 'Column';
$cache = new ApcuCache(new MoParser(__DIR__ . '/../data/little.mo'), 'foo', 'bar');
$actual = $cache->get($msgid);
$this->assertSame($expected, $actual);
}
public function testGetReturnsMsgidForCacheMiss(): void
{
$expected = 'Column';
$cache = new ApcuCache(new MoParser(null), 'foo', 'bar');
$actual = $cache->get($expected);
$this->assertSame($expected, $actual);
}
public function testStoresMsgidOnCacheMiss(): void
{
$expected = 'Column';
$locale = 'foo';
$domain = 'bar';
$cache = new ApcuCache(new MoParser(null), $locale, $domain);
$cache->get($expected);
$actual = apcu_fetch('mo_' . $locale . '.' . $domain . '.' . $expected);
$this->assertSame($expected, $actual);
}
public function testGetReloadsOnCacheMiss(): void
{
$expected = 'Pole';
$locale = 'foo';
$domain = 'bar';
$msgid = 'Column';
$cache = new ApcuCache(new MoParser(__DIR__ . '/../data/little.mo'), $locale, $domain);
apcu_delete('mo_' . $locale . '.' . $domain . '.' . ApcuCache::LOADED_KEY);
$actual = $cache->get($msgid);
$this->assertSame($expected, $actual);
}
public function testReloadOnMissHonorsLock(): void
{
$expected = 'Pole';
$locale = 'foo';
$domain = 'bar';
$msgid = 'Column';
$cache = new ApcuCache(new MoParser(null), $locale, $domain);
$method = new ReflectionMethod($cache, 'reloadOnMiss');
$method->setAccessible(true);
$key = 'mo_' . $locale . '.' . $domain . '.' . $msgid;
apcu_entry($key, static function () use ($expected): string {
sleep(1);
return $expected;
});
$actual = $method->invoke($cache, $msgid);
$this->assertSame($expected, $actual);
}
public function testSetSetsMsgstr(): void
{
$expected = 'Pole';
$msgid = 'Column';
$cache = new ApcuCache(new MoParser(null), 'foo', 'bar');
$cache->set($msgid, $expected);
$actual = $cache->get($msgid);
$this->assertSame($expected, $actual);
}
public function testHasReturnsFalse(): void
{
$cache = new ApcuCache(new MoParser(null), 'foo', 'bar');
$actual = $cache->has('Column');
$this->assertFalse($actual);
}
public function testHasReturnsTrue(): void
{
$cache = new ApcuCache(new MoParser(__DIR__ . '/../data/little.mo'), 'foo', 'bar');
$actual = $cache->has('Column');
$this->assertTrue($actual);
}
public function testSetAllSetsTranslations(): void
{
$translations = [
'foo' => 'bar',
'and' => 'another',
];
$cache = new ApcuCache(new MoParser(null), 'foo', 'bar');
$cache->setAll($translations);
foreach ($translations as $msgid => $expected) {
$actual = $cache->get($msgid);
$this->assertEquals($expected, $actual);
}
}
public function testCacheStoresPluralForms(): void
{
$expected = ['first', 'second'];
$plural = ["%d pig went to the market\n", "%d pigs went to the market\n"];
$msgid = implode(chr(0), $plural);
$cache = new ApcuCache(new MoParser(null), 'foo', 'bar');
$cache->set($msgid, implode(chr(0), $expected));
$msgstr = $cache->get($msgid);
$actual = explode(chr(0), $msgstr);
$this->assertSame($expected, $actual);
}
}

View File

@@ -0,0 +1,27 @@
<?php
declare(strict_types=1);
namespace PhpMyAdmin\MoTranslator\Tests\Cache;
use PhpMyAdmin\MoTranslator\Cache\ApcuCache;
use PhpMyAdmin\MoTranslator\CacheException;
use PhpMyAdmin\MoTranslator\MoParser;
use PHPUnit\Framework\TestCase;
use function apcu_enabled;
use function function_exists;
final class ApcuDisabledTest extends TestCase
{
public function testConstructorApcuNotEnabledThrowsException(): void
{
if (function_exists('apcu_enabled') && apcu_enabled()) {
$this->markTestSkipped('ext-apcu is enabled');
}
$this->expectException(CacheException::class);
$this->expectExceptionMessage('ACPu extension must be installed and enabled');
new ApcuCache(new MoParser(null), 'foo', 'bar');
}
}

View File

@@ -0,0 +1,82 @@
<?php
declare(strict_types=1);
namespace PhpMyAdmin\MoTranslator\Tests\Cache;
use PhpMyAdmin\MoTranslator\Cache\InMemoryCache;
use PhpMyAdmin\MoTranslator\MoParser;
use PHPUnit\Framework\TestCase;
/**
* @covers \PhpMyAdmin\MoTranslator\Cache\InMemoryCache
*/
class InMemoryCacheTest extends TestCase
{
public function testConstructorParsesCache(): void
{
$expected = 'Pole';
$parser = new MoParser(__DIR__ . '/../data/little.mo');
$cache = new InMemoryCache($parser);
$actual = $cache->get('Column');
$this->assertSame($expected, $actual);
}
public function testGetReturnsMsgidForCacheMiss(): void
{
$expected = 'Column';
$cache = new InMemoryCache(new MoParser(null));
$actual = $cache->get($expected);
$this->assertSame($expected, $actual);
}
public function testSetSetsMsgstr(): void
{
$expected = 'Pole';
$msgid = 'Column';
$cache = new InMemoryCache(new MoParser(null));
$cache->set($msgid, $expected);
$actual = $cache->get($msgid);
$this->assertSame($expected, $actual);
}
public function testHasReturnsFalse(): void
{
$cache = new InMemoryCache(new MoParser(null));
$actual = $cache->has('Column');
$this->assertFalse($actual);
}
public function testHasReturnsTrue(): void
{
$cache = new InMemoryCache(new MoParser(__DIR__ . '/../data/little.mo'));
$actual = $cache->has('Column');
$this->assertTrue($actual);
}
public function testSetAllSetsTranslations(): void
{
$translations = [
'foo' => 'bar',
'and' => 'another',
];
$cache = new InMemoryCache(new MoParser(null));
$cache->setAll($translations);
foreach ($translations as $msgid => $expected) {
$actual = $cache->get($msgid);
$this->assertEquals($expected, $actual);
}
}
public function testGetAllReturnsTranslations(): void
{
$expected = [
'foo' => 'bar',
'and' => 'another',
];
$cache = new InMemoryCache(new MoParser(null));
$cache->setAll($expected);
$actual = $cache->getAll();
$this->assertSame($expected, $actual);
}
}

View File

@@ -0,0 +1,102 @@
<?php
declare(strict_types=1);
namespace PhpMyAdmin\MoTranslator\Tests;
use PhpMyAdmin\MoTranslator\Loader;
use PHPUnit\Framework\TestCase;
/**
* Test for functions.
*/
class FunctionsTest extends TestCase
{
public function setUp(): void
{
Loader::loadFunctions();
_setlocale(0, 'cs');
_textdomain('phpmyadmin');
_bindtextdomain('phpmyadmin', __DIR__ . '/data/locale/');
_bind_textdomain_codeset('phpmyadmin', 'UTF-8');
}
public function testGettext(): void
{
$this->assertEquals(
'Typ',
_gettext('Type')
);
$this->assertEquals(
'Typ',
__('Type')
);
$this->assertEquals(
'%d sekundy',
_ngettext(
'%d second',
'%d seconds',
2
)
);
$this->assertEquals(
'%d seconds',
_npgettext(
'context',
'%d second',
'%d seconds',
2
)
);
$this->assertEquals(
'Tabulka',
_pgettext(
'Display format',
'Table'
)
);
}
public function testDomain(): void
{
$this->assertEquals(
'Typ',
_dgettext('phpmyadmin', 'Type')
);
$this->assertEquals(
'%d sekundy',
_dngettext(
'phpmyadmin',
'%d second',
'%d seconds',
2
)
);
$this->assertEquals(
'%d seconds',
_dnpgettext(
'phpmyadmin',
'context',
'%d second',
'%d seconds',
2
)
);
$this->assertEquals(
'Tabulka',
_dpgettext(
'phpmyadmin',
'Display format',
'Table'
)
);
}
}

View File

@@ -0,0 +1,325 @@
<?php
declare(strict_types=1);
namespace PhpMyAdmin\MoTranslator\Tests;
use PhpMyAdmin\MoTranslator\Cache\CacheFactoryInterface;
use PhpMyAdmin\MoTranslator\Cache\CacheInterface;
use PhpMyAdmin\MoTranslator\Loader;
use PhpMyAdmin\MoTranslator\MoParser;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use function getenv;
use function putenv;
/**
* Test for mo loading.
*/
class LoaderTest extends TestCase
{
/**
* @param array[] $expected
*
* @dataProvider localeList
*/
public function testListLocales(string $locale, array $expected): void
{
$this->assertEquals(
$expected,
Loader::listLocales($locale)
);
}
/**
* @return array[]
*/
public function localeList(): array
{
return [
[
'cs_CZ',
[
'cs_CZ',
'cs',
],
],
[
'sr_CS.UTF-8@latin',
[
'sr_CS.UTF-8@latin',
'sr_CS@latin',
'sr@latin',
'sr_CS.UTF-8',
'sr_CS',
'sr',
],
],
// For a locale containing country code, we prefer
// full locale name, but if that's not found, fall back
// to the language only locale name.
[
'sr_RS',
[
'sr_RS',
'sr',
],
],
// If language code is used, it's the only thing returned.
[
'sr',
['sr'],
],
// There is support for language and charset only.
[
'sr.UTF-8',
[
'sr.UTF-8',
'sr',
],
],
// It can also split out character set from the full locale name.
[
'sr_RS.UTF-8',
[
'sr_RS.UTF-8',
'sr_RS',
'sr',
],
],
// There is support for @modifier in locale names as well.
[
'sr_RS.UTF-8@latin',
[
'sr_RS.UTF-8@latin',
'sr_RS@latin',
'sr@latin',
'sr_RS.UTF-8',
'sr_RS',
'sr',
],
],
[
'sr.UTF-8@latin',
[
'sr.UTF-8@latin',
'sr@latin',
'sr.UTF-8',
'sr',
],
],
// We can pass in only language and modifier.
[
'sr@latin',
[
'sr@latin',
'sr',
],
],
// If locale name is not following the regular POSIX pattern,
// it's used verbatim.
[
'something',
['something'],
],
// Passing in an empty string returns an empty array.
[
'',
[],
],
];
}
private function getLoader(string $domain, string $locale): Loader
{
$loader = new Loader();
$loader->setlocale($locale);
$loader->textdomain($domain);
$loader->bindtextdomain($domain, __DIR__ . '/data/locale/');
return $loader;
}
public function testLocaleChange(): void
{
$loader = new Loader();
$loader->setlocale('cs');
$loader->textdomain('phpmyadmin');
$loader->bindtextdomain('phpmyadmin', __DIR__ . '/data/locale/');
$translator = $loader->getTranslator('phpmyadmin');
$this->assertEquals('Typ', $translator->gettext('Type'));
$loader->setlocale('be_BY');
$translator = $loader->getTranslator('phpmyadmin');
$this->assertEquals('Тып', $translator->gettext('Type'));
}
/**
* @dataProvider translatorData
*/
public function testGetTranslator(string $domain, string $locale, string $otherdomain, string $expected): void
{
$loader = $this->getLoader($domain, $locale);
$translator = $loader->getTranslator($otherdomain);
$this->assertEquals(
$expected,
$translator->gettext('Type')
);
}
/**
* @return array[]
*/
public function translatorData(): array
{
return [
[
'phpmyadmin',
'cs',
'',
'Typ',
],
[
'phpmyadmin',
'cs_CZ',
'',
'Typ',
],
[
'phpmyadmin',
'be_BY',
'',
'Тып',
],
[
'phpmyadmin',
'be@latin',
'',
'Typ',
],
[
'phpmyadmin',
'cs',
'other',
'Type',
],
[
'other',
'cs',
'phpmyadmin',
'Type',
],
];
}
public function testInstance(): void
{
$loader = Loader::getInstance();
$loader->setlocale('cs');
$loader->textdomain('phpmyadmin');
$loader->bindtextdomain('phpmyadmin', __DIR__ . '/data/locale/');
$translator = $loader->getTranslator();
$this->assertEquals(
'Typ',
$translator->gettext('Type')
);
/* Ensure the object survives */
$loader = Loader::getInstance();
$translator = $loader->getTranslator();
$this->assertEquals(
'Typ',
$translator->gettext('Type')
);
/* Ensure the object can support different locale files for the same domain */
$loader = Loader::getInstance();
$loader->setlocale('be_BY');
$loader->bindtextdomain('phpmyadmin', __DIR__ . '/data/locale/');
$translator = $loader->getTranslator();
$this->assertEquals(
'Тып',
$translator->gettext('Type')
);
}
public function testDetect(): void
{
$GLOBALS['lang'] = 'foo';
$loader = Loader::getInstance();
$this->assertEquals(
'foo',
$loader->detectlocale()
);
unset($GLOBALS['lang']);
}
public function testDetectEnv(): void
{
$loader = Loader::getInstance();
foreach (['LC_MESSAGES', 'LC_ALL', 'LANG'] as $var) {
putenv($var);
if (getenv($var) === false) {
continue;
}
$this->markTestSkipped('Unsetting environment does not work');
}
unset($GLOBALS['lang']);
putenv('LC_ALL=baz');
$this->assertEquals(
'baz',
$loader->detectlocale()
);
putenv('LC_ALL');
putenv('LC_MESSAGES=bar');
$this->assertEquals(
'bar',
$loader->detectlocale()
);
putenv('LC_MESSAGES');
putenv('LANG=barr');
$this->assertEquals(
'barr',
$loader->detectlocale()
);
putenv('LANG');
$this->assertEquals(
'en',
$loader->detectlocale()
);
}
public function testSetCacheFactory(): void
{
$expected = 'Foo';
$locale = 'be_BY';
$domain = 'apcu';
$cache = $this->createMock(CacheInterface::class);
$cache->method('get')
->willReturn($expected);
/** @var CacheFactoryInterface&MockObject $factory */
$factory = $this->createMock(CacheFactoryInterface::class);
$factory->expects($this->once())
->method('getInstance')
->with($this->isInstanceOf(MoParser::class), $locale, $domain)
->willReturn($cache);
Loader::setCacheFactory($factory);
$loader = Loader::getInstance();
$loader->setlocale($locale);
$loader->bindtextdomain($domain, __DIR__ . '/data/locale/');
$translator = $loader->getTranslator($domain);
$actual = $translator->gettext('Type');
$this->assertEquals($expected, $actual);
}
}

View File

@@ -0,0 +1,230 @@
<?php
declare(strict_types=1);
namespace PhpMyAdmin\MoTranslator\Tests;
use PhpMyAdmin\MoTranslator\Cache\InMemoryCache;
use PhpMyAdmin\MoTranslator\MoParser;
use PhpMyAdmin\MoTranslator\Translator;
use PHPUnit\Framework\TestCase;
use function basename;
use function glob;
use function strpos;
/**
* Test for MO files parsing.
*/
class MoFilesTest extends TestCase
{
/**
* @dataProvider provideMoFiles
*/
public function testMoFileTranslate(string $filename): void
{
$parser = $this->getTranslator($filename);
$this->assertEquals(
'Pole',
$parser->gettext('Column')
);
// Non existing string
$this->assertEquals(
'Column parser',
$parser->gettext('Column parser')
);
}
/**
* @dataProvider provideMoFiles
*/
public function testMoFilePlurals(string $filename): void
{
$parser = $this->getTranslator($filename);
$expected2 = '%d sekundy';
if (strpos($filename, 'invalid-formula.mo') !== false || strpos($filename, 'lessplurals.mo') !== false) {
$expected0 = '%d sekunda';
$expected2 = '%d sekunda';
} elseif (strpos($filename, 'plurals.mo') !== false || strpos($filename, 'noheader.mo') !== false) {
$expected0 = '%d sekundy';
} else {
$expected0 = '%d sekund';
}
$this->assertEquals(
$expected0,
$parser->ngettext(
'%d second',
'%d seconds',
0
)
);
$this->assertEquals(
'%d sekunda',
$parser->ngettext(
'%d second',
'%d seconds',
1
)
);
$this->assertEquals(
$expected2,
$parser->ngettext(
'%d second',
'%d seconds',
2
)
);
$this->assertEquals(
$expected0,
$parser->ngettext(
'%d second',
'%d seconds',
5
)
);
$this->assertEquals(
$expected0,
$parser->ngettext(
'%d second',
'%d seconds',
10
)
);
// Non existing string
$this->assertEquals(
'"%d" seconds',
$parser->ngettext(
'"%d" second',
'"%d" seconds',
10
)
);
}
/**
* @dataProvider provideMoFiles
*/
public function testMoFileContext(string $filename): void
{
$parser = $this->getTranslator($filename);
$this->assertEquals(
'Tabulka',
$parser->pgettext(
'Display format',
'Table'
)
);
}
/**
* @dataProvider provideNotTranslatedFiles
*/
public function testMoFileNotTranslated(string $filename): void
{
$parser = $this->getTranslator($filename);
$this->assertEquals(
'%d second',
$parser->ngettext(
'%d second',
'%d seconds',
1
)
);
}
/**
* @return array[]
*/
public function provideMoFiles(): array
{
return $this->getFiles('./tests/data/*.mo');
}
/**
* @return array[]
*/
public function provideErrorMoFiles(): array
{
return $this->getFiles('./tests/data/error/*.mo');
}
/**
* @return array[]
*/
public function provideNotTranslatedFiles(): array
{
return $this->getFiles('./tests/data/not-translated/*.mo');
}
/**
* @dataProvider provideErrorMoFiles
*/
public function testEmptyMoFile(string $file): void
{
$parser = new MoParser($file);
$translator = new Translator(new InMemoryCache($parser));
if (basename($file) === 'magic.mo') {
$this->assertEquals(Translator::ERROR_BAD_MAGIC, $parser->error);
} else {
$this->assertEquals(Translator::ERROR_READING, $parser->error);
}
$this->assertEquals(
'Table',
$translator->pgettext(
'Display format',
'Table'
)
);
$this->assertEquals(
'"%d" seconds',
$translator->ngettext(
'"%d" second',
'"%d" seconds',
10
)
);
}
/**
* @dataProvider provideMoFiles
*/
public function testExists(string $file): void
{
$parser = $this->getTranslator($file);
$this->assertEquals(
true,
$parser->exists('Column')
);
$this->assertEquals(
false,
$parser->exists('Column parser')
);
}
/**
* @param string $pattern path names pattern to match
*
* @return array[]
*/
private function getFiles(string $pattern): array
{
$files = glob($pattern);
if ($files === false) {
return [];
}
$result = [];
foreach ($files as $file) {
$result[] = [$file];
}
return $result;
}
private function getTranslator(string $filename): Translator
{
return new Translator(new InMemoryCache(new MoParser($filename)));
}
}

View File

@@ -0,0 +1,152 @@
<?php
declare(strict_types=1);
namespace PhpMyAdmin\MoTranslator\Tests;
use PhpMyAdmin\MoTranslator\Translator;
use PHPUnit\Framework\TestCase;
/**
* Test for gettext parsing.
*/
class PluralFormulaTest extends TestCase
{
/**
* Test for extractPluralsForms.
*
* @dataProvider pluralExtractionData
*/
public function testExtractPluralsForms(string $header, string $expected): void
{
$this->assertEquals(
$expected,
Translator::extractPluralsForms($header)
);
}
/**
* @return array[]
*/
public function pluralExtractionData(): array
{
return [
// It defaults to a "Western-style" plural header.
[
'',
'nplurals=2; plural=n == 1 ? 0 : 1;',
],
// Extracting it from the middle of the header works.
[
"Content-type: text/html; charset=UTF-8\n"
. "Plural-Forms: nplurals=1; plural=0;\n"
. "Last-Translator: nobody\n",
' nplurals=1; plural=0;',
],
// It's also case-insensitive.
[
"PLURAL-forms: nplurals=1; plural=0;\n",
' nplurals=1; plural=0;',
],
// It falls back to default if it's not on a separate line.
[
'Content-type: text/html; charset=UTF-8' // note the missing \n here
. "Plural-Forms: nplurals=1; plural=0;\n"
. "Last-Translator: nobody\n",
'nplurals=2; plural=n == 1 ? 0 : 1;',
],
];
}
/**
* @dataProvider pluralCounts
*/
public function testPluralCounts(string $expr, int $expected): void
{
$this->assertEquals(
$expected,
Translator::extractPluralCount($expr)
);
}
/**
* @return array[]
*/
public function pluralCounts(): array
{
return [
[
'',
1,
],
[
'foo=2; expr',
1,
],
[
'nplurals=2; epxr',
2,
],
[
' nplurals = 3 ; epxr',
3,
],
[
' nplurals = 4 ; epxr ; ',
4,
],
[
'nplurals',
1,
],
];
}
/**
* @dataProvider pluralExpressions
*/
public function testPluralExpression(string $expr, string $expected): void
{
$this->assertEquals(
$expected,
Translator::sanitizePluralExpression($expr)
);
}
/**
* @return array[]
*/
public function pluralExpressions(): array
{
return [
[
'',
'',
],
[
'nplurals=2; plural=n == 1 ? 0 : 1;',
'n == 1 ? 0 : 1',
],
[
' nplurals=1; plural=0;',
'0',
],
[
"nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 ? 4 : 5;\n",
'n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 ? 4 : 5',
],
[
' nplurals=1; plural=baz(n);',
'(n)',
],
[
' plural=n',
'n',
],
[
'nplurals',
'n',
],
];
}
}

View File

@@ -0,0 +1,125 @@
<?php
declare(strict_types=1);
namespace PhpMyAdmin\MoTranslator\Tests;
use PhpMyAdmin\MoTranslator\Cache\InMemoryCache;
use PhpMyAdmin\MoTranslator\MoParser;
use PhpMyAdmin\MoTranslator\Translator;
use PHPUnit\Framework\TestCase;
use function chr;
use function implode;
/**
* Test for gettext parsing.
*/
class PluralTest extends TestCase
{
/**
* Test for npgettext.
*
* @param int $number Number
* @param string $expected Expected output
*
* @dataProvider providerTestNpgettext
*/
public function testNpgettext(int $number, string $expected): void
{
$parser = $this->getTranslator('');
$result = $parser->npgettext('context', "%d pig went to the market\n", "%d pigs went to the market\n", $number);
$this->assertSame($expected, $result);
}
/**
* Data provider for test_npgettext.
*
* @return array[]
*/
public static function providerTestNpgettext(): array
{
return [
[
1,
"%d pig went to the market\n",
],
[
2,
"%d pigs went to the market\n",
],
];
}
/**
* Test for ngettext
*/
public function testNgettext(): void
{
$parser = $this->getTranslator('');
$translationKey = implode(chr(0), ["%d pig went to the market\n", "%d pigs went to the market\n"]);
$parser->setTranslation($translationKey, '');
$result = $parser->ngettext("%d pig went to the market\n", "%d pigs went to the market\n", 1);
$this->assertSame('', $result);
}
/**
* @return array[]
*/
public function dataProviderPluralForms(): array
{
return [
['Plural-Forms: nplurals=2; plural=n != 1;'],
['Plural-Forms: nplurals=1; plural=0;'],
['Plural-Forms: nplurals=2; plural=(n > 1);'],
[
'Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n'
. '%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;',
],
['Plural-Forms: nplurals=2; plural=n >= 2 && (n < 11 || n > 99);'],
['Plural-Forms: nplurals=4; plural=n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3;'],
['Plural-Forms: nplurals=3; plural=n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < 20)) ? 1 : 2;'],
[
'Plural-Forms: nplurals=2; plural=n != 1 && n != 2 && n != 3 &'
. '& (n % 10 == 4 || n % 10 == 6 || n % 10 == 9);',
],
];
}
/**
* Test for ngettext
*
* @see https://github.com/phpmyadmin/motranslator/issues/37
*
* @dataProvider dataProviderPluralForms
*/
public function testNgettextSelectString(string $pluralForms): void
{
$parser = $this->getTranslator('');
$parser->setTranslation(
'',
"Project-Id-Version: phpMyAdmin 5.1.0-dev\n"
. "Report-Msgid-Bugs-To: translators@phpmyadmin.net\n"
. "PO-Revision-Date: 2020-09-01 09:12+0000\n"
. "Last-Translator: William Desportes <williamdes@wdes.fr>\n"
. 'Language-Team: English (United Kingdom) '
. "<https:\/\/hosted.weblate.org\/projects\/phpmyadmin\/master\/en_GB\/>\n"
. "Language: en_GB\n"
. "MIME-Version: 1.0\n"
. "Content-Type: text\/plain; charset=UTF-8\n"
. "Content-Transfer-Encoding: 8bit\n"
. $pluralForms . "\n"
. "X-Generator: Weblate 4.2.1-dev\n"
. ''
);
$translationKey = implode(chr(0), ["%d pig went to the market\n", "%d pigs went to the market\n"]);
$parser->setTranslation($translationKey, 'ok');
$result = $parser->ngettext("%d pig went to the market\n", "%d pigs went to the market\n", 1);
$this->assertSame('ok', $result);
}
private function getTranslator(string $filename): Translator
{
return new Translator(new InMemoryCache(new MoParser($filename)));
}
}

View File

@@ -0,0 +1,40 @@
<?php
declare(strict_types=1);
namespace PhpMyAdmin\MoTranslator\Tests;
use PhpMyAdmin\MoTranslator\StringReader;
use PHPUnit\Framework\TestCase;
use function file_put_contents;
use function sys_get_temp_dir;
use function tempnam;
use function unlink;
class StringReaderTest extends TestCase
{
public function testReadFails(): void
{
$tempFile = (string) tempnam(sys_get_temp_dir(), 'phpMyAdmin_StringReaderTest');
$this->assertFileExists($tempFile);
$stringReader = new StringReader($tempFile);
unlink($tempFile);
$actual = $stringReader->read(-1, -1);
$this->assertSame('', $actual);
}
public function testReadIntArray(): void
{
$tempFile = (string) tempnam(sys_get_temp_dir(), 'phpMyAdmin_StringReaderTest');
file_put_contents($tempFile, "\0\0\0\0\0\0\0\0\0\0\0\0");
$this->assertFileExists($tempFile);
$stringReader = new StringReader($tempFile);
unlink($tempFile);
$actual = $stringReader->readintarray('V', 2, 2);
$this->assertSame([
1 => 0,
2 => 0,
], $actual);
}
}

View File

@@ -0,0 +1,98 @@
<?php
declare(strict_types=1);
namespace PhpMyAdmin\MoTranslator\Tests;
use PhpMyAdmin\MoTranslator\Cache\CacheInterface;
use PhpMyAdmin\MoTranslator\Cache\InMemoryCache;
use PhpMyAdmin\MoTranslator\CacheException;
use PhpMyAdmin\MoTranslator\MoParser;
use PhpMyAdmin\MoTranslator\Translator;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
/**
* Test for translator API
*/
class TranslatorTest extends TestCase
{
public function testConstructorWithFilenameParam(): void
{
$expected = 'Pole';
$translator = new Translator(__DIR__ . '/data/little.mo');
$actual = $translator->gettext('Column');
$this->assertSame($expected, $actual);
}
public function testConstructorWithNullParam(): void
{
$expected = 'Column';
$translator = new Translator(null);
$actual = $translator->gettext($expected);
$this->assertSame($expected, $actual);
}
/**
* Test on empty gettext
*/
public function testGettext(): void
{
$translator = $this->getTranslator('');
$this->assertEquals('Test', $translator->gettext('Test'));
}
/**
* Test set a translation
*/
public function testSetTranslation(): void
{
$translator = $this->getTranslator('');
$translator->setTranslation('Test', 'Translation');
$this->assertEquals('Translation', $translator->gettext('Test'));
}
/**
* Test get and set all translations
*/
public function testGetSetTranslations(): void
{
$transTable = ['Test' => 'Translation'];
$translator = $this->getTranslator('');
$translator->setTranslations($transTable);
$this->assertEquals('Translation', $translator->gettext('Test'));
$this->assertSame($transTable, $translator->getTranslations());
$translator = $this->getTranslator(null);
$translator->setTranslations($transTable);
$this->assertSame($transTable, $translator->getTranslations());
$this->assertEquals('Translation', $translator->gettext('Test'));
$transTable = [
'Test' => 'Translation',
'shouldIWriteTests' => 'as much as possible',
'is it hard' => 'it depends',
];
$translator = $this->getTranslator('');
$translator->setTranslations($transTable);
$this->assertSame($transTable, $translator->getTranslations());
$this->assertEquals('as much as possible', $translator->gettext('shouldIWriteTests'));
$translator = $this->getTranslator(null);
$translator->setTranslations($transTable);
$this->assertSame($transTable, $translator->getTranslations());
$this->assertEquals('it depends', $translator->gettext('is it hard'));
}
public function testGetTranslationsThrowsException(): void
{
/** @var CacheInterface&MockObject $cache */
$cache = $this->createMock(CacheInterface::class);
$translator = new Translator($cache);
$this->expectException(CacheException::class);
$translator->getTranslations();
}
private function getTranslator(?string $filename): Translator
{
return new Translator(new InMemoryCache(new MoParser($filename)));
}
}

Binary file not shown.

View File

@@ -0,0 +1 @@
<EFBFBD><12>1111<31><31><EFBFBD><EFBFBD>

View File

@@ -0,0 +1 @@
<EFBFBD><12>1111<31><7F><EFBFBD>

Binary file not shown.

View File

@@ -0,0 +1 @@
<EFBFBD><04><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>

View File

@@ -0,0 +1 @@
1234

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.