From 71eeda6e339a63767e203ef6acd8984f0a462647 Mon Sep 17 00:00:00 2001 From: Artur Kyryliuk Date: Sun, 30 Aug 2026 02:26:52 +0200 Subject: [PATCH] fix(manager): language set by admin for manager should be used. --- core/src/Core.php | 39 +++++++++++ core/src/ManagerTheme.php | 14 ++++ .../tests/Unit/ManagerPerUserLanguageTest.php | 69 +++++++++++++++++++ manager/includes/user_settings.inc.php | 31 --------- 4 files changed, 122 insertions(+), 31 deletions(-) create mode 100644 core/tests/Unit/ManagerPerUserLanguageTest.php delete mode 100755 manager/includes/user_settings.inc.php diff --git a/core/src/Core.php b/core/src/Core.php index 1d2061e943..f47a870cee 100644 --- a/core/src/Core.php +++ b/core/src/Core.php @@ -19,6 +19,7 @@ use Illuminate\Http\Request; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Cache; +use Illuminate\Support\Facades\Facade; use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Route; use Illuminate\Support\Str; @@ -6560,6 +6561,44 @@ public function getSettings() $this->getUserSettings(); $this->setConfig('site_timezone', $siteTimezone); $this->invokeEvent('OnLoadSettings', ['config' => &$this->config]); + + // The factory defaults read the manager lexicon (core/factory/settings.php), so + // ManagerTheme is already built from the system theme and language by the time the + // user settings above are merged. Realign it so a per-user manager_theme / + // manager_language (and anything OnLoadSettings changed) reaches the manager UI. + $this->syncManagerTheme(); + } + + /** + * Realign the already resolved ManagerTheme with the current manager_theme and + * manager_language. A different theme needs a new instance (the theme name drives the + * view namespaces, the style and the theme snippets/chunks); a different language only + * needs the lexicon read again. + */ + protected function syncManagerTheme(): void + { + if (!$this->isBackend() || !$this->resolved('ManagerTheme')) { + return; + } + + $managerTheme = $this['ManagerTheme']; + if (!$managerTheme instanceof ManagerTheme) { + return; + } + + $theme = (string) $this->getConfig('manager_theme', 'default'); + if ($theme !== '' && $theme !== $managerTheme->getTheme()) { + // Dropped, not rebuilt: the next call resolves it again from the merged config. + $this->forgetInstance('ManagerTheme'); + Facade::clearResolvedInstance('ManagerTheme'); + + return; + } + + $language = (string) $this->getConfig('manager_language'); + if ($language !== '' && $language !== $managerTheme->getLangName()) { + $managerTheme->reloadLang($language); + } } /** diff --git a/core/src/ManagerTheme.php b/core/src/ManagerTheme.php index 25e6799b2b..bf5fcb16ad 100644 --- a/core/src/ManagerTheme.php +++ b/core/src/ManagerTheme.php @@ -205,6 +205,20 @@ public function __construct(CoreInterface $core, string $theme) } } + /** + * Re-read the lexicon for another language. + * + * The theme is built while the configuration still only holds the system settings, + * so the core calls this once the per-user manager_language has been merged in. + * + * @param string $lang + * @return string + */ + public function reloadLang(string $lang): string + { + return $this->loadLang($lang); + } + protected function loadLang($lang = 'english') { $_lang = []; diff --git a/core/tests/Unit/ManagerPerUserLanguageTest.php b/core/tests/Unit/ManagerPerUserLanguageTest.php new file mode 100644 index 0000000000..3355624122 --- /dev/null +++ b/core/tests/Unit/ManagerPerUserLanguageTest.php @@ -0,0 +1,69 @@ +isPublic()); + self::assertSame(1, $method->getNumberOfRequiredParameters()); + } + + public function testCoreRefreshesTheManagerThemeAfterMergingUserSettings(): void + { + $mergePosition = mb_strpos(self::$coreSource, '$this->getUserSettings();'); + $syncPosition = mb_strpos(self::$coreSource, '$this->syncManagerTheme();'); + + self::assertIsInt($mergePosition); + self::assertIsInt($syncPosition); + self::assertGreaterThan($mergePosition, $syncPosition); + } + + public function testManagerThemeRefreshOnlyTouchesAnAlreadyBuiltBackendTheme(): void + { + $sync = mb_substr( + self::$coreSource, + (int) mb_strpos(self::$coreSource, 'protected function syncManagerTheme') + ); + $sync = mb_substr($sync, 0, (int) mb_strpos($sync, "\n }")); + + self::assertStringContainsString('$this->isBackend()', $sync); + self::assertStringContainsString("\$this->resolved('ManagerTheme')", $sync); + self::assertStringContainsString('reloadLang(', $sync); + // A different theme cannot be patched in place - the instance has to go. + self::assertStringContainsString("forgetInstance('ManagerTheme')", $sync); + self::assertStringContainsString("Facade::clearResolvedInstance('ManagerTheme')", $sync); + } +} diff --git a/manager/includes/user_settings.inc.php b/manager/includes/user_settings.inc.php deleted file mode 100755 index f895e2a250..0000000000 --- a/manager/includes/user_settings.inc.php +++ /dev/null @@ -1,31 +0,0 @@ -INCLUDE_ORDERING_ERROR

Please use the EVO Content Manager instead of accessing this file directly."); -} - -// START HACK -if (isset ($modx)) { - $user_id = EvolutionCMS()->getLoginUserID(); -} else { - $user_id = $_SESSION['mgrInternalKey']; -} -// END HACK - -if (!empty($user_id)) { - // Raymond: grab the user settings from the database. - $userSettings = \EvolutionCMS\Models\UserSetting::query() - ->select('setting_name', 'setting_value') - ->where('user', EvolutionCMS()->getLoginUserID())->get()->toArray(); - - $which_browser_default = $which_browser; - foreach ($userSettings as $row) { - if ($row['setting_name'] == 'which_browser' && $row['setting_value'] == 'default') { - $row['setting_value'] = $which_browser_default; - } - $settings[$row['setting_name']] = $row['setting_value']; - if (isset(EvolutionCMS()->config)) { - EvolutionCMS()->config[$row['setting_name']] = $row['setting_value']; - } - } - extract($settings, EXTR_OVERWRITE); -}