Replaced gettext translation with package
This allows to check if no translation is available
This commit is contained in:
parent
f90ab26fee
commit
508695efb2
|
@ -14,7 +14,6 @@ To report bugs use [engelsystem/issues](https://github.com/engelsystem/engelsyst
|
||||||
* PHP >= 7.1
|
* PHP >= 7.1
|
||||||
* Required modules:
|
* Required modules:
|
||||||
* dom
|
* dom
|
||||||
* gettext
|
|
||||||
* json
|
* json
|
||||||
* mbstring
|
* mbstring
|
||||||
* PDO
|
* PDO
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
],
|
],
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=7.1.0",
|
"php": ">=7.1.0",
|
||||||
"ext-gettext": "*",
|
|
||||||
"ext-json": "*",
|
"ext-json": "*",
|
||||||
"ext-libxml": "*",
|
"ext-libxml": "*",
|
||||||
"ext-mbstring": "*",
|
"ext-mbstring": "*",
|
||||||
|
@ -24,6 +23,7 @@
|
||||||
"ext-xml": "*",
|
"ext-xml": "*",
|
||||||
"doctrine/dbal": "^2.9",
|
"doctrine/dbal": "^2.9",
|
||||||
"erusev/parsedown": "^1.7",
|
"erusev/parsedown": "^1.7",
|
||||||
|
"gettext/gettext": "^4.6",
|
||||||
"illuminate/container": "5.8.*",
|
"illuminate/container": "5.8.*",
|
||||||
"illuminate/database": "5.8.*",
|
"illuminate/database": "5.8.*",
|
||||||
"illuminate/support": "5.8.*",
|
"illuminate/support": "5.8.*",
|
||||||
|
|
|
@ -134,12 +134,12 @@ return [
|
||||||
|
|
||||||
// Available locales in /locale/
|
// Available locales in /locale/
|
||||||
'locales' => [
|
'locales' => [
|
||||||
'de_DE.UTF-8' => 'Deutsch',
|
'de_DE' => 'Deutsch',
|
||||||
'en_US.UTF-8' => 'English',
|
'en_US' => 'English',
|
||||||
],
|
],
|
||||||
|
|
||||||
// The default locale to use
|
// The default locale to use
|
||||||
'default_locale' => env('DEFAULT_LOCALE', 'en_US.UTF-8'),
|
'default_locale' => env('DEFAULT_LOCALE', 'en_US'),
|
||||||
|
|
||||||
// Available T-Shirt sizes, set value to null if not available
|
// Available T-Shirt sizes, set value to null if not available
|
||||||
'tshirt_sizes' => [
|
'tshirt_sizes' => [
|
||||||
|
|
|
@ -35,8 +35,8 @@ RUN rm -f /app/import/* /app/config/config.php
|
||||||
# Build the PHP container
|
# Build the PHP container
|
||||||
FROM php:7-fpm-alpine
|
FROM php:7-fpm-alpine
|
||||||
WORKDIR /var/www
|
WORKDIR /var/www
|
||||||
RUN apk add --no-cache icu-dev gettext-dev && \
|
RUN apk add --no-cache icu-dev && \
|
||||||
docker-php-ext-install intl gettext pdo_mysql
|
docker-php-ext-install intl pdo_mysql
|
||||||
COPY --from=data /app/ /var/www
|
COPY --from=data /app/ /var/www
|
||||||
RUN chown -R www-data:www-data /var/www/import/ /var/www/storage/ && \
|
RUN chown -R www-data:www-data /var/www/import/ /var/www/storage/ && \
|
||||||
rm -r /var/www/html
|
rm -r /var/www/html
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Engelsystem\Migrations;
|
||||||
|
|
||||||
|
use Engelsystem\Database\Migration\Migration;
|
||||||
|
|
||||||
|
class FixUserLanguages extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migration
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
$connection = $this->schema->getConnection();
|
||||||
|
$connection
|
||||||
|
->table('users_settings')
|
||||||
|
->update([
|
||||||
|
'language' => $connection->raw('REPLACE(language, ".UTF-8", "")')
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migration
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
$connection = $this->schema->getConnection();
|
||||||
|
$connection
|
||||||
|
->table('users_settings')
|
||||||
|
->update([
|
||||||
|
'language' => $connection->raw('CONCAT(language, ".UTF-8")')
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,7 +10,7 @@ msgstr ""
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Generator: Poedit 1.8.11\n"
|
"X-Generator: Poedit 1.8.11\n"
|
||||||
"X-Poedit-KeywordsList: __;_e;translate;translatePlural;gettext;gettext_noop\n"
|
"X-Poedit-KeywordsList: __;_e;translate;translatePlural\n"
|
||||||
"X-Poedit-Basepath: ../../../..\n"
|
"X-Poedit-Basepath: ../../../..\n"
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
"X-Poedit-SourceCharset: UTF-8\n"
|
"X-Poedit-SourceCharset: UTF-8\n"
|
|
@ -0,0 +1,53 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Engelsystem\Helpers\Translation;
|
||||||
|
|
||||||
|
use Gettext\Translator;
|
||||||
|
|
||||||
|
class GettextTranslator extends Translator
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param string $domain
|
||||||
|
* @param string $context
|
||||||
|
* @param string $original
|
||||||
|
* @return string
|
||||||
|
* @throws TranslationNotFound
|
||||||
|
*/
|
||||||
|
public function dpgettext($domain, $context, $original)
|
||||||
|
{
|
||||||
|
$this->assertHasTranslation($domain, $context, $original);
|
||||||
|
|
||||||
|
return parent::dpgettext($domain, $context, $original);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $domain
|
||||||
|
* @param string $context
|
||||||
|
* @param string $original
|
||||||
|
* @param string $plural
|
||||||
|
* @param string $value
|
||||||
|
* @return string
|
||||||
|
* @throws TranslationNotFound
|
||||||
|
*/
|
||||||
|
public function dnpgettext($domain, $context, $original, $plural, $value)
|
||||||
|
{
|
||||||
|
$this->assertHasTranslation($domain, $context, $original);
|
||||||
|
|
||||||
|
return parent::dnpgettext($domain, $context, $original, $plural, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $domain
|
||||||
|
* @param string $context
|
||||||
|
* @param string $original
|
||||||
|
* @throws TranslationNotFound
|
||||||
|
*/
|
||||||
|
protected function assertHasTranslation($domain, $context, $original)
|
||||||
|
{
|
||||||
|
if ($this->getTranslation($domain, $context, $original)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new TranslationNotFound(implode('/', [$domain, $context, $original]));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Engelsystem\Helpers\Translation;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
class TranslationNotFound extends Exception
|
||||||
|
{
|
||||||
|
}
|
|
@ -4,11 +4,15 @@ namespace Engelsystem\Helpers\Translation;
|
||||||
|
|
||||||
use Engelsystem\Config\Config;
|
use Engelsystem\Config\Config;
|
||||||
use Engelsystem\Container\ServiceProvider;
|
use Engelsystem\Container\ServiceProvider;
|
||||||
|
use Gettext\Translations;
|
||||||
use Symfony\Component\HttpFoundation\Session\Session;
|
use Symfony\Component\HttpFoundation\Session\Session;
|
||||||
|
|
||||||
class TranslationServiceProvider extends ServiceProvider
|
class TranslationServiceProvider extends ServiceProvider
|
||||||
{
|
{
|
||||||
public function register()
|
/** @var GettextTranslator */
|
||||||
|
protected $translators = [];
|
||||||
|
|
||||||
|
public function register(): void
|
||||||
{
|
{
|
||||||
/** @var Config $config */
|
/** @var Config $config */
|
||||||
$config = $this->app->get('config');
|
$config = $this->app->get('config');
|
||||||
|
@ -17,41 +21,36 @@ class TranslationServiceProvider extends ServiceProvider
|
||||||
|
|
||||||
$locales = $config->get('locales');
|
$locales = $config->get('locales');
|
||||||
$locale = $config->get('default_locale');
|
$locale = $config->get('default_locale');
|
||||||
|
$fallbackLocale = $config->get('fallback_locale', 'en_US');
|
||||||
|
|
||||||
$sessionLocale = $session->get('locale', $locale);
|
$sessionLocale = $session->get('locale', $locale);
|
||||||
if (isset($locales[$sessionLocale])) {
|
if (isset($locales[$sessionLocale])) {
|
||||||
$locale = $sessionLocale;
|
$locale = $sessionLocale;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->initGettext();
|
|
||||||
$session->set('locale', $locale);
|
$session->set('locale', $locale);
|
||||||
|
|
||||||
$translator = $this->app->make(
|
$translator = $this->app->make(
|
||||||
Translator::class,
|
Translator::class,
|
||||||
['locale' => $locale, 'locales' => $locales, 'localeChangeCallback' => [$this, 'setLocale']]
|
[
|
||||||
|
'locale' => $locale,
|
||||||
|
'locales' => $locales,
|
||||||
|
'fallbackLocale' => $fallbackLocale,
|
||||||
|
'getTranslatorCallback' => [$this, 'getTranslator'],
|
||||||
|
'localeChangeCallback' => [$this, 'setLocale'],
|
||||||
|
]
|
||||||
);
|
);
|
||||||
$this->app->instance(Translator::class, $translator);
|
$this->app->instance(Translator::class, $translator);
|
||||||
$this->app->instance('translator', $translator);
|
$this->app->instance('translator', $translator);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $textDomain
|
|
||||||
* @param string $encoding
|
|
||||||
* @codeCoverageIgnore
|
|
||||||
*/
|
|
||||||
protected function initGettext($textDomain = 'default', $encoding = 'UTF-8')
|
|
||||||
{
|
|
||||||
bindtextdomain($textDomain, $this->app->get('path.lang'));
|
|
||||||
bind_textdomain_codeset($textDomain, $encoding);
|
|
||||||
textdomain($textDomain);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $locale
|
* @param string $locale
|
||||||
* @codeCoverageIgnore
|
* @codeCoverageIgnore
|
||||||
*/
|
*/
|
||||||
public function setLocale($locale)
|
public function setLocale(string $locale): void
|
||||||
{
|
{
|
||||||
|
$locale .= '.UTF-8';
|
||||||
// Set the users locale
|
// Set the users locale
|
||||||
putenv('LC_ALL=' . $locale);
|
putenv('LC_ALL=' . $locale);
|
||||||
setlocale(LC_ALL, $locale);
|
setlocale(LC_ALL, $locale);
|
||||||
|
@ -60,4 +59,28 @@ class TranslationServiceProvider extends ServiceProvider
|
||||||
putenv('LC_NUMERIC=C');
|
putenv('LC_NUMERIC=C');
|
||||||
setlocale(LC_NUMERIC, 'C');
|
setlocale(LC_NUMERIC, 'C');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $locale
|
||||||
|
* @return GettextTranslator
|
||||||
|
*/
|
||||||
|
public function getTranslator(string $locale): GettextTranslator
|
||||||
|
{
|
||||||
|
if (!isset($this->translators[$locale])) {
|
||||||
|
$file = $this->app->get('path.lang') . '/' . $locale . '/default.mo';
|
||||||
|
|
||||||
|
/** @var GettextTranslator $translator */
|
||||||
|
$translator = $this->app->make(GettextTranslator::class);
|
||||||
|
|
||||||
|
/** @var Translations $translations */
|
||||||
|
$translations = $this->app->make(Translations::class);
|
||||||
|
$translations->addFromMoFile($file);
|
||||||
|
|
||||||
|
$translator->loadTranslations($translations);
|
||||||
|
|
||||||
|
$this->translators[$locale] = $translator;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->translators[$locale];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,12 @@ class Translator
|
||||||
/** @var string */
|
/** @var string */
|
||||||
protected $locale;
|
protected $locale;
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
protected $fallbackLocale;
|
||||||
|
|
||||||
|
/** @var callable */
|
||||||
|
protected $getTranslatorCallback;
|
||||||
|
|
||||||
/** @var callable */
|
/** @var callable */
|
||||||
protected $localeChangeCallback;
|
protected $localeChangeCallback;
|
||||||
|
|
||||||
|
@ -17,15 +23,24 @@ class Translator
|
||||||
* Translator constructor.
|
* Translator constructor.
|
||||||
*
|
*
|
||||||
* @param string $locale
|
* @param string $locale
|
||||||
|
* @param string $fallbackLocale
|
||||||
|
* @param callable $getTranslatorCallback
|
||||||
* @param string[] $locales
|
* @param string[] $locales
|
||||||
* @param callable $localeChangeCallback
|
* @param callable $localeChangeCallback
|
||||||
*/
|
*/
|
||||||
public function __construct(string $locale, array $locales = [], callable $localeChangeCallback = null)
|
public function __construct(
|
||||||
{
|
string $locale,
|
||||||
|
string $fallbackLocale,
|
||||||
|
callable $getTranslatorCallback,
|
||||||
|
array $locales = [],
|
||||||
|
callable $localeChangeCallback = null
|
||||||
|
) {
|
||||||
$this->localeChangeCallback = $localeChangeCallback;
|
$this->localeChangeCallback = $localeChangeCallback;
|
||||||
|
$this->getTranslatorCallback = $getTranslatorCallback;
|
||||||
|
|
||||||
$this->setLocale($locale);
|
$this->setLocale($locale);
|
||||||
$this->setLocales($locales);
|
$this->fallbackLocale = $fallbackLocale;
|
||||||
|
$this->locales = $locales;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -37,9 +52,7 @@ class Translator
|
||||||
*/
|
*/
|
||||||
public function translate(string $key, array $replace = []): string
|
public function translate(string $key, array $replace = []): string
|
||||||
{
|
{
|
||||||
$translated = $this->translateGettext($key);
|
return $this->translateText('gettext', [$key], $replace);
|
||||||
|
|
||||||
return $this->replaceText($translated, $replace);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -53,7 +66,29 @@ class Translator
|
||||||
*/
|
*/
|
||||||
public function translatePlural(string $key, string $pluralKey, int $number, array $replace = []): string
|
public function translatePlural(string $key, string $pluralKey, int $number, array $replace = []): string
|
||||||
{
|
{
|
||||||
$translated = $this->translateGettextPlural($key, $pluralKey, $number);
|
return $this->translateText('ngettext', [$key, $pluralKey, $number], $replace);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $type
|
||||||
|
* @param array $parameters
|
||||||
|
* @param array $replace
|
||||||
|
* @return mixed|string
|
||||||
|
*/
|
||||||
|
protected function translateText(string $type, array $parameters, array $replace = [])
|
||||||
|
{
|
||||||
|
$translated = $parameters[0];
|
||||||
|
|
||||||
|
foreach ([$this->locale, $this->fallbackLocale] as $lang) {
|
||||||
|
/** @var GettextTranslator $translator */
|
||||||
|
$translator = call_user_func($this->getTranslatorCallback, $lang);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$translated = call_user_func_array([$translator, $type], $parameters);
|
||||||
|
break;
|
||||||
|
} catch (TranslationNotFound $e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return $this->replaceText($translated, $replace);
|
return $this->replaceText($translated, $replace);
|
||||||
}
|
}
|
||||||
|
@ -74,32 +109,6 @@ class Translator
|
||||||
return call_user_func_array('sprintf', array_merge([$key], $replace));
|
return call_user_func_array('sprintf', array_merge([$key], $replace));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Translate the key via gettext
|
|
||||||
*
|
|
||||||
* @param string $key
|
|
||||||
* @return string
|
|
||||||
* @codeCoverageIgnore
|
|
||||||
*/
|
|
||||||
protected function translateGettext(string $key): string
|
|
||||||
{
|
|
||||||
return gettext($key);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Translate the key via gettext
|
|
||||||
*
|
|
||||||
* @param string $key
|
|
||||||
* @param string $keyPlural
|
|
||||||
* @param int $number
|
|
||||||
* @return string
|
|
||||||
* @codeCoverageIgnore
|
|
||||||
*/
|
|
||||||
protected function translateGettextPlural(string $key, string $keyPlural, int $number): string
|
|
||||||
{
|
|
||||||
return ngettext($key, $keyPlural, $number);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
|
|
Binary file not shown.
|
@ -0,0 +1,3 @@
|
||||||
|
# Testing content
|
||||||
|
msgid "foo.bar"
|
||||||
|
msgstr "Foo Bar!"
|
|
@ -0,0 +1,67 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Engelsystem\Test\Unit\Helpers\Translation;
|
||||||
|
|
||||||
|
use Engelsystem\Helpers\Translation\GettextTranslator;
|
||||||
|
use Engelsystem\Helpers\Translation\TranslationNotFound;
|
||||||
|
use Engelsystem\Test\Unit\ServiceProviderTest;
|
||||||
|
use Gettext\Translation;
|
||||||
|
use Gettext\Translations;
|
||||||
|
|
||||||
|
class GettextTranslatorTest extends ServiceProviderTest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Helpers\Translation\GettextTranslator::assertHasTranslation()
|
||||||
|
*/
|
||||||
|
public function testNoTranslation()
|
||||||
|
{
|
||||||
|
$translations = $this->getTranslations();
|
||||||
|
|
||||||
|
$translator = new GettextTranslator();
|
||||||
|
$translator->loadTranslations($translations);
|
||||||
|
|
||||||
|
$this->assertEquals('Translation!', $translator->gettext('test.value'));
|
||||||
|
|
||||||
|
$this->expectException(TranslationNotFound::class);
|
||||||
|
$this->expectExceptionMessage('//foo.bar');
|
||||||
|
|
||||||
|
$translator->gettext('foo.bar');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Helpers\Translation\GettextTranslator::dpgettext()
|
||||||
|
*/
|
||||||
|
public function testDpgettext()
|
||||||
|
{
|
||||||
|
$translations = $this->getTranslations();
|
||||||
|
|
||||||
|
$translator = new GettextTranslator();
|
||||||
|
$translator->loadTranslations($translations);
|
||||||
|
|
||||||
|
$this->assertEquals('Translation!', $translator->dpgettext(null, null, 'test.value'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Helpers\Translation\GettextTranslator::dnpgettext()
|
||||||
|
*/
|
||||||
|
public function testDnpgettext()
|
||||||
|
{
|
||||||
|
$translations = $this->getTranslations();
|
||||||
|
|
||||||
|
$translator = new GettextTranslator();
|
||||||
|
$translator->loadTranslations($translations);
|
||||||
|
|
||||||
|
$this->assertEquals('Translations!', $translator->dnpgettext(null, null, 'test.value', 'test.values', 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getTranslations(): Translations
|
||||||
|
{
|
||||||
|
$translations = new Translations();
|
||||||
|
$translations[] =
|
||||||
|
(new Translation(null, 'test.value', 'test.values'))
|
||||||
|
->setTranslation('Translation!')
|
||||||
|
->setPluralTranslations(['Translations!']);
|
||||||
|
|
||||||
|
return $translations;
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,11 +14,14 @@ class TranslationServiceProviderTest extends ServiceProviderTest
|
||||||
/**
|
/**
|
||||||
* @covers \Engelsystem\Helpers\Translation\TranslationServiceProvider::register()
|
* @covers \Engelsystem\Helpers\Translation\TranslationServiceProvider::register()
|
||||||
*/
|
*/
|
||||||
public function testRegister()
|
public function testRegister(): void
|
||||||
{
|
{
|
||||||
|
$defaultLocale = 'fo_OO';
|
||||||
|
$locale = 'te_ST.WTF-9';
|
||||||
|
$locales = ['fo_OO' => 'Foo', 'fo_OO.BAR' => 'Foo (Bar)', 'te_ST.WTF-9' => 'WTF\'s Testing?'];
|
||||||
|
$config = new Config(['locales' => $locales, 'default_locale' => $defaultLocale]);
|
||||||
|
|
||||||
$app = $this->getApp(['make', 'instance', 'get']);
|
$app = $this->getApp(['make', 'instance', 'get']);
|
||||||
/** @var Config|MockObject $config */
|
|
||||||
$config = $this->createMock(Config::class);
|
|
||||||
/** @var Session|MockObject $session */
|
/** @var Session|MockObject $session */
|
||||||
$session = $this->createMock(Session::class);
|
$session = $this->createMock(Session::class);
|
||||||
/** @var Translator|MockObject $translator */
|
/** @var Translator|MockObject $translator */
|
||||||
|
@ -27,31 +30,14 @@ class TranslationServiceProviderTest extends ServiceProviderTest
|
||||||
/** @var TranslationServiceProvider|MockObject $serviceProvider */
|
/** @var TranslationServiceProvider|MockObject $serviceProvider */
|
||||||
$serviceProvider = $this->getMockBuilder(TranslationServiceProvider::class)
|
$serviceProvider = $this->getMockBuilder(TranslationServiceProvider::class)
|
||||||
->setConstructorArgs([$app])
|
->setConstructorArgs([$app])
|
||||||
->setMethods(['initGettext', 'setLocale'])
|
->setMethods(['setLocale'])
|
||||||
->getMock();
|
->getMock();
|
||||||
|
|
||||||
$serviceProvider->expects($this->once())
|
|
||||||
->method('initGettext');
|
|
||||||
|
|
||||||
$app->expects($this->exactly(2))
|
$app->expects($this->exactly(2))
|
||||||
->method('get')
|
->method('get')
|
||||||
->withConsecutive(['config'], ['session'])
|
->withConsecutive(['config'], ['session'])
|
||||||
->willReturnOnConsecutiveCalls($config, $session);
|
->willReturnOnConsecutiveCalls($config, $session);
|
||||||
|
|
||||||
$defaultLocale = 'fo_OO';
|
|
||||||
$locale = 'te_ST.WTF-9';
|
|
||||||
$locales = ['fo_OO' => 'Foo', 'fo_OO.BAR' => 'Foo (Bar)', 'te_ST.WTF-9' => 'WTF\'s Testing?'];
|
|
||||||
$config->expects($this->exactly(2))
|
|
||||||
->method('get')
|
|
||||||
->withConsecutive(
|
|
||||||
['locales'],
|
|
||||||
['default_locale']
|
|
||||||
)
|
|
||||||
->willReturnOnConsecutiveCalls(
|
|
||||||
$locales,
|
|
||||||
$defaultLocale
|
|
||||||
);
|
|
||||||
|
|
||||||
$session->expects($this->once())
|
$session->expects($this->once())
|
||||||
->method('get')
|
->method('get')
|
||||||
->with('locale', $defaultLocale)
|
->with('locale', $defaultLocale)
|
||||||
|
@ -67,6 +53,8 @@ class TranslationServiceProviderTest extends ServiceProviderTest
|
||||||
[
|
[
|
||||||
'locale' => $locale,
|
'locale' => $locale,
|
||||||
'locales' => $locales,
|
'locales' => $locales,
|
||||||
|
'fallbackLocale' => 'en_US',
|
||||||
|
'getTranslatorCallback' => [$serviceProvider, 'getTranslator'],
|
||||||
'localeChangeCallback' => [$serviceProvider, 'setLocale'],
|
'localeChangeCallback' => [$serviceProvider, 'setLocale'],
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
@ -81,4 +69,22 @@ class TranslationServiceProviderTest extends ServiceProviderTest
|
||||||
|
|
||||||
$serviceProvider->register();
|
$serviceProvider->register();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Helpers\Translation\TranslationServiceProvider::getTranslator()
|
||||||
|
*/
|
||||||
|
public function testGetTranslator(): void
|
||||||
|
{
|
||||||
|
$app = $this->getApp(['get']);
|
||||||
|
$serviceProvider = new TranslationServiceProvider($app);
|
||||||
|
|
||||||
|
$this->setExpects($app, 'get', ['path.lang'], __DIR__ . '/Assets');
|
||||||
|
|
||||||
|
// Get translator
|
||||||
|
$translator = $serviceProvider->getTranslator('fo_OO');
|
||||||
|
$this->assertEquals('Foo Bar!', $translator->gettext('foo.bar'));
|
||||||
|
|
||||||
|
// Retry from cache
|
||||||
|
$serviceProvider->getTranslator('fo_OO');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
namespace Engelsystem\Test\Unit\Helpers\Translation;
|
namespace Engelsystem\Test\Unit\Helpers\Translation;
|
||||||
|
|
||||||
|
use Engelsystem\Helpers\Translation\GettextTranslator;
|
||||||
|
use Engelsystem\Helpers\Translation\TranslationNotFound;
|
||||||
use Engelsystem\Helpers\Translation\Translator;
|
use Engelsystem\Helpers\Translation\Translator;
|
||||||
use Engelsystem\Test\Unit\ServiceProviderTest;
|
use Engelsystem\Test\Unit\ServiceProviderTest;
|
||||||
use PHPUnit\Framework\MockObject\MockObject;
|
use PHPUnit\Framework\MockObject\MockObject;
|
||||||
|
@ -19,18 +21,18 @@ class TranslatorTest extends ServiceProviderTest
|
||||||
*/
|
*/
|
||||||
public function testInit()
|
public function testInit()
|
||||||
{
|
{
|
||||||
$locales = ['te_ST.ER-01' => 'Tests', 'fo_OO' => 'SomeFOO'];
|
$locales = ['te_ST' => 'Tests', 'fo_OO' => 'SomeFOO'];
|
||||||
$locale = 'te_ST.ER-01';
|
$locale = 'te_ST';
|
||||||
|
|
||||||
/** @var callable|MockObject $callable */
|
/** @var callable|MockObject $localeChange */
|
||||||
$callable = $this->getMockBuilder(stdClass::class)
|
$localeChange = $this->getMockBuilder(stdClass::class)
|
||||||
->setMethods(['__invoke'])
|
->setMethods(['__invoke'])
|
||||||
->getMock();
|
->getMock();
|
||||||
$callable->expects($this->exactly(2))
|
$localeChange->expects($this->exactly(2))
|
||||||
->method('__invoke')
|
->method('__invoke')
|
||||||
->withConsecutive(['te_ST.ER-01'], ['fo_OO']);
|
->withConsecutive(['te_ST'], ['fo_OO']);
|
||||||
|
|
||||||
$translator = new Translator($locale, $locales, $callable);
|
$translator = new Translator($locale, 'fo_OO', function () { }, $locales, $localeChange);
|
||||||
|
|
||||||
$this->assertEquals($locales, $translator->getLocales());
|
$this->assertEquals($locales, $translator->getLocales());
|
||||||
$this->assertEquals($locale, $translator->getLocale());
|
$this->assertEquals($locale, $translator->getLocale());
|
||||||
|
@ -43,24 +45,23 @@ class TranslatorTest extends ServiceProviderTest
|
||||||
$this->assertEquals($newLocales, $translator->getLocales());
|
$this->assertEquals($newLocales, $translator->getLocales());
|
||||||
|
|
||||||
$this->assertTrue($translator->hasLocale('ip_SU-M'));
|
$this->assertTrue($translator->hasLocale('ip_SU-M'));
|
||||||
$this->assertFalse($translator->hasLocale('te_ST.ER-01'));
|
$this->assertFalse($translator->hasLocale('te_ST'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @covers \Engelsystem\Helpers\Translation\Translator::replaceText
|
|
||||||
* @covers \Engelsystem\Helpers\Translation\Translator::translate
|
* @covers \Engelsystem\Helpers\Translation\Translator::translate
|
||||||
*/
|
*/
|
||||||
public function testTranslate()
|
public function testTranslate()
|
||||||
{
|
{
|
||||||
/** @var Translator|MockObject $translator */
|
/** @var Translator|MockObject $translator */
|
||||||
$translator = $this->getMockBuilder(Translator::class)
|
$translator = $this->getMockBuilder(Translator::class)
|
||||||
->setConstructorArgs(['de_DE.UTF-8', ['de_DE.UTF-8' => 'Deutsch']])
|
->setConstructorArgs(['de_DE', 'en_US', function () { }, ['de_DE' => 'Deutsch']])
|
||||||
->setMethods(['translateGettext'])
|
->setMethods(['translateText'])
|
||||||
->getMock();
|
->getMock();
|
||||||
$translator->expects($this->exactly(2))
|
$translator->expects($this->exactly(2))
|
||||||
->method('translateGettext')
|
->method('translateText')
|
||||||
->withConsecutive(['Hello!'], ['My favourite number is %u!'])
|
->withConsecutive(['gettext', ['Hello!'], []], ['gettext', ['My favourite number is %u!'], [3]])
|
||||||
->willReturnOnConsecutiveCalls('Hallo!', 'Meine Lieblingszahl ist die %u!');
|
->willReturnOnConsecutiveCalls('Hallo!', 'Meine Lieblingszahl ist die 3!');
|
||||||
|
|
||||||
$return = $translator->translate('Hello!');
|
$return = $translator->translate('Hello!');
|
||||||
$this->assertEquals('Hallo!', $return);
|
$this->assertEquals('Hallo!', $return);
|
||||||
|
@ -76,15 +77,58 @@ class TranslatorTest extends ServiceProviderTest
|
||||||
{
|
{
|
||||||
/** @var Translator|MockObject $translator */
|
/** @var Translator|MockObject $translator */
|
||||||
$translator = $this->getMockBuilder(Translator::class)
|
$translator = $this->getMockBuilder(Translator::class)
|
||||||
->setConstructorArgs(['de_DE.UTF-8', ['de_DE.UTF-8' => 'Deutsch']])
|
->setConstructorArgs(['de_DE', 'en_US', function () { }, ['de_DE' => 'Deutsch']])
|
||||||
->setMethods(['translateGettextPlural'])
|
->setMethods(['translateText'])
|
||||||
->getMock();
|
->getMock();
|
||||||
$translator->expects($this->once())
|
$translator->expects($this->once())
|
||||||
->method('translateGettextPlural')
|
->method('translateText')
|
||||||
->with('%s apple', '%s apples', 2)
|
->with('ngettext', ['%s apple', '%s apples', 2], [2])
|
||||||
->willReturn('2 Äpfel');
|
->willReturn('2 Äpfel');
|
||||||
|
|
||||||
$return = $translator->translatePlural('%s apple', '%s apples', 2, [2]);
|
$return = $translator->translatePlural('%s apple', '%s apples', 2, [2]);
|
||||||
$this->assertEquals('2 Äpfel', $return);
|
$this->assertEquals('2 Äpfel', $return);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Helpers\Translation\Translator::translatePlural
|
||||||
|
* @covers \Engelsystem\Helpers\Translation\Translator::translateText
|
||||||
|
* @covers \Engelsystem\Helpers\Translation\Translator::replaceText
|
||||||
|
*/
|
||||||
|
public function testReplaceText()
|
||||||
|
{
|
||||||
|
/** @var GettextTranslator|MockObject $gtt */
|
||||||
|
$gtt = $this->createMock(GettextTranslator::class);
|
||||||
|
/** @var callable|MockObject $getTranslator */
|
||||||
|
$getTranslator = $this->getMockBuilder(stdClass::class)
|
||||||
|
->setMethods(['__invoke'])
|
||||||
|
->getMock();
|
||||||
|
$getTranslator->expects($this->exactly(5))
|
||||||
|
->method('__invoke')
|
||||||
|
->withConsecutive(['te_ST'], ['fo_OO'], ['te_ST'], ['fo_OO'], ['te_ST'])
|
||||||
|
->willReturn($gtt);
|
||||||
|
|
||||||
|
$i = 0;
|
||||||
|
$gtt->expects($this->exactly(4))
|
||||||
|
->method('gettext')
|
||||||
|
->willReturnCallback(function () use (&$i) {
|
||||||
|
$i++;
|
||||||
|
if ($i != 4) {
|
||||||
|
throw new TranslationNotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'Lorem %s???';
|
||||||
|
});
|
||||||
|
$this->setExpects($gtt, 'ngettext', ['foo.barf'], 'Lorem %s!');
|
||||||
|
|
||||||
|
$translator = new Translator('te_ST', 'fo_OO', $getTranslator, ['te_ST' => 'Test', 'fo_OO' => 'Foo']);
|
||||||
|
|
||||||
|
// No translation
|
||||||
|
$this->assertEquals('foo.bar', $translator->translate('foo.bar'));
|
||||||
|
|
||||||
|
// Fallback translation
|
||||||
|
$this->assertEquals('Lorem test2???', $translator->translate('foo.batz', ['test2']));
|
||||||
|
|
||||||
|
// Successful translation
|
||||||
|
$this->assertEquals('Lorem test3!', $translator->translatePlural('foo.barf', 'foo.bar2', 3, ['test3']));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue