From 4c9955b9aaba98b07cefc194a81a10ad0cddda27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Imobach=20Gonz=C3=A1lez=20Sosa?= Date: Wed, 10 Jan 2024 21:42:51 +0000 Subject: [PATCH 1/6] [rust] Consider the encoding when dealing with locales --- rust/agama-dbus-server/src/l10n/helpers.rs | 3 +-- rust/agama-locale-data/src/locale.rs | 20 +++++++++++++++++--- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/rust/agama-dbus-server/src/l10n/helpers.rs b/rust/agama-dbus-server/src/l10n/helpers.rs index 490203d5b1..3bccb04a8e 100644 --- a/rust/agama-dbus-server/src/l10n/helpers.rs +++ b/rust/agama-dbus-server/src/l10n/helpers.rs @@ -23,8 +23,7 @@ pub fn init_locale() -> Result> { /// pub fn set_service_locale(locale: &LocaleCode) { // Let's force the encoding to be 'UTF-8'. - let locale = format!("{}.UTF-8", locale); - if setlocale(LocaleCategory::LcAll, locale).is_none() { + if setlocale(LocaleCategory::LcAll, locale.to_string()).is_none() { log::warn!("Could not set the locale"); } } diff --git a/rust/agama-locale-data/src/locale.rs b/rust/agama-locale-data/src/locale.rs index 4c4f53d8b1..65ed2eeccb 100644 --- a/rust/agama-locale-data/src/locale.rs +++ b/rust/agama-locale-data/src/locale.rs @@ -11,12 +11,16 @@ pub struct LocaleCode { pub language: String, // ISO-3166 pub territory: String, - // encoding: String, + pub encoding: String, } impl Display for LocaleCode { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}_{}", &self.language, &self.territory) + write!( + f, + "{}_{}.{}", + &self.language, &self.territory, &self.encoding + ) } } @@ -25,6 +29,7 @@ impl Default for LocaleCode { Self { language: "en".to_string(), territory: "US".to_string(), + encoding: "UTF-8".to_string(), } } } @@ -37,14 +42,23 @@ impl TryFrom<&str> for LocaleCode { type Error = InvalidLocaleCode; fn try_from(value: &str) -> Result { - let locale_regexp: Regex = Regex::new(r"^([[:alpha:]]+)_([[:alpha:]]+)").unwrap(); + let locale_regexp: Regex = + Regex::new(r"^([[:alpha:]]+)_([[:alpha:]]+)(?:\.(.+))?").unwrap(); + let captures = locale_regexp .captures(value) .ok_or_else(|| InvalidLocaleCode(value.to_string()))?; + let encoding = captures + .get(3) + .map(|e| e.as_str()) + .unwrap_or("UTF-8") + .to_string(); + Ok(Self { language: captures.get(1).unwrap().as_str().to_string(), territory: captures.get(2).unwrap().as_str().to_string(), + encoding, }) } } From 12f6455f27b7f6289a5857b6c1a4ed36e17ebea6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Imobach=20Gonz=C3=A1lez=20Sosa?= Date: Thu, 11 Jan 2024 11:53:12 +0000 Subject: [PATCH 2/6] [web] Ignore the encoding from UILocale --- web/src/client/l10n.js | 2 +- web/src/context/installerL10n.jsx | 8 ++++++-- web/src/context/installerL10n.test.jsx | 20 ++++++++++---------- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/web/src/client/l10n.js b/web/src/client/l10n.js index ec5c79b207..dfab3001ce 100644 --- a/web/src/client/l10n.js +++ b/web/src/client/l10n.js @@ -37,7 +37,7 @@ const LOCALE_PATH = "/org/opensuse/Agama1/Locale"; /** * @typedef {object} Locale - * @property {string} id - Language id (e.g., "en_US"). + * @property {string} id - Language id (e.g., "en_US.UTF-8"). * @property {string} name - Language name (e.g., "English"). * @property {string} territory - Territory name (e.g., "United States"). */ diff --git a/web/src/context/installerL10n.jsx b/web/src/context/installerL10n.jsx index 7c8b85ae7c..37aeeb630b 100644 --- a/web/src/context/installerL10n.jsx +++ b/web/src/context/installerL10n.jsx @@ -109,12 +109,15 @@ function languageFromQuery() { * @see https://www.rfc-editor.org/info/bcp78 */ function languageFromLocale(locale) { - return locale.replace("_", "-").toLowerCase(); + const [language] = locale.split("."); + return language.replace("_", "-").toLowerCase(); } /** * Converts a RFC 5646 language tag to a locale. * + * It forces the encoding to "UTF-8". + * * @param {string} language * @return {string} * @@ -124,7 +127,8 @@ function languageFromLocale(locale) { */ function languageToLocale(language) { const [lang, country] = language.split("-"); - return (country) ? `${lang}_${country.toUpperCase()}` : lang; + const locale = (country) ? `${lang}_${country.toUpperCase()}` : lang; + return `${locale}.UTF-8`; } /** diff --git a/web/src/context/installerL10n.test.jsx b/web/src/context/installerL10n.test.jsx index cd7bee0468..4327927a90 100644 --- a/web/src/context/installerL10n.test.jsx +++ b/web/src/context/installerL10n.test.jsx @@ -96,7 +96,7 @@ describe("InstallerL10nProvider", () => { describe("when the Cockpit language is already set", () => { beforeEach(() => { document.cookie = "CockpitLang=en-us; path=/;"; - getUILocaleFn.mockResolvedValueOnce("en_US"); + getUILocaleFn.mockResolvedValueOnce("en_US.UTF-8"); }); it("displays the children content and does not reload", async () => { @@ -116,8 +116,8 @@ describe("InstallerL10nProvider", () => { describe("when the Cockpit language is set to an unsupported language", () => { beforeEach(() => { document.cookie = "CockpitLang=de-de; path=/;"; - getUILocaleFn.mockResolvedValueOnce("de_DE"); - getUILocaleFn.mockResolvedValueOnce("es_ES"); + getUILocaleFn.mockResolvedValueOnce("de_DE.UTF-8"); + getUILocaleFn.mockResolvedValueOnce("es_ES.UTF-8"); }); it("uses the first supported language from the browser", async () => { @@ -137,7 +137,7 @@ describe("InstallerL10nProvider", () => { ); await waitFor(() => screen.getByText("hola")); - expect(setUILocaleFn).toHaveBeenCalledWith("es_ES"); + expect(setUILocaleFn).toHaveBeenCalledWith("es_ES.UTF-8"); }); }); @@ -146,7 +146,7 @@ describe("InstallerL10nProvider", () => { // Ensure both, UI and backend mock languages, are in sync since // client.setUILocale is mocked too. // See navigator.language in the beforeAll at the top of the file. - getUILocaleFn.mockResolvedValue("es_ES"); + getUILocaleFn.mockResolvedValue("es_ES.UTF-8"); }); it("sets the preferred language from browser and reloads", async () => { @@ -201,7 +201,7 @@ describe("InstallerL10nProvider", () => { describe("when the Cockpit language is already set to 'cs-cz'", () => { beforeEach(() => { document.cookie = "CockpitLang=cs-cz; path=/;"; - getUILocaleFn.mockResolvedValueOnce("cs_CZ"); + getUILocaleFn.mockResolvedValueOnce("cs_CZ.UTF-8"); }); it("displays the children content and does not reload", async () => { @@ -246,14 +246,14 @@ describe("InstallerL10nProvider", () => { ); await waitFor(() => screen.getByText("ahoj")); - expect(setUILocaleFn).toHaveBeenCalledWith("cs_CZ"); + expect(setUILocaleFn).toHaveBeenCalledWith("cs_CZ.UTF-8"); }); }); describe("when the Cockpit language is not set", () => { beforeEach(() => { - getUILocaleFn.mockResolvedValueOnce("en_US"); - getUILocaleFn.mockResolvedValueOnce("cs_CZ"); + getUILocaleFn.mockResolvedValueOnce("en_US.UTF-8"); + getUILocaleFn.mockResolvedValueOnce("cs_CZ.UTF-8"); setUILocaleFn.mockResolvedValue(); }); @@ -274,7 +274,7 @@ describe("InstallerL10nProvider", () => { ); await waitFor(() => screen.getByText("ahoj")); - expect(setUILocaleFn).toHaveBeenCalledWith("cs_CZ"); + expect(setUILocaleFn).toHaveBeenCalledWith("cs_CZ.UTF-8"); }); }); }); From 80540e1ee7636d4ed4538240d3b02192df21f249 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Imobach=20Gonz=C3=A1lez=20Sosa?= Date: Thu, 11 Jan 2024 12:20:55 +0000 Subject: [PATCH 3/6] cargo_config is now included in vendor.tar --- rust/package/agama-cli.spec | 4 ---- 1 file changed, 4 deletions(-) diff --git a/rust/package/agama-cli.spec b/rust/package/agama-cli.spec index 3b7e70914f..d234ac3a01 100644 --- a/rust/package/agama-cli.spec +++ b/rust/package/agama-cli.spec @@ -26,8 +26,6 @@ License: GPL-2.0-only Url: https://github.com/opensuse/agama Source0: agama.tar Source1: vendor.tar.zst -# Generated by the cargo_vendor OBS service -Source2: cargo_config BuildRequires: cargo-packaging BuildRequires: pkgconfig(openssl) # used in tests for dbus service @@ -64,8 +62,6 @@ DBus service for agama project. It provides so far localization service. %prep %autosetup -a1 -n agama -mkdir .cargo -cp %{SOURCE2} .cargo/config # Remove exec bits to prevent an issue in fedora shebang checking. Uncomment only if required. # find vendor -type f -name \*.rs -exec chmod -x '{}' \; From d0f7b000bb9f81c535e060d9fd63f4f42c34b9dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Imobach=20Gonz=C3=A1lez=20Sosa?= Date: Thu, 11 Jan 2024 14:50:17 +0000 Subject: [PATCH 4/6] [service] Handle the locale properly --- service/lib/agama/dbus/software_service.rb | 6 ++++-- service/lib/agama/ui_locale.rb | 7 ++++--- service/test/agama/dbus/manager_service_test.rb | 3 ++- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/service/lib/agama/dbus/software_service.rb b/service/lib/agama/dbus/software_service.rb index efcdf52372..cc0404fdf1 100644 --- a/service/lib/agama/dbus/software_service.rb +++ b/service/lib/agama/dbus/software_service.rb @@ -98,13 +98,15 @@ def dbus_objects # Language change callback handler, activate new locale in the libzypp backend # @param locale [String] the new locale def locale_handler(locale) + language, = locale.split(".") + # set the locale in the Language module, when changing the repository # (product) it calls Pkg.SetTextLocale(Language.language) internally - Yast::Language.Set(locale) + Yast::Language.Set(language) # set libzypp locale (for communication only, Pkg.SetPackageLocale # call can be used for *installing* the language packages) - Yast::Pkg.SetTextLocale(locale) + Yast::Pkg.SetTextLocale(language) # refresh all enabled repositories to download the missing translation files Yast::Pkg.SourceGetCurrent(true).each do |src| diff --git a/service/lib/agama/ui_locale.rb b/service/lib/agama/ui_locale.rb index 01c1b10564..fc31e8b8a6 100644 --- a/service/lib/agama/ui_locale.rb +++ b/service/lib/agama/ui_locale.rb @@ -46,10 +46,11 @@ def initialize(locale_client, &block) def change_locale(locale) # TODO: check if we can use UTF-8 everywhere including strange arch consoles - Yast::WFM.SetLanguage(locale, "UTF-8") + language, encoding = locale.split(".") + Yast::WFM.SetLanguage(language, encoding) # explicitly set ENV to get localization also from libraries like libstorage - ENV["LANG"] = locale + ".UTF-8" - log.info "set yast language to #{locale}" + ENV["LANG"] = locale + log.info "set yast locale to #{locale}" # explicit call to textdomain to force fast gettext change of language ASAP textdomain "installation" end diff --git a/service/test/agama/dbus/manager_service_test.rb b/service/test/agama/dbus/manager_service_test.rb index 6149a198cf..ef886cc722 100644 --- a/service/test/agama/dbus/manager_service_test.rb +++ b/service/test/agama/dbus/manager_service_test.rb @@ -39,7 +39,8 @@ let(:users_obj) { instance_double(Agama::DBus::Users, path: "/org/opensuse/Agama/Users1") } let(:locale_client) do - instance_double(Agama::DBus::Clients::Locale, ui_locale: "en_US", on_ui_locale_change: nil) + instance_double(Agama::DBus::Clients::Locale, ui_locale: "en_US.UTF-8", + on_ui_locale_change: nil) end before do From f33057f5f73dbcf44b341436db74fd41a53146d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Imobach=20Gonz=C3=A1lez=20Sosa?= Date: Thu, 11 Jan 2024 12:15:28 +0000 Subject: [PATCH 5/6] Update the changes files --- rust/package/agama-cli.changes | 5 +++++ service/package/rubygem-agama.changes | 6 ++++++ web/package/cockpit-agama.changes | 6 ++++++ 3 files changed, 17 insertions(+) diff --git a/rust/package/agama-cli.changes b/rust/package/agama-cli.changes index 83df6d4a91..c259cd26a3 100644 --- a/rust/package/agama-cli.changes +++ b/rust/package/agama-cli.changes @@ -1,3 +1,8 @@ +------------------------------------------------------------------- +Thu Jan 11 15:34:15 UTC 2024 - Imobach Gonzalez Sosa + +- Include the encoding as part of the locales (gh#openSUSE/agama#987). + ------------------------------------------------------------------- Mon Jan 8 17:02:40 UTC 2024 - José Iván López González diff --git a/service/package/rubygem-agama.changes b/service/package/rubygem-agama.changes index 4cc4d3d58e..d2564ea3d1 100644 --- a/service/package/rubygem-agama.changes +++ b/service/package/rubygem-agama.changes @@ -1,3 +1,9 @@ +------------------------------------------------------------------- +Thu Jan 11 15:32:44 UTC 2024 - Imobach Gonzalez Sosa + +- Handle the encoding included in the UILocale D-Bus property + (gh#openSUSE/agama#987). + ------------------------------------------------------------------- Thu Jan 11 12:08:29 UTC 2024 - Ladislav Slezák diff --git a/web/package/cockpit-agama.changes b/web/package/cockpit-agama.changes index f9a6362b1a..ff1445f980 100644 --- a/web/package/cockpit-agama.changes +++ b/web/package/cockpit-agama.changes @@ -1,3 +1,9 @@ +------------------------------------------------------------------- +Thu Jan 11 15:34:26 UTC 2024 - Imobach Gonzalez Sosa + +- Ignore the encoding from the UILocale D-Bus property + (gh#openSUSE/agama#987). + ------------------------------------------------------------------- Mon Jan 8 15:55:39 UTC 2024 - David Diaz From f1536502c71edf59f040f761026df35e8d487cbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Imobach=20Gonz=C3=A1lez=20Sosa?= Date: Tue, 16 Jan 2024 09:38:15 +0000 Subject: [PATCH 6/6] Drop outdated comments --- rust/agama-dbus-server/src/l10n/helpers.rs | 1 - service/lib/agama/ui_locale.rb | 1 - 2 files changed, 2 deletions(-) diff --git a/rust/agama-dbus-server/src/l10n/helpers.rs b/rust/agama-dbus-server/src/l10n/helpers.rs index 3bccb04a8e..507094cd04 100644 --- a/rust/agama-dbus-server/src/l10n/helpers.rs +++ b/rust/agama-dbus-server/src/l10n/helpers.rs @@ -22,7 +22,6 @@ pub fn init_locale() -> Result> { /// Sets the service locale. /// pub fn set_service_locale(locale: &LocaleCode) { - // Let's force the encoding to be 'UTF-8'. if setlocale(LocaleCategory::LcAll, locale.to_string()).is_none() { log::warn!("Could not set the locale"); } diff --git a/service/lib/agama/ui_locale.rb b/service/lib/agama/ui_locale.rb index fc31e8b8a6..4f21dd046e 100644 --- a/service/lib/agama/ui_locale.rb +++ b/service/lib/agama/ui_locale.rb @@ -45,7 +45,6 @@ def initialize(locale_client, &block) private def change_locale(locale) - # TODO: check if we can use UTF-8 everywhere including strange arch consoles language, encoding = locale.split(".") Yast::WFM.SetLanguage(language, encoding) # explicitly set ENV to get localization also from libraries like libstorage