diff --git a/crates/ui-egui/locales/fr-formats.json b/crates/ui-egui/locales/fr-formats.json index ae832f80e..41756bbe0 100644 --- a/crates/ui-egui/locales/fr-formats.json +++ b/crates/ui-egui/locales/fr-formats.json @@ -298,7 +298,7 @@ "Move {n} photo{} to “{}”": "Déplacer {n} photo{} vers « {} »", "Move {n} photo{} to “{}”?": "Déplacer {n} photo{} vers « {} » ?", "Listing folders — folders: {folders}, files: {files}": "Liste des dossiers — dossiers : {folders}, fichiers : {files}", - "Moved {n} photo{} to “{}”. Edit → Undo moves them back.": "{n} photo{} déplacée(s) vers « {} ». Modifier → Annuler les remet en place.", + "Moved {n} photo{} to “{}”. Edit → Undo moves them back.": "{n} photo{0} déplacée{0} vers « {1} ». Modifier → Annuler les remet en place.", "Drop to review {n} item{} for import": "Déposez pour vérifier {n} élément{} avant l'import", "Drop to import {n} item{}": "Déposez pour importer {n} élément{}", "Drop to import {n} preset{}": "Déposez pour importer {n} préréglage{}", diff --git a/docs/localization-parity.md b/docs/localization-parity.md index 8a7ea2007..f2f94532c 100644 --- a/docs/localization-parity.md +++ b/docs/localization-parity.md @@ -62,7 +62,7 @@ string follows that. | 11 | Korean | `ko` | 0 (0%) | none | **no Korean (Hangul) face**: needs a non-Adobe OFL face in craft-fonts (Noto CJK is allowed only for Chinese) | no | none | 14–22 h | | 12 | Vietnamese | `vi` | 2,471 / 2,471 (100% key coverage of current union; intentional English like `ISO`/`OK` kept) | menus, panels, dialogs, presets, profiles, dates, formats; lower-layer errors English | Latin with stacked diacritics (Inter) | no (community contribution) | partial (catalog complete; lower-layer errors English) | 1–3 h | -## Other languages LightCraft ships (4) +## Other languages LightCraft ships (7) | Language | Code | UI strings translated | Script | Native review | Status | To `full` | |---|---|---:|---|---|---|---:| @@ -74,7 +74,7 @@ string follows that. | Finnish | `fi` | 2,610 / 3,308 (79%, measured 2026-10-17: 2,313 plain + 297 formats; the rest is What's New) | Latin (Inter) | yes (written with an agent; native-speaker review by @roopeg) | partial (lower-layer errors English) | 3–5 h | | Polish | `pl` | 2,159 messages + 291 formats; every format message translated (2026-10-15) | Latin (Inter) | no (AI-drafted; follow-up by a native speaker) | partial (lower-layer errors English) | 2–4 h (full native review) | -Target languages LightCraft lacks: Korean, Dutch, Swedish, Norwegian Bokmål, Thai +Target languages LightCraft lacks: Korean, Dutch, Norwegian Bokmål, Thai (Thai needs shaping and line breaking without spaces). Each Latin-script one is ~10–16 h; Thai ~20–35 h on top of the shaping work. @@ -91,9 +91,9 @@ Target languages LightCraft lacks: Korean, Dutch, Swedish, Norwegian Bokmål, Th ## Totals -- Bring the 10 shipped non-English catalogs to `full`: ~55–90 h (incl. the shared work). +- Bring the shipped non-English catalogs to `full` (17 on 2026-10-23; the estimate was made for 10): ~55–90 h (incl. the shared work). - Add the 5 missing key languages: ~145–255 h, most of it RTL and complex shaping in egui. -- Reach the target's 16 languages: + ~50–85 h (Dutch, Polish, Swedish, Norwegian, Thai). +- Reach the target's 16 languages: + ~30–55 h (Dutch, Norwegian, Thai; Polish and Swedish ship). ## Revision history diff --git a/xtask/src/ci_lock.rs b/xtask/src/ci_lock.rs index 321b0f391..9504beb20 100644 --- a/xtask/src/ci_lock.rs +++ b/xtask/src/ci_lock.rs @@ -56,13 +56,20 @@ fn owner_path(lock: &Path) -> PathBuf { lock.with_extension("lock.owner") } +/// What to do when the lock itself can't be set up (read-only home, sandbox, network mount). +const LOCK_HINT: &str = "set LIGHTCRAFT_CI_LOCK=off to run without the lock, or LIGHTCRAFT_CI_LOCK= to keep it elsewhere"; + /// Take the first free slot of `slots` in `dir`, or `None` when all are held. pub fn try_acquire(dir: &Path, slots: usize, owner: &str) -> Result, String> { - std::fs::create_dir_all(dir).map_err(|e| format!("ci lock: {}: {e}", dir.display()))?; + std::fs::create_dir_all(dir).map_err(|e| format!("ci lock: {}: {e} ({LOCK_HINT})", dir.display()))?; for slot in 0..slots.max(1) { let path = slot_path(dir, slot); - let file = - OpenOptions::new().create(true).truncate(false).write(true).open(&path).map_err(|e| format!("ci lock: {}: {e}", path.display()))?; + let file = OpenOptions::new() + .create(true) + .truncate(false) + .write(true) + .open(&path) + .map_err(|e| format!("ci lock: {}: {e} ({LOCK_HINT})", path.display()))?; match file.try_lock() { Ok(()) => { // a sidecar file, not the lock file: Windows locks are mandatory, so others couldn't read it @@ -71,7 +78,7 @@ pub fn try_acquire(dir: &Path, slots: usize, owner: &str) -> Result return Ok(Some(Held { _file: file, owner: owner_file })); } Err(TryLockError::WouldBlock) => continue, - Err(TryLockError::Error(e)) => return Err(format!("ci lock: {}: {e}", path.display())), + Err(TryLockError::Error(e)) => return Err(format!("ci lock: {}: {e} ({LOCK_HINT})", path.display())), } } Ok(None)