From ac802aae6ab6578aead2a46a089318fb76d9f9ec Mon Sep 17 00:00:00 2001 From: Curtis Conard Date: Tue, 21 Oct 2025 20:26:41 -0400 Subject: [PATCH 1/2] rework client-side language handling to improve availability --- lib/bundles/base.js | 3 ++ .../Extension/FrontEndAssetsExtension.php | 48 +++++++++---------- src/Html.php | 4 +- templates/layout/parts/head.html.twig | 4 +- 4 files changed, 30 insertions(+), 29 deletions(-) diff --git a/lib/bundles/base.js b/lib/bundles/base.js index c7cd592ec05..92f076defc2 100644 --- a/lib/bundles/base.js +++ b/lib/bundles/base.js @@ -97,6 +97,9 @@ window._ = require('lodash'); // add translation function into global scope // signature is almost the same as for PHP functions, but accept extra arguments for string variables window.i18n = require('gettext.js/lib/gettext').default({domain: 'glpi'}); +if (window.loadLocales !== undefined) { + await window.loadLocales(); +} const escape_msgid = function (msgid) { return msgid.replace(/%(\d+)\$/g, '%%$1\$'); diff --git a/src/Glpi/Application/View/Extension/FrontEndAssetsExtension.php b/src/Glpi/Application/View/Extension/FrontEndAssetsExtension.php index b43f98bf23b..d5a2b118044 100644 --- a/src/Glpi/Application/View/Extension/FrontEndAssetsExtension.php +++ b/src/Glpi/Application/View/Extension/FrontEndAssetsExtension.php @@ -242,36 +242,32 @@ public function localesJs(): string $locales_domains[$plugin] = Plugin::getPluginFilesVersion($plugin); } - $script = " - $(function() { - i18n.setLocale('" . \jsescape($_SESSION['glpilanguage']) . "'); - }); - - $.fn.select2.defaults.set( - 'language', - '" . \jsescape($CFG_GLPI['languages'][$_SESSION['glpilanguage']][2]) . "', - ); - "; - - foreach ($locales_domains as $locale_domain => $locale_version) { - $locales_path = Html::getPrefixedUrl( + $locales_json = json_encode(array_combine(array_keys($locales_domains), array_map(static function ($domain, $version) { + return Html::getPrefixedUrl( '/front/locale.php' - . '?domain=' . $locale_domain + . '?domain=' . $domain . '&lang=' . $_SESSION['glpilanguage'] - . '&v=' . FrontEnd::getVersionCacheKey($locale_version) + . '&v=' . FrontEnd::getVersionCacheKey($version) ); - $script .= " - $(function() { - $.ajax({ - type: 'GET', - url: '" . \jsescape($locales_path) . "', - success: function(json) { - i18n.loadJSON(json, '" . \jsescape($locale_domain) . "'); + }, array_keys($locales_domains), $locales_domains))); + + $script = << { + if (response.ok) { + return response.json().then(data => { + i18n.loadJSON(data, domain); + }); } - }); - }); - "; - } + })); + } + await Promise.all(promises); + } +JS; return Html::scriptBlock($script); } diff --git a/src/Html.php b/src/Html.php index a97c5be9037..f7644cdf749 100644 --- a/src/Html.php +++ b/src/Html.php @@ -1050,9 +1050,11 @@ public static function includeHeader( $theme = ThemeManager::getInstance()->getCurrentTheme(); $lang = $_SESSION['glpilanguage'] ?? Session::getPreferredLanguage(); + // Force lang to be BCP 47 compliant + $lang = str_replace('_', '-', $lang); $tpl_vars = [ - 'lang' => $CFG_GLPI["languages"][$lang][3], + 'lang' => $lang, 'title' => $title, 'theme' => $theme, 'is_anonymous_page' => false, diff --git a/templates/layout/parts/head.html.twig b/templates/layout/parts/head.html.twig index 26fa3114743..495209a30c4 100644 --- a/templates/layout/parts/head.html.twig +++ b/templates/layout/parts/head.html.twig @@ -79,6 +79,8 @@ {{ config_js() }} + {{ locales_js() }} + {% for js_file in js_files %} {% endfor %} @@ -86,6 +88,4 @@ {% for js_file in js_modules %} {% endfor %} - - {{ locales_js() }} From 9819b4d21faca1525095c18ace467a27356bce67 Mon Sep 17 00:00:00 2001 From: Curtis Conard Date: Wed, 29 Oct 2025 07:05:47 -0400 Subject: [PATCH 2/2] picky lint fix --- .../View/Extension/FrontEndAssetsExtension.php | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/Glpi/Application/View/Extension/FrontEndAssetsExtension.php b/src/Glpi/Application/View/Extension/FrontEndAssetsExtension.php index d5a2b118044..607a4c8de5d 100644 --- a/src/Glpi/Application/View/Extension/FrontEndAssetsExtension.php +++ b/src/Glpi/Application/View/Extension/FrontEndAssetsExtension.php @@ -242,14 +242,12 @@ public function localesJs(): string $locales_domains[$plugin] = Plugin::getPluginFilesVersion($plugin); } - $locales_json = json_encode(array_combine(array_keys($locales_domains), array_map(static function ($domain, $version) { - return Html::getPrefixedUrl( - '/front/locale.php' - . '?domain=' . $domain - . '&lang=' . $_SESSION['glpilanguage'] - . '&v=' . FrontEnd::getVersionCacheKey($version) - ); - }, array_keys($locales_domains), $locales_domains))); + $locales_json = json_encode(array_combine(array_keys($locales_domains), array_map(static fn($domain, $version) => Html::getPrefixedUrl( + '/front/locale.php' + . '?domain=' . $domain + . '&lang=' . $_SESSION['glpilanguage'] + . '&v=' . FrontEnd::getVersionCacheKey($version) + ), array_keys($locales_domains), $locales_domains))); $script = <<