From 3b91aa141f489013a4c9f0f8a5f11f739a2dc4b6 Mon Sep 17 00:00:00 2001 From: Arman <407448+armanist@users.noreply.github.com> Date: Wed, 15 Oct 2025 21:37:27 +0400 Subject: [PATCH 1/3] Refactor Lang library and move language configuration to a dedicated `lang.php` config file --- src/App/Traits/AppTrait.php | 8 +- .../Lang/Exceptions/LangException.php | 9 +- src/Libraries/Lang/Factories/LangFactory.php | 78 ++++++++ src/Libraries/Lang/Helpers/lang.php | 26 ++- src/Libraries/Lang/Lang.php | 174 ++++-------------- src/Libraries/Lang/Translator.php | 116 ++++++++++++ .../src/Controllers/AccountController.php.tpl | 3 +- .../src/Controllers/AuthController.php.tpl | 7 +- .../src/Controllers/BaseController.php.tpl | 4 +- .../src/Controllers/PageController.php.tpl | 4 +- .../src/Controllers/PostController.php.tpl | 7 +- .../Lang/Factories/LangFactoryTest.php | 64 +++++++ .../Lang/Helpers/LangHelperFunctionsTest.php | 53 ++---- tests/Unit/Libraries/Lang/LangTest.php | 109 +++++------ tests/Unit/Libraries/Lang/TranslatorTest.php | 39 ++++ tests/_root/shared/config/lang.php | 13 ++ 16 files changed, 442 insertions(+), 272 deletions(-) create mode 100644 src/Libraries/Lang/Factories/LangFactory.php create mode 100644 src/Libraries/Lang/Translator.php create mode 100644 tests/Unit/Libraries/Lang/Factories/LangFactoryTest.php create mode 100644 tests/Unit/Libraries/Lang/TranslatorTest.php create mode 100644 tests/_root/shared/config/lang.php diff --git a/src/App/Traits/AppTrait.php b/src/App/Traits/AppTrait.php index 1faa7757..37f7f8d9 100644 --- a/src/App/Traits/AppTrait.php +++ b/src/App/Traits/AppTrait.php @@ -9,22 +9,22 @@ * @author Arman Ag. * @copyright Copyright (c) 2018 Softberg LLC (https://softberg.org) * @link http://quantum.softberg.org/ - * @since 2.9.8 + * @since 2.9.9 */ namespace Quantum\App\Traits; use Quantum\Libraries\Logger\Factories\LoggerFactory; use Quantum\Libraries\Lang\Exceptions\LangException; +use Quantum\Libraries\Lang\Factories\LangFactory; use Quantum\Environment\Exceptions\EnvException; use Quantum\Config\Exceptions\ConfigException; use Quantum\App\Exceptions\BaseException; use Quantum\Di\Exceptions\DiException; use Quantum\Environment\Environment; -use Quantum\Libraries\Lang\Lang; use Quantum\Tracer\ErrorHandler; -use Quantum\Config\Config; use Quantum\Loader\Loader; +use Quantum\Config\Config; use Quantum\Loader\Setup; use ReflectionException; use Quantum\App\App; @@ -169,7 +169,7 @@ protected function setupErrorHandler() */ protected function loadLanguage() { - $lang = Lang::getInstance(); + $lang = LangFactory::get(); if ($lang->isEnabled()) { $lang->load(); diff --git a/src/Libraries/Lang/Exceptions/LangException.php b/src/Libraries/Lang/Exceptions/LangException.php index d455a741..acb08e15 100644 --- a/src/Libraries/Lang/Exceptions/LangException.php +++ b/src/Libraries/Lang/Exceptions/LangException.php @@ -9,7 +9,7 @@ * @author Arman Ag. * @copyright Copyright (c) 2018 Softberg LLC (https://softberg.org) * @link http://quantum.softberg.org/ - * @since 2.9.7 + * @since 2.9.9 */ namespace Quantum\Libraries\Lang\Exceptions; @@ -24,12 +24,11 @@ class LangException extends BaseException { /** - * @param string $name * @return LangException */ - public static function translationsNotFound(string $name): LangException + public static function translationsNotFound(): LangException { - return new static(t('exception.translation_files_not_found', $name), E_WARNING); + return new static('Translation files not found', E_WARNING); } /** @@ -37,6 +36,6 @@ public static function translationsNotFound(string $name): LangException */ public static function misconfiguredDefaultConfig(): LangException { - return new static(t('exception.misconfigured_lang_default_config'), E_WARNING); + return new static('Misconfigured lang default config', E_WARNING); } } \ No newline at end of file diff --git a/src/Libraries/Lang/Factories/LangFactory.php b/src/Libraries/Lang/Factories/LangFactory.php new file mode 100644 index 00000000..a1629ac1 --- /dev/null +++ b/src/Libraries/Lang/Factories/LangFactory.php @@ -0,0 +1,78 @@ + + * @copyright Copyright (c) 2018 Softberg LLC (https://softberg.org) + * @link http://quantum.softberg.org/ + * @since 2.9.9 + */ + +namespace Quantum\Libraries\Lang\Factories; + +use Quantum\Libraries\Lang\Exceptions\LangException; +use Quantum\Config\Exceptions\ConfigException; +use Quantum\Di\Exceptions\DiException; +use Quantum\Libraries\Lang\Translator; +use Quantum\Libraries\Lang\Lang; +use Quantum\Http\Request; +use Quantum\Loader\Setup; +use ReflectionException; + +/** + * Class LangFactory + * @package Quantum\Libraries\Lang + */ +class LangFactory +{ + + /** + * @var Lang|null Cached Lang instance + */ + private static $instance = null; + + /** + * @return Lang + * @throws ConfigException + * @throws LangException + * @throws DiException + * @throws ReflectionException + */ + public static function get(): Lang + { + if (self::$instance !== null) { + return self::$instance; + } + + if (!config()->has('lang')) { + config()->import(new Setup('config', 'lang')); + } + + $isEnabled = filter_var(config()->get('lang.enabled'), FILTER_VALIDATE_BOOLEAN); + + + $langSegmentIndex = (int)config()->get('lang.url_segment'); + + if (!empty(route_prefix()) && $langSegmentIndex == 1) { + $langSegmentIndex++; + } + + $lang = Request::getSegment($langSegmentIndex); + + if (empty($lang) || !in_array($lang, (array)config()->get('lang.supported'))) { + $lang = config()->get('lang.default'); + } + + if (!$lang) { + throw LangException::misconfiguredDefaultConfig(); + } + + $translator = new Translator($lang); + + return self::$instance = new Lang($lang, $isEnabled, $translator); + } +} diff --git a/src/Libraries/Lang/Helpers/lang.php b/src/Libraries/Lang/Helpers/lang.php index c0ce28b5..6558cf3b 100644 --- a/src/Libraries/Lang/Helpers/lang.php +++ b/src/Libraries/Lang/Helpers/lang.php @@ -9,18 +9,25 @@ * @author Arman Ag. * @copyright Copyright (c) 2018 Softberg LLC (https://softberg.org) * @link http://quantum.softberg.org/ - * @since 2.9.5 + * @since 2.9.9 */ -use Quantum\Libraries\Lang\Lang; +use Quantum\Libraries\Lang\Exceptions\LangException; +use Quantum\Libraries\Lang\Factories\LangFactory; +use Quantum\Config\Exceptions\ConfigException; +use Quantum\Di\Exceptions\DiException; /** * Gets the current lang * @return string|null + * @throws ConfigException + * @throws DiException + * @throws LangException + * @throws ReflectionException */ function current_lang(): ?string { - return Lang::getInstance()->getLang(); + return LangFactory::get()->getLang(); } /** @@ -28,16 +35,25 @@ function current_lang(): ?string * @param string $key * @param $params * @return string|null + * @throws ConfigException + * @throws ReflectionException + * @throws DiException + * @throws LangException */ function t(string $key, $params = null): ?string { - return Lang::getInstance()->getTranslation($key, $params); + return LangFactory::get()->getTranslation($key, $params); } /** * Outputs the translation * @param string $key - * @param mixed $params + * @param $params + * @return void + * @throws ConfigException + * @throws DiException + * @throws LangException + * @throws ReflectionException */ function _t(string $key, $params = null) { diff --git a/src/Libraries/Lang/Lang.php b/src/Libraries/Lang/Lang.php index 8d2ef7f6..3d95b2ac 100644 --- a/src/Libraries/Lang/Lang.php +++ b/src/Libraries/Lang/Lang.php @@ -9,208 +9,108 @@ * @author Arman Ag. * @copyright Copyright (c) 2018 Softberg LLC (https://softberg.org) * @link http://quantum.softberg.org/ - * @since 2.9.8 + * @since 2.9.9 */ namespace Quantum\Libraries\Lang; -use Quantum\Libraries\Storage\Factories\FileSystemFactory; -use Quantum\Libraries\Lang\Exceptions\LangException; +use Quantum\Config\Exceptions\ConfigException; use Quantum\App\Exceptions\BaseException; use Quantum\Di\Exceptions\DiException; -use Dflydev\DotAccessData\Data; -use Quantum\Loader\Loader; -use Quantum\Http\Request; -use Quantum\Loader\Setup; use ReflectionException; -use Quantum\Di\Di; /** - * Language class + * Class Lang * @package Quantum\Libraries\Lang */ class Lang { /** - * Config key for lang segment + * @var string|null */ - const LANG_SEGMENT = 'lang_segment'; + private $currentLang = null; /** - * Current language - * @var string + * @var Translator */ - private static $currentLang; + private $translator; /** - * Translations - * @var Data - */ - private static $translations = null; - - /** - * @var bool + * @var bool */ private $isEnabled; /** - * Instance of Lang - * @var Lang - */ - private static $instance = null; - - /** - * @throws LangException + * @param string $lang + * @param bool $isEnabled + * @param Translator $translator */ - private function __construct() + public function __construct(string $lang, bool $isEnabled, Translator $translator) { - $this->isEnabled = filter_var(config()->get('multilang'), FILTER_VALIDATE_BOOLEAN); - - $langSegmentIndex = (int)config()->get(Lang::LANG_SEGMENT); - - if (!empty(route_prefix()) && $langSegmentIndex == 1) { - $langSegmentIndex++; - } - - $lang = Request::getSegment($langSegmentIndex); - - if (empty($lang) && !config()->get('lang_default')) { - throw LangException::misconfiguredDefaultConfig(); - } - - if (empty($lang) || !in_array($lang, (array)config()->get('langs'))) { - $lang = config()->get('lang_default'); - } - + $this->isEnabled = $isEnabled; + $this->translator = $translator; $this->setLang($lang); } /** - * GetInstance - * @return Lang - */ - public static function getInstance(): Lang - { - if (self::$instance === null) { - self::$instance = new self(); - } - - return self::$instance; - } - - /** - * @return bool - */ - public function isEnabled(): bool - { - return $this->isEnabled; - } - - /** - *Loads translations - * @throws DiException - * @throws LangException - * @throws ReflectionException - * @throws BaseException - */ - public function load() - { - $fs = FileSystemFactory::get(); - - $langDir = modules_dir() . DS . current_module() . DS . 'resources' . DS . 'lang' . DS . $this->getLang(); - - $files = $fs->glob($langDir . DS . "*.php"); - - if (is_array($files) && !count($files)) { - $langDir = base_dir() . DS . 'shared' . DS . 'resources' . DS . 'lang' . DS . $this->getLang(); - - $files = $fs->glob($langDir . DS . "*.php"); - - if (is_array($files) && !count($files)) { - throw LangException::translationsNotFound($this->getLang()); - } - } - - $translations = []; - - foreach ($files as $file) { - $fileName = $fs->fileName($file); - - $setup = new Setup(); - $setup->setPathPrefix('resources' . DS . 'lang' . DS . $this->getLang()); - $setup->setFilename($fileName); - $setup->setHierarchy(true); - - $translations[$fileName] = Di::get(Loader::class)->setup($setup)->load(); - } - - $this->setTranslations($translations); - } - - /** - * Sets current language + * Set current language * @param string $lang * @return $this */ - public function setLang(string $lang): Lang + public function setLang(string $lang): self { - self::$currentLang = $lang; + $this->currentLang = $lang; return $this; } /** - * Gets the current language + * Get current language * @return string|null */ public function getLang(): ?string { - return self::$currentLang; + return $this->currentLang; } /** - * Sets translations manually (for testing purposes) - * @param array $translations + * Is multilang enabled + * @return bool */ - public function setTranslations(array $translations) + public function isEnabled(): bool { - if (self::$translations === null) { - self::$translations = new Data(); - } - - self::$translations->import($translations); + return $this->isEnabled; } /** - * Gets the whole translations of current language - * @return Data + * Load translations + * @throws Exceptions\LangException + * @throws BaseException + * @throws ConfigException + * @throws DiException + * @throws ReflectionException */ - public function getTranslations(): ?Data + public function load(): void { - return self::$translations; + $this->translator->loadTranslations(); } /** - * Gets the translation by given key + * Get translation by key * @param string $key - * @param string|array $params + * @param $params * @return string|null */ public function getTranslation(string $key, $params = null): ?string { - if (self::$translations && self::$translations->has($key)) { - $message = self::$translations->get($key); - return $params ? _message($message, $params) : $message; - } - - return $key; + return $this->translator->get($key, $params); } /** - * Flushes loaded translations + * Flush loaded translations */ - public function flush() + public function flush(): void { - self::$translations = null; + $this->translator->flush(); } } \ No newline at end of file diff --git a/src/Libraries/Lang/Translator.php b/src/Libraries/Lang/Translator.php new file mode 100644 index 00000000..cbd3b133 --- /dev/null +++ b/src/Libraries/Lang/Translator.php @@ -0,0 +1,116 @@ + + * @copyright Copyright (c) 2018 Softberg LLC (https://softberg.org) + * @link http://quantum.softberg.org/ + * @since 2.9.9 + */ + +namespace Quantum\Libraries\Lang; + +use Quantum\Libraries\Lang\Exceptions\LangException; +use Quantum\Config\Exceptions\ConfigException; +use Quantum\App\Exceptions\BaseException; +use Quantum\Di\Exceptions\DiException; +use Dflydev\DotAccessData\Data; +use Quantum\Loader\Loader; +use Quantum\Loader\Setup; +use ReflectionException; +use Quantum\Di\Di; + +/** + * Class Translator + * @package Quantum\Libraries\Lang + */ +class Translator +{ + + protected string $lang; + + /** + * @var Data|null + */ + private $translations = null; + + /** + * @param string $lang + */ + public function __construct(string $lang) + { + $this->lang = $lang; + } + + /** + * Load translation file + * @throws BaseException + * @throws ConfigException + * @throws DiException + * @throws LangException + * @throws ReflectionException + */ + public function loadTranslations(): void + { + + if ($this->translations !== null) { + return; + } + + $langDir = modules_dir() . DS . current_module() . DS . 'resources' . DS . 'lang' . DS . $this->lang; + $files = fs()->glob($langDir . DS . "*.php"); + + if (is_array($files) && !count($files)) { + $langDir = base_dir() . DS . 'shared' . DS . 'resources' . DS . 'lang' . DS . $this->lang; + $files = fs()->glob($langDir . DS . "*.php"); + + if (is_array($files) && !count($files)) { + throw LangException::translationsNotFound(); + } + } + + $translations = []; + + foreach ($files as $file) { + $fileName = fs()->fileName($file); + + $setup = new Setup(); + $setup->setPathPrefix('resources' . DS . 'lang' . DS . $this->lang); + $setup->setFilename($fileName); + $setup->setHierarchy(true); + + $translations[$fileName] = Di::get(Loader::class)->setup($setup)->load(); + } + + $this->translations = new Data(); + $this->translations->import($translations); + } + + /** + * Get translation by key + * @param string $key + * @param array|null $params + * @return string + */ + public function get(string $key, array $params = null): string + { + if ($this->translations && $this->translations->has($key)) { + $message = $this->translations->get($key); + return $params ? _message($message, $params) : $message; + } + + return $key; + } + + /** + * Reset translations + */ + public function flush(): void + { + $this->translations = null; + } +} \ No newline at end of file diff --git a/src/Module/Templates/DemoWeb/src/Controllers/AccountController.php.tpl b/src/Module/Templates/DemoWeb/src/Controllers/AccountController.php.tpl index 09c97ccb..c459fa61 100644 --- a/src/Module/Templates/DemoWeb/src/Controllers/AccountController.php.tpl +++ b/src/Module/Templates/DemoWeb/src/Controllers/AccountController.php.tpl @@ -9,7 +9,7 @@ * @author Arman Ag. * @copyright Copyright (c) 2018 Softberg LLC (https://softberg.org) * @link http://quantum.softberg.org/ - * @since 2.9.8 + * @since 2.9.9 */ namespace {{MODULE_NAMESPACE}}\Controllers; @@ -56,7 +56,6 @@ class AccountController extends BaseController { $this->view->setParams([ 'title' => t('common.account_settings') . ' | ' . config()->get('app_name'), - 'langs' => config()->get('langs') ]); $response->html($this->view->render('account/form')); diff --git a/src/Module/Templates/DemoWeb/src/Controllers/AuthController.php.tpl b/src/Module/Templates/DemoWeb/src/Controllers/AuthController.php.tpl index 1d908f07..a0e11331 100644 --- a/src/Module/Templates/DemoWeb/src/Controllers/AuthController.php.tpl +++ b/src/Module/Templates/DemoWeb/src/Controllers/AuthController.php.tpl @@ -9,7 +9,7 @@ * @author Arman Ag. * @copyright Copyright (c) 2018 Softberg LLC (https://softberg.org) * @link http://quantum.softberg.org/ - * @since 2.9.8 + * @since 2.9.9 */ namespace {{MODULE_NAMESPACE}}\Controllers; @@ -78,7 +78,6 @@ class AuthController extends BaseController } else { $this->view->setParams([ 'title' => t('common.signin') . ' | ' . config()->get('app_name'), - 'langs' => config()->get('langs') ]); $response->html($this->view->render(self::VIEW_SIGNIN)); @@ -109,7 +108,6 @@ class AuthController extends BaseController $this->view->setParams([ // 'captcha' => captcha(), 'title' => t('common.signup') . ' | ' . config()->get('app_name'), - 'langs' => config()->get('langs') ]); $response->html($this->view->render(self::VIEW_SIGNUP)); @@ -140,7 +138,6 @@ class AuthController extends BaseController } else { $this->view->setParams([ 'title' => t('common.forget_password') . ' | ' . config()->get('app_name'), - 'langs' => config()->get('langs'), ]); $response->html($this->view->render(self::VIEW_FORGET)); @@ -160,7 +157,6 @@ class AuthController extends BaseController } else { $this->view->setParams([ 'title' => t('common.reset_password') . ' | ' . config()->get('app_name'), - 'langs' => config()->get('langs'), 'reset_token' => $request->get('reset_token') ]); @@ -186,7 +182,6 @@ class AuthController extends BaseController } else { $this->view->setParams([ 'title' => t('common.two_fa') . ' | ' . config()->get('app_name'), - 'langs' => config()->get('langs'), 'code' => route_param('code') ]); diff --git a/src/Module/Templates/DemoWeb/src/Controllers/BaseController.php.tpl b/src/Module/Templates/DemoWeb/src/Controllers/BaseController.php.tpl index 8a0cf488..c5658e3f 100644 --- a/src/Module/Templates/DemoWeb/src/Controllers/BaseController.php.tpl +++ b/src/Module/Templates/DemoWeb/src/Controllers/BaseController.php.tpl @@ -9,7 +9,7 @@ * @author Arman Ag. * @copyright Copyright (c) 2018 Softberg LLC (https://softberg.org) * @link http://quantum.softberg.org/ - * @since 2.9.8 + * @since 2.9.9 */ namespace {{MODULE_NAMESPACE}}\Controllers; @@ -47,5 +47,7 @@ abstract class BaseController extends RouteController new Asset(Asset::JS, 'shared/js/easymde.min.js'), new Asset(Asset::JS, '{{MODULE_NAME}}/js/custom.js') ]); + + $this->view->setParam('langs', config()->get('lang.supported')); } } \ No newline at end of file diff --git a/src/Module/Templates/DemoWeb/src/Controllers/PageController.php.tpl b/src/Module/Templates/DemoWeb/src/Controllers/PageController.php.tpl index 7daf7851..f45aa337 100644 --- a/src/Module/Templates/DemoWeb/src/Controllers/PageController.php.tpl +++ b/src/Module/Templates/DemoWeb/src/Controllers/PageController.php.tpl @@ -9,7 +9,7 @@ * @author Arman Ag. * @copyright Copyright (c) 2018 Softberg LLC (https://softberg.org) * @link http://quantum.softberg.org/ - * @since 2.9.8 + * @since 2.9.9 */ namespace {{MODULE_NAMESPACE}}\Controllers; @@ -36,7 +36,6 @@ class PageController extends BaseController { $this->view->setParams([ 'title' => config()->get('app_name'), - 'langs' => config()->get('langs') ]); $response->html($this->view->render('pages/index')); @@ -50,7 +49,6 @@ class PageController extends BaseController { $this->view->setParams([ 'title' => t('common.about') . ' | ' . config()->get('app_name'), - 'langs' => config()->get('langs') ]); $response->html($this->view->render('pages/about')); diff --git a/src/Module/Templates/DemoWeb/src/Controllers/PostController.php.tpl b/src/Module/Templates/DemoWeb/src/Controllers/PostController.php.tpl index 8ca3b700..6cc87c72 100644 --- a/src/Module/Templates/DemoWeb/src/Controllers/PostController.php.tpl +++ b/src/Module/Templates/DemoWeb/src/Controllers/PostController.php.tpl @@ -9,7 +9,7 @@ * @author Arman Ag. * @copyright Copyright (c) 2018 Softberg LLC (https://softberg.org) * @link http://quantum.softberg.org/ - * @since 2.9.8 + * @since 2.9.9 */ namespace {{MODULE_NAMESPACE}}\Controllers; @@ -70,7 +70,6 @@ class PostController extends BaseController $this->view->setParams([ 'title' => t('common.posts') . ' | ' . config()->get('app_name'), - 'langs' => config()->get('langs'), 'posts' => $this->postService->transformData($paginatedPosts->data()->all()), 'pagination' => $paginatedPosts ]); @@ -98,7 +97,6 @@ class PostController extends BaseController $this->view->setParams([ 'title' => $post->title . ' | ' . config()->get('app_name'), - 'langs' => config()->get('langs'), 'post' => new RawParam(current($this->postService->transformData([$post]))), 'referer' => $ref, ]); @@ -117,7 +115,6 @@ class PostController extends BaseController $this->view->setParams([ 'title' => t('common.my_posts') . ' | ' . config()->get('app_name'), - 'langs' => config()->get('langs'), 'posts' => $this->postService->transformData($myPosts->all()) ]); @@ -135,7 +132,6 @@ class PostController extends BaseController $this->view->setParams([ 'title' => t('common.new_post') . ' | ' . config()->get('app_name'), - 'langs' => config()->get('langs'), 'referer' => $ref ]); @@ -186,7 +182,6 @@ class PostController extends BaseController $this->view->setParams([ 'title' => $post->title . ' | ' . config()->get('app_name'), - 'langs' => config()->get('langs'), 'post' => $post->asArray(), 'referer' => $ref ]); diff --git a/tests/Unit/Libraries/Lang/Factories/LangFactoryTest.php b/tests/Unit/Libraries/Lang/Factories/LangFactoryTest.php new file mode 100644 index 00000000..e89d58c7 --- /dev/null +++ b/tests/Unit/Libraries/Lang/Factories/LangFactoryTest.php @@ -0,0 +1,64 @@ +setPrivateProperty(LangFactory::class, 'instance', null); + + config()->set('lang', [ + 'enabled' => true, + 'default' => 'en', + 'supported' => ['en', 'es'], + 'url_segment' => 1 + ]); + } + + public function testLangFactoryGetLangInstance(): void + { + $lang = LangFactory::get(); + + $this->assertInstanceOf(Lang::class, $lang); + + $this->assertEquals('en', $lang->getLang()); + + $this->assertTrue($lang->isEnabled()); + } + + public function testLangFactoryGetReturnsSameInstance(): void + { + $first = LangFactory::get(); + + $second = LangFactory::get(); + + $this->assertSame($first, $second); + } + + public function testLangFactoryGetFallsBackToDefaultIfSegmentInvalid(): void + { + config()->set('lang.url_segment', 0); + + $lang = LangFactory::get(); + + $this->assertEquals('en', $lang->getLang()); + } + + public function testGetThrowsIfNoDefaultConfigured(): void + { + $this->expectException(LangException::class); + + config()->set('lang.default', null); + + LangFactory::get(); + } +} \ No newline at end of file diff --git a/tests/Unit/Libraries/Lang/Helpers/LangHelperFunctionsTest.php b/tests/Unit/Libraries/Lang/Helpers/LangHelperFunctionsTest.php index 0b665eeb..17d9efc2 100644 --- a/tests/Unit/Libraries/Lang/Helpers/LangHelperFunctionsTest.php +++ b/tests/Unit/Libraries/Lang/Helpers/LangHelperFunctionsTest.php @@ -2,68 +2,45 @@ namespace Quantum\Tests\Unit\Libraries\Lang\Helpers; +use Quantum\Libraries\Lang\Factories\LangFactory; use Quantum\Tests\Unit\AppTestCase; -use Quantum\Libraries\Lang\Lang; class LangHelperFunctionsTest extends AppTestCase { + private $lang; + public function setUp(): void { parent::setUp(); + + $this->lang = LangFactory::get(); + + $this->lang->load(); } public function testCurrentLang() { $this->assertEquals('en', current_lang()); - Lang::getInstance()->setLang('am'); + $this->lang->setLang('am'); $this->assertEquals('am', current_lang()); } public function testHelperT() { - $translations = [ - 'custom' => [ - 'label' => 'Testing', - 'info' => 'Information about the new feature' - ] - ]; - - Lang::getInstance()->setTranslations($translations); + $this->assertEquals('Testing', t('custom.test')); - $this->assertEquals('Testing', t('custom.label')); - - $this->assertEquals('Information about the new feature', t('custom.info')); - } - - public function testHelperTWithParams() - { - $translations = [ - 'custom' => [ - 'info' => 'Information about the new feature: {%1}' - ] - ]; - - Lang::getInstance()->setTranslations($translations); - - $this->assertEquals('Information about the new feature: new', t('custom.info', 'new')); + $this->assertEquals('Information about the new feature', t('custom.info', ['new'])); } public function testHelperUnderscoreT() { - $translations = [ - 'custom' => [ - 'test' => 'Testing' - ] - ]; - - Lang::getInstance()->setTranslations($translations); - ob_start(); _t('custom.test'); + $output = ob_get_clean(); $this->assertEquals('Testing', $output); @@ -71,14 +48,6 @@ public function testHelperUnderscoreT() public function testHelperTFail() { - $translations = [ - 'custom' => [ - 'label' => 'Testing', - ] - ]; - - Lang::getInstance()->setTranslations($translations); - $this->assertEquals('custom.non_existing_key', t('custom.non_existing_key')); } } \ No newline at end of file diff --git a/tests/Unit/Libraries/Lang/LangTest.php b/tests/Unit/Libraries/Lang/LangTest.php index 7fd05be0..a6f416a0 100644 --- a/tests/Unit/Libraries/Lang/LangTest.php +++ b/tests/Unit/Libraries/Lang/LangTest.php @@ -1,86 +1,73 @@ lang = new Lang('en', true, $translator); + + RouteController::setCurrentRoute([ + "route" => "api-signin", + "method" => "POST", + "controller" => "SomeController", + "action" => "signin", + "module" => "Test", + ]); + } - private $lang; - - public function setUp(): void - { - parent::setUp(); - - $this->lang = Lang::getInstance(); - - $this->lang->setLang('en'); - - RouteController::setCurrentRoute([ - "route" => "api-signin", - "method" => "POST", - "controller" => "SomeController", - "action" => "signin", - "module" => "Test", - ]); - } + public function testLangGetSet() + { + $this->assertEquals('en', $this->lang->getLang()); - public function testLangLoad() - { - $this->lang->flush(); + $this->lang->setLang('ru'); - $this->assertEmpty($this->lang->getTranslations()); + $this->assertEquals('ru', $this->lang->getLang()); + } - $this->lang->load(); + public function testLangIsEnabled(): void + { + $this->assertTrue($this->lang->isEnabled()); - $this->assertNotEmpty($this->lang->getTranslations()); - } + $langDisabled = new Lang('en', false, new Translator('en')); - public function testLangGetSet() - { - $this->assertEquals('en', $this->lang->getLang()); + $this->assertFalse($langDisabled->isEnabled()); + } - $this->lang->setLang('ru'); - $this->assertEquals('ru', $this->lang->getLang()); - } + public function testLangLoadAndGetTranslation(): void + { + $this->lang->flush(); - public function testSetTranslations() - { - $translations = [ - 'custom' => [ - 'label' => 'Black', - 'note' => 'Note this is a new feature' - ] - ]; + $this->assertEquals('custom.test', $this->lang->getTranslation('custom.test')); - $this->lang->setTranslations($translations); + $this->lang->load(); - $this->assertNotNull($this->lang->getTranslations()); + $this->assertEquals('Testing', $this->lang->getTranslation('custom.test')); - $this->assertEquals('Black', $this->lang->getTranslation('custom.label')); - $this->assertEquals('Note this is a new feature', $this->lang->getTranslation('custom.note')); - } + $this->assertEquals('Information about the new feature', $this->lang->getTranslation('custom.info', ['new'])); + } - public function testGetTranslation() - { - $this->assertEquals('Testing', $this->lang->getTranslation('custom.test')); + public function testLangFlushResetsTranslations(): void + { + $this->lang->load(); - $this->assertEquals('Information about the new feature', $this->lang->getTranslation('custom.info', 'new')); + $this->assertEquals('Testing', $this->lang->getTranslation('custom.test')); - $this->assertEquals('custom.not-exists', $this->lang->getTranslation('custom.not-exists')); - } + $this->lang->flush(); + $this->assertEquals('test', $this->lang->getTranslation('test')); } } \ No newline at end of file diff --git a/tests/Unit/Libraries/Lang/TranslatorTest.php b/tests/Unit/Libraries/Lang/TranslatorTest.php new file mode 100644 index 00000000..db971baa --- /dev/null +++ b/tests/Unit/Libraries/Lang/TranslatorTest.php @@ -0,0 +1,39 @@ +assertInstanceOf(Translator::class, $translator); + } + + public function testTranslatorLoadTranslations(): void + { + $translator = new Translator('en'); + + $translator->loadTranslations(); + + $this->assertEquals('Testing', $translator->get('custom.test')); + + $this->assertEquals('Information about the value feature', $translator->get('custom.info', ['param' => 'value'])); + } + + public function testTranslatorGetTranslation(): void + { + $translator = new Translator('en'); + + $translator->loadTranslations(); + + $result = $translator->get('custom.info', ['new']); + + $this->assertEquals('Information about the new feature', $result); + } +} diff --git a/tests/_root/shared/config/lang.php b/tests/_root/shared/config/lang.php new file mode 100644 index 00000000..abd9dc00 --- /dev/null +++ b/tests/_root/shared/config/lang.php @@ -0,0 +1,13 @@ + true, + 'supported' => ['en', 'ru', 'am'], + 'default' => 'en', + 'url_segment' => 1, +]; \ No newline at end of file From c566782e780117c58edba59eebbd48ec36384da6 Mon Sep 17 00:00:00 2001 From: Arman <407448+armanist@users.noreply.github.com> Date: Wed, 15 Oct 2025 21:55:04 +0400 Subject: [PATCH 2/3] Correcting the argument type --- src/Libraries/Lang/Factories/LangFactory.php | 1 - src/Libraries/Lang/Translator.php | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Libraries/Lang/Factories/LangFactory.php b/src/Libraries/Lang/Factories/LangFactory.php index a1629ac1..268dad89 100644 --- a/src/Libraries/Lang/Factories/LangFactory.php +++ b/src/Libraries/Lang/Factories/LangFactory.php @@ -54,7 +54,6 @@ public static function get(): Lang $isEnabled = filter_var(config()->get('lang.enabled'), FILTER_VALIDATE_BOOLEAN); - $langSegmentIndex = (int)config()->get('lang.url_segment'); if (!empty(route_prefix()) && $langSegmentIndex == 1) { diff --git a/src/Libraries/Lang/Translator.php b/src/Libraries/Lang/Translator.php index cbd3b133..bd1ea335 100644 --- a/src/Libraries/Lang/Translator.php +++ b/src/Libraries/Lang/Translator.php @@ -93,10 +93,10 @@ public function loadTranslations(): void /** * Get translation by key * @param string $key - * @param array|null $params + * @param array|string|null $params * @return string */ - public function get(string $key, array $params = null): string + public function get(string $key, $params = null): string { if ($this->translations && $this->translations->has($key)) { $message = $this->translations->get($key); From a0e4dc4dc42be087c3b21e49a4a21cc39fb72c9c Mon Sep 17 00:00:00 2001 From: Arman <407448+armanist@users.noreply.github.com> Date: Wed, 15 Oct 2025 22:09:09 +0400 Subject: [PATCH 3/3] Removing type declaration --- src/Libraries/Lang/Translator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Libraries/Lang/Translator.php b/src/Libraries/Lang/Translator.php index bd1ea335..86bff14b 100644 --- a/src/Libraries/Lang/Translator.php +++ b/src/Libraries/Lang/Translator.php @@ -31,7 +31,7 @@ class Translator { - protected string $lang; + protected $lang; /** * @var Data|null