Files
nvrl bd4f797d1f feat(gui): polish pass over wording, icons and responsiveness
The Sync page gives each folder one card with its state, a Synced /
Online only switch and a menu for the rest; switching either way asks
first and the download prompt shows the free space on the disk.

Enabling, disabling and restarting the Proton Drive service ran
systemctl on GTK's main thread and froze the window. They now run in
the background, and every Retry button goes through one shared restart
helper.

Ten icons are bundled under resources/icons for glyphs no stock theme
has or that read ambiguously (sync, share, people, link, menu, map and
so on). A new test fails when the app or search prompt asks for a
symbolic icon that is neither bundled nor on a list checked against
Adwaita 50, libadwaita and GTK, or when a bundled icon is missing from
the resource manifest. The tray's sync icon, which Adwaita 50 no longer
ships, is now view-refresh.

Wording follows one glossary, recorded in docs/TRANSLATING.md: "Proton
Drive service" instead of "mount service" or "daemon", "Online only"
instead of "On-demand", "Proton Drive folder" instead of "mountpoint".
Dialog headings and buttons use title case and page titles match the
sidebar. Dates go through one formatter (app/dates.rs) and sizes
through i18n::human_bytes, and the cache label is translated.

The status tick stops while the window is hidden or minimized and runs
every fifth tick while it is unfocused, refreshing as soon as it gains
focus. "Sync complete" is announced only for large batches and only
when the window isn't focused. Smaller fixes: Empty Trash hides when
there is nothing to empty, copy buttons confirm with a check mark, the
sidebar status spins until the first report, and Photos moves Import
and Find Duplicates into a menu beside a labelled Select toggle.

All catalogs are updated and complete.
2026-09-28 13:26:59 +02:00

4.9 KiB

Translating Proton Drive for Linux

The desktop app (pdfs-app), the tray (pdfs-tray) and the search prompt (pdfs-prompt) are translated with GNU gettext in the pdfs text domain. The pdfs command-line tool and the daemon's own messages stay in English, because scripts parse their output.

US English is the source language. The shipped catalogs are listed in po/LINGUAS: German, British English, Spanish, French, Italian, Dutch, Polish and Brazilian Portuguese.

Picking a language

The apps follow the system locale (LANGUAGE, LC_ALL, LC_MESSAGES, LANG). Preferences → General → Appearance → Language overrides that for the app, the tray and the prompt. The choice is stored as language in config.json and takes effect the next time they start.

Layout

Path Purpose
crates/pdfs-gui/src/i18n.rs Locale setup and the gettext, gettext_f, ngettext_f, pgettext and gettext_noop helpers
po/POTFILES.in Sources that xgettext scans
po/pdfs.pot The template, generated from the sources
po/<lang>.po One catalog per language
po/update.sh Regenerates the template and merges it into every catalog
po/build.sh <localedir> Compiles the catalogs to <localedir>/<lang>/LC_MESSAGES/pdfs.mo

Updating an existing translation

  1. Run po/update.sh. It regenerates po/pdfs.pot and merges new and changed strings into each catalog, marking changed ones fuzzy.

  2. Edit po/<lang>.po with a PO editor (Poedit, Lokalize, GNOME Translation Editor) or a text editor. Translate the empty entries and review every fuzzy one, then remove its fuzzy flag.

  3. Check the catalog with msgfmt --check --statistics -o /dev/null po/<lang>.po.

  4. Try it from the source tree:

    po/build.sh target/locale
    PDFS_LOCALEDIR=target/locale LANGUAGE=<lang> cargo run -p pdfs-gui --bin pdfs-app
    

Adding a language

  1. Add the code (for example sv or pt_PT) to po/LINGUAS, keeping the list sorted.
  2. Run po/update.sh. It creates po/<lang>.po from the template with msginit.
  3. Fill in the Plural-Forms header if msginit did not, and translate the catalog.
  4. Add the code and the language's own name to LANGUAGES in crates/pdfs-gui/src/i18n.rs, so the Preferences picker offers it.
  5. Add GenericName[<lang>], Comment[<lang>] and Keywords[<lang>] lines to the two desktop files in packaging/.

cargo test -p pdfs-gui checks that every language in the picker has a catalog, that po/POTFILES.in lists every source file that calls gettext, and that every catalog passes msgfmt --check.

Rules for translators

  • Keep every {placeholder} from the English text. You may move it, but not rename or drop it. msgfmt --check rejects a catalog where they differ. Plural forms keep {n} in every form.
  • Read the #. translator comments above an entry. They explain placeholders and date formats.
  • Date entries such as %b %e are strftime formats for GLib's DateTime::format. Translate them into the order and separators your language uses, not into literal dates.
  • A msgctxt such as verb or column tells you which meaning of a short word is meant.
  • Keep product names as they are: Proton Drive, Proton, Google Takeout.
  • Use the same term for the same thing across the catalog, and follow the terminology of your desktop (GNOME or KDE) for common actions such as Trash, Preferences and Cancel.
  • The English UI uses one term per concept. Pick one translation for each and keep it:
    Concept English term
    The root of the user's Drive My files
    The background service Proton Drive service (never "daemon" or "mount")
    A folder with a full copy on this computer Synced folder
    A folder whose files download when opened Online-only folder
    A single file kept on this computer Available offline
    A single file that is not on this computer Online only
    Where My files appears on disk Proton Drive folder
    Stop syncing a folder Stop syncing
    Two versions of one file Conflict

Rules for developers

  • Wrap every user-visible GUI string: gettext("Move to Trash").
  • Never build a sentence from translated pieces or with format!. Use named placeholders: gettext_f("Moved {name} to Trash", &[("name", &name)]).
  • Counts use ngettext_f("{n} item", "{n} items", count, &[]); {n} is filled in for you.
  • Give short, ambiguous words a context: pgettext("verb", "Open").
  • Mark labels in const tables with gettext_noop and translate them where they are shown.
  • The message id must be a single string literal on one line, since xgettext reads literals only.
  • Add a // Translators: comment on the line above a call whose meaning is not obvious.
  • Do not translate log messages, CLI output, action or icon names, or values the daemon sends back.
  • Run po/update.sh after changing strings and commit the updated template and catalogs.