Compare commits

...
Author SHA1 Message Date
nvrl 5b7f17bdaf Merge branch 'fix/db-errors-not-offline' into fix/diagnose-coverage
# Conflicts:
#	docs/BUGS.md
2026-10-31 19:26:38 +01:00
nvrl 73068f5868 Merge branch 'fix/mount-failure-surfaced' into fix/db-errors-not-offline
# Conflicts:
#	docs/BUGS.md
2026-10-31 19:26:36 +01:00
nvrl b093010b64 Merge branch 'fix/never-synced-label' into fix/mount-failure-surfaced
# Conflicts:
#	docs/BUGS.md
#	po/de.po
#	po/en_GB.po
#	po/es.po
#	po/fr.po
#	po/it.po
#	po/nl.po
#	po/pdfs.pot
#	po/pl.po
#	po/pt_BR.po
2026-10-31 19:26:34 +01:00
nvrl a617b2b410 fix(cli): have diagnose report failing writes, a pause and folders in error
diagnose dropped most of the Status reply and never looked at the synced
folders, so it said "No problems found" while a folder would not sync
(B268, issue #53). It now warns about writes that keep failing, a write
a day old, a pause, folders in error or conflict, and a control socket
nothing listens on.
2026-10-31 10:57:34 +01:00
nvrl bdbfc0bfd4 fix(core): read database errors handed to from_api as internal, not offline
from_api took every error that was not a ProtonError for a transport
failure. Pin, unpin, the searches and node loads hand it pdfs_core
errors from the cache and the database, so a failure there said
"You're offline" (B266, the rest of B205). The source chain now
decides, and only an error with neither type reads as offline.
2026-10-31 10:53:25 +01:00
nvrl e9577f953f fix(cli,core,fuse,gui): say why the mount keeps failing, and back off
A mount that failed on every try retried every 5 s forever, and the
reason was only in the journal: the app and the tray said Connecting...
for days (B263, issue #40). The retry now doubles to a 2-minute ceiling,
and the last failure is kept in mount-failure.json for the app, the
tray, pdfs diagnose and systemctl status.

The early returns in mount left the workers they had started running
beside the next attempt (B264). They are now stopped on every error
path, without telling systemd the daemon is stopping.
2026-10-31 10:49:01 +01:00
19 changed files with 955 additions and 340 deletions

No files matched your search

+230 -9
View File
@@ -2384,12 +2384,21 @@ where
/// an external unmount triggers a remount; errors back off and retry. This is
/// the entry point for the systemd user service.
fn cmd_daemon(mountpoint: Option<PathBuf>) -> Result<()> {
let state_dir = AppDirs::new()?.state_dir();
// A failure an earlier daemon recorded is not this one's.
pdfs_core::mountfail::clear(&state_dir);
let mut failure: Option<pdfs_core::mountfail::MountFailure> = None;
loop {
// Wait until a session is stored. The GUI enables this service on login,
// but the service may also start at boot before the user has logged in.
wait_for_session(auth::ready, pdfs_fuse::idle_sleep)?;
match mount_once(mountpoint.clone()) {
let outcome = mount_once(mountpoint.clone());
if outcome.is_ok() {
// The mount came up, so the next failure starts a new run of them.
failure = None;
}
match outcome {
Ok(pdfs_fuse::MountOutcome::Shutdown) => {
tracing::info!("daemon stopping");
return Ok(());
@@ -2404,13 +2413,51 @@ fn cmd_daemon(mountpoint: Option<PathBuf>) -> Result<()> {
Err(e) => {
// `{:#}` so the whole anyhow chain lands in the log — the top
// context alone ("mount failed") never says *why*.
tracing::error!(error = format!("{e:#}"), "mount failed; retrying in 5s");
pdfs_fuse::idle_sleep(std::time::Duration::from_secs(5));
let error = format!("{e:#}");
let now = unix_now();
let attempts = failure.as_ref().map_or(1, |f| f.attempts.saturating_add(1));
let delay = mount_retry_delay(attempts);
tracing::error!(
error,
attempts,
retry_secs = delay.as_secs(),
"mount failed; retrying"
);
let record = pdfs_core::mountfail::MountFailure {
error: error.clone(),
since: failure.as_ref().map_or(now, |f| f.since),
attempts,
next_attempt: now + delay.as_secs() as i64,
};
if let Err(e) = pdfs_core::mountfail::record(&state_dir, &record) {
tracing::warn!(error = %e, "could not record the mount failure");
}
pdfs_fuse::notify_status(&format!("Mount failing: {error}"));
failure = Some(record);
pdfs_fuse::idle_sleep(delay);
}
}
}
}
/// How long to wait before mount attempt `attempts + 1`, after `attempts`
/// failures in a row.
///
/// Doubles from 5 s to a 2-minute ceiling. A flat 5 s retry sent about four
/// requests to Proton per attempt, tens of thousands a day from an account
/// whose mount fails on a key, which no retry fixes (`docs/BUGS.md` B263). The
/// ceiling stays at minutes because a cold start without a network fails the
/// same way, and must mount soon after the network returns.
fn mount_retry_delay(attempts: u32) -> std::time::Duration {
const BASE_SECS: u64 = 5;
const MAX_SECS: u64 = 120;
let factor = 1u64
.checked_shl(attempts.saturating_sub(1))
.unwrap_or(u64::MAX);
std::time::Duration::from_secs(BASE_SECS.saturating_mul(factor).min(MAX_SECS))
}
/// One mount run: resume the session, mount, and block until the mount ends
/// (clean shutdown or external unmount). Returns the [`MountOutcome`] so the
/// daemon loop can decide whether to exit or remount.
@@ -3399,6 +3446,79 @@ fn cmd_sync_limit(up: Option<u64>, down: Option<u64>) -> Result<()> {
})?)
}
/// How long the oldest write may wait to upload before `diagnose` calls it
/// out. Under a day it is a slow link or a big file; past it, something is
/// holding the queue.
const STAGED_STALE_SECS: u64 = 86_400;
/// `diagnose` findings for the queue and the pause, from the `Status` reply.
/// `paused_for` is how long a timed pause still runs, in seconds.
fn sync_health(
failing_ops: u64,
failing_error: Option<&str>,
staged_bytes: u64,
staged_oldest_secs: u64,
paused: bool,
paused_for: Option<i64>,
) -> Vec<(DiagnoseLevel, &'static str, String)> {
let mut findings = Vec::new();
if failing_ops > 0 {
findings.push((
DiagnoseLevel::Warn,
" failing writes",
match failing_error {
Some(error) => format!("{failing_ops} keep failing; the last error: {error}"),
None => format!("{failing_ops} keep failing"),
},
));
}
if staged_bytes > 0 && staged_oldest_secs >= STAGED_STALE_SECS {
findings.push((
DiagnoseLevel::Warn,
" oldest unsent write",
format!(
"{} old, {} only on this computer",
human_secs(staged_oldest_secs),
human_bytes(staged_bytes)
),
));
}
if paused {
findings.push((
DiagnoseLevel::Warn,
" sync",
match paused_for {
Some(left) if left > 0 => {
format!("paused for another {}", human_secs(left as u64))
}
_ => "paused until resumed (`pdfs sync resume`)".to_string(),
},
));
}
findings
}
/// `diagnose` findings for the synced folders that need someone to look.
fn folder_health(
folders: &[pdfs_core::control::SyncFolderInfo],
) -> Vec<(DiagnoseLevel, String, String)> {
folders
.iter()
.filter_map(|folder| {
let what = match folder.state.as_str() {
"error" => "sync error; `pdfs sync list` and the activity feed say more",
"conflict" => "conflict copies to look at",
_ => return None,
};
Some((
DiagnoseLevel::Warn,
format!(" synced folder [{}]", folder.id),
format!("{}: {what}", folder.local_path),
))
})
.collect()
}
fn unix_now() -> i64 {
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
@@ -3735,21 +3855,26 @@ fn cmd_diagnose() -> Result<()> {
let socket_exists = socket.exists();
let socket_kind_ok =
std::fs::symlink_metadata(&socket).is_ok_and(|m| m.file_type().is_socket());
// A stale socket file with no listener is the common failure, so the reply
// is what decides this rather than the file's existence.
let status = control_request(CtlRequest::Status);
report.finding(
if socket_exists && !socket_kind_ok {
DiagnoseLevel::Fail
} else if socket_exists {
} else if socket_exists && status.is_ok() {
DiagnoseLevel::Ok
} else {
DiagnoseLevel::Warn
},
" control socket",
socket.display().to_string(),
if socket_exists && socket_kind_ok && status.is_err() {
format!("{} (left over; nothing listens on it)", socket.display())
} else {
socket.display().to_string()
},
);
// A stale socket file with no listener is the common failure, so the reply
// is what decides this rather than the file's existence.
let mut daemon_responding = false;
match control_request(CtlRequest::Status) {
match status {
Ok(CtlResponse::Status {
mountpoint,
online,
@@ -3757,6 +3882,12 @@ fn cmd_diagnose() -> Result<()> {
tokens_unsaved,
pending_uploads,
pending_changes,
failing_ops,
failing_error,
staged_bytes,
staged_oldest_secs,
paused,
paused_until,
version,
..
}) => {
@@ -3831,6 +3962,27 @@ fn cmd_diagnose() -> Result<()> {
format!("{pending} waiting to upload")
},
);
// The rest of the daemon's state that the report used to drop:
// writes that keep failing, a pause, a folder in error. Each of
// them stops changes from reaching Drive while everything above
// reads as fine (`docs/BUGS.md` B268).
for (level, check, detail) in sync_health(
failing_ops,
failing_error.as_deref(),
staged_bytes,
staged_oldest_secs,
paused,
paused_until.map(|until| until - unix_now()),
) {
report.finding(level, check, detail);
}
if let Ok(CtlResponse::SyncFolders { items }) =
control_request(CtlRequest::ListSyncFolders)
{
for (level, check, detail) in folder_health(&items) {
report.finding(level, &check, detail);
}
}
match await_integrity_check() {
Ok(CtlResponse::CacheReport {
integrity_problems,
@@ -3887,7 +4039,23 @@ fn cmd_diagnose() -> Result<()> {
" daemon responding",
format!("stopped or unreachable: {e:#}"),
);
println!(" (start it with `systemctl --user start proton-drive.service`)");
match pdfs_core::mountfail::read(&dirs.state_dir()) {
// A daemon whose mount keeps failing never opens the socket,
// so this is the only place its reason shows (B263).
Some(failure) => report.finding(
DiagnoseLevel::Fail,
" mount",
format!(
"failing for {}, {} attempt(s): {}",
human_secs(unix_now().saturating_sub(failure.since).max(0) as u64),
failure.attempts,
failure.error
),
),
None => println!(
" (start it with `systemctl --user start proton-drive.service`)"
),
}
}
}
@@ -4012,6 +4180,50 @@ mod pause_tests {
mod diagnose_tests {
use super::*;
/// A healthy queue says nothing; writes that keep failing, an old unsent
/// write and a pause each say so (`docs/BUGS.md` B268).
#[test]
fn a_stuck_queue_or_a_pause_is_reported() {
assert!(sync_health(0, None, 0, 0, false, None).is_empty());
assert!(sync_health(0, None, 4096, STAGED_STALE_SECS - 1, false, None).is_empty());
let checks: Vec<&str> = sync_health(
2,
Some("upload a.txt: quota"),
4096,
STAGED_STALE_SECS,
true,
Some(600),
)
.into_iter()
.map(|(level, check, _)| {
assert!(matches!(level, DiagnoseLevel::Warn));
check.trim()
})
.collect();
assert_eq!(checks, ["failing writes", "oldest unsent write", "sync"]);
}
/// Issue #53: a folder that would not sync, and `diagnose` found nothing.
#[test]
fn a_synced_folder_in_error_is_reported() {
let folder = |id: i64, state: &str| pdfs_core::control::SyncFolderInfo {
id,
local_path: format!("/home/u/f{id}"),
remote_uid: "vol~link".into(),
mode: "mirror".into(),
state: state.into(),
last_sync: 0,
pending_mode: None,
progress: None,
paused: false,
};
let findings =
folder_health(&[folder(1, "idle"), folder(2, "error"), folder(3, "syncing")]);
assert_eq!(findings.len(), 1);
assert_eq!(findings[0].1.trim(), "synced folder [2]");
assert!(findings[0].2.starts_with("/home/u/f2: sync error"));
}
#[test]
fn finding_severity_is_counted_centrally() {
let mut report = DiagnoseReport::default();
@@ -4047,6 +4259,15 @@ mod diagnose_tests {
#[cfg(test)]
mod login_wait_tests {
use super::*;
/// The mount retry backs off from 5 s to a ceiling of minutes, rather than
/// asking Proton every 5 s forever (`docs/BUGS.md` B263).
#[test]
fn a_failing_mount_backs_off_to_a_ceiling() {
let secs: Vec<u64> = (1..=8).map(|n| mount_retry_delay(n).as_secs()).collect();
assert_eq!(secs, [5, 10, 20, 40, 80, 120, 120, 120]);
assert_eq!(mount_retry_delay(u32::MAX).as_secs(), 120);
}
use std::time::Duration;
#[test]
+52 -16
View File
@@ -160,13 +160,14 @@ impl CoreError {
/// telling the user their connection is down beats telling them the
/// server refused. The SDK's other failures say what went wrong instead
/// (see [`proton_kind`]).
///
/// Callers also hand it this crate's [`Error`] from the cache and the
/// database, which is not a transport error at all. Taking those for
/// "offline" told the user their connection was down when a pin failed on
/// the database (`docs/BUGS.md` B266), so the source chain is searched for
/// either type before falling back.
pub fn from_api(e: &(dyn std::error::Error + 'static), what: &str) -> Self {
let kind = match e.downcast_ref::<proton_sdk::ProtonError>() {
Some(proton) => proton_kind(proton),
// Not the SDK's at all: a timeout around the call, or the socket.
None => ErrorKind::Offline,
};
Self::new(kind, format!("{what}: {e}"))
Self::new(api_kind_of(e), format!("{what}: {e}"))
}
/// Prefix the message while keeping the classification.
@@ -208,19 +209,40 @@ impl From<serde_json::Error> for CoreError {
impl From<Error> for CoreError {
fn from(e: Error) -> Self {
let kind = match &e {
Error::NotLoggedIn
| Error::ReloginRequired
| Error::Locked
| Error::WrongMailboxPassword
| Error::HumanVerificationRequired(_) => ErrorKind::Denied,
Error::Proton(proton) => proton_kind(proton),
_ => ErrorKind::Internal,
};
Self::new(kind, e.to_string())
Self::new(core_kind(&e), e.to_string())
}
}
/// What this crate's [`Error`] means to a front-end.
fn core_kind(e: &Error) -> ErrorKind {
match e {
Error::NotLoggedIn
| Error::ReloginRequired
| Error::Locked
| Error::WrongMailboxPassword
| Error::HumanVerificationRequired(_) => ErrorKind::Denied,
Error::Proton(proton) => proton_kind(proton),
_ => ErrorKind::Internal,
}
}
/// The kind for [`CoreError::from_api`]: the first SDK or crate error in `e`'s
/// source chain decides it.
fn api_kind_of(e: &(dyn std::error::Error + 'static)) -> ErrorKind {
let mut cause = Some(e);
while let Some(err) = cause {
if let Some(proton) = err.downcast_ref::<proton_sdk::ProtonError>() {
return proton_kind(proton);
}
if let Some(core) = err.downcast_ref::<Error>() {
return core_kind(core);
}
cause = err.source();
}
// Not the SDK's at all: a timeout around the call, or the socket.
ErrorKind::Offline
}
/// What a failed SDK call means to a front-end.
///
/// Only a transport failure is the connection. The rest happened on this
@@ -414,6 +436,20 @@ mod tests {
assert_ne!(e.kind, ErrorKind::Offline);
}
/// A pin or a search that fails on the database is not the connection, so
/// it must not say "You're offline" (`docs/BUGS.md` B266). An SDK error
/// wrapped in this crate's type classifies as the SDK error does.
#[test]
fn a_database_error_handed_to_from_api_is_not_offline() {
let db = Error::Other("database is locked".into());
assert_eq!(CoreError::from_api(&db, "pin").kind, ErrorKind::Internal);
let wrapped = Error::Proton(api(C::DoesNotExist));
assert_eq!(
CoreError::from_api(&wrapped, "load node").kind,
ErrorKind::NotFound
);
}
/// `Error` is the plumbing type; converting it must classify as sharply as
/// the direct path, or the two disagree about the same failure.
#[test]
+1
View File
@@ -15,6 +15,7 @@ pub mod kernelkey;
pub mod keycheck;
pub mod localindex;
pub mod menu;
pub mod mountfail;
pub mod mounts;
pub mod opener;
pub mod places;
+75
View File
@@ -0,0 +1,75 @@
//! Why the daemon's mount keeps failing, for the front ends to read.
//!
//! The control socket opens only once a mount has succeeded, so a daemon whose
//! mount fails on every try had no way to say why. The app and the tray showed
//! "Connecting…" for days while the reason sat in the journal (`docs/BUGS.md`
//! B263). The daemon now writes its last failure to a small file in the state
//! directory, next to the control socket, and removes it once a mount is up.
use std::path::{Path, PathBuf};
use serde::{Deserialize, Serialize};
/// The file's name inside the state directory.
const FILE_NAME: &str = "mount-failure.json";
/// The last failed mount attempt.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
pub struct MountFailure {
/// The error, in English, as the journal has it.
pub error: String,
/// Unix seconds of the first failure in this run of failures.
pub since: i64,
/// Failed attempts in a row.
pub attempts: u32,
/// Unix seconds of the next attempt.
pub next_attempt: i64,
}
/// Where the failure is kept for the state directory `state_dir`.
pub fn path(state_dir: &Path) -> PathBuf {
state_dir.join(FILE_NAME)
}
/// Record `failure`, replacing the one before it. Written to a temporary file
/// and renamed, so a reader never sees half of it.
pub fn record(state_dir: &Path, failure: &MountFailure) -> std::io::Result<()> {
let json = serde_json::to_vec(failure).map_err(std::io::Error::other)?;
let tmp = state_dir.join(format!("{FILE_NAME}.tmp"));
std::fs::write(&tmp, json)?;
std::fs::rename(&tmp, path(state_dir))
}
/// Forget the failure: a mount is up, or a new daemon has started.
pub fn clear(state_dir: &Path) {
let _ = std::fs::remove_file(path(state_dir));
}
/// The recorded failure, if there is one and it can be read.
pub fn read(state_dir: &Path) -> Option<MountFailure> {
let bytes = std::fs::read(path(state_dir)).ok()?;
serde_json::from_slice(&bytes).ok()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_recorded_failure_reads_back_until_cleared() {
let dir = std::env::temp_dir().join(format!("pdfs-mountfail-{}", std::process::id()));
std::fs::create_dir_all(&dir).unwrap();
assert_eq!(read(&dir), None);
let failure = MountFailure {
error: "fetch My Files root: missing key".into(),
since: 1_700_000_000,
attempts: 3,
next_attempt: 1_700_000_040,
};
record(&dir, &failure).unwrap();
assert_eq!(read(&dir), Some(failure));
clear(&dir);
assert_eq!(read(&dir), None);
let _ = std::fs::remove_dir_all(&dir);
}
}
+1 -1
View File
@@ -124,7 +124,7 @@ use mount::{
};
use reads::{BlockFlight, BlockRing, PREFETCH_BUDGET, Prefetch, ReaderSlot, STREAM_BYPASS_MIN};
use state::{Entry, Intervals, PendingRevision, State, StateGuard, WriteHandle};
pub use systemd::idle_sleep;
pub use systemd::{idle_sleep, status as notify_status};
use tracing::{debug, error, info, warn};
use transfers::{CountingWriter, JobGuard, OwnedCountingReader, TransferRegistry};
use r#virtual::{
+71 -28
View File
@@ -541,12 +541,11 @@ pub(crate) fn mount_with(
// and sweeps all operating on a mount that no longer exists (`docs/BUGS.md` B44).
let mut workers: Vec<std::thread::JoinHandle<()>> = Vec::new();
for worker in 0..DRAIN_WORKERS {
let core = core.clone();
workers.push(
std::thread::Builder::new()
.name(format!("pdfs-drain-{worker}"))
.spawn(move || core.run_pending_drain(worker == 0))?,
);
let drain_core = core.clone();
let spawned = std::thread::Builder::new()
.name(format!("pdfs-drain-{worker}"))
.spawn(move || drain_core.run_pending_drain(worker == 0));
keep_or_abandon(&core, control_socket, &mut workers, spawned)?;
}
// Start the folder-sync engine. It watches every mirror folder, polls the
@@ -566,24 +565,22 @@ pub(crate) fn mount_with(
info!("conflict sweep disabled by configuration");
} else {
info!(mode = ?sweep_mode, "conflict sweep enabled");
let core = core.clone();
workers.push(
std::thread::Builder::new()
.name("pdfs-conflict-sweep".into())
.spawn(move || core.run_conflict_sweep_loop())?,
);
let sweep_core = core.clone();
let spawned = std::thread::Builder::new()
.name("pdfs-conflict-sweep".into())
.spawn(move || sweep_core.run_conflict_sweep_loop());
keep_or_abandon(&core, control_socket, &mut workers, spawned)?;
}
// Watch the link for the life of the mount: a mount from the cache waits for
// the network to come back, and an online one can lose it at any moment and
// must notice it coming back just the same.
{
let core = core.clone();
workers.push(
std::thread::Builder::new()
.name("pdfs-online-probe".into())
.spawn(move || core.run_online_probe())?,
);
let probe_core = core.clone();
let spawned = std::thread::Builder::new()
.name("pdfs-online-probe".into())
.spawn(move || probe_core.run_online_probe());
keep_or_abandon(&core, control_socket, &mut workers, spawned)?;
}
// Keep the launcher prompt's "This computer" index fresh. Its own thread:
@@ -594,11 +591,10 @@ pub(crate) fn mount_with(
let transfers = core.transfers.clone();
let mountpoint = mountpoint.to_path_buf();
let shutdown = core.shutdown.clone();
workers.push(
std::thread::Builder::new()
.name("pdfs-localindex".into())
.spawn(move || run_local_index(db, indexing, transfers, mountpoint, shutdown))?,
);
let spawned = std::thread::Builder::new()
.name("pdfs-localindex".into())
.spawn(move || run_local_index(db, indexing, transfers, mountpoint, shutdown));
keep_or_abandon(&core, control_socket, &mut workers, spawned)?;
}
// Bind the control socket before the FUSE session takes over the thread. A
@@ -607,12 +603,18 @@ pub(crate) fn mount_with(
let old_umask = unsafe { libc::umask(0o77) };
let listener_res = UnixListener::bind(control_socket);
unsafe { libc::umask(old_umask) };
let listener = listener_res?;
let listener = match listener_res {
Ok(listener) => listener,
Err(error) => {
abandon_workers(&core, control_socket, workers);
return Err(error);
}
};
// Owner-only before anything can connect: a peer on this socket commands the
// daemon's authenticated session without a credential of its own (B6).
if let Err(e) = pdfs_core::config::restrict_socket(control_socket) {
error!(error = %e, "cannot restrict control socket permissions; refusing to serve");
let _ = std::fs::remove_file(control_socket);
abandon_workers(&core, control_socket, workers);
return Err(std::io::Error::other(format!(
"control socket permissions: {e}"
)));
@@ -623,7 +625,7 @@ pub(crate) fn mount_with(
let bg = match spawn_session(&core, mountpoint, root) {
Ok(session) => session,
Err(error) => {
let _ = std::fs::remove_file(control_socket);
abandon_workers(&core, control_socket, workers);
return Err(error);
}
};
@@ -643,7 +645,7 @@ pub(crate) fn mount_with(
Err(error) => {
// A failure here abandons the mount, so the background threads
// started above have to be told to stop with it.
stop_workers(&core, control_socket, workers);
abandon_workers(&core, control_socket, workers);
let secondaries = core.mounts.lock().close_and_drain();
for (id, mount) in secondaries {
if let Err(unmount_error) = mount.teardown() {
@@ -693,8 +695,12 @@ pub(crate) fn mount_with(
}
}
// The mount is live and the control socket answers: this is the moment the
// unit is actually usable, which is what `Type=notify` reports.
// unit is actually usable, which is what `Type=notify` reports. Whatever
// failure an earlier attempt recorded for the front ends is over.
systemd::ready();
if let Some(state_dir) = control_socket.parent() {
pdfs_core::mountfail::clear(state_dir);
}
// Re-establish on-demand mounts only after the primary session is live.
// Keep the worker so shutdown can close publication, wait for any in-flight
@@ -860,6 +866,43 @@ fn stop_workers(core: &Core, control_socket: &Path, workers: Vec<std::thread::Jo
// Say so before the joins: a teardown that takes a while must not be read as
// a missed watchdog ping and turned into a kill.
systemd::stopping();
halt_workers(core, control_socket, workers);
}
/// Stop the threads a mount attempt started before it failed.
///
/// The early returns used to leave them running: every retry started another
/// set beside the last one's, and their `Core` kept the database open, so the
/// next attempt could fail on its lock instead of the real error
/// (`docs/BUGS.md` B264). Unlike [`stop_workers`] this does not tell systemd
/// the daemon is stopping, because it is about to try again, and a manager
/// told so would wait for the process to exit and then kill it.
fn abandon_workers(core: &Core, control_socket: &Path, workers: Vec<std::thread::JoinHandle<()>>) {
halt_workers(core, control_socket, workers);
}
/// Keep a worker the mount just spawned, or, if the spawn failed, stop the
/// ones already running and hand the error back.
fn keep_or_abandon(
core: &Core,
control_socket: &Path,
workers: &mut Vec<std::thread::JoinHandle<()>>,
spawned: std::io::Result<std::thread::JoinHandle<()>>,
) -> std::io::Result<()> {
match spawned {
Ok(handle) => {
workers.push(handle);
Ok(())
}
Err(error) => {
abandon_workers(core, control_socket, std::mem::take(workers));
Err(error)
}
}
}
/// Signal every worker to stop, then join them up to [`WORKER_JOIN_DEADLINE`].
fn halt_workers(core: &Core, control_socket: &Path, workers: Vec<std::thread::JoinHandle<()>>) {
core.shutdown.stop();
core.wake_drain();
let _ = core.sync_tx.send(sync::SyncMsg::Stop);
+9 -1
View File
@@ -64,11 +64,19 @@ fn send_abstract(socket: &UnixDatagram, name: &str, message: &str) -> bool {
/// so `systemctl --user start` returns when the mount actually works rather than
/// when the process exists.
pub(crate) fn ready() {
if notify("READY=1\n") {
if notify("READY=1\nSTATUS=Mounted\n") {
debug!("notified systemd: ready");
}
}
/// Set the one-line status `systemctl --user status` shows for the unit, such
/// as why the mount keeps failing (`docs/BUGS.md` B263).
pub fn status(text: &str) {
// A newline would end the `STATUS=` line and start another variable.
let line = text.replace('\n', " ");
notify(&format!("STATUS={line}\n"));
}
/// Tell the manager the daemon is still healthy.
pub(crate) fn watchdog_ping() {
let _ = notify("WATCHDOG=1\n");
+29 -7
View File
@@ -1797,13 +1797,35 @@ pub(crate) fn service_unreachable(
);
return;
}
status(
&ui,
"network-idle-symbolic",
&gettext("Connecting…"),
&gettext("Waiting for the Proton Drive service to start."),
false,
);
// Running but not answering may be a mount that fails on every try,
// which never opens the socket. Its reason is in a file the daemon
// keeps for this (B263); "Connecting…" alone looked like a slow start
// for as long as it lasted.
let state_dir = ui.dirs.state_dir();
let failure = gio::spawn_blocking(move || pdfs_core::mountfail::read(&state_dir))
.await
.ok()
.flatten();
match failure {
Some(failure) => status(
&ui,
"dialog-warning-symbolic",
&gettext("Can't open your Drive"),
// Translators: {error} is an error message, in English.
&gettext_f(
"The Proton Drive service keeps failing to start and tries again on its own. The last error was: {error}",
&[("error", &failure.error)],
),
true,
),
None => status(
&ui,
"network-idle-symbolic",
&gettext("Connecting…"),
&gettext("Waiting for the Proton Drive service to start."),
false,
),
}
glib::timeout_add_local_once(CONNECT_RETRY_INTERVAL, move || {
if ui.stack.visible_child_name().as_deref() == Some(page) {
reload(&ui);
+18
View File
@@ -194,6 +194,24 @@ fn poll_state(socket: &Path, default_mountpoint: &Path) -> DriveState {
),
Phase::Attention,
),
// A daemon whose mount fails on every try never opens the
// socket; the app says why (B263).
Ok(s)
if socket
.parent()
.and_then(pdfs_core::mountfail::read)
.is_some() =>
{
(
// Translators: {username} is the Proton account name. The
// service keeps failing to start; the app shows the error.
gettext_f(
"Signed in as {username} — can't open your Drive",
&[("username", &s.username)],
),
Phase::Attention,
)
}
Ok(s) => (
// Translators: {username} is the Proton account name.
gettext_f(
+48 -17
View File
@@ -72,12 +72,8 @@ original wording.
| [B271](#b271--one-failed-listing-makes-a-large-first-sync-start-over-from-nothing) | One failed listing makes a large first sync start over from nothing | Not fixed |
| [B270](#b270--one-file-left-in-a-mirror-folder-clears-the-wipe-guard-for-all-the-others) | One file left in a mirror folder clears the wipe guard for all the others | Not fixed |
| [B269](#b269--a-restore-that-skipped-every-folder-reports-success) | A restore that skipped every folder reports success | Not fixed |
| [B268](#b268--pdfs-diagnose-says-no-problems-found-while-sync-is-stuck) | `pdfs diagnose` says "No problems found" while sync is stuck | Not fixed |
| [B267](#b267--a-key-failure-at-a-start-from-a-warm-cache-shows-as-offline-for-good) | A key failure at a start from a warm cache shows as offline for good | Not fixed |
| [B266](#b266--pin-unpin-search-and-node-loads-report-a-database-error-as-offline) | Pin, unpin, search and node loads report a database error as "offline" | Not fixed |
| [B265](#b265--address-keys-whose-token-is-for-an-inactive-account-key-never-open) | Address keys whose token is for an inactive account key never open | Needs an SDK change; not reproduced |
| [B264](#b264--a-mount-that-fails-after-starting-its-workers-leaves-them-running) | A mount that fails after starting its workers leaves them running | Not fixed |
| [B263](#b263--a-mount-that-can-never-succeed-retries-every-5-s-and-tells-only-the-journal) | A mount that can never succeed retries every 5 s and tells only the journal | Not fixed |
| [B134](#b134--a-file-deleted-online-while-the-drain-checks-its-write-is-kept-as-a-conflict-copy) | A file deleted online while the drain checks its write is kept as a conflict copy | Only with `local_first` off |
| [B91](#b91--the-daemon-hung-overnight-and-nothing-could-say-what-it-was-waiting-on) | The daemon hung overnight, and nothing could say what it was waiting on | The cause is not diagnosed; the daemon now reports where it is stuck and is restarted |
| [B67](#b67--fresh-state-restore-can-silently-select-a-new-device-high-22) | Fresh-state restore can silently select a new device (HIGH-22) | An ambiguous device after a loss of local state is not asked about |
@@ -90,6 +86,8 @@ original wording.
| Entry | Title | What is left |
|---|---|---|
| [B268](#b268--pdfs-diagnose-says-no-problems-found-while-sync-is-stuck) | `pdfs diagnose` says "No problems found" while sync is stuck | The sync engine's state is not checked |
| [B263](#b263--a-mount-that-can-never-succeed-retries-every-5-s-and-tells-only-the-journal) | A mount that can never succeed retries every 5 s and tells only the journal | Errors no retry fixes back off like network errors |
| [B262](#b262--watching-a-large-synced-folder-holds-up-the-sync-engine-and-a-failed-watch-is-never-retried) | Watching a large synced folder holds up the sync engine, and a failed watch is never retried | The first pass still waits for the watch; a failed watch is not shown in the app |
| [B259](#b259--the-sync-engine-can-die-or-hang-and-nothing-shows-it-until-a-restart) | The sync engine can die or hang, and nothing shows it until a restart | No pass deadline; an ended engine is reported, not restarted; the trigger in #53 is not known |
| [B199](#b199--a-stopped-share-stays-on-the-shared-by-me-page-for-minutes) | A stopped share stays on the Shared by me page for minutes | The share itself is not deleted; the SDK has no call for it |
@@ -112,6 +110,8 @@ a live account since.
| Entry | Title |
|---|---|
| [B266](#b266--pin-unpin-search-and-node-loads-report-a-database-error-as-offline) | Pin, unpin, search and node loads report a database error as "offline" |
| [B264](#b264--a-mount-that-fails-after-starting-its-workers-leaves-them-running) | A mount that fails after starting its workers leaves them running |
| [B261](#b261--a-folder-that-has-never-synced-reads-up-to-date) | A folder that has never synced reads "up to date" |
| [B272](#b272--after-a-folder-is-removed-and-added-again-its-file-events-go-to-the-old-id) | After a folder is removed and added again, its file events go to the old id |
| [B260](#b260--the-poll-pushes-a-new-folders-first-sync-behind-every-other-folder) | The poll pushes a new folder's first sync behind every other folder |
@@ -484,7 +484,7 @@ exit path.
### B268 — `pdfs diagnose` says "No problems found" while sync is stuck
**Status:** Open
**Status:** Partly fixed. The sync engine's own state is not checked yet.
**Found:** 2026-10-31, issue #53: a folder that never synced, and `diagnose` found nothing.
**Where:** `diagnose` in `crates/pdfs-cli/src/main.rs`
@@ -497,8 +497,16 @@ folders or for `Diagnostics`, so a folder in error and a stalled worker are not
control socket file with no daemon behind it is also reported `[ok]`; only the next line says
the daemon does not answer.
**Fix.** Not done. Warn on failing or parked writes, a pause, old staged data and folders in
error, and report the sync engine's state once B259 exposes it.
**Fix.** `diagnose` warns about writes that keep failing (with the last error), a write that
has waited a day or more to upload, a pause, and each synced folder in `error` or `conflict`
(`sync_health` and `folder_health` in `crates/pdfs-cli/src/main.rs`). A control socket file
that nothing listens on is a warning, not `[ok]`. Parked uploads are left out: a file still
wearing a download's temporary name is normal. Not done: the sync engine's state, which
`Diagnostics` reports once B259's change is in.
**Test:** `a_stuck_queue_or_a_pause_is_reported` and `a_synced_folder_in_error_is_reported` in
`pdfs-cli`. On 2026-10-31 the new `diagnose` against a healthy 3.6.0 daemon still reported
"No problems found".
---
@@ -525,7 +533,7 @@ report the others as their own state through `Status`.
### B266 — Pin, unpin, search and node loads report a database error as "offline"
**Status:** Open
**Status:** Fixed, not verified live
**Found:** 2026-10-31, code audit after issue #38. B205 fixed the photo upload path only.
**Where:** `CoreError::from_api` in `crates/pdfs-core/src/error.rs`; its callers in
`crates/pdfs-fuse/src/lib.rs` (`pin`, `unpin`, the searches, `load node`)
@@ -538,8 +546,11 @@ it was written for SDK calls, where that means a transport error. These callers
`pdfs_core::Error` values from the cache and the database. A `ProtonError` wrapped in
`pdfs_core::Error::Proton` also misses the downcast, since the source chain is not walked.
**Fix.** Not done. Use `CoreError::internal` at the database callers, and walk the source
chain in `from_api` before falling back.
**Fix.** `from_api` walks the source chain. The first `ProtonError` or `pdfs_core::Error` in it
decides the kind, the same way `From<Error>` does, and only an error with neither, a transport
error, reads as offline. That covers every caller at once, the database ones included.
**Test:** `a_database_error_handed_to_from_api_is_not_offline` in `pdfs-core`.
---
@@ -569,7 +580,7 @@ tokens, and only the active ones for signing. Skip and log an address that canno
### B264 — A mount that fails after starting its workers leaves them running
**Status:** Open
**Status:** Fixed, not verified live
**Found:** 2026-10-31, code audit after issue #40.
**Where:** `run_mount` in `crates/pdfs-fuse/src/mount.rs`
@@ -583,14 +594,20 @@ permission check, a `spawn_session` error, and a `?` on a later thread spawn) sk
the `flock` held, every later attempt fails with "another daemon is using cache.db" instead
of the real error. That part is inferred from the code and not observed.
**Fix.** Not done. Bind the socket and check the mountpoint before any worker starts, and stop
the workers on every error path.
**Fix.** Every early return in `mount` after the first worker starts stops the workers
(`abandon_workers`, `keep_or_abandon` in `crates/pdfs-fuse/src/mount.rs`). Unlike a normal stop
it does not send `STOPPING=1`, because the daemon is about to retry and systemd would
otherwise wait for it to exit and then kill it. The control-thread failure path, which already
stopped its workers, no longer sends it either.
**Test:** none of its own; the simulations (`sim::daemon`, 55 passed) cover the normal start
and stop.
---
### B263 — A mount that can never succeed retries every 5 s and tells only the journal
**Status:** Open
**Status:** Partly fixed. Errors that no retry fixes are not told apart from network errors yet.
**Found:** 2026-10-31, issue #40: the app showed "Connecting… waiting for the Proton Drive
service" for days, `pdfs diagnose` only reported the control socket missing, and the reporter
uninstalled.
@@ -607,9 +624,23 @@ four requests, so a broken account sends tens of thousands a day, which may also
Proton's sign-in blocks (#39). The control socket is bound only after the mount succeeds, and
the error is written nowhere a front end can read it.
**Fix.** Not done. Back off exponentially, treat key, `KeysLocked` and 4xx errors as permanent
with a long back-off, and write the last error where the app, the tray and `diagnose` can
show it (a state file, and `STATUS=` to systemd).
**Fix.**
- The retry doubles from 5 s to a 2-minute ceiling (`mount_retry_delay` in
`crates/pdfs-cli/src/main.rs`), about 720 attempts a day instead of 17,000. The ceiling stays
at minutes because a cold start without a network fails the same way and has to mount soon
after the network returns.
- Each failure is written to `mount-failure.json` in the state directory
(`crates/pdfs-core/src/mountfail.rs`), with the error, since when it fails and the attempt
count. A mount that comes up removes it, and so does a new daemon.
- The app shows "Can't open your Drive" with the error and a Retry button instead of
"Connecting…". The tray says "Signed in as … — can't open your Drive". `pdfs diagnose` reports
`[FAIL] mount: failing for …`. `systemctl --user status` shows the error as the unit's status.
- Not done: key, `KeysLocked` and 4xx errors still retry like network errors, only less often.
**Test:** `a_failing_mount_backs_off_to_a_ceiling` in `pdfs-cli`;
`a_recorded_failure_reads_back_until_cleared` in `pdfs-core`. On 2026-10-31 a second
`pdfs daemon` beside the running one failed on the database lock three times in 18 s (at 0, 5
and 15 s) and recorded `attempts: 3` with the lock error.
---
+47 -29
View File
@@ -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-31 10:26+0100\n"
"POT-Creation-Date: 2026-10-31 19:26+0100\n"
"PO-Revision-Date: 2026-09-23 12:00+0200\n"
"Last-Translator: Proton Drive for Linux contributors\n"
"Language-Team: German\n"
@@ -424,14 +424,27 @@ msgstr "Nicht verbunden"
msgid "The Proton Drive service isn't running."
msgstr "Der Proton-Drive-Dienst läuft nicht."
#: crates/pdfs-gui/src/app/main.rs:1803
#: crates/pdfs-gui/src/app/main.rs:1813
msgid "Can't open your Drive"
msgstr "Proton Drive kann nicht geöffnet werden"
#: crates/pdfs-gui/src/app/main.rs:1816
#, rust-format
msgid ""
"The Proton Drive service keeps failing to start and tries again on its own. "
"The last error was: {error}"
msgstr ""
"Der Proton-Drive-Dienst kann wiederholt nicht starten und versucht es "
"selbstständig erneut. Letzter Fehler: {error}"
#: crates/pdfs-gui/src/app/main.rs:1824
#: crates/pdfs-gui/src/app/pages/status.rs:355
#: crates/pdfs-gui/src/hud/mod.rs:269 crates/pdfs-gui/src/hud/mod.rs:579
#: crates/pdfs-gui/src/main.rs:475 crates/pdfs-gui/src/main.rs:517
#: crates/pdfs-gui/src/main.rs:493 crates/pdfs-gui/src/main.rs:535
msgid "Connecting…"
msgstr "Verbindung wird hergestellt …"
#: crates/pdfs-gui/src/app/main.rs:1804
#: crates/pdfs-gui/src/app/main.rs:1825
msgid "Waiting for the Proton Drive service to start."
msgstr "Warten auf den Start des Proton-Drive-Dienstes."
@@ -2919,7 +2932,7 @@ msgid "Sync paused until you resume"
msgstr "Synchronisierung bis zur Fortsetzung pausiert"
#: crates/pdfs-gui/src/app/pages/locations.rs:570
#: crates/pdfs-gui/src/app/pages/status.rs:1445 crates/pdfs-gui/src/main.rs:290
#: crates/pdfs-gui/src/app/pages/status.rs:1445 crates/pdfs-gui/src/main.rs:308
msgid "Sync paused"
msgstr "Synchronisierung pausiert"
@@ -5147,7 +5160,7 @@ msgstr "Wird {time} fortgesetzt"
msgid "Until you resume"
msgstr "Bis zur manuellen Fortsetzung"
#: crates/pdfs-gui/src/app/pages/status.rs:1464 crates/pdfs-gui/src/main.rs:292
#: crates/pdfs-gui/src/app/pages/status.rs:1464 crates/pdfs-gui/src/main.rs:310
#, rust-format
msgid "{n} change needs attention"
msgid_plural "{n} changes need attention"
@@ -6382,52 +6395,57 @@ msgstr "Proton Drive reagiert nicht"
msgid "Signed in as {username} — locked"
msgstr "Angemeldet als {username} – gesperrt"
#: crates/pdfs-gui/src/main.rs:200
#: crates/pdfs-gui/src/main.rs:209
#, rust-format
msgid "Signed in as {username} — can't open your Drive"
msgstr "Angemeldet als {username} – Proton Drive kann nicht geöffnet werden"
#: crates/pdfs-gui/src/main.rs:218
#, rust-format
msgid "Signed in as {username} — not connected"
msgstr "Angemeldet als {username} – nicht verbunden"
#: crates/pdfs-gui/src/main.rs:205
#: crates/pdfs-gui/src/main.rs:223
msgid "Not signed in"
msgstr "Nicht angemeldet"
#. Translators: {error} is an error message, in English.
#: crates/pdfs-gui/src/main.rs:208
#: crates/pdfs-gui/src/main.rs:226
#, rust-format
msgid "Error: {error}"
msgstr "Fehler: {error}"
#: crates/pdfs-gui/src/main.rs:230
#: crates/pdfs-gui/src/main.rs:248
msgid "Proton Drive sent an unexpected reply"
msgstr "Proton Drive hat unerwartet geantwortet"
#: crates/pdfs-gui/src/main.rs:284
#: crates/pdfs-gui/src/main.rs:302
msgid "Session expired — sign in again"
msgstr "Sitzung abgelaufen – erneut anmelden"
#: crates/pdfs-gui/src/main.rs:286
#: crates/pdfs-gui/src/main.rs:304
msgid "Sign-in not saved — unlock your keyring"
msgstr "Anmeldung nicht gespeichert – Schlüsselbund entsperren"
#: crates/pdfs-gui/src/main.rs:289
#: crates/pdfs-gui/src/main.rs:307
msgid "Update not finished — restart Proton Drive"
msgstr "Update nicht abgeschlossen – Proton Drive neu starten"
#: crates/pdfs-gui/src/main.rs:299
#: crates/pdfs-gui/src/main.rs:317
#, rust-format
msgid "Up to date in {mountpoint} ({n} pinned)"
msgid_plural "Up to date in {mountpoint} ({n} pinned)"
msgstr[0] "Aktuell in {mountpoint} ({n} angeheftet)"
msgstr[1] "Aktuell in {mountpoint} ({n} angeheftet)"
#: crates/pdfs-gui/src/main.rs:306
#: crates/pdfs-gui/src/main.rs:324
#, rust-format
msgid "Syncing — {queued} ({n} pinned)"
msgid_plural "Syncing — {queued} ({n} pinned)"
msgstr[0] "Wird synchronisiert – {queued} ({n} angeheftet)"
msgstr[1] "Wird synchronisiert – {queued} ({n} angeheftet)"
#: crates/pdfs-gui/src/main.rs:313
#: crates/pdfs-gui/src/main.rs:331
#, rust-format
msgid "Offline — cached files only ({n} pinned)"
msgid_plural "Offline — cached files only ({n} pinned)"
@@ -6435,60 +6453,60 @@ msgstr[0] "Offline – nur zwischengespeicherte Dateien ({n} angeheftet)"
msgstr[1] "Offline – nur zwischengespeicherte Dateien ({n} angeheftet)"
#. Translators: {queued} is a queue summary such as "3 uploads queued".
#: crates/pdfs-gui/src/main.rs:319
#: crates/pdfs-gui/src/main.rs:337
#, rust-format
msgid "Offline — {queued}"
msgstr "Offline – {queued}"
#. Translators: a menu item that opens the list of failing changes.
#: crates/pdfs-gui/src/main.rs:358
#: crates/pdfs-gui/src/main.rs:376
#, rust-format
msgid "{n} issue — View"
msgid_plural "{n} issues — View"
msgstr[0] "{n} Problem – Anzeigen"
msgstr[1] "{n} Probleme – Anzeigen"
#: crates/pdfs-gui/src/main.rs:465
#: crates/pdfs-gui/src/main.rs:483
msgid "Sign In…"
msgstr "Anmelden …"
#: crates/pdfs-gui/src/main.rs:466
#: crates/pdfs-gui/src/main.rs:484
msgid "Sign In Again…"
msgstr "Erneut anmelden …"
#: crates/pdfs-gui/src/main.rs:469
#: crates/pdfs-gui/src/main.rs:487
msgid "Open Proton Drive"
msgstr "Proton Drive öffnen"
#: crates/pdfs-gui/src/main.rs:473
#: crates/pdfs-gui/src/main.rs:491
msgid "Restart Proton Drive"
msgstr "Proton Drive neu starten"
#: crates/pdfs-gui/src/main.rs:482
#: crates/pdfs-gui/src/main.rs:500
msgid "Open Folder"
msgstr "Ordner öffnen"
#: crates/pdfs-gui/src/main.rs:494
#: crates/pdfs-gui/src/main.rs:512
msgid "Resume Sync"
msgstr "Synchronisierung fortsetzen"
#: crates/pdfs-gui/src/main.rs:496
#: crates/pdfs-gui/src/main.rs:514
msgid "Pause Sync"
msgstr "Synchronisierung pausieren"
#: crates/pdfs-gui/src/main.rs:515
#: crates/pdfs-gui/src/main.rs:533
msgid "Connect"
msgstr "Verbinden"
#: crates/pdfs-gui/src/main.rs:522
#: crates/pdfs-gui/src/main.rs:540
msgid "Hide Tray Icon"
msgstr "Symbol im Benachrichtigungsfeld ausblenden"
#: crates/pdfs-gui/src/main.rs:526
#: crates/pdfs-gui/src/main.rs:544
msgid "Stop Proton Drive…"
msgstr "Proton Drive beenden …"
#: crates/pdfs-gui/src/main.rs:530
#: crates/pdfs-gui/src/main.rs:548
msgid "Quit"
msgstr "Beenden"
+47 -29
View File
@@ -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-31 10:26+0100\n"
"POT-Creation-Date: 2026-10-31 19:26+0100\n"
"PO-Revision-Date: 2026-09-23 12:00+0200\n"
"Last-Translator: Proton Drive for Linux contributors\n"
"Language-Team: English (United Kingdom)\n"
@@ -420,14 +420,27 @@ msgstr "Not connected"
msgid "The Proton Drive service isn't running."
msgstr "The Proton Drive service isn't running."
#: crates/pdfs-gui/src/app/main.rs:1803
#: crates/pdfs-gui/src/app/main.rs:1813
msgid "Can't open your Drive"
msgstr "Can't open your Drive"
#: crates/pdfs-gui/src/app/main.rs:1816
#, rust-format
msgid ""
"The Proton Drive service keeps failing to start and tries again on its own. "
"The last error was: {error}"
msgstr ""
"The Proton Drive service keeps failing to start and tries again on its own. "
"The last error was: {error}"
#: crates/pdfs-gui/src/app/main.rs:1824
#: crates/pdfs-gui/src/app/pages/status.rs:355
#: crates/pdfs-gui/src/hud/mod.rs:269 crates/pdfs-gui/src/hud/mod.rs:579
#: crates/pdfs-gui/src/main.rs:475 crates/pdfs-gui/src/main.rs:517
#: crates/pdfs-gui/src/main.rs:493 crates/pdfs-gui/src/main.rs:535
msgid "Connecting…"
msgstr "Connecting…"
#: crates/pdfs-gui/src/app/main.rs:1804
#: crates/pdfs-gui/src/app/main.rs:1825
msgid "Waiting for the Proton Drive service to start."
msgstr "Waiting for the Proton Drive service to start."
@@ -2880,7 +2893,7 @@ msgid "Sync paused until you resume"
msgstr "Sync paused until you resume"
#: crates/pdfs-gui/src/app/pages/locations.rs:570
#: crates/pdfs-gui/src/app/pages/status.rs:1445 crates/pdfs-gui/src/main.rs:290
#: crates/pdfs-gui/src/app/pages/status.rs:1445 crates/pdfs-gui/src/main.rs:308
msgid "Sync paused"
msgstr "Sync paused"
@@ -5046,7 +5059,7 @@ msgstr "Resumes {time}"
msgid "Until you resume"
msgstr "Until you resume"
#: crates/pdfs-gui/src/app/pages/status.rs:1464 crates/pdfs-gui/src/main.rs:292
#: crates/pdfs-gui/src/app/pages/status.rs:1464 crates/pdfs-gui/src/main.rs:310
#, rust-format
msgid "{n} change needs attention"
msgid_plural "{n} changes need attention"
@@ -6257,52 +6270,57 @@ msgstr "Proton Drive isn't responding"
msgid "Signed in as {username} — locked"
msgstr "Signed in as {username} — locked"
#: crates/pdfs-gui/src/main.rs:200
#: crates/pdfs-gui/src/main.rs:209
#, rust-format
msgid "Signed in as {username} — can't open your Drive"
msgstr "Signed in as {username} — can't open your Drive"
#: crates/pdfs-gui/src/main.rs:218
#, rust-format
msgid "Signed in as {username} — not connected"
msgstr "Signed in as {username} — not connected"
#: crates/pdfs-gui/src/main.rs:205
#: crates/pdfs-gui/src/main.rs:223
msgid "Not signed in"
msgstr "Not signed in"
#. Translators: {error} is an error message, in English.
#: crates/pdfs-gui/src/main.rs:208
#: crates/pdfs-gui/src/main.rs:226
#, rust-format
msgid "Error: {error}"
msgstr "Error: {error}"
#: crates/pdfs-gui/src/main.rs:230
#: crates/pdfs-gui/src/main.rs:248
msgid "Proton Drive sent an unexpected reply"
msgstr "Proton Drive sent an unexpected reply"
#: crates/pdfs-gui/src/main.rs:284
#: crates/pdfs-gui/src/main.rs:302
msgid "Session expired — sign in again"
msgstr "Session expired — sign in again"
#: crates/pdfs-gui/src/main.rs:286
#: crates/pdfs-gui/src/main.rs:304
msgid "Sign-in not saved — unlock your keyring"
msgstr "Sign-in not saved — unlock your keyring"
#: crates/pdfs-gui/src/main.rs:289
#: crates/pdfs-gui/src/main.rs:307
msgid "Update not finished — restart Proton Drive"
msgstr "Update not finished — restart Proton Drive"
#: crates/pdfs-gui/src/main.rs:299
#: crates/pdfs-gui/src/main.rs:317
#, rust-format
msgid "Up to date in {mountpoint} ({n} pinned)"
msgid_plural "Up to date in {mountpoint} ({n} pinned)"
msgstr[0] "Up to date in {mountpoint} ({n} pinned)"
msgstr[1] "Up to date in {mountpoint} ({n} pinned)"
#: crates/pdfs-gui/src/main.rs:306
#: crates/pdfs-gui/src/main.rs:324
#, rust-format
msgid "Syncing — {queued} ({n} pinned)"
msgid_plural "Syncing — {queued} ({n} pinned)"
msgstr[0] "Syncing — {queued} ({n} pinned)"
msgstr[1] "Syncing — {queued} ({n} pinned)"
#: crates/pdfs-gui/src/main.rs:313
#: crates/pdfs-gui/src/main.rs:331
#, rust-format
msgid "Offline — cached files only ({n} pinned)"
msgid_plural "Offline — cached files only ({n} pinned)"
@@ -6310,60 +6328,60 @@ msgstr[0] "Offline — cached files only ({n} pinned)"
msgstr[1] "Offline — cached files only ({n} pinned)"
#. Translators: {queued} is a queue summary such as "3 uploads queued".
#: crates/pdfs-gui/src/main.rs:319
#: crates/pdfs-gui/src/main.rs:337
#, rust-format
msgid "Offline — {queued}"
msgstr "Offline — {queued}"
#. Translators: a menu item that opens the list of failing changes.
#: crates/pdfs-gui/src/main.rs:358
#: crates/pdfs-gui/src/main.rs:376
#, rust-format
msgid "{n} issue — View"
msgid_plural "{n} issues — View"
msgstr[0] "{n} issue — View"
msgstr[1] "{n} issues — View"
#: crates/pdfs-gui/src/main.rs:465
#: crates/pdfs-gui/src/main.rs:483
msgid "Sign In…"
msgstr "Sign In…"
#: crates/pdfs-gui/src/main.rs:466
#: crates/pdfs-gui/src/main.rs:484
msgid "Sign In Again…"
msgstr "Sign In Again…"
#: crates/pdfs-gui/src/main.rs:469
#: crates/pdfs-gui/src/main.rs:487
msgid "Open Proton Drive"
msgstr "Open Proton Drive"
#: crates/pdfs-gui/src/main.rs:473
#: crates/pdfs-gui/src/main.rs:491
msgid "Restart Proton Drive"
msgstr "Restart Proton Drive"
#: crates/pdfs-gui/src/main.rs:482
#: crates/pdfs-gui/src/main.rs:500
msgid "Open Folder"
msgstr "Open Folder"
#: crates/pdfs-gui/src/main.rs:494
#: crates/pdfs-gui/src/main.rs:512
msgid "Resume Sync"
msgstr "Resume Sync"
#: crates/pdfs-gui/src/main.rs:496
#: crates/pdfs-gui/src/main.rs:514
msgid "Pause Sync"
msgstr "Pause Sync"
#: crates/pdfs-gui/src/main.rs:515
#: crates/pdfs-gui/src/main.rs:533
msgid "Connect"
msgstr "Connect"
#: crates/pdfs-gui/src/main.rs:522
#: crates/pdfs-gui/src/main.rs:540
msgid "Hide Tray Icon"
msgstr "Hide Tray Icon"
#: crates/pdfs-gui/src/main.rs:526
#: crates/pdfs-gui/src/main.rs:544
msgid "Stop Proton Drive…"
msgstr "Stop Proton Drive…"
#: crates/pdfs-gui/src/main.rs:530
#: crates/pdfs-gui/src/main.rs:548
msgid "Quit"
msgstr "Quit"
+47 -29
View File
@@ -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-31 10:26+0100\n"
"POT-Creation-Date: 2026-10-31 19:26+0100\n"
"PO-Revision-Date: 2026-09-23 12:00+0200\n"
"Last-Translator: Proton Drive for Linux contributors\n"
"Language-Team: Spanish\n"
@@ -422,14 +422,27 @@ msgstr "Sin conexión"
msgid "The Proton Drive service isn't running."
msgstr "El servicio de Proton Drive no está en ejecución."
#: crates/pdfs-gui/src/app/main.rs:1803
#: crates/pdfs-gui/src/app/main.rs:1813
msgid "Can't open your Drive"
msgstr "No se puede abrir Proton Drive"
#: crates/pdfs-gui/src/app/main.rs:1816
#, rust-format
msgid ""
"The Proton Drive service keeps failing to start and tries again on its own. "
"The last error was: {error}"
msgstr ""
"El servicio de Proton Drive no consigue iniciarse y vuelve a intentarlo por "
"sí solo. Último error: {error}"
#: crates/pdfs-gui/src/app/main.rs:1824
#: crates/pdfs-gui/src/app/pages/status.rs:355
#: crates/pdfs-gui/src/hud/mod.rs:269 crates/pdfs-gui/src/hud/mod.rs:579
#: crates/pdfs-gui/src/main.rs:475 crates/pdfs-gui/src/main.rs:517
#: crates/pdfs-gui/src/main.rs:493 crates/pdfs-gui/src/main.rs:535
msgid "Connecting…"
msgstr "Conectando…"
#: crates/pdfs-gui/src/app/main.rs:1804
#: crates/pdfs-gui/src/app/main.rs:1825
msgid "Waiting for the Proton Drive service to start."
msgstr "Esperando a que se inicie el servicio de Proton Drive."
@@ -2902,7 +2915,7 @@ msgid "Sync paused until you resume"
msgstr "Sincronización en pausa hasta que la reanude"
#: crates/pdfs-gui/src/app/pages/locations.rs:570
#: crates/pdfs-gui/src/app/pages/status.rs:1445 crates/pdfs-gui/src/main.rs:290
#: crates/pdfs-gui/src/app/pages/status.rs:1445 crates/pdfs-gui/src/main.rs:308
msgid "Sync paused"
msgstr "Sincronización en pausa"
@@ -5106,7 +5119,7 @@ msgstr "Se reanuda {time}"
msgid "Until you resume"
msgstr "Hasta que la reanude"
#: crates/pdfs-gui/src/app/pages/status.rs:1464 crates/pdfs-gui/src/main.rs:292
#: crates/pdfs-gui/src/app/pages/status.rs:1464 crates/pdfs-gui/src/main.rs:310
#, rust-format
msgid "{n} change needs attention"
msgid_plural "{n} changes need attention"
@@ -6338,52 +6351,57 @@ msgstr "Proton Drive no responde"
msgid "Signed in as {username} — locked"
msgstr "Sesión iniciada como {username} — bloqueado"
#: crates/pdfs-gui/src/main.rs:200
#: crates/pdfs-gui/src/main.rs:209
#, rust-format
msgid "Signed in as {username} — can't open your Drive"
msgstr "Sesión iniciada como {username} — no se puede abrir Proton Drive"
#: crates/pdfs-gui/src/main.rs:218
#, rust-format
msgid "Signed in as {username} — not connected"
msgstr "Sesión iniciada como {username} — sin conexión"
#: crates/pdfs-gui/src/main.rs:205
#: crates/pdfs-gui/src/main.rs:223
msgid "Not signed in"
msgstr "Sesión no iniciada"
#. Translators: {error} is an error message, in English.
#: crates/pdfs-gui/src/main.rs:208
#: crates/pdfs-gui/src/main.rs:226
#, rust-format
msgid "Error: {error}"
msgstr "Error: {error}"
#: crates/pdfs-gui/src/main.rs:230
#: crates/pdfs-gui/src/main.rs:248
msgid "Proton Drive sent an unexpected reply"
msgstr "Proton Drive envió una respuesta inesperada"
#: crates/pdfs-gui/src/main.rs:284
#: crates/pdfs-gui/src/main.rs:302
msgid "Session expired — sign in again"
msgstr "Sesión caducada: vuelva a iniciar sesión"
#: crates/pdfs-gui/src/main.rs:286
#: crates/pdfs-gui/src/main.rs:304
msgid "Sign-in not saved — unlock your keyring"
msgstr "Inicio de sesión no guardado: desbloquee el depósito de claves"
#: crates/pdfs-gui/src/main.rs:289
#: crates/pdfs-gui/src/main.rs:307
msgid "Update not finished — restart Proton Drive"
msgstr "Actualización sin terminar: reinicie Proton Drive"
#: crates/pdfs-gui/src/main.rs:299
#: crates/pdfs-gui/src/main.rs:317
#, rust-format
msgid "Up to date in {mountpoint} ({n} pinned)"
msgid_plural "Up to date in {mountpoint} ({n} pinned)"
msgstr[0] "Actualizado en {mountpoint} ({n} fijado)"
msgstr[1] "Actualizado en {mountpoint} ({n} fijados)"
#: crates/pdfs-gui/src/main.rs:306
#: crates/pdfs-gui/src/main.rs:324
#, rust-format
msgid "Syncing — {queued} ({n} pinned)"
msgid_plural "Syncing — {queued} ({n} pinned)"
msgstr[0] "Sincronizando: {queued} ({n} anclado)"
msgstr[1] "Sincronizando: {queued} ({n} anclados)"
#: crates/pdfs-gui/src/main.rs:313
#: crates/pdfs-gui/src/main.rs:331
#, rust-format
msgid "Offline — cached files only ({n} pinned)"
msgid_plural "Offline — cached files only ({n} pinned)"
@@ -6391,60 +6409,60 @@ msgstr[0] "Sin conexión: solo archivos en caché ({n} anclado)"
msgstr[1] "Sin conexión: solo archivos en caché ({n} anclados)"
#. Translators: {queued} is a queue summary such as "3 uploads queued".
#: crates/pdfs-gui/src/main.rs:319
#: crates/pdfs-gui/src/main.rs:337
#, rust-format
msgid "Offline — {queued}"
msgstr "Sin conexión: {queued}"
#. Translators: a menu item that opens the list of failing changes.
#: crates/pdfs-gui/src/main.rs:358
#: crates/pdfs-gui/src/main.rs:376
#, rust-format
msgid "{n} issue — View"
msgid_plural "{n} issues — View"
msgstr[0] "{n} problema: ver"
msgstr[1] "{n} problemas: ver"
#: crates/pdfs-gui/src/main.rs:465
#: crates/pdfs-gui/src/main.rs:483
msgid "Sign In…"
msgstr "Iniciar sesión…"
#: crates/pdfs-gui/src/main.rs:466
#: crates/pdfs-gui/src/main.rs:484
msgid "Sign In Again…"
msgstr "Volver a iniciar sesión…"
#: crates/pdfs-gui/src/main.rs:469
#: crates/pdfs-gui/src/main.rs:487
msgid "Open Proton Drive"
msgstr "Abrir Proton Drive"
#: crates/pdfs-gui/src/main.rs:473
#: crates/pdfs-gui/src/main.rs:491
msgid "Restart Proton Drive"
msgstr "Reiniciar Proton Drive"
#: crates/pdfs-gui/src/main.rs:482
#: crates/pdfs-gui/src/main.rs:500
msgid "Open Folder"
msgstr "Abrir carpeta"
#: crates/pdfs-gui/src/main.rs:494
#: crates/pdfs-gui/src/main.rs:512
msgid "Resume Sync"
msgstr "Reanudar la sincronización"
#: crates/pdfs-gui/src/main.rs:496
#: crates/pdfs-gui/src/main.rs:514
msgid "Pause Sync"
msgstr "Pausar la sincronización"
#: crates/pdfs-gui/src/main.rs:515
#: crates/pdfs-gui/src/main.rs:533
msgid "Connect"
msgstr "Conectar"
#: crates/pdfs-gui/src/main.rs:522
#: crates/pdfs-gui/src/main.rs:540
msgid "Hide Tray Icon"
msgstr "Ocultar el icono de la bandeja"
#: crates/pdfs-gui/src/main.rs:526
#: crates/pdfs-gui/src/main.rs:544
msgid "Stop Proton Drive…"
msgstr "Detener Proton Drive…"
#: crates/pdfs-gui/src/main.rs:530
#: crates/pdfs-gui/src/main.rs:548
msgid "Quit"
msgstr "Salir"
+47 -29
View File
@@ -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-31 10:26+0100\n"
"POT-Creation-Date: 2026-10-31 19:26+0100\n"
"PO-Revision-Date: 2026-09-23 12:00+0200\n"
"Last-Translator: Proton Drive for Linux contributors\n"
"Language-Team: French\n"
@@ -424,14 +424,27 @@ msgstr "Non connecté"
msgid "The Proton Drive service isn't running."
msgstr "Le service Proton Drive n’est pas en cours d’exécution."
#: crates/pdfs-gui/src/app/main.rs:1803
#: crates/pdfs-gui/src/app/main.rs:1813
msgid "Can't open your Drive"
msgstr "Impossible d’ouvrir Proton Drive"
#: crates/pdfs-gui/src/app/main.rs:1816
#, rust-format
msgid ""
"The Proton Drive service keeps failing to start and tries again on its own. "
"The last error was: {error}"
msgstr ""
"Le service Proton Drive n’arrive pas à démarrer et réessaie de lui-même. "
"Dernière erreur : {error}"
#: crates/pdfs-gui/src/app/main.rs:1824
#: crates/pdfs-gui/src/app/pages/status.rs:355
#: crates/pdfs-gui/src/hud/mod.rs:269 crates/pdfs-gui/src/hud/mod.rs:579
#: crates/pdfs-gui/src/main.rs:475 crates/pdfs-gui/src/main.rs:517
#: crates/pdfs-gui/src/main.rs:493 crates/pdfs-gui/src/main.rs:535
msgid "Connecting…"
msgstr "Connexion…"
#: crates/pdfs-gui/src/app/main.rs:1804
#: crates/pdfs-gui/src/app/main.rs:1825
msgid "Waiting for the Proton Drive service to start."
msgstr "En attente du démarrage du service Proton Drive."
@@ -2919,7 +2932,7 @@ msgid "Sync paused until you resume"
msgstr "Synchronisation en pause jusqu’à la reprise"
#: crates/pdfs-gui/src/app/pages/locations.rs:570
#: crates/pdfs-gui/src/app/pages/status.rs:1445 crates/pdfs-gui/src/main.rs:290
#: crates/pdfs-gui/src/app/pages/status.rs:1445 crates/pdfs-gui/src/main.rs:308
msgid "Sync paused"
msgstr "Synchronisation en pause"
@@ -5149,7 +5162,7 @@ msgstr "Reprise {time}"
msgid "Until you resume"
msgstr "Jusqu’à la reprise"
#: crates/pdfs-gui/src/app/pages/status.rs:1464 crates/pdfs-gui/src/main.rs:292
#: crates/pdfs-gui/src/app/pages/status.rs:1464 crates/pdfs-gui/src/main.rs:310
#, rust-format
msgid "{n} change needs attention"
msgid_plural "{n} changes need attention"
@@ -6386,52 +6399,57 @@ msgstr "Proton Drive ne répond pas"
msgid "Signed in as {username} — locked"
msgstr "Connecté en tant que {username} — verrouillé"
#: crates/pdfs-gui/src/main.rs:200
#: crates/pdfs-gui/src/main.rs:209
#, rust-format
msgid "Signed in as {username} — can't open your Drive"
msgstr "Connecté en tant que {username} — impossible d’ouvrir Proton Drive"
#: crates/pdfs-gui/src/main.rs:218
#, rust-format
msgid "Signed in as {username} — not connected"
msgstr "Connecté en tant que {username} — non connecté"
#: crates/pdfs-gui/src/main.rs:205
#: crates/pdfs-gui/src/main.rs:223
msgid "Not signed in"
msgstr "Non connecté"
#. Translators: {error} is an error message, in English.
#: crates/pdfs-gui/src/main.rs:208
#: crates/pdfs-gui/src/main.rs:226
#, rust-format
msgid "Error: {error}"
msgstr "Erreur : {error}"
#: crates/pdfs-gui/src/main.rs:230
#: crates/pdfs-gui/src/main.rs:248
msgid "Proton Drive sent an unexpected reply"
msgstr "Proton Drive a envoyé une réponse inattendue"
#: crates/pdfs-gui/src/main.rs:284
#: crates/pdfs-gui/src/main.rs:302
msgid "Session expired — sign in again"
msgstr "Session expirée — reconnectez-vous"
#: crates/pdfs-gui/src/main.rs:286
#: crates/pdfs-gui/src/main.rs:304
msgid "Sign-in not saved — unlock your keyring"
msgstr "Connexion non enregistrée — déverrouillez votre trousseau"
#: crates/pdfs-gui/src/main.rs:289
#: crates/pdfs-gui/src/main.rs:307
msgid "Update not finished — restart Proton Drive"
msgstr "Mise à jour inachevée — redémarrez Proton Drive"
#: crates/pdfs-gui/src/main.rs:299
#: crates/pdfs-gui/src/main.rs:317
#, rust-format
msgid "Up to date in {mountpoint} ({n} pinned)"
msgid_plural "Up to date in {mountpoint} ({n} pinned)"
msgstr[0] "À jour dans {mountpoint} ({n} épinglé)"
msgstr[1] "À jour dans {mountpoint} ({n} épinglés)"
#: crates/pdfs-gui/src/main.rs:306
#: crates/pdfs-gui/src/main.rs:324
#, rust-format
msgid "Syncing — {queued} ({n} pinned)"
msgid_plural "Syncing — {queued} ({n} pinned)"
msgstr[0] "Synchronisation — {queued} ({n} épinglé)"
msgstr[1] "Synchronisation — {queued} ({n} épinglés)"
#: crates/pdfs-gui/src/main.rs:313
#: crates/pdfs-gui/src/main.rs:331
#, rust-format
msgid "Offline — cached files only ({n} pinned)"
msgid_plural "Offline — cached files only ({n} pinned)"
@@ -6439,60 +6457,60 @@ msgstr[0] "Hors ligne — fichiers en cache uniquement ({n} épinglé)"
msgstr[1] "Hors ligne — fichiers en cache uniquement ({n} épinglés)"
#. Translators: {queued} is a queue summary such as "3 uploads queued".
#: crates/pdfs-gui/src/main.rs:319
#: crates/pdfs-gui/src/main.rs:337
#, rust-format
msgid "Offline — {queued}"
msgstr "Hors ligne — {queued}"
#. Translators: a menu item that opens the list of failing changes.
#: crates/pdfs-gui/src/main.rs:358
#: crates/pdfs-gui/src/main.rs:376
#, rust-format
msgid "{n} issue — View"
msgid_plural "{n} issues — View"
msgstr[0] "{n} problème — Afficher"
msgstr[1] "{n} problèmes — Afficher"
#: crates/pdfs-gui/src/main.rs:465
#: crates/pdfs-gui/src/main.rs:483
msgid "Sign In…"
msgstr "Se connecter…"
#: crates/pdfs-gui/src/main.rs:466
#: crates/pdfs-gui/src/main.rs:484
msgid "Sign In Again…"
msgstr "Se reconnecter…"
#: crates/pdfs-gui/src/main.rs:469
#: crates/pdfs-gui/src/main.rs:487
msgid "Open Proton Drive"
msgstr "Ouvrir Proton Drive"
#: crates/pdfs-gui/src/main.rs:473
#: crates/pdfs-gui/src/main.rs:491
msgid "Restart Proton Drive"
msgstr "Redémarrer Proton Drive"
#: crates/pdfs-gui/src/main.rs:482
#: crates/pdfs-gui/src/main.rs:500
msgid "Open Folder"
msgstr "Ouvrir le dossier"
#: crates/pdfs-gui/src/main.rs:494
#: crates/pdfs-gui/src/main.rs:512
msgid "Resume Sync"
msgstr "Reprendre la synchronisation"
#: crates/pdfs-gui/src/main.rs:496
#: crates/pdfs-gui/src/main.rs:514
msgid "Pause Sync"
msgstr "Mettre en pause la synchronisation"
#: crates/pdfs-gui/src/main.rs:515
#: crates/pdfs-gui/src/main.rs:533
msgid "Connect"
msgstr "Connecter"
#: crates/pdfs-gui/src/main.rs:522
#: crates/pdfs-gui/src/main.rs:540
msgid "Hide Tray Icon"
msgstr "Masquer l’icône de la zone de notification"
#: crates/pdfs-gui/src/main.rs:526
#: crates/pdfs-gui/src/main.rs:544
msgid "Stop Proton Drive…"
msgstr "Arrêter Proton Drive…"
#: crates/pdfs-gui/src/main.rs:530
#: crates/pdfs-gui/src/main.rs:548
msgid "Quit"
msgstr "Quitter"
+47 -29
View File
@@ -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-31 10:26+0100\n"
"POT-Creation-Date: 2026-10-31 19:26+0100\n"
"PO-Revision-Date: 2026-09-23 12:00+0200\n"
"Last-Translator: Proton Drive for Linux contributors\n"
"Language-Team: Italian\n"
@@ -420,14 +420,27 @@ msgstr "Non connesso"
msgid "The Proton Drive service isn't running."
msgstr "Il servizio di Proton Drive non è in esecuzione."
#: crates/pdfs-gui/src/app/main.rs:1803
#: crates/pdfs-gui/src/app/main.rs:1813
msgid "Can't open your Drive"
msgstr "Impossibile aprire Proton Drive"
#: crates/pdfs-gui/src/app/main.rs:1816
#, rust-format
msgid ""
"The Proton Drive service keeps failing to start and tries again on its own. "
"The last error was: {error}"
msgstr ""
"Il servizio di Proton Drive non riesce ad avviarsi e riprova da solo. Ultimo "
"errore: {error}"
#: crates/pdfs-gui/src/app/main.rs:1824
#: crates/pdfs-gui/src/app/pages/status.rs:355
#: crates/pdfs-gui/src/hud/mod.rs:269 crates/pdfs-gui/src/hud/mod.rs:579
#: crates/pdfs-gui/src/main.rs:475 crates/pdfs-gui/src/main.rs:517
#: crates/pdfs-gui/src/main.rs:493 crates/pdfs-gui/src/main.rs:535
msgid "Connecting…"
msgstr "Connessione…"
#: crates/pdfs-gui/src/app/main.rs:1804
#: crates/pdfs-gui/src/app/main.rs:1825
msgid "Waiting for the Proton Drive service to start."
msgstr "In attesa dell’avvio del servizio di Proton Drive."
@@ -2917,7 +2930,7 @@ msgid "Sync paused until you resume"
msgstr "Sincronizzazione in pausa finché non riprendi"
#: crates/pdfs-gui/src/app/pages/locations.rs:570
#: crates/pdfs-gui/src/app/pages/status.rs:1445 crates/pdfs-gui/src/main.rs:290
#: crates/pdfs-gui/src/app/pages/status.rs:1445 crates/pdfs-gui/src/main.rs:308
msgid "Sync paused"
msgstr "Sincronizzazione in pausa"
@@ -5125,7 +5138,7 @@ msgstr "Riprende {time}"
msgid "Until you resume"
msgstr "Finché non riprendi"
#: crates/pdfs-gui/src/app/pages/status.rs:1464 crates/pdfs-gui/src/main.rs:292
#: crates/pdfs-gui/src/app/pages/status.rs:1464 crates/pdfs-gui/src/main.rs:310
#, rust-format
msgid "{n} change needs attention"
msgid_plural "{n} changes need attention"
@@ -6362,52 +6375,57 @@ msgstr "Proton Drive non risponde"
msgid "Signed in as {username} — locked"
msgstr "Accesso effettuato come {username} — bloccato"
#: crates/pdfs-gui/src/main.rs:200
#: crates/pdfs-gui/src/main.rs:209
#, rust-format
msgid "Signed in as {username} — can't open your Drive"
msgstr "Accesso effettuato come {username} — impossibile aprire Proton Drive"
#: crates/pdfs-gui/src/main.rs:218
#, rust-format
msgid "Signed in as {username} — not connected"
msgstr "Accesso effettuato come {username} — non connesso"
#: crates/pdfs-gui/src/main.rs:205
#: crates/pdfs-gui/src/main.rs:223
msgid "Not signed in"
msgstr "Accesso non eseguito"
#. Translators: {error} is an error message, in English.
#: crates/pdfs-gui/src/main.rs:208
#: crates/pdfs-gui/src/main.rs:226
#, rust-format
msgid "Error: {error}"
msgstr "Errore: {error}"
#: crates/pdfs-gui/src/main.rs:230
#: crates/pdfs-gui/src/main.rs:248
msgid "Proton Drive sent an unexpected reply"
msgstr "Proton Drive ha inviato una risposta inattesa"
#: crates/pdfs-gui/src/main.rs:284
#: crates/pdfs-gui/src/main.rs:302
msgid "Session expired — sign in again"
msgstr "Sessione scaduta: accedi di nuovo"
#: crates/pdfs-gui/src/main.rs:286
#: crates/pdfs-gui/src/main.rs:304
msgid "Sign-in not saved — unlock your keyring"
msgstr "Accesso non salvato: sblocca il portachiavi"
#: crates/pdfs-gui/src/main.rs:289
#: crates/pdfs-gui/src/main.rs:307
msgid "Update not finished — restart Proton Drive"
msgstr "Aggiornamento non completato: riavvia Proton Drive"
#: crates/pdfs-gui/src/main.rs:299
#: crates/pdfs-gui/src/main.rs:317
#, rust-format
msgid "Up to date in {mountpoint} ({n} pinned)"
msgid_plural "Up to date in {mountpoint} ({n} pinned)"
msgstr[0] "Aggiornato in {mountpoint} ({n} fissato)"
msgstr[1] "Aggiornato in {mountpoint} ({n} fissati)"
#: crates/pdfs-gui/src/main.rs:306
#: crates/pdfs-gui/src/main.rs:324
#, rust-format
msgid "Syncing — {queued} ({n} pinned)"
msgid_plural "Syncing — {queued} ({n} pinned)"
msgstr[0] "Sincronizzazione: {queued} ({n} fissato)"
msgstr[1] "Sincronizzazione: {queued} ({n} fissati)"
#: crates/pdfs-gui/src/main.rs:313
#: crates/pdfs-gui/src/main.rs:331
#, rust-format
msgid "Offline — cached files only ({n} pinned)"
msgid_plural "Offline — cached files only ({n} pinned)"
@@ -6415,60 +6433,60 @@ msgstr[0] "Offline: solo file in cache ({n} fissato)"
msgstr[1] "Offline: solo file in cache ({n} fissati)"
#. Translators: {queued} is a queue summary such as "3 uploads queued".
#: crates/pdfs-gui/src/main.rs:319
#: crates/pdfs-gui/src/main.rs:337
#, rust-format
msgid "Offline — {queued}"
msgstr "Offline: {queued}"
#. Translators: a menu item that opens the list of failing changes.
#: crates/pdfs-gui/src/main.rs:358
#: crates/pdfs-gui/src/main.rs:376
#, rust-format
msgid "{n} issue — View"
msgid_plural "{n} issues — View"
msgstr[0] "{n} problema: visualizza"
msgstr[1] "{n} problemi: visualizza"
#: crates/pdfs-gui/src/main.rs:465
#: crates/pdfs-gui/src/main.rs:483
msgid "Sign In…"
msgstr "Accedi…"
#: crates/pdfs-gui/src/main.rs:466
#: crates/pdfs-gui/src/main.rs:484
msgid "Sign In Again…"
msgstr "Accedi di nuovo…"
#: crates/pdfs-gui/src/main.rs:469
#: crates/pdfs-gui/src/main.rs:487
msgid "Open Proton Drive"
msgstr "Apri Proton Drive"
#: crates/pdfs-gui/src/main.rs:473
#: crates/pdfs-gui/src/main.rs:491
msgid "Restart Proton Drive"
msgstr "Riavvia Proton Drive"
#: crates/pdfs-gui/src/main.rs:482
#: crates/pdfs-gui/src/main.rs:500
msgid "Open Folder"
msgstr "Apri cartella"
#: crates/pdfs-gui/src/main.rs:494
#: crates/pdfs-gui/src/main.rs:512
msgid "Resume Sync"
msgstr "Riprendi sincronizzazione"
#: crates/pdfs-gui/src/main.rs:496
#: crates/pdfs-gui/src/main.rs:514
msgid "Pause Sync"
msgstr "Metti in pausa sincronizzazione"
#: crates/pdfs-gui/src/main.rs:515
#: crates/pdfs-gui/src/main.rs:533
msgid "Connect"
msgstr "Connetti"
#: crates/pdfs-gui/src/main.rs:522
#: crates/pdfs-gui/src/main.rs:540
msgid "Hide Tray Icon"
msgstr "Nascondi icona nell'area di notifica"
#: crates/pdfs-gui/src/main.rs:526
#: crates/pdfs-gui/src/main.rs:544
msgid "Stop Proton Drive…"
msgstr "Arresta Proton Drive…"
#: crates/pdfs-gui/src/main.rs:530
#: crates/pdfs-gui/src/main.rs:548
msgid "Quit"
msgstr "Esci"
+47 -29
View File
@@ -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-31 10:26+0100\n"
"POT-Creation-Date: 2026-10-31 19:26+0100\n"
"PO-Revision-Date: 2026-09-23 12:00+0200\n"
"Last-Translator: Proton Drive for Linux contributors\n"
"Language-Team: Dutch\n"
@@ -421,14 +421,27 @@ msgstr "Niet verbonden"
msgid "The Proton Drive service isn't running."
msgstr "De Proton Drive-service draait niet."
#: crates/pdfs-gui/src/app/main.rs:1803
#: crates/pdfs-gui/src/app/main.rs:1813
msgid "Can't open your Drive"
msgstr "Kan Proton Drive niet openen"
#: crates/pdfs-gui/src/app/main.rs:1816
#, rust-format
msgid ""
"The Proton Drive service keeps failing to start and tries again on its own. "
"The last error was: {error}"
msgstr ""
"De Proton Drive-service kan steeds niet starten en probeert het zelf "
"opnieuw. Laatste fout: {error}"
#: crates/pdfs-gui/src/app/main.rs:1824
#: crates/pdfs-gui/src/app/pages/status.rs:355
#: crates/pdfs-gui/src/hud/mod.rs:269 crates/pdfs-gui/src/hud/mod.rs:579
#: crates/pdfs-gui/src/main.rs:475 crates/pdfs-gui/src/main.rs:517
#: crates/pdfs-gui/src/main.rs:493 crates/pdfs-gui/src/main.rs:535
msgid "Connecting…"
msgstr "Verbinden…"
#: crates/pdfs-gui/src/app/main.rs:1804
#: crates/pdfs-gui/src/app/main.rs:1825
msgid "Waiting for the Proton Drive service to start."
msgstr "Wachten tot de Proton Drive-service is gestart."
@@ -2907,7 +2920,7 @@ msgid "Sync paused until you resume"
msgstr "Synchronisatie gepauzeerd totdat je hervat"
#: crates/pdfs-gui/src/app/pages/locations.rs:570
#: crates/pdfs-gui/src/app/pages/status.rs:1445 crates/pdfs-gui/src/main.rs:290
#: crates/pdfs-gui/src/app/pages/status.rs:1445 crates/pdfs-gui/src/main.rs:308
msgid "Sync paused"
msgstr "Synchronisatie gepauzeerd"
@@ -5119,7 +5132,7 @@ msgstr "Hervat {time}"
msgid "Until you resume"
msgstr "Totdat je hervat"
#: crates/pdfs-gui/src/app/pages/status.rs:1464 crates/pdfs-gui/src/main.rs:292
#: crates/pdfs-gui/src/app/pages/status.rs:1464 crates/pdfs-gui/src/main.rs:310
#, rust-format
msgid "{n} change needs attention"
msgid_plural "{n} changes need attention"
@@ -6348,52 +6361,57 @@ msgstr "Proton Drive reageert niet"
msgid "Signed in as {username} — locked"
msgstr "Aangemeld als {username} — vergrendeld"
#: crates/pdfs-gui/src/main.rs:200
#: crates/pdfs-gui/src/main.rs:209
#, rust-format
msgid "Signed in as {username} — can't open your Drive"
msgstr "Aangemeld als {username} — kan Proton Drive niet openen"
#: crates/pdfs-gui/src/main.rs:218
#, rust-format
msgid "Signed in as {username} — not connected"
msgstr "Aangemeld als {username} — niet verbonden"
#: crates/pdfs-gui/src/main.rs:205
#: crates/pdfs-gui/src/main.rs:223
msgid "Not signed in"
msgstr "Niet aangemeld"
#. Translators: {error} is an error message, in English.
#: crates/pdfs-gui/src/main.rs:208
#: crates/pdfs-gui/src/main.rs:226
#, rust-format
msgid "Error: {error}"
msgstr "Fout: {error}"
#: crates/pdfs-gui/src/main.rs:230
#: crates/pdfs-gui/src/main.rs:248
msgid "Proton Drive sent an unexpected reply"
msgstr "Proton Drive gaf een onverwacht antwoord"
#: crates/pdfs-gui/src/main.rs:284
#: crates/pdfs-gui/src/main.rs:302
msgid "Session expired — sign in again"
msgstr "Sessie verlopen — meld je opnieuw aan"
#: crates/pdfs-gui/src/main.rs:286
#: crates/pdfs-gui/src/main.rs:304
msgid "Sign-in not saved — unlock your keyring"
msgstr "Aanmelding niet opgeslagen — ontgrendel je sleutelbos"
#: crates/pdfs-gui/src/main.rs:289
#: crates/pdfs-gui/src/main.rs:307
msgid "Update not finished — restart Proton Drive"
msgstr "Update niet voltooid — start Proton Drive opnieuw"
#: crates/pdfs-gui/src/main.rs:299
#: crates/pdfs-gui/src/main.rs:317
#, rust-format
msgid "Up to date in {mountpoint} ({n} pinned)"
msgid_plural "Up to date in {mountpoint} ({n} pinned)"
msgstr[0] "Bijgewerkt in {mountpoint} ({n} vastgezet)"
msgstr[1] "Bijgewerkt in {mountpoint} ({n} vastgezet)"
#: crates/pdfs-gui/src/main.rs:306
#: crates/pdfs-gui/src/main.rs:324
#, rust-format
msgid "Syncing — {queued} ({n} pinned)"
msgid_plural "Syncing — {queued} ({n} pinned)"
msgstr[0] "Synchroniseren — {queued} ({n} vastgezet)"
msgstr[1] "Synchroniseren — {queued} ({n} vastgezet)"
#: crates/pdfs-gui/src/main.rs:313
#: crates/pdfs-gui/src/main.rs:331
#, rust-format
msgid "Offline — cached files only ({n} pinned)"
msgid_plural "Offline — cached files only ({n} pinned)"
@@ -6401,60 +6419,60 @@ msgstr[0] "Offline — alleen bestanden in cache ({n} vastgezet)"
msgstr[1] "Offline — alleen bestanden in cache ({n} vastgezet)"
#. Translators: {queued} is a queue summary such as "3 uploads queued".
#: crates/pdfs-gui/src/main.rs:319
#: crates/pdfs-gui/src/main.rs:337
#, rust-format
msgid "Offline — {queued}"
msgstr "Offline — {queued}"
#. Translators: a menu item that opens the list of failing changes.
#: crates/pdfs-gui/src/main.rs:358
#: crates/pdfs-gui/src/main.rs:376
#, rust-format
msgid "{n} issue — View"
msgid_plural "{n} issues — View"
msgstr[0] "{n} probleem — Bekijken"
msgstr[1] "{n} problemen — Bekijken"
#: crates/pdfs-gui/src/main.rs:465
#: crates/pdfs-gui/src/main.rs:483
msgid "Sign In…"
msgstr "Aanmelden…"
#: crates/pdfs-gui/src/main.rs:466
#: crates/pdfs-gui/src/main.rs:484
msgid "Sign In Again…"
msgstr "Opnieuw aanmelden…"
#: crates/pdfs-gui/src/main.rs:469
#: crates/pdfs-gui/src/main.rs:487
msgid "Open Proton Drive"
msgstr "Proton Drive openen"
#: crates/pdfs-gui/src/main.rs:473
#: crates/pdfs-gui/src/main.rs:491
msgid "Restart Proton Drive"
msgstr "Proton Drive opnieuw starten"
#: crates/pdfs-gui/src/main.rs:482
#: crates/pdfs-gui/src/main.rs:500
msgid "Open Folder"
msgstr "Map openen"
#: crates/pdfs-gui/src/main.rs:494
#: crates/pdfs-gui/src/main.rs:512
msgid "Resume Sync"
msgstr "Synchronisatie hervatten"
#: crates/pdfs-gui/src/main.rs:496
#: crates/pdfs-gui/src/main.rs:514
msgid "Pause Sync"
msgstr "Synchronisatie pauzeren"
#: crates/pdfs-gui/src/main.rs:515
#: crates/pdfs-gui/src/main.rs:533
msgid "Connect"
msgstr "Verbinden"
#: crates/pdfs-gui/src/main.rs:522
#: crates/pdfs-gui/src/main.rs:540
msgid "Hide Tray Icon"
msgstr "Pictogram in systeemvak verbergen"
#: crates/pdfs-gui/src/main.rs:526
#: crates/pdfs-gui/src/main.rs:544
msgid "Stop Proton Drive…"
msgstr "Proton Drive stoppen…"
#: crates/pdfs-gui/src/main.rs:530
#: crates/pdfs-gui/src/main.rs:548
msgid "Quit"
msgstr "Afsluiten"
+45 -29
View File
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: proton-drive-linux 3.6.0\n"
"Report-Msgid-Bugs-To: https://github.com/narrrl/proton-drive-linux/issues\n"
"POT-Creation-Date: 2026-10-31 10:26+0100\n"
"POT-Creation-Date: 2026-10-31 19:26+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -397,14 +397,25 @@ msgstr ""
msgid "The Proton Drive service isn't running."
msgstr ""
#: crates/pdfs-gui/src/app/main.rs:1803
#: crates/pdfs-gui/src/app/main.rs:1813
msgid "Can't open your Drive"
msgstr ""
#: crates/pdfs-gui/src/app/main.rs:1816
#, rust-format
msgid ""
"The Proton Drive service keeps failing to start and tries again on its own. "
"The last error was: {error}"
msgstr ""
#: crates/pdfs-gui/src/app/main.rs:1824
#: crates/pdfs-gui/src/app/pages/status.rs:355
#: crates/pdfs-gui/src/hud/mod.rs:269 crates/pdfs-gui/src/hud/mod.rs:579
#: crates/pdfs-gui/src/main.rs:475 crates/pdfs-gui/src/main.rs:517
#: crates/pdfs-gui/src/main.rs:493 crates/pdfs-gui/src/main.rs:535
msgid "Connecting…"
msgstr ""
#: crates/pdfs-gui/src/app/main.rs:1804
#: crates/pdfs-gui/src/app/main.rs:1825
msgid "Waiting for the Proton Drive service to start."
msgstr ""
@@ -2799,7 +2810,7 @@ msgid "Sync paused until you resume"
msgstr ""
#: crates/pdfs-gui/src/app/pages/locations.rs:570
#: crates/pdfs-gui/src/app/pages/status.rs:1445 crates/pdfs-gui/src/main.rs:290
#: crates/pdfs-gui/src/app/pages/status.rs:1445 crates/pdfs-gui/src/main.rs:308
msgid "Sync paused"
msgstr ""
@@ -4894,7 +4905,7 @@ msgstr ""
msgid "Until you resume"
msgstr ""
#: crates/pdfs-gui/src/app/pages/status.rs:1464 crates/pdfs-gui/src/main.rs:292
#: crates/pdfs-gui/src/app/pages/status.rs:1464 crates/pdfs-gui/src/main.rs:310
#, rust-format
msgid "{n} change needs attention"
msgid_plural "{n} changes need attention"
@@ -6082,52 +6093,57 @@ msgstr ""
msgid "Signed in as {username} — locked"
msgstr ""
#: crates/pdfs-gui/src/main.rs:200
#: crates/pdfs-gui/src/main.rs:209
#, rust-format
msgid "Signed in as {username} — can't open your Drive"
msgstr ""
#: crates/pdfs-gui/src/main.rs:218
#, rust-format
msgid "Signed in as {username} — not connected"
msgstr ""
#: crates/pdfs-gui/src/main.rs:205
#: crates/pdfs-gui/src/main.rs:223
msgid "Not signed in"
msgstr ""
#. Translators: {error} is an error message, in English.
#: crates/pdfs-gui/src/main.rs:208
#: crates/pdfs-gui/src/main.rs:226
#, rust-format
msgid "Error: {error}"
msgstr ""
#: crates/pdfs-gui/src/main.rs:230
#: crates/pdfs-gui/src/main.rs:248
msgid "Proton Drive sent an unexpected reply"
msgstr ""
#: crates/pdfs-gui/src/main.rs:284
#: crates/pdfs-gui/src/main.rs:302
msgid "Session expired — sign in again"
msgstr ""
#: crates/pdfs-gui/src/main.rs:286
#: crates/pdfs-gui/src/main.rs:304
msgid "Sign-in not saved — unlock your keyring"
msgstr ""
#: crates/pdfs-gui/src/main.rs:289
#: crates/pdfs-gui/src/main.rs:307
msgid "Update not finished — restart Proton Drive"
msgstr ""
#: crates/pdfs-gui/src/main.rs:299
#: crates/pdfs-gui/src/main.rs:317
#, rust-format
msgid "Up to date in {mountpoint} ({n} pinned)"
msgid_plural "Up to date in {mountpoint} ({n} pinned)"
msgstr[0] ""
msgstr[1] ""
#: crates/pdfs-gui/src/main.rs:306
#: crates/pdfs-gui/src/main.rs:324
#, rust-format
msgid "Syncing — {queued} ({n} pinned)"
msgid_plural "Syncing — {queued} ({n} pinned)"
msgstr[0] ""
msgstr[1] ""
#: crates/pdfs-gui/src/main.rs:313
#: crates/pdfs-gui/src/main.rs:331
#, rust-format
msgid "Offline — cached files only ({n} pinned)"
msgid_plural "Offline — cached files only ({n} pinned)"
@@ -6135,60 +6151,60 @@ msgstr[0] ""
msgstr[1] ""
#. Translators: {queued} is a queue summary such as "3 uploads queued".
#: crates/pdfs-gui/src/main.rs:319
#: crates/pdfs-gui/src/main.rs:337
#, rust-format
msgid "Offline — {queued}"
msgstr ""
#. Translators: a menu item that opens the list of failing changes.
#: crates/pdfs-gui/src/main.rs:358
#: crates/pdfs-gui/src/main.rs:376
#, rust-format
msgid "{n} issue — View"
msgid_plural "{n} issues — View"
msgstr[0] ""
msgstr[1] ""
#: crates/pdfs-gui/src/main.rs:465
#: crates/pdfs-gui/src/main.rs:483
msgid "Sign In…"
msgstr ""
#: crates/pdfs-gui/src/main.rs:466
#: crates/pdfs-gui/src/main.rs:484
msgid "Sign In Again…"
msgstr ""
#: crates/pdfs-gui/src/main.rs:469
#: crates/pdfs-gui/src/main.rs:487
msgid "Open Proton Drive"
msgstr ""
#: crates/pdfs-gui/src/main.rs:473
#: crates/pdfs-gui/src/main.rs:491
msgid "Restart Proton Drive"
msgstr ""
#: crates/pdfs-gui/src/main.rs:482
#: crates/pdfs-gui/src/main.rs:500
msgid "Open Folder"
msgstr ""
#: crates/pdfs-gui/src/main.rs:494
#: crates/pdfs-gui/src/main.rs:512
msgid "Resume Sync"
msgstr ""
#: crates/pdfs-gui/src/main.rs:496
#: crates/pdfs-gui/src/main.rs:514
msgid "Pause Sync"
msgstr ""
#: crates/pdfs-gui/src/main.rs:515
#: crates/pdfs-gui/src/main.rs:533
msgid "Connect"
msgstr ""
#: crates/pdfs-gui/src/main.rs:522
#: crates/pdfs-gui/src/main.rs:540
msgid "Hide Tray Icon"
msgstr ""
#: crates/pdfs-gui/src/main.rs:526
#: crates/pdfs-gui/src/main.rs:544
msgid "Stop Proton Drive…"
msgstr ""
#: crates/pdfs-gui/src/main.rs:530
#: crates/pdfs-gui/src/main.rs:548
msgid "Quit"
msgstr ""
+47 -29
View File
@@ -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-31 10:26+0100\n"
"POT-Creation-Date: 2026-10-31 19:26+0100\n"
"PO-Revision-Date: 2026-09-23 12:00+0200\n"
"Last-Translator: Proton Drive for Linux contributors\n"
"Language-Team: Polish\n"
@@ -425,14 +425,27 @@ msgstr "Brak połączenia"
msgid "The Proton Drive service isn't running."
msgstr "Usługa Proton Drive nie jest uruchomiona."
#: crates/pdfs-gui/src/app/main.rs:1803
#: crates/pdfs-gui/src/app/main.rs:1813
msgid "Can't open your Drive"
msgstr "Nie można otworzyć Proton Drive"
#: crates/pdfs-gui/src/app/main.rs:1816
#, rust-format
msgid ""
"The Proton Drive service keeps failing to start and tries again on its own. "
"The last error was: {error}"
msgstr ""
"Usługa Proton Drive nie może się uruchomić i sama ponawia próby. Ostatni "
"błąd: {error}"
#: crates/pdfs-gui/src/app/main.rs:1824
#: crates/pdfs-gui/src/app/pages/status.rs:355
#: crates/pdfs-gui/src/hud/mod.rs:269 crates/pdfs-gui/src/hud/mod.rs:579
#: crates/pdfs-gui/src/main.rs:475 crates/pdfs-gui/src/main.rs:517
#: crates/pdfs-gui/src/main.rs:493 crates/pdfs-gui/src/main.rs:535
msgid "Connecting…"
msgstr "Łączenie…"
#: crates/pdfs-gui/src/app/main.rs:1804
#: crates/pdfs-gui/src/app/main.rs:1825
msgid "Waiting for the Proton Drive service to start."
msgstr "Oczekiwanie na uruchomienie usługi Proton Drive."
@@ -2973,7 +2986,7 @@ msgid "Sync paused until you resume"
msgstr "Wstrzymano synchronizację do czasu wznowienia"
#: crates/pdfs-gui/src/app/pages/locations.rs:570
#: crates/pdfs-gui/src/app/pages/status.rs:1445 crates/pdfs-gui/src/main.rs:290
#: crates/pdfs-gui/src/app/pages/status.rs:1445 crates/pdfs-gui/src/main.rs:308
msgid "Sync paused"
msgstr "Wstrzymano synchronizację"
@@ -5200,7 +5213,7 @@ msgstr "Wznowienie {time}"
msgid "Until you resume"
msgstr "Do czasu wznowienia"
#: crates/pdfs-gui/src/app/pages/status.rs:1464 crates/pdfs-gui/src/main.rs:292
#: crates/pdfs-gui/src/app/pages/status.rs:1464 crates/pdfs-gui/src/main.rs:310
#, rust-format
msgid "{n} change needs attention"
msgid_plural "{n} changes need attention"
@@ -6451,38 +6464,43 @@ msgstr "Proton Drive nie odpowiada"
msgid "Signed in as {username} — locked"
msgstr "Zalogowano jako {username} — zablokowane"
#: crates/pdfs-gui/src/main.rs:200
#: crates/pdfs-gui/src/main.rs:209
#, rust-format
msgid "Signed in as {username} — can't open your Drive"
msgstr "Zalogowano jako {username} — nie można otworzyć Proton Drive"
#: crates/pdfs-gui/src/main.rs:218
#, rust-format
msgid "Signed in as {username} — not connected"
msgstr "Zalogowano jako {username} — brak połączenia"
#: crates/pdfs-gui/src/main.rs:205
#: crates/pdfs-gui/src/main.rs:223
msgid "Not signed in"
msgstr "Nie zalogowano"
#. Translators: {error} is an error message, in English.
#: crates/pdfs-gui/src/main.rs:208
#: crates/pdfs-gui/src/main.rs:226
#, rust-format
msgid "Error: {error}"
msgstr "Błąd: {error}"
#: crates/pdfs-gui/src/main.rs:230
#: crates/pdfs-gui/src/main.rs:248
msgid "Proton Drive sent an unexpected reply"
msgstr "Proton Drive wysłał nieoczekiwaną odpowiedź"
#: crates/pdfs-gui/src/main.rs:284
#: crates/pdfs-gui/src/main.rs:302
msgid "Session expired — sign in again"
msgstr "Sesja wygasła — zaloguj się ponownie"
#: crates/pdfs-gui/src/main.rs:286
#: crates/pdfs-gui/src/main.rs:304
msgid "Sign-in not saved — unlock your keyring"
msgstr "Logowanie nie zostało zapisane — odblokuj bazę kluczy"
#: crates/pdfs-gui/src/main.rs:289
#: crates/pdfs-gui/src/main.rs:307
msgid "Update not finished — restart Proton Drive"
msgstr "Aktualizacja niedokończona — uruchom ponownie Proton Drive"
#: crates/pdfs-gui/src/main.rs:299
#: crates/pdfs-gui/src/main.rs:317
#, rust-format
msgid "Up to date in {mountpoint} ({n} pinned)"
msgid_plural "Up to date in {mountpoint} ({n} pinned)"
@@ -6490,7 +6508,7 @@ msgstr[0] "Aktualne w {mountpoint} ({n} przypięty)"
msgstr[1] "Aktualne w {mountpoint} ({n} przypięte)"
msgstr[2] "Aktualne w {mountpoint} ({n} przypiętych)"
#: crates/pdfs-gui/src/main.rs:306
#: crates/pdfs-gui/src/main.rs:324
#, rust-format
msgid "Syncing — {queued} ({n} pinned)"
msgid_plural "Syncing — {queued} ({n} pinned)"
@@ -6498,7 +6516,7 @@ msgstr[0] "Synchronizowanie — {queued} (przypięte: {n})"
msgstr[1] "Synchronizowanie — {queued} (przypięte: {n})"
msgstr[2] "Synchronizowanie — {queued} (przypięte: {n})"
#: crates/pdfs-gui/src/main.rs:313
#: crates/pdfs-gui/src/main.rs:331
#, rust-format
msgid "Offline — cached files only ({n} pinned)"
msgid_plural "Offline — cached files only ({n} pinned)"
@@ -6507,13 +6525,13 @@ msgstr[1] "Offline — tylko pliki w pamięci podręcznej (przypięte: {n})"
msgstr[2] "Offline — tylko pliki w pamięci podręcznej (przypięte: {n})"
#. Translators: {queued} is a queue summary such as "3 uploads queued".
#: crates/pdfs-gui/src/main.rs:319
#: crates/pdfs-gui/src/main.rs:337
#, rust-format
msgid "Offline — {queued}"
msgstr "Offline — {queued}"
#. Translators: a menu item that opens the list of failing changes.
#: crates/pdfs-gui/src/main.rs:358
#: crates/pdfs-gui/src/main.rs:376
#, rust-format
msgid "{n} issue — View"
msgid_plural "{n} issues — View"
@@ -6521,47 +6539,47 @@ msgstr[0] "{n} problem — wyświetl"
msgstr[1] "{n} problemy — wyświetl"
msgstr[2] "{n} problemów — wyświetl"
#: crates/pdfs-gui/src/main.rs:465
#: crates/pdfs-gui/src/main.rs:483
msgid "Sign In…"
msgstr "Zaloguj się…"
#: crates/pdfs-gui/src/main.rs:466
#: crates/pdfs-gui/src/main.rs:484
msgid "Sign In Again…"
msgstr "Zaloguj się ponownie…"
#: crates/pdfs-gui/src/main.rs:469
#: crates/pdfs-gui/src/main.rs:487
msgid "Open Proton Drive"
msgstr "Otwórz Proton Drive"
#: crates/pdfs-gui/src/main.rs:473
#: crates/pdfs-gui/src/main.rs:491
msgid "Restart Proton Drive"
msgstr "Uruchom ponownie Proton Drive"
#: crates/pdfs-gui/src/main.rs:482
#: crates/pdfs-gui/src/main.rs:500
msgid "Open Folder"
msgstr "Otwórz katalog"
#: crates/pdfs-gui/src/main.rs:494
#: crates/pdfs-gui/src/main.rs:512
msgid "Resume Sync"
msgstr "Wznów synchronizację"
#: crates/pdfs-gui/src/main.rs:496
#: crates/pdfs-gui/src/main.rs:514
msgid "Pause Sync"
msgstr "Wstrzymaj synchronizację"
#: crates/pdfs-gui/src/main.rs:515
#: crates/pdfs-gui/src/main.rs:533
msgid "Connect"
msgstr "Połącz"
#: crates/pdfs-gui/src/main.rs:522
#: crates/pdfs-gui/src/main.rs:540
msgid "Hide Tray Icon"
msgstr "Ukryj ikonę w obszarze powiadamiania"
#: crates/pdfs-gui/src/main.rs:526
#: crates/pdfs-gui/src/main.rs:544
msgid "Stop Proton Drive…"
msgstr "Zatrzymaj Proton Drive…"
#: crates/pdfs-gui/src/main.rs:530
#: crates/pdfs-gui/src/main.rs:548
msgid "Quit"
msgstr "Zakończ"
+47 -29
View File
@@ -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-31 10:26+0100\n"
"POT-Creation-Date: 2026-10-31 19:26+0100\n"
"PO-Revision-Date: 2026-09-23 12:00+0200\n"
"Last-Translator: Proton Drive for Linux contributors\n"
"Language-Team: Portuguese (Brazil)\n"
@@ -420,14 +420,27 @@ msgstr "Não conectado"
msgid "The Proton Drive service isn't running."
msgstr "O serviço do Proton Drive não está em execução."
#: crates/pdfs-gui/src/app/main.rs:1803
#: crates/pdfs-gui/src/app/main.rs:1813
msgid "Can't open your Drive"
msgstr "Não foi possível abrir o Proton Drive"
#: crates/pdfs-gui/src/app/main.rs:1816
#, rust-format
msgid ""
"The Proton Drive service keeps failing to start and tries again on its own. "
"The last error was: {error}"
msgstr ""
"O serviço do Proton Drive não consegue iniciar e tenta de novo sozinho. "
"Último erro: {error}"
#: crates/pdfs-gui/src/app/main.rs:1824
#: crates/pdfs-gui/src/app/pages/status.rs:355
#: crates/pdfs-gui/src/hud/mod.rs:269 crates/pdfs-gui/src/hud/mod.rs:579
#: crates/pdfs-gui/src/main.rs:475 crates/pdfs-gui/src/main.rs:517
#: crates/pdfs-gui/src/main.rs:493 crates/pdfs-gui/src/main.rs:535
msgid "Connecting…"
msgstr "Conectando…"
#: crates/pdfs-gui/src/app/main.rs:1804
#: crates/pdfs-gui/src/app/main.rs:1825
msgid "Waiting for the Proton Drive service to start."
msgstr "Aguardando o serviço do Proton Drive iniciar."
@@ -2903,7 +2916,7 @@ msgid "Sync paused until you resume"
msgstr "Sincronização pausada até você retomar"
#: crates/pdfs-gui/src/app/pages/locations.rs:570
#: crates/pdfs-gui/src/app/pages/status.rs:1445 crates/pdfs-gui/src/main.rs:290
#: crates/pdfs-gui/src/app/pages/status.rs:1445 crates/pdfs-gui/src/main.rs:308
msgid "Sync paused"
msgstr "Sincronização pausada"
@@ -5104,7 +5117,7 @@ msgstr "Retoma {time}"
msgid "Until you resume"
msgstr "Até você retomar"
#: crates/pdfs-gui/src/app/pages/status.rs:1464 crates/pdfs-gui/src/main.rs:292
#: crates/pdfs-gui/src/app/pages/status.rs:1464 crates/pdfs-gui/src/main.rs:310
#, rust-format
msgid "{n} change needs attention"
msgid_plural "{n} changes need attention"
@@ -6335,52 +6348,57 @@ msgstr "O Proton Drive não está respondendo"
msgid "Signed in as {username} — locked"
msgstr "Conectado como {username} — bloqueado"
#: crates/pdfs-gui/src/main.rs:200
#: crates/pdfs-gui/src/main.rs:209
#, rust-format
msgid "Signed in as {username} — can't open your Drive"
msgstr "Conectado como {username} — não foi possível abrir o Proton Drive"
#: crates/pdfs-gui/src/main.rs:218
#, rust-format
msgid "Signed in as {username} — not connected"
msgstr "Conectado como {username} — sem conexão"
#: crates/pdfs-gui/src/main.rs:205
#: crates/pdfs-gui/src/main.rs:223
msgid "Not signed in"
msgstr "Não conectado"
#. Translators: {error} is an error message, in English.
#: crates/pdfs-gui/src/main.rs:208
#: crates/pdfs-gui/src/main.rs:226
#, rust-format
msgid "Error: {error}"
msgstr "Erro: {error}"
#: crates/pdfs-gui/src/main.rs:230
#: crates/pdfs-gui/src/main.rs:248
msgid "Proton Drive sent an unexpected reply"
msgstr "O Proton Drive enviou uma resposta inesperada"
#: crates/pdfs-gui/src/main.rs:284
#: crates/pdfs-gui/src/main.rs:302
msgid "Session expired — sign in again"
msgstr "Sessão expirada — entre novamente"
#: crates/pdfs-gui/src/main.rs:286
#: crates/pdfs-gui/src/main.rs:304
msgid "Sign-in not saved — unlock your keyring"
msgstr "Login não salvo — desbloqueie o chaveiro"
#: crates/pdfs-gui/src/main.rs:289
#: crates/pdfs-gui/src/main.rs:307
msgid "Update not finished — restart Proton Drive"
msgstr "Atualização não concluída — reinicie o Proton Drive"
#: crates/pdfs-gui/src/main.rs:299
#: crates/pdfs-gui/src/main.rs:317
#, rust-format
msgid "Up to date in {mountpoint} ({n} pinned)"
msgid_plural "Up to date in {mountpoint} ({n} pinned)"
msgstr[0] "Atualizado em {mountpoint} ({n} fixado)"
msgstr[1] "Atualizado em {mountpoint} ({n} fixados)"
#: crates/pdfs-gui/src/main.rs:306
#: crates/pdfs-gui/src/main.rs:324
#, rust-format
msgid "Syncing — {queued} ({n} pinned)"
msgid_plural "Syncing — {queued} ({n} pinned)"
msgstr[0] "Sincronizando — {queued} ({n} fixado)"
msgstr[1] "Sincronizando — {queued} ({n} fixados)"
#: crates/pdfs-gui/src/main.rs:313
#: crates/pdfs-gui/src/main.rs:331
#, rust-format
msgid "Offline — cached files only ({n} pinned)"
msgid_plural "Offline — cached files only ({n} pinned)"
@@ -6388,60 +6406,60 @@ msgstr[0] "Offline — somente arquivos em cache ({n} fixado)"
msgstr[1] "Offline — somente arquivos em cache ({n} fixados)"
#. Translators: {queued} is a queue summary such as "3 uploads queued".
#: crates/pdfs-gui/src/main.rs:319
#: crates/pdfs-gui/src/main.rs:337
#, rust-format
msgid "Offline — {queued}"
msgstr "Offline — {queued}"
#. Translators: a menu item that opens the list of failing changes.
#: crates/pdfs-gui/src/main.rs:358
#: crates/pdfs-gui/src/main.rs:376
#, rust-format
msgid "{n} issue — View"
msgid_plural "{n} issues — View"
msgstr[0] "{n} problema — Ver"
msgstr[1] "{n} problemas — Ver"
#: crates/pdfs-gui/src/main.rs:465
#: crates/pdfs-gui/src/main.rs:483
msgid "Sign In…"
msgstr "Entrar…"
#: crates/pdfs-gui/src/main.rs:466
#: crates/pdfs-gui/src/main.rs:484
msgid "Sign In Again…"
msgstr "Entrar novamente…"
#: crates/pdfs-gui/src/main.rs:469
#: crates/pdfs-gui/src/main.rs:487
msgid "Open Proton Drive"
msgstr "Abrir o Proton Drive"
#: crates/pdfs-gui/src/main.rs:473
#: crates/pdfs-gui/src/main.rs:491
msgid "Restart Proton Drive"
msgstr "Reiniciar o Proton Drive"
#: crates/pdfs-gui/src/main.rs:482
#: crates/pdfs-gui/src/main.rs:500
msgid "Open Folder"
msgstr "Abrir pasta"
#: crates/pdfs-gui/src/main.rs:494
#: crates/pdfs-gui/src/main.rs:512
msgid "Resume Sync"
msgstr "Retomar sincronização"
#: crates/pdfs-gui/src/main.rs:496
#: crates/pdfs-gui/src/main.rs:514
msgid "Pause Sync"
msgstr "Pausar sincronização"
#: crates/pdfs-gui/src/main.rs:515
#: crates/pdfs-gui/src/main.rs:533
msgid "Connect"
msgstr "Conectar"
#: crates/pdfs-gui/src/main.rs:522
#: crates/pdfs-gui/src/main.rs:540
msgid "Hide Tray Icon"
msgstr "Ocultar ícone da bandeja"
#: crates/pdfs-gui/src/main.rs:526
#: crates/pdfs-gui/src/main.rs:544
msgid "Stop Proton Drive…"
msgstr "Parar o Proton Drive…"
#: crates/pdfs-gui/src/main.rs:530
#: crates/pdfs-gui/src/main.rs:548
msgid "Quit"
msgstr "Sair"