diff --git a/rust/agama-cli/doc/backend-for-testing.md b/rust/agama-cli/doc/backend-for-testing.md index a5612620ac..d23c993cf7 100644 --- a/rust/agama-cli/doc/backend-for-testing.md +++ b/rust/agama-cli/doc/backend-for-testing.md @@ -33,53 +33,8 @@ of [.github/workflows/ci.yml][ci.yml]. [ci.yml]: https://github.com/openSUSE/agama/blob/25462f57ab695d6910beb59ff0b21a7afaeda47e/.github/workflows/ci.yml +## Resulting Script -```sh -# https://build.opensuse.org/package/show/systemsmanagement:Agama:Staging/agama-testing -CIMAGE=registry.opensuse.org/systemsmanagement/agama/staging/containers/opensuse/agama-testing:latest -# rename this if you test multiple things -CNAME=agama -# the '?' here will report a shell error -# if you accidentally paste a command without setting the variable first -echo ${CNAME?} - -test -f service/agama.gemspec || echo "You should run this from a checkout of agama" - -# destroy the previous instance -podman stop ${CNAME?} -podman rm ${CNAME?} - -mkdir -p ./mnt/log-yast2 # needed? -mkdir -p ./mnt/run-agama # only needed for D-Bus access from outside, unused now - -# Update our image -podman pull ${CIMAGE?} - -podman run --name ${CNAME?} \ - --privileged --detach --ipc=host \ - -v .:/checkout -v ./mnt/run-agama:/run/agama -v ./mnt/log-yast2:/var/log/YaST2 \ - ${CIMAGE?} - -# shortcut for the following -CEXEC="podman exec ${CNAME?} bash -c" - -${CEXEC?} "cd /checkout && ./setup-services.sh" - -# Optional: explicit service start using a separate log file -${CEXEC?} "cd /checkout/service && (bundle exec bin/agamactl > service.log 2>&1 &)" - -# Now the CLI is in the same repo, just symlink it -${CEXEC?} "ln -sfv /checkout/./rust/target/debug/agama /usr/bin/agama" - -# Optional: Play! -${CEXEC?} "agama -f yaml config show" - -# Optional: show logs of autostarted services -${CEXEC?} "journalctl --since=-5min" - -# Optional: show logs of explicitly started services -${CEXEC?} "cat /checkout/service/service.log" - -# Optional: Interactive shell in the container -podman exec --tty --interactive ${CNAME?} bash -``` +The script, which used to be inlined here, is now at +[`/testing_using_container.sh`](../../../testing_using_container.sh). +>>>>>>> 8f2f0404 (copied the script part of rust/agama-cli/doc/backend-for-testing.md) diff --git a/rust/agama-dbus-server/src/l10n/helpers.rs b/rust/agama-dbus-server/src/l10n/helpers.rs index 490203d5b1..507094cd04 100644 --- a/rust/agama-dbus-server/src/l10n/helpers.rs +++ b/rust/agama-dbus-server/src/l10n/helpers.rs @@ -22,9 +22,7 @@ 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'. - 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-dbus-server/src/network/model.rs b/rust/agama-dbus-server/src/network/model.rs index 0205b2fe2b..3991ef7a77 100644 --- a/rust/agama-dbus-server/src/network/model.rs +++ b/rust/agama-dbus-server/src/network/model.rs @@ -161,6 +161,57 @@ mod tests { use crate::network::error::NetworkStateError; use uuid::Uuid; + #[test] + fn test_macaddress() { + let mut val: Option = None; + assert!(matches!( + MacAddress::try_from(&val).unwrap(), + MacAddress::Unset + )); + + val = Some(String::from("")); + assert!(matches!( + MacAddress::try_from(&val).unwrap(), + MacAddress::Unset + )); + + val = Some(String::from("preserve")); + assert!(matches!( + MacAddress::try_from(&val).unwrap(), + MacAddress::Preserve + )); + + val = Some(String::from("permanent")); + assert!(matches!( + MacAddress::try_from(&val).unwrap(), + MacAddress::Permanent + )); + + val = Some(String::from("random")); + assert!(matches!( + MacAddress::try_from(&val).unwrap(), + MacAddress::Random + )); + + val = Some(String::from("stable")); + assert!(matches!( + MacAddress::try_from(&val).unwrap(), + MacAddress::Stable + )); + + val = Some(String::from("This is not a MACAddr")); + assert!(matches!( + MacAddress::try_from(&val), + Err(InvalidMacAddress(_)) + )); + + val = Some(String::from("de:ad:be:ef:2b:ad")); + assert_eq!( + MacAddress::try_from(&val).unwrap().to_string(), + String::from("de:ad:be:ef:2b:ad").to_uppercase() + ); + } + #[test] fn test_add_connection() { let mut state = NetworkState::default(); @@ -457,6 +508,17 @@ impl FromStr for MacAddress { } } +impl TryFrom<&Option> for MacAddress { + type Error = InvalidMacAddress; + + fn try_from(value: &Option) -> Result { + match &value { + Some(str) => MacAddress::from_str(str), + None => Ok(Self::Unset), + } + } +} + impl fmt::Display for MacAddress { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let output = match &self { 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, }) } } 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/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 '{}' \; diff --git a/service/lib/agama/dbus/software_service.rb b/service/lib/agama/dbus/software_service.rb index 245f2f6a97..cc0404fdf1 100644 --- a/service/lib/agama/dbus/software_service.rb +++ b/service/lib/agama/dbus/software_service.rb @@ -59,15 +59,8 @@ def start # registering the language change callback to work properly export @ui_locale = UILocale.new(Clients::Locale.instance) do |locale| - # set the locale in the Language module, when changing the repository - # (product) it calls Pkg.SetTextLocale(Language.language) internally - Yast::Language.Set(locale) - # set libzypp locale (for communication only, Pkg.SetPackageLocale - # call can be used for installing the language packages) - Yast::Pkg.SetTextLocale(locale) - # TODO: libzypp shows the pattern names and descriptions using the - # locale set at the repository refresh time, here we should refresh - # the repositories with the new locale + # call the language change handler + locale_handler(locale) end end @@ -101,6 +94,41 @@ def dbus_objects Agama::DBus::Software::Proposal.new(logger) ] end + + # 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(language) + + # set libzypp locale (for communication only, Pkg.SetPackageLocale + # call can be used for *installing* the language packages) + Yast::Pkg.SetTextLocale(language) + + # refresh all enabled repositories to download the missing translation files + Yast::Pkg.SourceGetCurrent(true).each do |src| + Yast::Pkg.SourceForceRefreshNow(src) + end + + # remember the currently selected packages and patterns by YaST + # (ignore the automatic selections done by the solver) + # + # NOTE: we will need to handle also the tabooed and soft-locked objects + # when we allow to set them via UI or CLI + selected = Y2Packager::Resolvable.find(status: :selected, transact_by: :appl_high) + + # save and reload all repositories to activate the new translations + Yast::Pkg.SourceSaveAll + Yast::Pkg.SourceFinishAll + Yast::Pkg.SourceRestore + Yast::Pkg.SourceLoad + + # restore back the selected objects + selected.each { |s| Yast::Pkg.ResolvableInstall(s.name, s.kind) } + end end end end diff --git a/service/lib/agama/network.rb b/service/lib/agama/network.rb index 23eef44e37..972ec5162f 100644 --- a/service/lib/agama/network.rb +++ b/service/lib/agama/network.rb @@ -52,6 +52,7 @@ def install attr_reader :logger ETC_NM_DIR = "/etc/NetworkManager" + RUN_NM_DIR = "/run/NetworkManager" private_constant :ETC_NM_DIR def enable_service @@ -68,6 +69,13 @@ def enable_service def copy_files return unless Dir.exist?(ETC_NM_DIR) + # runtime configuration is copied first, so in case of later modification + # on same interface it gets overwriten (bsc#1210541). + copy_directory( + File.join(RUN_NM_DIR, "system-connections"), + File.join(Yast::Installation.destdir, ETC_NM_DIR, "system-connections") + ) + copy_directory( File.join(ETC_NM_DIR, "system-connections"), File.join(Yast::Installation.destdir, ETC_NM_DIR, "system-connections") diff --git a/service/lib/agama/ui_locale.rb b/service/lib/agama/ui_locale.rb index 01c1b10564..4f21dd046e 100644 --- a/service/lib/agama/ui_locale.rb +++ b/service/lib/agama/ui_locale.rb @@ -45,11 +45,11 @@ def initialize(locale_client, &block) private 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/package/rubygem-agama.changes b/service/package/rubygem-agama.changes index 6ff8911f76..15837bc65c 100644 --- a/service/package/rubygem-agama.changes +++ b/service/package/rubygem-agama.changes @@ -1,3 +1,19 @@ +------------------------------------------------------------------- +Tue Jan 16 10:49:14 UTC 2024 - Michal Filka + +- bsc#1210541, gh#openSUSE/agama#516 + - copy NM's runtime config created on dracut's request to the target +------------------------------------------------------------------- +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 + +- Translate the pattern descriptions (gh#openSUSE/agama#859) + ------------------------------------------------------------------- Thu Dec 21 14:23:48 UTC 2023 - Imobach Gonzalez Sosa 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 diff --git a/setup-services.sh b/setup-services.sh index e9a4596a1f..29abd1da43 100755 --- a/setup-services.sh +++ b/setup-services.sh @@ -102,6 +102,15 @@ fi # Rubygem dependencies ( cd $MYDIR/service + + if [ -d /checkout-ruby-dbus ]; then + # we are in a container, told to use that one + # instead of a released version + # edit +Gemfile and -gemspec + sed -e '/ruby-dbus/d' -i Gemfile agama.gemspec + sed -e '/gemspec/a gem "ruby-dbus", path: "/checkout-ruby-dbus"' -i Gemfile + fi + bundle config set --local path 'vendor/bundle' bundle install ) diff --git a/testing_using_container.sh b/testing_using_container.sh new file mode 100755 index 0000000000..87becab2c6 --- /dev/null +++ b/testing_using_container.sh @@ -0,0 +1,56 @@ +#!/bin/bash +# Run checked-out Agama in a podman container. +# This is meant to be run from a working copy of the git repo. +# It uses the systemsmanagement:Agama:Staging/agama-testing image as +# a platform and runs /setup.sh +# +# Details: +# - container name: agama +# - port 9090 is exposed so that web UI works +# - 'WITH_RUBY_DBUS=1 $0' will prefer ../ruby-dbus to any ruby-dbus.gem + +set -x +set -eu + +# https://build.opensuse.org/package/show/systemsmanagement:Agama:Staging/agama-testing +CIMAGE=registry.opensuse.org/systemsmanagement/agama/staging/containers/opensuse/agama-testing:latest +# rename this if you test multiple things +CNAME=agama + +test -f service/agama.gemspec || { echo "You should run this from a checkout of agama"; exit 1; } + +# destroy the previous instance, can fail if there is no previous instance +podman stop ${CNAME?} || : no problem if there was nothing to stop +podman rm ${CNAME?} || : no problem if there was nothing to remove + +# Update our image +podman pull ${CIMAGE?} + +# Optionally use a git version of ruby-dbus +# because Agama pushes its limits so it's better +# to set up for easy testing +MORE_VOLUMES=() +if [ "${WITH_RUBY_DBUS-}" = 1 ]; then + MORE_VOLUMES=(-v ../ruby-dbus:/checkout-ruby-dbus) +fi + +podman run --name ${CNAME?} \ + --privileged --detach --ipc=host \ + -v .:/checkout \ + ${MORE_VOLUMES[@]} \ + -p 9090:9090 \ + ${CIMAGE?} + +# shortcut for the following +CEXEC="podman exec ${CNAME?} bash -c" + +${CEXEC?} "cd /checkout && ./setup.sh" + +# Now the CLI is in the same repo, just symlink it +${CEXEC?} "ln -sfv /checkout/./rust/target/debug/agama /usr/bin/agama" + +# Manually start cockpit as socket activation does not work with port forwarding +${CEXEC?} "systemctl start cockpit" + +# Interactive shell in the container +podman exec --tty --interactive ${CNAME?} bash 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 diff --git a/web/po/id.po b/web/po/id.po index 18188ecb91..401f0600cf 100644 --- a/web/po/id.po +++ b/web/po/id.po @@ -8,10 +8,10 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-01-10 02:19+0000\n" -"PO-Revision-Date: 2023-12-31 20:39+0000\n" +"PO-Revision-Date: 2024-01-12 18:59+0000\n" "Last-Translator: Arif Budiman \n" -"Language-Team: Indonesian \n" +"Language-Team: Indonesian \n" "Language: id\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -92,7 +92,7 @@ msgstr "Muat ulang" #: src/components/core/DevelopmentInfo.jsx:55 msgid "Cockpit server" -msgstr "" +msgstr "Server Cockpit" #: src/components/core/FileViewer.jsx:65 msgid "Reading file..." @@ -103,13 +103,12 @@ msgid "Cannot read the file" msgstr "Tidak dapat membaca berkas" #: src/components/core/InstallButton.jsx:37 -#, fuzzy msgid "" "There are some reported issues. Please review them in the previous steps " "before proceeding with the installation." msgstr "" -"Ada beberapa masalah yang dilaporkan. Silakan periksa [daftar masalah] " -"sebelum melanjutkan penginstalan." +"Ada beberapa masalah yang dilaporkan. Silakan periksa kembali pada langkah " +"sebelumnya sebelum melanjutkan instalasi." #: src/components/core/InstallButton.jsx:49 msgid "Confirm Installation" @@ -247,9 +246,8 @@ msgid "Show global options" msgstr "Tampilkan opsi global" #: src/components/core/Page.jsx:215 -#, fuzzy msgid "Page Actions" -msgstr "Tindakan yang Direncanakan" +msgstr "Tindakan Halaman" #: src/components/core/PasswordAndConfirmationInput.jsx:35 msgid "Passwords do not match" @@ -315,9 +313,8 @@ msgid "Installer Options" msgstr "Opsi Penginstal" #: src/components/core/Sidebar.jsx:128 -#, fuzzy msgid "Hide installer options" -msgstr "Opsi Penginstal" +msgstr "Sembunyikan opsi penginstal" #: src/components/core/Sidebar.jsx:136 msgid "Diagnostic tools" @@ -325,24 +322,20 @@ msgstr "Alat bantu diagnostik" #. TRANSLATORS: Titles used for the popup displaying found section issues #: src/components/core/ValidationErrors.jsx:53 -#, fuzzy msgid "Software issues" -msgstr "Perangkat Lunak %s" +msgstr "Masalah perangkat lunak" #: src/components/core/ValidationErrors.jsx:54 -#, fuzzy msgid "Product issues" -msgstr "Produk" +msgstr "Masalah Produk" #: src/components/core/ValidationErrors.jsx:55 -#, fuzzy msgid "Storage issues" -msgstr "Tampilkan masalah" +msgstr "Masalah penyimpanan" #: src/components/core/ValidationErrors.jsx:57 -#, fuzzy msgid "Found Issues" -msgstr "Tampilkan masalah" +msgstr "Masalah yang Ditemukan" #. TRANSLATORS: %d is replaced with the number of errors found #: src/components/core/ValidationErrors.jsx:77 @@ -623,9 +616,8 @@ msgid "Gateway" msgstr "Gateway" #: src/components/network/NetworkPage.jsx:38 -#, fuzzy msgid "No wired connections found." -msgstr "Tidak ditemukan koneksi kabel" +msgstr "Tidak ditemukan koneksi kabel." #: src/components/network/NetworkPage.jsx:53 msgid "" @@ -641,9 +633,8 @@ msgstr "" "tidak ada atau dinonaktifkan." #: src/components/network/NetworkPage.jsx:58 -#, fuzzy msgid "No WiFi connections found." -msgstr "Tidak ditemukan koneksi WiFi" +msgstr "Tidak ditemukan koneksi WiFi." #. TRANSLATORS: button label #: src/components/network/NetworkPage.jsx:70 @@ -1156,7 +1147,7 @@ msgstr[0] "Tampilkan tindakan subvolume %d" #: src/components/storage/ProposalActionsSection.jsx:78 msgid "Actions to create the file systems and to ensure the system boots." msgstr "" -"Tindakan untuk membuat sistem file dan memastikan sistem melakukan booting." +"Tindakan untuk membuat sistem berkas dan memastikan sistem melakukan booting." #. TRANSLATORS: section title, list of planned actions for the selected device, #. e.g. "delete partition A", "create partition B with filesystem C", ... @@ -1199,9 +1190,8 @@ msgid "Installation device" msgstr "Perangkat penginstalan" #: src/components/storage/ProposalSettingsSection.jsx:154 -#, fuzzy msgid "No devices found." -msgstr "Tidak ada perangkat yang ditemukan" +msgstr "Tidak ada perangkat yang ditemukan." #: src/components/storage/ProposalSettingsSection.jsx:241 msgid "Devices for creating the volume group" @@ -1216,7 +1206,7 @@ msgid "" "Configuration of the system volume group. All the file systems will be " "created in a logical volume of the system volume group." msgstr "" -"Konfigurasi grup volume sistem. Semua sistem file akan dibuat dalam volume " +"Konfigurasi grup volume sistem. Semua sistem berkas akan dibuat dalam volume " "logis dari grup volume sistem." #: src/components/storage/ProposalSettingsSection.jsx:320 @@ -1255,7 +1245,7 @@ msgid "" "file systems." msgstr "" "Memilih cara mengosongkan ruang pada disk yang dipilih untuk mengalokasikan " -"sistem file." +"sistem berkas." #. TRANSLATORS: To be completed with the rest of a sentence like "deleting all content" #: src/components/storage/ProposalSettingsSection.jsx:584 @@ -1296,7 +1286,7 @@ msgstr "Mengatur ulang ke default" #: src/components/storage/ProposalVolumes.jsx:137 #: src/components/storage/ProposalVolumes.jsx:141 msgid "Add file system" -msgstr "Tambahkan sistem file" +msgstr "Tambahkan sistem berkas" #. TRANSLATORS: minimum device size, %s is replaced by size string, e.g. "17.5 GiB" #: src/components/storage/ProposalVolumes.jsx:191 @@ -1343,7 +1333,7 @@ msgstr "Menghapus" #: src/components/storage/ProposalVolumes.jsx:275 msgid "Edit file system" -msgstr "Mengedit sistem file" +msgstr "Edit sistem berkas" #: src/components/storage/ProposalVolumes.jsx:307 #: src/components/storage/VolumeForm.jsx:727 @@ -1365,7 +1355,7 @@ msgstr "Tabel dengan titik pemasangan" #: src/components/storage/ProposalVolumes.jsx:408 msgid "File systems to create in your system" -msgstr "Sistem file yang akan dibuat di sistem Anda" +msgstr "Sistem berkas yang akan dibuat di sistem Anda" #. TRANSLATORS: description of Btrfs snapshots feature. #: src/components/storage/VolumeForm.jsx:172 @@ -1385,12 +1375,12 @@ msgstr "Opsi untuk jenis sistem berkas tergantung pada produk dan titik mount." #: src/components/storage/VolumeForm.jsx:275 msgid "More info for file system types" -msgstr "Info lebih lanjut untuk jenis sistem file" +msgstr "Info lebih lanjut untuk jenis sistem berkas" #. TRANSLATORS: label for the file system selector. #: src/components/storage/VolumeForm.jsx:286 msgid "File system type" -msgstr "Jenis sistem file" +msgstr "Jenis sistem berkas" #. TRANSLATORS: item which affects the final computed partition size #: src/components/storage/VolumeForm.jsx:318 @@ -1402,7 +1392,7 @@ msgstr "konfigurasi snapshot" #: src/components/storage/VolumeForm.jsx:323 #, c-format msgid "the presence of the file system for %s" -msgstr "keberadaan sistem file untuk %s" +msgstr "keberadaan sistem berkas untuk %s" #. TRANSLATORS: conjunction for merging two list items #: src/components/storage/VolumeForm.jsx:325 @@ -1427,7 +1417,7 @@ msgstr "Ukuran yang dihitung secara otomatis menurut produk yang dipilih." #: src/components/storage/VolumeForm.jsx:355 msgid "Exact size for the file system." -msgstr "Ukuran yang tepat untuk sistem file." +msgstr "Ukuran yang tepat untuk sistem berkas." #. TRANSLATORS: requested partition size #: src/components/storage/VolumeForm.jsx:367 @@ -1445,9 +1435,9 @@ msgid "" "given minimum and maximum. If no maximum is given then the file system will " "be as big as possible." msgstr "" -"Batas untuk ukuran sistem file. Ukuran akhir akan berupa nilai antara " +"Batas untuk ukuran sistem berkas. Ukuran akhir akan berupa nilai antara " "minimum dan maksimum yang diberikan. Jika tidak ada nilai maksimum yang " -"diberikan, maka sistem file akan sebesar mungkin." +"diberikan, maka sistem berkas akan sebesar mungkin." #. TRANSLATORS: the minimal partition size #: src/components/storage/VolumeForm.jsx:417 @@ -1533,9 +1523,8 @@ msgid "Deactivated" msgstr "Dinonaktifkan" #: src/components/storage/ZFCPPage.jsx:417 -#, fuzzy msgid "No zFCP controllers found." -msgstr "Tidak ditemukan pengontrol zFCP" +msgstr "Tidak ditemukan pengontrol zFCP." #: src/components/storage/ZFCPPage.jsx:418 msgid "Please, try to read the zFCP devices again." @@ -1582,9 +1571,8 @@ msgid "Activate zFCP disk" msgstr "Mengaktifkan disk zFCP" #: src/components/storage/ZFCPPage.jsx:553 -#, fuzzy msgid "No zFCP disks found." -msgstr "Tidak ditemukan disk zFCP" +msgstr "Tidak ditemukan disk zFCP." #. TRANSLATORS: button label #: src/components/storage/ZFCPPage.jsx:572 @@ -1812,9 +1800,8 @@ msgid "Interface" msgstr "Antarmuka" #: src/components/storage/iscsi/TargetsSection.jsx:139 -#, fuzzy msgid "No iSCSI targets found." -msgstr "Tidak ada target iSCSI yang ditemukan" +msgstr "Tidak ditemukan target iSCSI." #: src/components/storage/iscsi/TargetsSection.jsx:140 msgid "" @@ -1920,9 +1907,8 @@ msgid "PiB" msgstr "PiB" #: src/components/users/FirstUser.jsx:44 -#, fuzzy msgid "No user defined yet." -msgstr "Belum ada pengguna yang ditetapkan" +msgstr "Belum ada pengguna yang ditetapkan." #: src/components/users/FirstUser.jsx:47 msgid "" @@ -1982,9 +1968,8 @@ msgid "Auto-login" msgstr "Masuk otomatis" #: src/components/users/RootAuthMethods.jsx:35 -#, fuzzy msgid "No root authentication method defined yet." -msgstr "Belum ada metode autentikasi root yang ditetapkan" +msgstr "Belum ada metode autentikasi root yang ditetapkan." #: src/components/users/RootAuthMethods.jsx:38 msgid "" diff --git a/web/po/sv.po b/web/po/sv.po index 933c7a895b..cd3d032231 100644 --- a/web/po/sv.po +++ b/web/po/sv.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-01-10 02:19+0000\n" -"PO-Revision-Date: 2024-01-03 08:02+0000\n" +"PO-Revision-Date: 2024-01-10 12:59+0000\n" "Last-Translator: Luna Jernberg \n" "Language-Team: Swedish \n" @@ -101,13 +101,12 @@ msgid "Cannot read the file" msgstr "Kan inte läsa fil" #: src/components/core/InstallButton.jsx:37 -#, fuzzy msgid "" "There are some reported issues. Please review them in the previous steps " "before proceeding with the installation." msgstr "" -"Det finns några rapporterade problem. Vänligen kontrollera [listan över " -"problem] innan du fortsätter med installationen." +"Det finns några rapporterade problem. Vänligen granska dem i de föregående " +"stegen innan du fortsätter med installationen." #: src/components/core/InstallButton.jsx:49 msgid "Confirm Installation" @@ -322,24 +321,20 @@ msgstr "Diagnostik verktyg" #. TRANSLATORS: Titles used for the popup displaying found section issues #: src/components/core/ValidationErrors.jsx:53 -#, fuzzy msgid "Software issues" -msgstr "Programvara %s" +msgstr "Programvaruproblem" #: src/components/core/ValidationErrors.jsx:54 -#, fuzzy msgid "Product issues" -msgstr "Produkt" +msgstr "Produktproblem" #: src/components/core/ValidationErrors.jsx:55 -#, fuzzy msgid "Storage issues" -msgstr "Visa problem" +msgstr "Lagringsproblem" #: src/components/core/ValidationErrors.jsx:57 -#, fuzzy msgid "Found Issues" -msgstr "Visa problem" +msgstr "Hittade problem" #. TRANSLATORS: %d is replaced with the number of errors found #: src/components/core/ValidationErrors.jsx:77 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"); }); }); });