From b48fac36941e8e0703f3f480e870f94affc0a41a Mon Sep 17 00:00:00 2001 From: Martin Sirringhaus Date: Fri, 10 Oct 2025 15:17:08 +0200 Subject: [PATCH 1/2] Wire up translations --- CONTRIBUTING.md | 22 ++ credentialsd-ui/data/resources/ui/window.ui | 20 +- credentialsd-ui/meson.build | 8 +- credentialsd-ui/po/LINGUAS | 2 + credentialsd-ui/po/POTFILES.in | 10 +- credentialsd-ui/po/credentialsd-ui.pot | 215 +++++++++++++++++ credentialsd-ui/po/de_DE.po | 217 +++++++++++++++++ credentialsd-ui/po/en_US.po | 223 ++++++++++++++++++ credentialsd-ui/po/meson.build | 11 +- .../src/gui/view_model/gtk/application.rs | 3 +- .../src/gui/view_model/gtk/device.rs | 19 +- credentialsd-ui/src/gui/view_model/gtk/mod.rs | 57 +++-- credentialsd-ui/src/gui/view_model/mod.rs | 38 +-- credentialsd-ui/src/meson.build | 11 +- 14 files changed, 784 insertions(+), 72 deletions(-) create mode 100644 credentialsd-ui/po/credentialsd-ui.pot create mode 100644 credentialsd-ui/po/de_DE.po create mode 100644 credentialsd-ui/po/en_US.po diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ca8ab14..0250117 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -192,3 +192,25 @@ formatting and linting tools [mentioned above](#code-formatting-and-linting). You should also follow the install instructions in [`BUILDING.md`](/BUILDING.md) and execute authentication flows in a browser to ensure that everything still works as it should. + +# Translations + +credentialsd-ui is using [gettext-rs](https://github.com/gettext-rs/gettext-rs) to translate user-facing strings. + +Please wrap all user-facing messages in `gettext("my string")`-calls and add the files you add them to, to `credentialsd-ui/po/POTFILES`. + +If you introduce a new language, also add them to `credentialsd-ui/po/LINGUAS`. + +Then `cd` into your build-directory (e.g. `build/`) and run + +``` + # To update the POT template file, in case new strings have been added in the sources + meson compile credentialds-ui-pot + # and to update the individual language files + meson compile credentialds-ui-update-po +``` +to update the template, so it contains all messages to be translated. + +Meson should take care of building the translations. + +When using the development-profile to build, meson will use the locally built translations. diff --git a/credentialsd-ui/data/resources/ui/window.ui b/credentialsd-ui/data/resources/ui/window.ui index c3c1639..af10dac 100644 --- a/credentialsd-ui/data/resources/ui/window.ui +++ b/credentialsd-ui/data/resources/ui/window.ui @@ -40,13 +40,13 @@ choose_device - Choose device + Choose device vertical - Devices + Devices @@ -69,7 +69,7 @@ usb - Plug in security key + Plug in security key vertical @@ -110,7 +110,7 @@ hybrid_qr - Scan the QR code to connect your device + Scan the QR code to connect your device vertical @@ -155,13 +155,13 @@ choose_credential - Choose credential + Choose credential vertical - Choose credential + Choose credential @@ -184,13 +184,13 @@ completed - Complete + Complete vertical - Done! + Done! @@ -201,7 +201,7 @@ failed - Something went wrong. + Something went wrong. vertical @@ -214,7 +214,7 @@ - Something went wrong while retrieving a credential. Please try again later or use a different authenticator. + Something went wrong while retrieving a credential. Please try again later or use a different authenticator. diff --git a/credentialsd-ui/meson.build b/credentialsd-ui/meson.build index d2e2cb3..b8c9f7b 100644 --- a/credentialsd-ui/meson.build +++ b/credentialsd-ui/meson.build @@ -31,8 +31,6 @@ localedir = prefix / get_option('localedir') datadir = prefix / get_option('datadir') pkgdatadir = datadir / gui_executable_name iconsdir = datadir / 'icons' -podir = meson.project_source_root() / meson.current_source_dir() / 'po' -gettext_package = gui_executable_name if get_option('profile') == 'development' profile = 'Devel' @@ -71,6 +69,10 @@ if get_option('cargo_offline') == true cargo_options += ['--offline'] endif +# Localization setup +podir = meson.project_source_root() / meson.current_source_dir() / 'po' +gettext_package = gui_executable_name + subdir('data') subdir('po') subdir('src') @@ -79,4 +81,4 @@ gnome.post_install( gtk_update_icon_cache: true, glib_compile_schemas: true, update_desktop_database: true, -) \ No newline at end of file +) diff --git a/credentialsd-ui/po/LINGUAS b/credentialsd-ui/po/LINGUAS index e69de29..845d78b 100644 --- a/credentialsd-ui/po/LINGUAS +++ b/credentialsd-ui/po/LINGUAS @@ -0,0 +1,2 @@ +en_US +de_DE diff --git a/credentialsd-ui/po/POTFILES.in b/credentialsd-ui/po/POTFILES.in index 3417f90..c342f04 100644 --- a/credentialsd-ui/po/POTFILES.in +++ b/credentialsd-ui/po/POTFILES.in @@ -1,6 +1,8 @@ -data/xyz.iinuwa.CredentialManager.desktop.in.in -data/xyz.iinuwa.CredentialManager.gschema.xml.in -data/xyz.iinuwa.CredentialManager.metainfo.xml.in.in +data/xyz.iinuwa.credentialsd.CredentialsUi.desktop.in.in +data/xyz.iinuwa.credentialsd.CredentialsUi.gschema.xml.in +data/xyz.iinuwa.credentialsd.CredentialsUi.metainfo.xml.in.in data/resources/ui/shortcuts.ui data/resources/ui/window.ui -src/application.rs +src/gui/view_model/gtk/mod.rs +src/gui/view_model/gtk/device.rs +src/gui/view_model/mod.rs diff --git a/credentialsd-ui/po/credentialsd-ui.pot b/credentialsd-ui/po/credentialsd-ui.pot new file mode 100644 index 0000000..46f60db --- /dev/null +++ b/credentialsd-ui/po/credentialsd-ui.pot @@ -0,0 +1,215 @@ +msgid "" +msgstr "" +"POT-Creation-Date: 2025-10-13 11:55+0200\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" + +#. Insert your license of choice here +#. LGPL-3.0-only +#: data/xyz.iinuwa.credentialsd.CredentialsUi.desktop.in.in:2 +#: data/xyz.iinuwa.credentialsd.CredentialsUi.metainfo.xml.in.in:8 +#: src/gui/view_model/gtk/mod.rs:372 +msgid "Credential Manager" +msgstr "" + +#: data/xyz.iinuwa.credentialsd.CredentialsUi.desktop.in.in:3 +#: data/xyz.iinuwa.credentialsd.CredentialsUi.metainfo.xml.in.in:9 +msgid "Write a GTK + Rust application" +msgstr "" + +#: data/xyz.iinuwa.credentialsd.CredentialsUi.desktop.in.in:9 +msgid "Gnome;GTK;" +msgstr "" + +#: data/xyz.iinuwa.credentialsd.CredentialsUi.gschema.xml.in:6 +msgid "Window width" +msgstr "" + +#: data/xyz.iinuwa.credentialsd.CredentialsUi.gschema.xml.in:10 +msgid "Window height" +msgstr "" + +#: data/xyz.iinuwa.credentialsd.CredentialsUi.gschema.xml.in:14 +msgid "Window maximized state" +msgstr "" + +#: data/xyz.iinuwa.credentialsd.CredentialsUi.metainfo.xml.in.in:11 +msgid "" +"A boilerplate template for GTK + Rust. It uses Meson as a build system and " +"has flatpak support by default." +msgstr "" + +#: data/xyz.iinuwa.credentialsd.CredentialsUi.metainfo.xml.in.in:16 +msgid "Registering a credential" +msgstr "" + +#. developer_name tag deprecated with Appstream 1.0 +#: data/xyz.iinuwa.credentialsd.CredentialsUi.metainfo.xml.in.in:34 +msgid "Isaiah Inuwa" +msgstr "" + +#: data/resources/ui/shortcuts.ui:11 +msgctxt "shortcut window" +msgid "General" +msgstr "" + +#: data/resources/ui/shortcuts.ui:14 +msgctxt "shortcut window" +msgid "Show Shortcuts" +msgstr "" + +#: data/resources/ui/shortcuts.ui:20 +msgctxt "shortcut window" +msgid "Quit" +msgstr "" + +#: data/resources/ui/window.ui:6 +msgid "_Preferences" +msgstr "" + +#: data/resources/ui/window.ui:10 +msgid "_Keyboard Shortcuts" +msgstr "" + +#: data/resources/ui/window.ui:43 +msgid "Choose device" +msgstr "" + +#: data/resources/ui/window.ui:49 +msgid "Devices" +msgstr "" + +#: data/resources/ui/window.ui:72 +msgid "Plug in security key" +msgstr "" + +#: data/resources/ui/window.ui:113 +msgid "Scan the QR code to connect your device" +msgstr "" + +#: data/resources/ui/window.ui:158 data/resources/ui/window.ui:164 +msgid "Choose credential" +msgstr "" + +#: data/resources/ui/window.ui:187 +msgid "Complete" +msgstr "" + +#: data/resources/ui/window.ui:193 +msgid "Done!" +msgstr "" + +#: data/resources/ui/window.ui:204 +msgid "Something went wrong." +msgstr "" + +#: data/resources/ui/window.ui:217 src/gui/view_model/mod.rs:233 +msgid "" +"Something went wrong while retrieving a credential. Please try again later " +"or use a different authenticator." +msgstr "" + +#: src/gui/view_model/gtk/mod.rs:137 +msgid "Enter your PIN." +msgstr "" + +#: src/gui/view_model/gtk/mod.rs:140 +msgid "One attempt remaining." +msgid_plural "%d attempts remaining." +msgstr[0] "" +msgstr[1] "" + +#: src/gui/view_model/gtk/mod.rs:154 +msgid "Touch your device again. One attempt remaining." +msgid_plural "Touch your device again. %d attempts remaining." +msgstr[0] "" +msgstr[1] "" + +#: src/gui/view_model/gtk/mod.rs:160 +msgid "Touch your device." +msgstr "" + +#: src/gui/view_model/gtk/mod.rs:165 +msgid "Touch your device" +msgstr "" + +#: src/gui/view_model/gtk/mod.rs:168 +msgid "Scan the QR code with your device to begin authentication." +msgstr "" + +#: src/gui/view_model/gtk/mod.rs:178 +msgid "" +"Connecting to your device. Make sure both devices are near each other and " +"have Bluetooth enabled." +msgstr "" + +#: src/gui/view_model/gtk/mod.rs:186 +msgid "Device connected. Follow the instructions on your device" +msgstr "" + +#: src/gui/view_model/gtk/mod.rs:312 +msgid "Insert your security key." +msgstr "" + +#: src/gui/view_model/gtk/mod.rs:328 +msgid "Multiple devices found. Please select with which to proceed." +msgstr "" + +#: src/gui/view_model/gtk/device.rs:57 +msgid "A Bluetooth device" +msgstr "" + +#: src/gui/view_model/gtk/device.rs:58 +msgid "This device" +msgstr "" + +#: src/gui/view_model/gtk/device.rs:59 +msgid "A mobile device" +msgstr "" + +#: src/gui/view_model/gtk/device.rs:60 +msgid "Linked Device" +msgstr "" + +#: src/gui/view_model/gtk/device.rs:61 +msgid "An NFC device" +msgstr "" + +#: src/gui/view_model/gtk/device.rs:62 +msgid "A security key" +msgstr "" + +#: src/gui/view_model/mod.rs:65 +msgid "Create new credential" +msgstr "" + +#: src/gui/view_model/mod.rs:66 +msgid "Use a credential" +msgstr "" + +#: src/gui/view_model/mod.rs:173 +msgid "Failed to select credential from device." +msgstr "" + +#: src/gui/view_model/mod.rs:227 +msgid "No matching credentials found on this authenticator." +msgstr "" + +#: src/gui/view_model/mod.rs:230 +msgid "" +"No more PIN attempts allowed. Try removing your device and plugging it back " +"in." +msgstr "" + +#: src/gui/view_model/mod.rs:236 +msgid "This credential is already registered on this authenticator." +msgstr "" + +#: src/gui/view_model/mod.rs:284 +msgid "Something went wrong. Try again later or use a different authenticator." +msgstr "" diff --git a/credentialsd-ui/po/de_DE.po b/credentialsd-ui/po/de_DE.po new file mode 100644 index 0000000..92a1170 --- /dev/null +++ b/credentialsd-ui/po/de_DE.po @@ -0,0 +1,217 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2025-10-10 14:45+0200\n" +"PO-Revision-Date: 2025-10-10 14:45+0200\n" +"Last-Translator: Martin Sirringhaus \n" +"Language: de_DE\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" + +#. Insert your license of choice here +#. LGPL-3.0-only +#: data/xyz.iinuwa.credentialsd.CredentialsUi.desktop.in.in:2 +#: data/xyz.iinuwa.credentialsd.CredentialsUi.metainfo.xml.in.in:8 +#: src/gui/view_model/gtk/mod.rs:370 +msgid "Credential Manager" +msgstr "Zugangsdatenmanager" + +#: data/xyz.iinuwa.credentialsd.CredentialsUi.desktop.in.in:3 +#: data/xyz.iinuwa.credentialsd.CredentialsUi.metainfo.xml.in.in:9 +msgid "Write a GTK + Rust application" +msgstr "" + +#: data/xyz.iinuwa.credentialsd.CredentialsUi.desktop.in.in:9 +msgid "Gnome;GTK;" +msgstr "Gnome;GTK;" + +#: data/xyz.iinuwa.credentialsd.CredentialsUi.gschema.xml.in:6 +msgid "Window width" +msgstr "Fensterbreite" + +#: data/xyz.iinuwa.credentialsd.CredentialsUi.gschema.xml.in:10 +msgid "Window height" +msgstr "Fensterhöhe" + +#: data/xyz.iinuwa.credentialsd.CredentialsUi.gschema.xml.in:14 +msgid "Window maximized state" +msgstr "Fenster maximiert" + +#: data/xyz.iinuwa.credentialsd.CredentialsUi.metainfo.xml.in.in:11 +msgid "" +"A boilerplate template for GTK + Rust. It uses Meson as a build system and " +"has flatpak support by default." +msgstr "" +"Eine Vorlage für eine GTK + Rust Anwendung." + +#: data/xyz.iinuwa.credentialsd.CredentialsUi.metainfo.xml.in.in:16 +msgid "Registering a credential" +msgstr "Zugangsdaten registrieren" + +#: data/resources/ui/shortcuts.ui:11 +msgctxt "shortcut window" +msgid "General" +msgstr "Allgemein" + +#: data/resources/ui/shortcuts.ui:14 +msgctxt "shortcut window" +msgid "Show Shortcuts" +msgstr "Zeige Kürzel" + +#: data/resources/ui/shortcuts.ui:20 +msgctxt "shortcut window" +msgid "Quit" +msgstr "Beenden" + +#: data/resources/ui/window.ui:6 +msgid "_Preferences" +msgstr "Einstellungen" + +#: data/resources/ui/window.ui:10 +msgid "_Keyboard Shortcuts" +msgstr "Tastaturkürzel" + +#: data/resources/ui/window.ui:43 +msgid "Choose device" +msgstr "Gerät auswählen" + +#: data/resources/ui/window.ui:49 +msgid "Devices" +msgstr "Geräte" + +#: data/resources/ui/window.ui:72 +msgid "Plug in security key" +msgstr "Stecken Sie Ihren Security-Token ein" + +#: data/resources/ui/window.ui:113 +msgid "Scan the QR code to connect your device" +msgstr "Scannen Sie den QR-Code, um Ihr Gerät zu verbinden" + +#: data/resources/ui/window.ui:158 data/resources/ui/window.ui:164 +msgid "Choose credential" +msgstr "Wählen Sie Zugangsdaten aus" + +#: data/resources/ui/window.ui:187 +msgid "Complete" +msgstr "Abgeschlossen" + +#: data/resources/ui/window.ui:193 +msgid "Done!" +msgstr "Fertig!" + +#: data/resources/ui/window.ui:204 +msgid "Something went wrong." +msgstr "Etwas ist schief gegangen." + +#: data/resources/ui/window.ui:217 src/gui/view_model/mod.rs:233 +msgid "" +"Something went wrong while retrieving a credential. Please try again later " +"or use a different authenticator." +msgstr "" +"Beim Abrufen Ihrer Zugangsdaten ist ein Fehler aufgetreten. Versuchen Sie es " +"später wieder, oder verwenden Sie einen anderen Security-Token." + +#: src/gui/view_model/gtk/mod.rs:137 +msgid "Enter your PIN." +msgstr "Geben Sie Ihren PIN ein." + +#: src/gui/view_model/gtk/mod.rs:140 +msgid "One attempt remaining." +msgid_plural "%d attempts remaining." +msgstr[0] "Sie haben nur noch einen Versuch." +msgstr[1] "Sie haben noch %d Versuche." + +#: src/gui/view_model/gtk/mod.rs:154 +msgid "Touch your device again. One attempt remaining." +msgid_plural "Touch your device again. %d attempts remaining." +msgstr[0] "Berühren Sie Ihr Gerät. Sie haben nur noch einen Versuch." +msgstr[1] "Berühren Sie nochmal Ihr Gerät. Sie haben nur noch %d Versuche." + +#: src/gui/view_model/gtk/mod.rs:160 +msgid "Touch your device." +msgstr "Berühren Sie Ihr Gerät." + +#: src/gui/view_model/gtk/mod.rs:165 +msgid "Touch your device" +msgstr "Berühren Sie Ihr Gerät." + +#: src/gui/view_model/gtk/mod.rs:168 +msgid "Scan the QR code with your device to begin authentication." +msgstr "Scannen Sie den QR code mit ihrem Gerät um die Authentifizierung zu beginnen." + +#: src/gui/view_model/gtk/mod.rs:178 +msgid "" +"Connecting to your device. Make sure both devices are near each other and " +"have Bluetooth enabled." +msgstr "" +"Verbindung zu Ihrem Gerät wird aufgebaut. Stellen Sie sicher, dass beide Geräte nah beieinander sind und Bluetooth aktiviert haben." + +#: src/gui/view_model/gtk/mod.rs:186 +msgid "Device connected. Follow the instructions on your device" +msgstr "Verbindung hergestellt. Folgen Sie den Anweisungen auf Ihrem Gerät." + +#: src/gui/view_model/gtk/mod.rs:312 +msgid "Insert your security key." +msgstr "Stecken Sie Ihren Security-Token ein." + +#: src/gui/view_model/gtk/mod.rs:328 +msgid "Multiple devices found. Please select with which to proceed." +msgstr "Mehrere Geräte gefunden. Bitte wählen Sie einen aus, um fortzufahren." + +#: src/gui/view_model/gtk/device.rs:57 +msgid "A Bluetooth device" +msgstr "Ein Bluetooth-Gerät" + +#: src/gui/view_model/gtk/device.rs:58 +msgid "This device" +msgstr "Dieses Gerät" + +#: src/gui/view_model/gtk/device.rs:59 +msgid "A mobile device" +msgstr "Ein mobiles Gerät" + +#: src/gui/view_model/gtk/device.rs:60 +msgid "Linked Device" +msgstr "Verbundenes Gerät" + +#: src/gui/view_model/gtk/device.rs:61 +msgid "An NFC device" +msgstr "Ein NFC-Gerät" + +#: src/gui/view_model/gtk/device.rs:62 +msgid "A security key" +msgstr "Ein Security-Token" + +#: src/gui/view_model/mod.rs:65 +msgid "Create new credential" +msgstr "Neue Zugangsdaten erstellen" + +#: src/gui/view_model/mod.rs:66 +msgid "Use a credential" +msgstr "Zugangsdaten abrufen" + +#: src/gui/view_model/mod.rs:173 +msgid "Failed to select credential from device." +msgstr "Zugangsdaten vom Gerät konnten nicht ausgewählt werden." + +#: src/gui/view_model/mod.rs:227 +msgid "No matching credentials found on this authenticator." +msgstr "Keine passenden Zugangsdaten auf diesem Gerät gefunden." + +#: src/gui/view_model/mod.rs:230 +msgid "" +"No more PIN attempts allowed. Try removing your device and plugging it back " +"in." +msgstr "Keine weiteren PIN-Eingaben erlaubt. Versuchen Sie ihr Gerät aus- und wieder einzustecken." + +#: src/gui/view_model/mod.rs:236 +msgid "This credential is already registered on this authenticator." +msgstr "Diese Zugangsdaten sind bereits auf diesem Gerät registriert." + +#: src/gui/view_model/mod.rs:284 +msgid "Something went wrong. Try again later or use a different authenticator." +msgstr "" +"Es ist ein Fehler aufgetreten. Bitte versuchen Sie es später noch einmal, " +"oder benutzen Sie ein anderes Gerät." diff --git a/credentialsd-ui/po/en_US.po b/credentialsd-ui/po/en_US.po new file mode 100644 index 0000000..885ed9c --- /dev/null +++ b/credentialsd-ui/po/en_US.po @@ -0,0 +1,223 @@ +msgid "" +msgstr "" +"POT-Creation-Date: 2025-10-10 14:45+0200\n" +"PO-Revision-Date: 2025-10-10 14:45+0200\n" +"Last-Translator: Martin Sirringhaus \n" +"Language: en_US\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" + +#. Insert your license of choice here +#. LGPL-3.0-only +#: data/xyz.iinuwa.credentialsd.CredentialsUi.desktop.in.in:2 +#: data/xyz.iinuwa.credentialsd.CredentialsUi.metainfo.xml.in.in:8 +#: src/gui/view_model/gtk/mod.rs:370 +msgid "Credential Manager" +msgstr "Credential Manager" + +#: data/xyz.iinuwa.credentialsd.CredentialsUi.desktop.in.in:3 +#: data/xyz.iinuwa.credentialsd.CredentialsUi.metainfo.xml.in.in:9 +msgid "Write a GTK + Rust application" +msgstr "Write a GTK + Rust application" + +#: data/xyz.iinuwa.credentialsd.CredentialsUi.desktop.in.in:9 +msgid "Gnome;GTK;" +msgstr "Gnome;GTK;" + +#: data/xyz.iinuwa.credentialsd.CredentialsUi.gschema.xml.in:6 +msgid "Window width" +msgstr "Window width" + +#: data/xyz.iinuwa.credentialsd.CredentialsUi.gschema.xml.in:10 +msgid "Window height" +msgstr "Window height" + +#: data/xyz.iinuwa.credentialsd.CredentialsUi.gschema.xml.in:14 +msgid "Window maximized state" +msgstr "Window maximized state" + +#: data/xyz.iinuwa.credentialsd.CredentialsUi.metainfo.xml.in.in:11 +msgid "" +"A boilerplate template for GTK + Rust. It uses Meson as a build system and " +"has flatpak support by default." +msgstr "" +"A boilerplate template for GTK + Rust. It uses Meson as a build system and " +"has flatpak support by default." + +#: data/xyz.iinuwa.credentialsd.CredentialsUi.metainfo.xml.in.in:16 +msgid "Registering a credential" +msgstr "Registering a credential" + +#. developer_name tag deprecated with Appstream 1.0 +#: data/xyz.iinuwa.credentialsd.CredentialsUi.metainfo.xml.in.in:34 +msgid "Isaiah Inuwa" +msgstr "Isaiah Inuwa" + +#: data/resources/ui/shortcuts.ui:11 +msgctxt "shortcut window" +msgid "General" +msgstr "General" + +#: data/resources/ui/shortcuts.ui:14 +msgctxt "shortcut window" +msgid "Show Shortcuts" +msgstr "Show Shortcuts" + +#: data/resources/ui/shortcuts.ui:20 +msgctxt "shortcut window" +msgid "Quit" +msgstr "Quit" + +#: data/resources/ui/window.ui:6 +msgid "_Preferences" +msgstr "_Preferences" + +#: data/resources/ui/window.ui:10 +msgid "_Keyboard Shortcuts" +msgstr "Keyboard Shortcuts" + +#: data/resources/ui/window.ui:43 +msgid "Choose device" +msgstr "Choose device" + +#: data/resources/ui/window.ui:49 +msgid "Devices" +msgstr "Devices" + +#: data/resources/ui/window.ui:72 +msgid "Plug in security key" +msgstr "Plug in security key" + +#: data/resources/ui/window.ui:113 +msgid "Scan the QR code to connect your device" +msgstr "Scan the QR code to connect your device" + +#: data/resources/ui/window.ui:158 data/resources/ui/window.ui:164 +msgid "Choose credential" +msgstr "Choose credential" + +#: data/resources/ui/window.ui:187 +msgid "Complete" +msgstr "Complete" + +#: data/resources/ui/window.ui:193 +msgid "Done!" +msgstr "Done!" + +#: data/resources/ui/window.ui:204 +msgid "Something went wrong." +msgstr "Something went wrong." + +#: data/resources/ui/window.ui:217 src/gui/view_model/mod.rs:233 +msgid "" +"Something went wrong while retrieving a credential. Please try again later " +"or use a different authenticator." +msgstr "" +"Something went wrong while retrieving a credential. Please try again later " +"or use a different authenticator." + +#: src/gui/view_model/gtk/mod.rs:137 +msgid "Enter your PIN." +msgstr "Enter your PIN." + +#: src/gui/view_model/gtk/mod.rs:140 +msgid "One attempt remaining." +msgid_plural "%d attempts remaining." +msgstr[0] "One attempt remaining." +msgstr[1] "%d attempts remaining." + +#: src/gui/view_model/gtk/mod.rs:154 +msgid "Touch your device again. One attempt remaining." +msgid_plural "Touch your device again. %d attempts remaining." +msgstr[0] "Touch your device again. One attempt remaining." +msgstr[1] "Touch your device again. %d attempts remaining." + +#: src/gui/view_model/gtk/mod.rs:160 +msgid "Touch your device." +msgstr "Touch your device." + +#: src/gui/view_model/gtk/mod.rs:165 +msgid "Touch your device" +msgstr "Touch your device" + +#: src/gui/view_model/gtk/mod.rs:168 +msgid "Scan the QR code with your device to begin authentication." +msgstr "Scan the QR code with your device to begin authentication." + +#: src/gui/view_model/gtk/mod.rs:178 +msgid "" +"Connecting to your device. Make sure both devices are near each other and " +"have Bluetooth enabled." +msgstr "" +"Connecting to your device. Make sure both devices are near each other and " +"have Bluetooth enabled." + +#: src/gui/view_model/gtk/mod.rs:186 +msgid "Device connected. Follow the instructions on your device" +msgstr "Device connected. Follow the instructions on your device" + +#: src/gui/view_model/gtk/mod.rs:312 +msgid "Insert your security key." +msgstr "Insert your security key." + +#: src/gui/view_model/gtk/mod.rs:328 +msgid "Multiple devices found. Please select with which to proceed." +msgstr "Multiple devices found. Please select with which to proceed." + +#: src/gui/view_model/gtk/device.rs:57 +msgid "A Bluetooth device" +msgstr "A Bluetooth device" + +#: src/gui/view_model/gtk/device.rs:58 +msgid "This device" +msgstr "This device" + +#: src/gui/view_model/gtk/device.rs:59 +msgid "A mobile device" +msgstr "A mobile device" + +#: src/gui/view_model/gtk/device.rs:60 +msgid "Linked Device" +msgstr "Linked Device" + +#: src/gui/view_model/gtk/device.rs:61 +msgid "An NFC device" +msgstr "An NFC device" + +#: src/gui/view_model/gtk/device.rs:62 +msgid "A security key" +msgstr "A security key" + +#: src/gui/view_model/mod.rs:65 +msgid "Create new credential" +msgstr "Create new credential" + +#: src/gui/view_model/mod.rs:66 +msgid "Use a credential" +msgstr "Use a credential" + +#: src/gui/view_model/mod.rs:173 +msgid "Failed to select credential from device." +msgstr "Failed to select credential from device." + +#: src/gui/view_model/mod.rs:227 +msgid "No matching credentials found on this authenticator." +msgstr "No matching credentials found on this authenticator." + +#: src/gui/view_model/mod.rs:230 +msgid "" +"No more PIN attempts allowed. Try removing your device and plugging it back " +"in." +msgstr "" +"No more PIN attempts allowed. Try removing your device and plugging it back " +"in." + +#: src/gui/view_model/mod.rs:236 +msgid "This credential is already registered on this authenticator." +msgstr "This credential is already registered on this authenticator." + +#: src/gui/view_model/mod.rs:284 +msgid "Something went wrong. Try again later or use a different authenticator." +msgstr "Something went wrong. Try again later or use a different authenticator." diff --git a/credentialsd-ui/po/meson.build b/credentialsd-ui/po/meson.build index 57d1266..3b8d88e 100644 --- a/credentialsd-ui/po/meson.build +++ b/credentialsd-ui/po/meson.build @@ -1 +1,10 @@ -i18n.gettext(gettext_package, preset: 'glib') +i18n = import('i18n') + +# This creates build targets: 'credentialsd-ui-pot', 'credentialsd-ui-update-po', etc. +i18n.gettext(gettext_package, + args: ['--directory=' + meson.project_source_root() / 'credentialsd-ui', + '--from-code=UTF-8', + '--copyright-holder="The Credentials for Linux Project"', + '--msgid-bugs-address="https://github.com/linux-credentials/credentialsd/issues"', + ], +) diff --git a/credentialsd-ui/src/gui/view_model/gtk/application.rs b/credentialsd-ui/src/gui/view_model/gtk/application.rs index 82216cd..7ffa2b6 100644 --- a/credentialsd-ui/src/gui/view_model/gtk/application.rs +++ b/credentialsd-ui/src/gui/view_model/gtk/application.rs @@ -6,7 +6,7 @@ use gtk::subclass::prelude::*; use gtk::{gdk, gio, glib}; use super::{ViewModel, window::CredentialsUiWindow}; -use crate::config::{APP_ID, PKGDATADIR, PROFILE, VERSION}; +use crate::config::{APP_ID, LOCALEDIR, PKGDATADIR, PROFILE, VERSION}; use crate::gui::view_model::{ViewEvent, ViewUpdate}; mod imp { @@ -152,6 +152,7 @@ impl CredentialsUi { info!("Credentials UI ({})", APP_ID); info!("Version: {} ({})", VERSION, PROFILE); info!("Datadir: {}", PKGDATADIR); + info!("Localedir: {}", LOCALEDIR); ApplicationExtManual::run(self) } diff --git a/credentialsd-ui/src/gui/view_model/gtk/device.rs b/credentialsd-ui/src/gui/view_model/gtk/device.rs index ad859ef..7992f56 100644 --- a/credentialsd-ui/src/gui/view_model/gtk/device.rs +++ b/credentialsd-ui/src/gui/view_model/gtk/device.rs @@ -1,5 +1,6 @@ use std::cell::RefCell; +use gettextrs::gettext; use glib::Object; use gtk::glib; use gtk::prelude::*; @@ -51,28 +52,28 @@ impl DeviceObject { } } -fn transport_name(transport: &Transport) -> &'static str { +fn transport_name(transport: &Transport) -> String { match transport { - Transport::Ble => "A Bluetooth device", - Transport::Internal => "This device", - Transport::HybridQr => "A mobile device", - Transport::HybridLinked => "TODO: Linked Device", - Transport::Nfc => "An NFC device", - Transport::Usb => "A security key", + Transport::Ble => gettext("A Bluetooth device"), + Transport::Internal => gettext("This device"), + Transport::HybridQr => gettext("A mobile device"), + Transport::HybridLinked => gettext("Linked Device"), + Transport::Nfc => gettext("An NFC device"), + Transport::Usb => gettext("A security key"), // Transport::PasskeyProvider => ("symbolic-link-symbolic", "ACME Password Manager"), } } impl From for DeviceObject { fn from(value: crate::gui::view_model::Device) -> Self { let name = transport_name(&value.transport); - Self::new(&value.id, &value.transport, name) + Self::new(&value.id, &value.transport, &name) } } impl From<&crate::gui::view_model::Device> for DeviceObject { fn from(value: &crate::gui::view_model::Device) -> Self { let name = transport_name(&value.transport); - Self::new(&value.id, &value.transport, name) + Self::new(&value.id, &value.transport, &name) } } diff --git a/credentialsd-ui/src/gui/view_model/gtk/mod.rs b/credentialsd-ui/src/gui/view_model/gtk/mod.rs index 966c5f6..cb7a647 100644 --- a/credentialsd-ui/src/gui/view_model/gtk/mod.rs +++ b/credentialsd-ui/src/gui/view_model/gtk/mod.rs @@ -4,7 +4,7 @@ pub mod device; mod window; use async_std::channel::{Receiver, Sender}; -use gettextrs::{LocaleCategory, gettext}; +use gettextrs::{LocaleCategory, gettext, ngettext}; use glib::clone; use gtk::gdk::Texture; use gtk::gdk_pixbuf::Pixbuf; @@ -134,34 +134,38 @@ impl ViewModel { view_model.waiting_for_device(&device) } ViewUpdate::UsbNeedsPin { attempts_left } => { - let prompt = match attempts_left { - Some(1) => { - "Enter your PIN. 1 attempt remaining.".to_string() - } - Some(attempts_left) => format!( - "Enter your PIN. {attempts_left} attempts remaining." - ), - None => "Enter your PIN.".to_string(), - }; + let mut prompt = gettext("Enter your PIN."); + if let Some(left) = attempts_left { + let localized = ngettext( + "One attempt remaining.", + "%d attempts remaining.", + left, + ); + prompt.push(' '); + prompt += &localized.replace("%d", &format!("{}", left)); + } view_model.set_prompt(prompt); view_model.set_usb_pin_entry_visible(true); } ViewUpdate::UsbNeedsUserVerification { attempts_left } => { let prompt = match attempts_left { - Some(1) => "Touch your device again. 1 attempt remaining." - .to_string(), - Some(attempts_left) => format!( - "Touch your device again. {attempts_left} attempts remaining." - ), - None => "Touch your device.".to_string(), + Some(left) => { + let localized = ngettext( + "Touch your device again. One attempt remaining.", + "Touch your device again. %d attempts remaining.", + left, + ); + localized.replace("%d", &format!("{}", left)) + } + None => gettext("Touch your device."), }; view_model.set_prompt(prompt); } ViewUpdate::UsbNeedsUserPresence => { - view_model.set_prompt("Touch your device"); + view_model.set_prompt(gettext("Touch your device")); } ViewUpdate::HybridNeedsQrCode(qr_code) => { - view_model.set_prompt("Scan the QR code with your device to begin authentication."); + view_model.set_prompt(gettext("Scan the QR code with your device to begin authentication.")); let texture = view_model.draw_qr_code(&qr_code); view_model.set_qr_code_paintable(&texture); view_model.set_qr_code_visible(true); @@ -170,17 +174,17 @@ impl ViewModel { ViewUpdate::HybridConnecting => { view_model.set_qr_code_visible(false); _ = view_model.qr_code_paintable().take(); - view_model.set_prompt( + view_model.set_prompt(gettext( "Connecting to your device. Make sure both devices are near each other and have Bluetooth enabled.", - ); + )); view_model.set_qr_spinner_visible(true); } ViewUpdate::HybridConnected => { view_model.set_qr_code_visible(false); _ = view_model.qr_code_paintable().take(); - view_model.set_prompt( + view_model.set_prompt(gettext( "Device connected. Follow the instructions on your device", - ); + )); view_model.set_qr_spinner_visible(false); } ViewUpdate::Completed => { @@ -190,6 +194,7 @@ impl ViewModel { ViewUpdate::Failed(error_msg) => { view_model.set_qr_spinner_visible(false); view_model.set_failed(true); + // These are already gettext messages view_model.set_prompt(error_msg); } ViewUpdate::Cancelled => { @@ -304,7 +309,7 @@ impl ViewModel { fn waiting_for_device(&self, device: &Device) { match device.transport { Transport::Usb => { - self.set_prompt("Insert your security key."); + self.set_prompt(gettext("Insert your security key.")); } Transport::HybridQr => { self.set_prompt(""); @@ -319,7 +324,9 @@ impl ViewModel { } fn selecting_device(&self) { - self.set_prompt("Multiple devices found. Please select with which to proceed."); + self.set_prompt(gettext( + "Multiple devices found. Please select with which to proceed.", + )); } pub async fn send_usb_device_pin(&self, pin: String) { @@ -358,6 +365,8 @@ pub fn start_gtk_app( gettextrs::setlocale(LocaleCategory::LcAll, ""); gettextrs::bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR).expect("Unable to bind the text domain"); gettextrs::textdomain(GETTEXT_PACKAGE).expect("Unable to switch to the text domain"); + gettextrs::bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8") + .expect("Unable to set codeset to UTF-8"); if glib::application_name().is_none() { glib::set_application_name(&gettext("Credential Manager")); diff --git a/credentialsd-ui/src/gui/view_model/mod.rs b/credentialsd-ui/src/gui/view_model/mod.rs index 6f8ceae..8930305 100644 --- a/credentialsd-ui/src/gui/view_model/mod.rs +++ b/credentialsd-ui/src/gui/view_model/mod.rs @@ -7,6 +7,7 @@ use async_std::{ channel::{Receiver, Sender}, sync::Mutex as AsyncMutex, }; +use gettextrs::gettext; use serde::{Deserialize, Serialize}; use tracing::{error, info}; @@ -61,8 +62,8 @@ impl ViewModel { async fn update_title(&mut self) { self.title = match self.operation { - Operation::Create => "Create new credential", - Operation::Get => "Use a credential", + Operation::Create => gettext("Create new credential"), + Operation::Get => gettext("Use a credential"), } .to_string(); self.tx_update @@ -166,10 +167,11 @@ impl ViewModel { .await .is_err() { - let error_msg = "Failed to select credential from device."; - tracing::error!(error_msg); + tracing::error!("Failed to select credential from device."); self.tx_update - .send(ViewUpdate::Failed(error_msg.to_string())) + .send(ViewUpdate::Failed(gettext( + "Failed to select credential from device.", + ))) .await .unwrap(); } @@ -220,20 +222,20 @@ impl ViewModel { } // TODO: Provide more specific error messages using the wrapped Error. UsbState::Failed(err) => { - let error_msg = String::from(match err { + let error_msg = match err { Error::NoCredentials => { - "No matching credentials found on this authenticator." + gettext("No matching credentials found on this authenticator.") } - Error::PinAttemptsExhausted => { - "No more PIN attempts allowed. Try removing your device and plugging it back in." - } - Error::AuthenticatorError | Error::Internal(_) => { - "Something went wrong while retrieving a credential. Please try again later or use a different authenticator." - } - Error::CredentialExcluded => { - "This credential is already registered on this authenticator." - } - }); + Error::PinAttemptsExhausted => gettext( + "No more PIN attempts allowed. Try removing your device and plugging it back in.", + ), + Error::AuthenticatorError | Error::Internal(_) => gettext( + "Something went wrong while retrieving a credential. Please try again later or use a different authenticator.", + ), + Error::CredentialExcluded => gettext( + "This credential is already registered on this authenticator.", + ), + }; self.tx_update .send(ViewUpdate::Failed(error_msg)) .await @@ -279,7 +281,7 @@ impl ViewModel { } HybridState::Failed => { self.hybrid_qr_code_data = None; - self.tx_update.send(ViewUpdate::Failed(String::from("Something went wrong. Try again later or use a different authenticator."))).await.unwrap(); + self.tx_update.send(ViewUpdate::Failed(gettext("Something went wrong. Try again later or use a different authenticator."))).await.unwrap(); } }; } /* diff --git a/credentialsd-ui/src/meson.build b/credentialsd-ui/src/meson.build index 02e7d8c..198de49 100644 --- a/credentialsd-ui/src/meson.build +++ b/credentialsd-ui/src/meson.build @@ -8,10 +8,17 @@ if (get_option('profile') == 'development') else global_conf.set_quoted('PKGDATADIR', pkgdatadir) endif +if (get_option('profile') == 'development') + global_conf.set_quoted( + 'LOCALEDIR', + meson.project_build_root() / gui_build_dir / 'po', + ) +else + global_conf.set_quoted('LOCALEDIR', localedir) +endif global_conf.set_quoted('PROFILE', profile) global_conf.set_quoted('VERSION', version + version_suffix) global_conf.set_quoted('GETTEXT_PACKAGE', gettext_package) -global_conf.set_quoted('LOCALEDIR', localedir) configure_file(input: 'config.rs.in', output: 'config.rs', configuration: global_conf) # Copy the config.rs output to the source directory. @@ -67,4 +74,4 @@ test( '--nocapture', ], protocol: 'exitcode', -) \ No newline at end of file +) From 735b49ec4e35a744351461cefa88af6a469632d5 Mon Sep 17 00:00:00 2001 From: Martin Sirringhaus Date: Fri, 24 Oct 2025 08:12:07 +0200 Subject: [PATCH 2/2] Do not concatenate translated strings and fix typo in CONTRIBUTING.md --- CONTRIBUTING.md | 4 +-- credentialsd-ui/po/credentialsd-ui.pot | 19 ++++++----- credentialsd-ui/po/de_DE.po | 34 +++++++++++-------- credentialsd-ui/po/en_US.po | 29 ++++++++-------- credentialsd-ui/src/gui/view_model/gtk/mod.rs | 14 ++++---- 5 files changed, 54 insertions(+), 46 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0250117..2a25e89 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -205,9 +205,9 @@ Then `cd` into your build-directory (e.g. `build/`) and run ``` # To update the POT template file, in case new strings have been added in the sources - meson compile credentialds-ui-pot + meson compile credentialsd-ui-pot # and to update the individual language files - meson compile credentialds-ui-update-po + meson compile credentialsd-ui-update-po ``` to update the template, so it contains all messages to be translated. diff --git a/credentialsd-ui/po/credentialsd-ui.pot b/credentialsd-ui/po/credentialsd-ui.pot index 46f60db..4bd2739 100644 --- a/credentialsd-ui/po/credentialsd-ui.pot +++ b/credentialsd-ui/po/credentialsd-ui.pot @@ -1,6 +1,9 @@ msgid "" msgstr "" -"POT-Creation-Date: 2025-10-13 11:55+0200\n" +"Project-Id-Version: credentialsd-ui\n" +"Report-Msgid-Bugs-To: \"https://github.com/linux-credentials/credentialsd/" +"issues\"\n" +"POT-Creation-Date: 2025-10-24 08:05+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: \n" @@ -114,16 +117,16 @@ msgid "" "or use a different authenticator." msgstr "" -#: src/gui/view_model/gtk/mod.rs:137 -msgid "Enter your PIN." -msgstr "" - -#: src/gui/view_model/gtk/mod.rs:140 -msgid "One attempt remaining." -msgid_plural "%d attempts remaining." +#: src/gui/view_model/gtk/mod.rs:139 +msgid "Enter your PIN. One attempt remaining." +msgid_plural "Enter your PIN. %d attempts remaining." msgstr[0] "" msgstr[1] "" +#: src/gui/view_model/gtk/mod.rs:145 +msgid "Enter your PIN." +msgstr "" + #: src/gui/view_model/gtk/mod.rs:154 msgid "Touch your device again. One attempt remaining." msgid_plural "Touch your device again. %d attempts remaining." diff --git a/credentialsd-ui/po/de_DE.po b/credentialsd-ui/po/de_DE.po index 92a1170..b07fe20 100644 --- a/credentialsd-ui/po/de_DE.po +++ b/credentialsd-ui/po/de_DE.po @@ -1,7 +1,9 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" -"POT-Creation-Date: 2025-10-10 14:45+0200\n" +"Report-Msgid-Bugs-To: \"https://github.com/linux-credentials/credentialsd/" +"issues\"\n" +"POT-Creation-Date: 2025-10-24 08:05+0200\n" "PO-Revision-Date: 2025-10-10 14:45+0200\n" "Last-Translator: Martin Sirringhaus \n" "Language: de_DE\n" @@ -14,7 +16,7 @@ msgstr "" #. LGPL-3.0-only #: data/xyz.iinuwa.credentialsd.CredentialsUi.desktop.in.in:2 #: data/xyz.iinuwa.credentialsd.CredentialsUi.metainfo.xml.in.in:8 -#: src/gui/view_model/gtk/mod.rs:370 +#: src/gui/view_model/gtk/mod.rs:372 msgid "Credential Manager" msgstr "Zugangsdatenmanager" @@ -43,8 +45,7 @@ msgstr "Fenster maximiert" msgid "" "A boilerplate template for GTK + Rust. It uses Meson as a build system and " "has flatpak support by default." -msgstr "" -"Eine Vorlage für eine GTK + Rust Anwendung." +msgstr "Eine Vorlage für eine GTK + Rust Anwendung." #: data/xyz.iinuwa.credentialsd.CredentialsUi.metainfo.xml.in.in:16 msgid "Registering a credential" @@ -113,16 +114,17 @@ msgstr "" "Beim Abrufen Ihrer Zugangsdaten ist ein Fehler aufgetreten. Versuchen Sie es " "später wieder, oder verwenden Sie einen anderen Security-Token." -#: src/gui/view_model/gtk/mod.rs:137 +#: src/gui/view_model/gtk/mod.rs:139 +#, fuzzy +msgid "Enter your PIN. One attempt remaining." +msgid_plural "Enter your PIN. %d attempts remaining." +msgstr[0] "Geben Sie Ihren PIN ein. Sie haben nur noch einen Versuch." +msgstr[1] "Geben Sie Ihren PIN ein. Sie haben noch %d Versuche." + +#: src/gui/view_model/gtk/mod.rs:145 msgid "Enter your PIN." msgstr "Geben Sie Ihren PIN ein." -#: src/gui/view_model/gtk/mod.rs:140 -msgid "One attempt remaining." -msgid_plural "%d attempts remaining." -msgstr[0] "Sie haben nur noch einen Versuch." -msgstr[1] "Sie haben noch %d Versuche." - #: src/gui/view_model/gtk/mod.rs:154 msgid "Touch your device again. One attempt remaining." msgid_plural "Touch your device again. %d attempts remaining." @@ -139,14 +141,16 @@ msgstr "Berühren Sie Ihr Gerät." #: src/gui/view_model/gtk/mod.rs:168 msgid "Scan the QR code with your device to begin authentication." -msgstr "Scannen Sie den QR code mit ihrem Gerät um die Authentifizierung zu beginnen." +msgstr "" +"Scannen Sie den QR code mit ihrem Gerät um die Authentifizierung zu beginnen." #: src/gui/view_model/gtk/mod.rs:178 msgid "" "Connecting to your device. Make sure both devices are near each other and " "have Bluetooth enabled." msgstr "" -"Verbindung zu Ihrem Gerät wird aufgebaut. Stellen Sie sicher, dass beide Geräte nah beieinander sind und Bluetooth aktiviert haben." +"Verbindung zu Ihrem Gerät wird aufgebaut. Stellen Sie sicher, dass beide " +"Geräte nah beieinander sind und Bluetooth aktiviert haben." #: src/gui/view_model/gtk/mod.rs:186 msgid "Device connected. Follow the instructions on your device" @@ -204,7 +208,9 @@ msgstr "Keine passenden Zugangsdaten auf diesem Gerät gefunden." msgid "" "No more PIN attempts allowed. Try removing your device and plugging it back " "in." -msgstr "Keine weiteren PIN-Eingaben erlaubt. Versuchen Sie ihr Gerät aus- und wieder einzustecken." +msgstr "" +"Keine weiteren PIN-Eingaben erlaubt. Versuchen Sie ihr Gerät aus- und wieder " +"einzustecken." #: src/gui/view_model/mod.rs:236 msgid "This credential is already registered on this authenticator." diff --git a/credentialsd-ui/po/en_US.po b/credentialsd-ui/po/en_US.po index 885ed9c..acf7832 100644 --- a/credentialsd-ui/po/en_US.po +++ b/credentialsd-ui/po/en_US.po @@ -1,6 +1,8 @@ msgid "" msgstr "" -"POT-Creation-Date: 2025-10-10 14:45+0200\n" +"Report-Msgid-Bugs-To: \"https://github.com/linux-credentials/credentialsd/" +"issues\"\n" +"POT-Creation-Date: 2025-10-24 08:05+0200\n" "PO-Revision-Date: 2025-10-10 14:45+0200\n" "Last-Translator: Martin Sirringhaus \n" "Language: en_US\n" @@ -13,7 +15,7 @@ msgstr "" #. LGPL-3.0-only #: data/xyz.iinuwa.credentialsd.CredentialsUi.desktop.in.in:2 #: data/xyz.iinuwa.credentialsd.CredentialsUi.metainfo.xml.in.in:8 -#: src/gui/view_model/gtk/mod.rs:370 +#: src/gui/view_model/gtk/mod.rs:372 msgid "Credential Manager" msgstr "Credential Manager" @@ -50,11 +52,6 @@ msgstr "" msgid "Registering a credential" msgstr "Registering a credential" -#. developer_name tag deprecated with Appstream 1.0 -#: data/xyz.iinuwa.credentialsd.CredentialsUi.metainfo.xml.in.in:34 -msgid "Isaiah Inuwa" -msgstr "Isaiah Inuwa" - #: data/resources/ui/shortcuts.ui:11 msgctxt "shortcut window" msgid "General" @@ -118,16 +115,17 @@ msgstr "" "Something went wrong while retrieving a credential. Please try again later " "or use a different authenticator." -#: src/gui/view_model/gtk/mod.rs:137 +#: src/gui/view_model/gtk/mod.rs:139 +#, fuzzy +msgid "Enter your PIN. One attempt remaining." +msgid_plural "Enter your PIN. %d attempts remaining." +msgstr[0] "Enter your PIN. One attempt remaining." +msgstr[1] "Enter your PIN. %d attempts remaining." + +#: src/gui/view_model/gtk/mod.rs:145 msgid "Enter your PIN." msgstr "Enter your PIN." -#: src/gui/view_model/gtk/mod.rs:140 -msgid "One attempt remaining." -msgid_plural "%d attempts remaining." -msgstr[0] "One attempt remaining." -msgstr[1] "%d attempts remaining." - #: src/gui/view_model/gtk/mod.rs:154 msgid "Touch your device again. One attempt remaining." msgid_plural "Touch your device again. %d attempts remaining." @@ -220,4 +218,5 @@ msgstr "This credential is already registered on this authenticator." #: src/gui/view_model/mod.rs:284 msgid "Something went wrong. Try again later or use a different authenticator." -msgstr "Something went wrong. Try again later or use a different authenticator." +msgstr "" +"Something went wrong. Try again later or use a different authenticator." diff --git a/credentialsd-ui/src/gui/view_model/gtk/mod.rs b/credentialsd-ui/src/gui/view_model/gtk/mod.rs index cb7a647..b22555f 100644 --- a/credentialsd-ui/src/gui/view_model/gtk/mod.rs +++ b/credentialsd-ui/src/gui/view_model/gtk/mod.rs @@ -134,16 +134,16 @@ impl ViewModel { view_model.waiting_for_device(&device) } ViewUpdate::UsbNeedsPin { attempts_left } => { - let mut prompt = gettext("Enter your PIN."); - if let Some(left) = attempts_left { + let prompt = if let Some(left) = attempts_left { let localized = ngettext( - "One attempt remaining.", - "%d attempts remaining.", + "Enter your PIN. One attempt remaining.", + "Enter your PIN. %d attempts remaining.", left, ); - prompt.push(' '); - prompt += &localized.replace("%d", &format!("{}", left)); - } + localized.replace("%d", &format!("{}", left)) + } else { + gettext("Enter your PIN.") + }; view_model.set_prompt(prompt); view_model.set_usb_pin_entry_visible(true); }