From 4836c5a84affd205c272786b1548a547e70066ac Mon Sep 17 00:00:00 2001 From: Nils Pukropp Date: Fri, 16 Oct 2026 11:56:14 +0200 Subject: [PATCH] fix(cli,fuse,gui): make --wait fail when an import or re-date did `import-google-photos --wait` and `redate-photos --wait` exited 0 however the run ended, and a run that failed as a whole left no summary, so the CLI said no import had run and the app said it finished. Failed runs now leave a summary with the reason, `--wait` exits 1 on failure, cancel or failed photos, and the app shows the reason (B239). --- crates/pdfs-cli/src/main.rs | 44 +- crates/pdfs-core/src/control.rs | 8 + crates/pdfs-fuse/src/redate.rs | 9 +- crates/pdfs-fuse/src/takeout.rs | 10 +- crates/pdfs-gui/src/app/pages/takeout.rs | 20 +- docs/BUGS.md | 27 + po/de.po | 1360 ++++++++++----------- po/en_GB.po | 1360 ++++++++++----------- po/es.po | 1360 ++++++++++----------- po/fr.po | 1360 ++++++++++----------- po/it.po | 1360 ++++++++++----------- po/nl.po | 1360 ++++++++++----------- po/pdfs.pot | 1363 +++++++++++----------- po/pl.po | 1360 ++++++++++----------- po/pt_BR.po | 1360 ++++++++++----------- 15 files changed, 6259 insertions(+), 6102 deletions(-) diff --git a/crates/pdfs-cli/src/main.rs b/crates/pdfs-cli/src/main.rs index 890d8f3..6986e54 100644 --- a/crates/pdfs-cli/src/main.rs +++ b/crates/pdfs-cli/src/main.rs @@ -2598,7 +2598,10 @@ fn cmd_import_google_photos(archives: Vec, dry_run: bool, wait: bool) - } => continue, CtlResponse::ImportStatus { summary, .. } => { print_import_summary(summary.as_ref()); - return Ok(()); + return finished_run( + "the import", + summary.map(|s| (s.failed, s.cancelled, s.error)), + ); } CtlResponse::Error { message, kind } => bail!("{}", cli_error(kind, &message)), other => bail!("unexpected response: {other:?}"), @@ -2641,7 +2644,10 @@ fn cmd_redate_photos( CtlResponse::RedateStatus { running: true, .. } => continue, CtlResponse::RedateStatus { summary, .. } => { print_redate_summary(summary.as_ref()); - return Ok(()); + return finished_run( + "the re-date", + summary.map(|s| (s.failed, s.cancelled, s.error)), + ); } CtlResponse::Error { message, kind } => bail!("{}", cli_error(kind, &message)), other => bail!("unexpected response: {other:?}"), @@ -2649,6 +2655,22 @@ fn cmd_redate_photos( } } +/// How a run `--wait` followed ended, as the exit status: an error when it +/// failed, was cancelled, or left photos failed, so a script can tell. +/// `outcome` is `(failed, cancelled, error)`; `None` when the daemon has no +/// result, which happens when it restarted during the run. +fn finished_run(what: &str, outcome: Option<(usize, bool, Option)>) -> Result<()> { + match outcome { + None => bail!("{what} ended without a result; the service may have restarted"), + Some((_, _, Some(error))) => bail!("{what} failed: {error}"), + Some((_, true, None)) => bail!("{what} was cancelled"), + Some((failed, false, None)) if failed > 0 => { + bail!("{what} finished, but {failed} photo(s) failed") + } + Some(_) => Ok(()), + } +} + /// A `YYYY-MM-DD` day as epoch seconds at UTC midnight. Reuses the Takeout /// scanner's date reader, which already accepts exactly this spelling. fn parse_day(day: &str) -> Result { @@ -2684,6 +2706,10 @@ fn print_redate_summary(summary: Option<&pdfs_core::control::RedateSummary>) { println!("No re-date has run yet."); return; }; + if let Some(error) = &summary.error { + println!("Failed : {error}"); + return; + } println!("Photos examined : {}", summary.examined); println!("Mis-dated : {}", summary.candidates); if summary.dry_run { @@ -2743,6 +2769,10 @@ fn print_import_summary(summary: Option<&pdfs_core::control::ImportSummary>) { println!("No import has run yet."); return; }; + if let Some(error) = &summary.error { + println!("Failed : {error}"); + return; + } println!("Photos in export : {}", summary.found); println!("Uploaded : {}", summary.uploaded); println!("Already on Proton: {}", summary.duplicates); @@ -3757,6 +3787,16 @@ mod login_wait_tests { assert_eq!(login_poll_delay(u32::MAX), Duration::from_secs(15)); } + #[test] + fn a_waited_for_run_that_did_not_fully_succeed_exits_with_an_error() { + assert!(finished_run("the import", Some((0, false, None))).is_ok()); + assert!(finished_run("the import", Some((3, false, None))).is_err()); + assert!(finished_run("the import", Some((0, true, None))).is_err()); + let failed = finished_run("the import", Some((0, false, Some("not a zip".into())))); + assert!(failed.unwrap_err().to_string().contains("not a zip")); + assert!(finished_run("the import", None).is_err()); + } + #[test] fn waiting_for_a_session_stops_hammering_the_keyring() { let mut checks_left = 20; diff --git a/crates/pdfs-core/src/control.rs b/crates/pdfs-core/src/control.rs index 1a01fa9..202240d 100644 --- a/crates/pdfs-core/src/control.rs +++ b/crates/pdfs-core/src/control.rs @@ -1591,6 +1591,10 @@ pub struct RedateSummary { /// name implies)` — what a dry run is read for. #[serde(default)] pub samples: Vec<(String, i64, i64)>, + /// Why the run as a whole failed, when it did. The counts are then + /// empty: the run never got to the photos. + #[serde(default)] + pub error: Option, } /// How a Google Photos Takeout import is going, or how the last one ended @@ -1620,6 +1624,10 @@ pub struct ImportSummary { pub bytes: u64, /// True when the run stopped early because it was cancelled. pub cancelled: bool, + /// Why the run as a whole failed, when it did, such as an archive that + /// is not a zip. The counts are then empty. + #[serde(default)] + pub error: Option, } /// One album in a [`Response::Albums`] listing. diff --git a/crates/pdfs-fuse/src/redate.rs b/crates/pdfs-fuse/src/redate.rs index b5bf463..aeda224 100644 --- a/crates/pdfs-fuse/src/redate.rs +++ b/crates/pdfs-fuse/src/redate.rs @@ -292,7 +292,14 @@ impl Core { let mut state = REDATE.lock(); state.running = false; state.cancel = None; - state.last = outcome.as_ref().ok().cloned(); + state.last = Some(match &outcome { + Ok(summary) => summary.clone(), + Err(e) => RedateSummary { + error: Some(e.to_string()), + dry_run, + ..Default::default() + }, + }); match &outcome { Ok(summary) => info!( candidates = summary.candidates, diff --git a/crates/pdfs-fuse/src/takeout.rs b/crates/pdfs-fuse/src/takeout.rs index 650e938..a3031d6 100644 --- a/crates/pdfs-fuse/src/takeout.rs +++ b/crates/pdfs-fuse/src/takeout.rs @@ -544,7 +544,15 @@ impl Core { let mut state = IMPORT.lock(); state.running = false; state.cancel = None; - state.last = outcome.as_ref().ok().cloned(); + // A failed run is reported too: without it, `--wait` read + // "no import has run" and exited as if all was well. + state.last = Some(match &outcome { + Ok(summary) => summary.clone(), + Err(e) => ImportSummary { + error: Some(e.to_string()), + ..Default::default() + }, + }); } match outcome { Ok(summary) => { diff --git a/crates/pdfs-gui/src/app/pages/takeout.rs b/crates/pdfs-gui/src/app/pages/takeout.rs index 8e888b5..62a6049 100644 --- a/crates/pdfs-gui/src/app/pages/takeout.rs +++ b/crates/pdfs-gui/src/app/pages/takeout.rs @@ -646,7 +646,12 @@ pub(crate) fn refresh_takeout(ui: &Rc) { // An import runs for hours, so its ending is announced rather than // left to be discovered: a toast for whoever is looking at the // window, and a desktop notification for whoever is not. - if was_running { + let failed = summary.as_ref().and_then(|s| s.error.clone()); + if was_running && let Some(error) = &failed { + let headline = gettext("Couldn't import from Google Photos"); + toast_error(&ui, &headline, error); + notify("takeout-import", &headline, error); + } else if was_running { let dry = ui.takeout.dry_run.get(); let headline = if dry { gettext("Scan finished") @@ -702,7 +707,18 @@ fn repaint_summary(ui: &Rc, summary: &ImportSummary) { } else { gettext("Last import") }); - ui.takeout.summary_group.set_description(Some(&if dry { + ui.takeout.summary_group.set_description(Some(&if let Some(error) = &summary.error { + // The reason is the service's own text, which is not translated. A + // group's description is markup, and the reason may name a path. + glib::markup_escape_text(&gettext_f( + "{what}: {detail}", + &[ + ("what", &gettext("Couldn't import from Google Photos")), + ("detail", error), + ], + )) + .to_string() + } else if dry { gettext("Nothing was uploaded — this is what an import would do.") } else if summary.cancelled { gettext("Stopped early. Everything uploaded so far is in your timeline; run it again to continue where it left off.") diff --git a/docs/BUGS.md b/docs/BUGS.md index 7037d55..30d333d 100644 --- a/docs/BUGS.md +++ b/docs/BUGS.md @@ -100,6 +100,7 @@ a live account since. | Entry | Title | |---|---| +| [B239](#b239----wait-reports-success-for-imports-and-re-dates-that-failed) | --wait reports success for imports and re-dates that failed | | [B238](#b238--draining-a-large-offline-batch-is-quadratic-in-its-size) | Draining a large offline batch is quadratic in its size | | [B237](#b237--every-reconnect-resends-refused-uploads-all-in-the-same-second) | Every reconnect resends refused uploads, all in the same second | | [B236](#b236--imported-re-dated-and-app-uploaded-photos-have-no-thumbnail) | Imported, re-dated and app-uploaded photos have no thumbnail | @@ -341,6 +342,32 @@ a live account since. Newest first. +### B239 — --wait reports success for imports and re-dates that failed + +**Status:** Fixed, not verified live +**Found:** 2026-10-16, architecture audit (`FINDINGS.md` section 3, CLI). +**Where:** `finished_run`, `cmd_import_google_photos` and `cmd_redate_photos` in +`crates/pdfs-cli/src/main.rs`; the run threads in `crates/pdfs-fuse/src/takeout.rs` and +`redate.rs`; `ImportSummary::error` and `RedateSummary::error` in `crates/pdfs-core/src/control.rs`; +`refresh_takeout` in `crates/pdfs-gui/src/app/pages/takeout.rs` + +**Repro:** `pdfs import-google-photos --wait notes.txt; echo $?`, or an import where some photos +fail to upload, or one cancelled from the app. + +**Cause.** `--wait` exited 0 however the run ended. A run that failed as a whole (an archive that +is not a zip) left no summary at all, so the CLI printed "No import has run yet" and the app +announced "Import finished". A run with failed photos, or a cancelled one, also exited 0. A +script could not tell any of these from a clean run. + +**Fix.** A run that fails as a whole now leaves a summary with the reason. `--wait` exits 1 when +the run failed, was cancelled, left photos failed, or ended without a result, and says which. +The app shows the reason instead of "Import finished". + +**Test:** `tests::a_waited_for_run_that_did_not_fully_succeed_exits_with_an_error` in +`crates/pdfs-cli/src/main.rs`. + +--- + ### B238 — Draining a large offline batch is quadratic in its size **Status:** Fixed, not verified live diff --git a/po/de.po b/po/de.po index fc20637..2f70772 100644 --- a/po/de.po +++ b/po/de.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: proton-drive-linux 2.1.0\n" "Report-Msgid-Bugs-To: https://github.com/narrrl/proton-drive-linux/issues\n" -"POT-Creation-Date: 2026-10-13 18:38+0200\n" +"POT-Creation-Date: 2026-10-16 11:55+0200\n" "PO-Revision-Date: 2026-09-23 12:00+0200\n" "Last-Translator: Proton Drive for Linux contributors\n" "Language-Team: German\n" @@ -30,7 +30,7 @@ msgstr[1] "vor {n} Min." #. Translators: strftime format for the time of day in the activity feed, such as "14:05". #. Translators: strftime format for the time a photo was taken, shown on its tile, such as "14:05". #: crates/pdfs-gui/src/app/dates.rs:44 -#: crates/pdfs-gui/src/app/pages/activity.rs:838 +#: crates/pdfs-gui/src/app/pages/activity.rs:840 #: crates/pdfs-gui/src/app/pages/photos.rs:2774 msgid "%H:%M" msgstr "%H:%M" @@ -60,17 +60,17 @@ msgstr "%A, %-d. %B %Y, %H:%M" #: crates/pdfs-gui/src/app/main.rs:764 #: crates/pdfs-gui/src/app/pages/activity_text.rs:539 #: crates/pdfs-gui/src/app/pages/browser.rs:454 -#: crates/pdfs-gui/src/app/pages/browser.rs:831 -#: crates/pdfs-gui/src/app/pages/browser.rs:1236 -#: crates/pdfs-gui/src/app/pages/browser.rs:2102 -#: crates/pdfs-gui/src/app/pages/browser.rs:2179 -#: crates/pdfs-gui/src/app/pages/locations.rs:1665 +#: crates/pdfs-gui/src/app/pages/browser.rs:833 +#: crates/pdfs-gui/src/app/pages/browser.rs:1238 +#: crates/pdfs-gui/src/app/pages/browser.rs:2104 +#: crates/pdfs-gui/src/app/pages/browser.rs:2181 +#: crates/pdfs-gui/src/app/pages/locations.rs:1667 #: crates/pdfs-gui/src/app/pages/shared_by_me.rs:252 #: crates/pdfs-gui/src/app/pages/trash.rs:191 crates/pdfs-gui/src/prompt.rs:171 msgid "My files" msgstr "Meine Dateien" -#: crates/pdfs-gui/src/app/main.rs:767 crates/pdfs-gui/src/app/main.rs:1398 +#: crates/pdfs-gui/src/app/main.rs:767 crates/pdfs-gui/src/app/main.rs:1412 #: crates/pdfs-gui/src/app/pages/albums.rs:638 #: crates/pdfs-gui/src/app/pages/photos.rs:845 #: crates/pdfs-gui/src/app/pages/places.rs:441 @@ -79,7 +79,7 @@ msgstr "Fotos" #: crates/pdfs-gui/src/app/main.rs:772 #: crates/pdfs-gui/src/app/pages/shared.rs:168 -#: crates/pdfs-gui/src/app/pages/shared.rs:482 +#: crates/pdfs-gui/src/app/pages/shared.rs:484 msgid "Shared with me" msgstr "Mit mir geteilt" @@ -90,7 +90,7 @@ msgstr "Von mir geteilt" #: crates/pdfs-gui/src/app/main.rs:780 #: crates/pdfs-gui/src/app/pages/devices.rs:140 -#: crates/pdfs-gui/src/app/pages/devices.rs:485 +#: crates/pdfs-gui/src/app/pages/devices.rs:489 msgid "Computers" msgstr "Computer" @@ -107,36 +107,37 @@ msgstr "Synchronisierung" #. Translators: a failed action's toast. {what} says what failed, such as #. "Couldn't rename"; {detail} is the reason, usually untranslated text #. from the mount service. -#: crates/pdfs-gui/src/app/main.rs:1099 +#: crates/pdfs-gui/src/app/main.rs:1109 +#: crates/pdfs-gui/src/app/pages/takeout.rs:714 #, rust-format msgid "{what}: {detail}" msgstr "{what}: {detail}" -#: crates/pdfs-gui/src/app/main.rs:1118 +#: crates/pdfs-gui/src/app/main.rs:1132 msgid "You're offline" msgstr "Keine Internetverbindung" -#: crates/pdfs-gui/src/app/main.rs:1119 +#: crates/pdfs-gui/src/app/main.rs:1133 msgid "That's not there any more" msgstr "Das ist nicht mehr vorhanden" -#: crates/pdfs-gui/src/app/main.rs:1120 +#: crates/pdfs-gui/src/app/main.rs:1134 msgid "You don't have access to that" msgstr "Kein Zugriff darauf" -#: crates/pdfs-gui/src/app/main.rs:1121 +#: crates/pdfs-gui/src/app/main.rs:1135 msgid "Something changed this first" msgstr "Etwas anderes hat dies zuerst geändert" -#: crates/pdfs-gui/src/app/main.rs:1122 +#: crates/pdfs-gui/src/app/main.rs:1136 msgid "Your Proton Drive is full" msgstr "Das Proton Drive ist voll" -#: crates/pdfs-gui/src/app/main.rs:1209 +#: crates/pdfs-gui/src/app/main.rs:1223 msgid "Proton Drive for Linux" msgstr "Proton Drive for Linux" -#: crates/pdfs-gui/src/app/main.rs:1217 +#: crates/pdfs-gui/src/app/main.rs:1231 msgid "" "Files-on-demand Proton Drive for the Linux desktop.\n" "\n" @@ -148,23 +149,23 @@ msgstr "" "Inoffizieller Client – nicht mit Proton AG verbunden, von Proton AG " "unterstützt oder befürwortet." -#: crates/pdfs-gui/src/app/main.rs:1222 +#: crates/pdfs-gui/src/app/main.rs:1236 msgid "Source Code" msgstr "Quellcode" -#: crates/pdfs-gui/src/app/main.rs:1226 +#: crates/pdfs-gui/src/app/main.rs:1240 msgid "Proton Terms of Service" msgstr "Nutzungsbedingungen von Proton" -#: crates/pdfs-gui/src/app/main.rs:1230 +#: crates/pdfs-gui/src/app/main.rs:1244 msgid "Proton Privacy Policy" msgstr "Datenschutzerklärung von Proton" -#: crates/pdfs-gui/src/app/main.rs:1235 +#: crates/pdfs-gui/src/app/main.rs:1249 msgid "Disclaimer" msgstr "Haftungsausschluss" -#: crates/pdfs-gui/src/app/main.rs:1239 +#: crates/pdfs-gui/src/app/main.rs:1253 msgid "" "This is an unofficial, community-built client. It is not affiliated with, " "endorsed by, or supported by Proton AG.\n" @@ -189,7 +190,7 @@ msgstr "" "bereitgestellt. Daten, deren Verlust nicht hinnehmbar ist, sollten " "zusätzlich gesichert werden." -#: crates/pdfs-gui/src/app/main.rs:1247 +#: crates/pdfs-gui/src/app/main.rs:1261 msgid "" "Places are named with data from GeoNames, licensed under GeoNames, lizenziert unter CC BY 4.0." -#: crates/pdfs-gui/src/app/main.rs:1255 +#: crates/pdfs-gui/src/app/main.rs:1269 msgid "" "The places map is drawn from Natural Earth land outlines and country borders, which are in the " @@ -209,7 +210,7 @@ msgstr "" "href=\"https://www.naturalearthdata.com/\">Natural Earth gezeichnet, die " "gemeinfrei sind." -#: crates/pdfs-gui/src/app/main.rs:1263 +#: crates/pdfs-gui/src/app/main.rs:1277 msgid "" "The street map, when turned on, comes from OpenFreeMap in the GeoNames, licensed under GeoNames, licensed under CC BY 4.0." -#: crates/pdfs-gui/src/app/main.rs:1255 +#: crates/pdfs-gui/src/app/main.rs:1269 msgid "" "The places map is drawn from Natural Earth land outlines and country borders, which are in the " @@ -206,7 +207,7 @@ msgstr "" "\">Natural Earth land outlines and country borders, which are in the " "public domain." -#: crates/pdfs-gui/src/app/main.rs:1263 +#: crates/pdfs-gui/src/app/main.rs:1277 msgid "" "The street map, when turned on, comes from OpenFreeMap in the GeoNames, licensed under GeoNames, con licencia CC BY 4.0." -#: crates/pdfs-gui/src/app/main.rs:1255 +#: crates/pdfs-gui/src/app/main.rs:1269 msgid "" "The places map is drawn from Natural Earth land outlines and country borders, which are in the " @@ -207,7 +208,7 @@ msgstr "" "fronteras de países de Natural " "Earth, que son de dominio público." -#: crates/pdfs-gui/src/app/main.rs:1263 +#: crates/pdfs-gui/src/app/main.rs:1277 msgid "" "The street map, when turned on, comes from OpenFreeMap in the GeoNames, licensed under GeoNames, sous licence CC BY 4.0." -#: crates/pdfs-gui/src/app/main.rs:1255 +#: crates/pdfs-gui/src/app/main.rs:1269 msgid "" "The places map is drawn from Natural Earth land outlines and country borders, which are in the " @@ -208,7 +209,7 @@ msgstr "" "frontières des pays de Natural " "Earth, qui sont dans le domaine public." -#: crates/pdfs-gui/src/app/main.rs:1263 +#: crates/pdfs-gui/src/app/main.rs:1277 msgid "" "The street map, when turned on, comes from OpenFreeMap in the GeoNames, licensed under GeoNames, con licenza CC BY 4.0." -#: crates/pdfs-gui/src/app/main.rs:1255 +#: crates/pdfs-gui/src/app/main.rs:1269 msgid "" "The places map is drawn from Natural Earth land outlines and country borders, which are in the " @@ -206,7 +207,7 @@ msgstr "" "confini nazionali di Natural " "Earth, che sono di pubblico dominio." -#: crates/pdfs-gui/src/app/main.rs:1263 +#: crates/pdfs-gui/src/app/main.rs:1277 msgid "" "The street map, when turned on, comes from OpenFreeMap in the GeoNames, licensed under GeoNames, gelicentieerd onder CC BY 4.0." -#: crates/pdfs-gui/src/app/main.rs:1255 +#: crates/pdfs-gui/src/app/main.rs:1269 msgid "" "The places map is drawn from Natural Earth land outlines and country borders, which are in the " @@ -207,7 +208,7 @@ msgstr "" "href=\"https://www.naturalearthdata.com/\">Natural Earth, die in het " "publieke domein vallen." -#: crates/pdfs-gui/src/app/main.rs:1263 +#: crates/pdfs-gui/src/app/main.rs:1277 msgid "" "The street map, when turned on, comes from OpenFreeMap in the \n" "Language-Team: LANGUAGE \n" @@ -33,7 +33,7 @@ msgstr[1] "" #. Translators: strftime format for the time of day in the activity feed, such as "14:05". #. Translators: strftime format for the time a photo was taken, shown on its tile, such as "14:05". #: crates/pdfs-gui/src/app/dates.rs:44 -#: crates/pdfs-gui/src/app/pages/activity.rs:838 +#: crates/pdfs-gui/src/app/pages/activity.rs:840 #: crates/pdfs-gui/src/app/pages/photos.rs:2774 msgid "%H:%M" msgstr "" @@ -63,17 +63,17 @@ msgstr "" #: crates/pdfs-gui/src/app/main.rs:764 #: crates/pdfs-gui/src/app/pages/activity_text.rs:539 #: crates/pdfs-gui/src/app/pages/browser.rs:454 -#: crates/pdfs-gui/src/app/pages/browser.rs:831 -#: crates/pdfs-gui/src/app/pages/browser.rs:1236 -#: crates/pdfs-gui/src/app/pages/browser.rs:2102 -#: crates/pdfs-gui/src/app/pages/browser.rs:2179 -#: crates/pdfs-gui/src/app/pages/locations.rs:1665 +#: crates/pdfs-gui/src/app/pages/browser.rs:833 +#: crates/pdfs-gui/src/app/pages/browser.rs:1238 +#: crates/pdfs-gui/src/app/pages/browser.rs:2104 +#: crates/pdfs-gui/src/app/pages/browser.rs:2181 +#: crates/pdfs-gui/src/app/pages/locations.rs:1667 #: crates/pdfs-gui/src/app/pages/shared_by_me.rs:252 #: crates/pdfs-gui/src/app/pages/trash.rs:191 crates/pdfs-gui/src/prompt.rs:171 msgid "My files" msgstr "" -#: crates/pdfs-gui/src/app/main.rs:767 crates/pdfs-gui/src/app/main.rs:1398 +#: crates/pdfs-gui/src/app/main.rs:767 crates/pdfs-gui/src/app/main.rs:1412 #: crates/pdfs-gui/src/app/pages/albums.rs:638 #: crates/pdfs-gui/src/app/pages/photos.rs:845 #: crates/pdfs-gui/src/app/pages/places.rs:441 @@ -82,7 +82,7 @@ msgstr "" #: crates/pdfs-gui/src/app/main.rs:772 #: crates/pdfs-gui/src/app/pages/shared.rs:168 -#: crates/pdfs-gui/src/app/pages/shared.rs:482 +#: crates/pdfs-gui/src/app/pages/shared.rs:484 msgid "Shared with me" msgstr "" @@ -93,7 +93,7 @@ msgstr "" #: crates/pdfs-gui/src/app/main.rs:780 #: crates/pdfs-gui/src/app/pages/devices.rs:140 -#: crates/pdfs-gui/src/app/pages/devices.rs:485 +#: crates/pdfs-gui/src/app/pages/devices.rs:489 msgid "Computers" msgstr "" @@ -110,36 +110,37 @@ msgstr "" #. Translators: a failed action's toast. {what} says what failed, such as #. "Couldn't rename"; {detail} is the reason, usually untranslated text #. from the mount service. -#: crates/pdfs-gui/src/app/main.rs:1099 +#: crates/pdfs-gui/src/app/main.rs:1109 +#: crates/pdfs-gui/src/app/pages/takeout.rs:714 #, rust-format msgid "{what}: {detail}" msgstr "" -#: crates/pdfs-gui/src/app/main.rs:1118 +#: crates/pdfs-gui/src/app/main.rs:1132 msgid "You're offline" msgstr "" -#: crates/pdfs-gui/src/app/main.rs:1119 +#: crates/pdfs-gui/src/app/main.rs:1133 msgid "That's not there any more" msgstr "" -#: crates/pdfs-gui/src/app/main.rs:1120 +#: crates/pdfs-gui/src/app/main.rs:1134 msgid "You don't have access to that" msgstr "" -#: crates/pdfs-gui/src/app/main.rs:1121 +#: crates/pdfs-gui/src/app/main.rs:1135 msgid "Something changed this first" msgstr "" -#: crates/pdfs-gui/src/app/main.rs:1122 +#: crates/pdfs-gui/src/app/main.rs:1136 msgid "Your Proton Drive is full" msgstr "" -#: crates/pdfs-gui/src/app/main.rs:1209 +#: crates/pdfs-gui/src/app/main.rs:1223 msgid "Proton Drive for Linux" msgstr "" -#: crates/pdfs-gui/src/app/main.rs:1217 +#: crates/pdfs-gui/src/app/main.rs:1231 msgid "" "Files-on-demand Proton Drive for the Linux desktop.\n" "\n" @@ -147,23 +148,23 @@ msgid "" "AG." msgstr "" -#: crates/pdfs-gui/src/app/main.rs:1222 +#: crates/pdfs-gui/src/app/main.rs:1236 msgid "Source Code" msgstr "" -#: crates/pdfs-gui/src/app/main.rs:1226 +#: crates/pdfs-gui/src/app/main.rs:1240 msgid "Proton Terms of Service" msgstr "" -#: crates/pdfs-gui/src/app/main.rs:1230 +#: crates/pdfs-gui/src/app/main.rs:1244 msgid "Proton Privacy Policy" msgstr "" -#: crates/pdfs-gui/src/app/main.rs:1235 +#: crates/pdfs-gui/src/app/main.rs:1249 msgid "Disclaimer" msgstr "" -#: crates/pdfs-gui/src/app/main.rs:1239 +#: crates/pdfs-gui/src/app/main.rs:1253 msgid "" "This is an unofficial, community-built client. It is not affiliated with, " "endorsed by, or supported by Proton AG.\n" @@ -176,21 +177,21 @@ msgid "" "of any data you cannot afford to lose." msgstr "" -#: crates/pdfs-gui/src/app/main.rs:1247 +#: crates/pdfs-gui/src/app/main.rs:1261 msgid "" "Places are named with data from GeoNames, licensed under CC BY 4.0." msgstr "" -#: crates/pdfs-gui/src/app/main.rs:1255 +#: crates/pdfs-gui/src/app/main.rs:1269 msgid "" "The places map is drawn from Natural Earth land outlines and country borders, which are in the " "public domain." msgstr "" -#: crates/pdfs-gui/src/app/main.rs:1263 +#: crates/pdfs-gui/src/app/main.rs:1277 msgid "" "The street map, when turned on, comes from OpenFreeMap in the GeoNames, licensed under GeoNames udostępnionych na licencji CC BY 4.0." -#: crates/pdfs-gui/src/app/main.rs:1255 +#: crates/pdfs-gui/src/app/main.rs:1269 msgid "" "The places map is drawn from Natural Earth land outlines and country borders, which are in the " @@ -210,7 +211,7 @@ msgstr "" "www.naturalearthdata.com/\">Natural Earth, które należą do domeny " "publicznej." -#: crates/pdfs-gui/src/app/main.rs:1263 +#: crates/pdfs-gui/src/app/main.rs:1277 msgid "" "The street map, when turned on, comes from OpenFreeMap in the GeoNames, licensed under GeoNames, licenciados sob CC BY 4.0." -#: crates/pdfs-gui/src/app/main.rs:1255 +#: crates/pdfs-gui/src/app/main.rs:1269 msgid "" "The places map is drawn from Natural Earth land outlines and country borders, which are in the " @@ -206,7 +207,7 @@ msgstr "" "fronteiras de países do Natural Earth, que são de domínio público." -#: crates/pdfs-gui/src/app/main.rs:1263 +#: crates/pdfs-gui/src/app/main.rs:1277 msgid "" "The street map, when turned on, comes from OpenFreeMap in the