diff --git a/.gitignore b/.gitignore index 3ee90a37..7482310e 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,7 @@ _vimrc_local.vim # Project files /config/config.php +/config/lang/ /test/coverage /public/coverage /coverage diff --git a/src/Helpers/Translation/TranslationServiceProvider.php b/src/Helpers/Translation/TranslationServiceProvider.php index 097d54d4..fb4cb5df 100644 --- a/src/Helpers/Translation/TranslationServiceProvider.php +++ b/src/Helpers/Translation/TranslationServiceProvider.php @@ -8,6 +8,7 @@ use Engelsystem\Http\Request; use Gettext\Loader\MoLoader; use Gettext\Loader\PoLoader; use Gettext\Translations; +use Illuminate\Contracts\Container\BindingResolutionException; use Illuminate\Support\Str; use Symfony\Component\HttpFoundation\Session\Session; @@ -74,19 +75,15 @@ class TranslationServiceProvider extends ServiceProvider /** @var Translations $translations */ $translations = $this->app->call([Translations::class, 'create']); + $path = $this->app->get('path.lang'); foreach ($names as $name) { - $file = $this->getFile($locale, $name); - if (Str::endsWith($file, '.mo')) { - /** @var MoLoader $loader */ - $loader = $this->app->make(MoLoader::class); - } else { - /** @var PoLoader $loader */ - $loader = $this->app->make(PoLoader::class); - } - - $translations = $loader->loadFile($file, $translations); + $file = $this->getFile($locale, $path, $name); + $translations = $this->loadFile($file, $translations); } + $file = $this->getFile($locale, $this->app->get('path.config') . '/lang', 'custom'); + $translations = $this->loadFile($file, $translations); + $translator = GettextTranslator::createFromTranslations($translations); $this->translators[$locale] = $translator; } @@ -94,9 +91,20 @@ class TranslationServiceProvider extends ServiceProvider return $this->translators[$locale]; } - protected function getFile(string $locale, string $name = 'default'): string + protected function loadFile(string $file, Translations $translations): Translations { - $filepath = $file = $this->app->get('path.lang') . '/' . $locale . '/' . $name; + if (!file_exists($file)) { + return $translations; + } + + $loader = $this->getFileLoader($file); + + return $loader->loadFile($file, $translations); + } + + protected function getFile(string $locale, string $basePath, string $name = 'default'): string + { + $filepath = $basePath . '/' . $locale . '/' . $name; $file = $filepath . '.mo'; if (!file_exists($file)) { @@ -105,4 +113,18 @@ class TranslationServiceProvider extends ServiceProvider return $file; } + + /** + * @throws BindingResolutionException + */ + protected function getFileLoader(string $file): MoLoader|PoLoader + { + if (Str::endsWith($file, '.mo')) { + /** @var MoLoader $loader */ + return $this->app->make(MoLoader::class); + } else { + /** @var PoLoader $loader */ + return $this->app->make(PoLoader::class); + } + } } diff --git a/tests/Unit/Helpers/Translation/Assets/ba_RR/additional.po b/tests/Unit/Helpers/Translation/Assets/ba_RR/additional.po index 72383947..dd0f99c7 100644 --- a/tests/Unit/Helpers/Translation/Assets/ba_RR/additional.po +++ b/tests/Unit/Helpers/Translation/Assets/ba_RR/additional.po @@ -1,3 +1,9 @@ # Testing content msgid "validation.foo.bar" msgstr "B Arr required!" + +msgid "msg.additional" +msgstr "Additional" + +msgid "msg.overwritten" +msgstr "From additional" diff --git a/tests/Unit/Helpers/Translation/Assets/ba_RR/default.po b/tests/Unit/Helpers/Translation/Assets/ba_RR/default.po index 887e2daa..8fd7138a 100644 --- a/tests/Unit/Helpers/Translation/Assets/ba_RR/default.po +++ b/tests/Unit/Helpers/Translation/Assets/ba_RR/default.po @@ -1,3 +1,9 @@ # Testing content msgid "foo.bar" msgstr "B Arr!" + +msgid "msg.default" +msgstr "Default" + +msgid "msg.overwritten" +msgstr "From default" diff --git a/tests/Unit/Helpers/Translation/Assets/config/lang/ba_RR/custom.po b/tests/Unit/Helpers/Translation/Assets/config/lang/ba_RR/custom.po new file mode 100644 index 00000000..c0a0c3ad --- /dev/null +++ b/tests/Unit/Helpers/Translation/Assets/config/lang/ba_RR/custom.po @@ -0,0 +1,8 @@ +msgid "msg.default" +msgstr "Custom default" + +msgid "msg.additional" +msgstr "Custom additional" + +msgid "msg.overwritten" +msgstr "Custom overwritten" diff --git a/tests/Unit/Helpers/Translation/TranslationServiceProviderTest.php b/tests/Unit/Helpers/Translation/TranslationServiceProviderTest.php index 8d63d3e0..85d21ce0 100644 --- a/tests/Unit/Helpers/Translation/TranslationServiceProviderTest.php +++ b/tests/Unit/Helpers/Translation/TranslationServiceProviderTest.php @@ -2,13 +2,13 @@ namespace Engelsystem\Test\Unit\Helpers\Translation; +use Engelsystem\Application; use Engelsystem\Config\Config; use Engelsystem\Helpers\Translation\TranslationServiceProvider; use Engelsystem\Helpers\Translation\Translator; use Engelsystem\Http\Request; use Engelsystem\Test\Unit\ServiceProviderTest; use PHPUnit\Framework\MockObject\MockObject; -use PHPUnit\Framework\MockObject\Rule\InvokedCount; use Symfony\Component\HttpFoundation\Session\Session; class TranslationServiceProviderTest extends ServiceProviderTest @@ -79,13 +79,15 @@ class TranslationServiceProviderTest extends ServiceProviderTest /** * @covers \Engelsystem\Helpers\Translation\TranslationServiceProvider::getTranslator + * @covers \Engelsystem\Helpers\Translation\TranslationServiceProvider::getFile + * @covers \Engelsystem\Helpers\Translation\TranslationServiceProvider::getFileLoader + * @covers \Engelsystem\Helpers\Translation\TranslationServiceProvider::loadFile */ public function testGetTranslator(): void { - $app = $this->getApp(['get']); - $serviceProvider = new TranslationServiceProvider($app); + $app = $this->getConfiguredApp(); - $this->setExpects($app, 'get', ['path.lang'], __DIR__ . '/Assets', new InvokedCount(2)); + $serviceProvider = new TranslationServiceProvider($app); // Get translator $translator = $serviceProvider->getTranslator('fo_OO'); @@ -99,11 +101,12 @@ class TranslationServiceProviderTest extends ServiceProviderTest /** * @covers \Engelsystem\Helpers\Translation\TranslationServiceProvider::getTranslator * @covers \Engelsystem\Helpers\Translation\TranslationServiceProvider::getFile + * @covers \Engelsystem\Helpers\Translation\TranslationServiceProvider::getFileLoader + * @covers \Engelsystem\Helpers\Translation\TranslationServiceProvider::loadFile */ public function testGetTranslatorFromPo(): void { - $app = $this->getApp(['get']); - $this->setExpects($app, 'get', ['path.lang'], __DIR__ . '/Assets', new InvokedCount(2)); + $app = $this->getConfiguredApp(); $serviceProvider = new TranslationServiceProvider($app); @@ -112,4 +115,31 @@ class TranslationServiceProviderTest extends ServiceProviderTest $this->assertEquals('B Arr!', $translator->gettext('foo.bar')); $this->assertEquals('B Arr required!', $translator->gettext('validation.foo.bar')); } + + /** + * @covers \Engelsystem\Helpers\Translation\TranslationServiceProvider::getTranslator + */ + public function testGetTranslatorCustom(): void + { + $app = $this->getConfiguredApp(); + + $serviceProvider = new TranslationServiceProvider($app); + + // Get translation from the custom.po file + $translator = $serviceProvider->getTranslator('ba_RR'); + $this->assertEquals('Custom default', $translator->gettext('msg.default')); + $this->assertEquals('Custom additional', $translator->gettext('msg.additional')); + $this->assertEquals('Custom overwritten', $translator->gettext('msg.overwritten')); + } + + private function getConfiguredApp(): Application|MockObject + { + $app = $this->getApp(['get']); + $app->expects($this->exactly(2)) + ->method('get') + ->withConsecutive(['path.lang'], ['path.config']) + ->willReturn(__DIR__ . '/Assets', __DIR__ . '/Assets/config'); + + return $app; + } }