mirror of
https://github.com/storytold/lightcraft.git
synced 2026-10-24 10:09:01 -06:00
Merge PR #541
This commit is contained in:
@@ -355,7 +355,7 @@ CRAFT_FONTS_DIR=../craft-fonts cargo run --release -p lightcraft
|
||||
Without it LightCraft builds and runs the same, but Chinese and Japanese text have no glyphs. Fonts are never committed to this
|
||||
repo; see [craftrules `standards/fonts.md`](https://github.com/storytold/craftrules/blob/main/standards/fonts.md).
|
||||
|
||||
**Interface language:** **Edit → Language** (English, 简体中文, 繁體中文(台灣), 日本語, Português (Brasil), Deutsch) or **Settings → General →
|
||||
**Interface language:** **Edit → Language** (English, 简体中文, 繁體中文(台灣), 日本語, Português (Brasil), Español, Deutsch, Русский, Français) or **Settings → General →
|
||||
Language**; the choice applies immediately and persists. See [docs/localization.md](docs/localization.md).
|
||||
|
||||
**Logs:** the desktop app writes its log to standard error and to `logs/lightcraft.log` in its settings folder
|
||||
|
||||
@@ -0,0 +1,210 @@
|
||||
{
|
||||
" ({unsure} with several look-alike files: use Locate)": " ({unsure} avec plusieurs fichiers similaires : utilisez Localiser)",
|
||||
" ({} in Recently Deleted)": " ({} dans « Supprimés récemment »)",
|
||||
" · {:.0}% clipped": " · {:.0}% écrêté",
|
||||
" · {failed} couldn't be rendered": " · {failed} impossible(s) à afficher",
|
||||
" · {skipped} skipped (file exists)": " · {skipped} ignoré(s) (le fichier existe)",
|
||||
" · {} duplicate{} skipped": " · {} doublon{} ignoré(s)",
|
||||
" · {} failed: {}": " · {} échec(s) : {}",
|
||||
" · {} moved": " · {} déplacé(s)",
|
||||
" · {} not readable": " · {} illisible(s)",
|
||||
" · {} original{} left at the source": " · {} original/originaux{} conservé(s) à la source",
|
||||
" · {} restored from Recently Deleted": " · {} restauré(s) depuis « Supprimés récemment »",
|
||||
" — not carried over: {}{}": " — non transféré : {}{}",
|
||||
"+{} more": "+{} de plus",
|
||||
", {failed} file{} not readable": ", {failed} fichier{} illisible(s)",
|
||||
"; {kept} already had a location": " ; {kept} possédaient déjà un emplacement",
|
||||
"; {outside} outside its time range": " ; {outside} hors de leur plage horaire",
|
||||
"@{}: {} PRs, {} commits, +{} / −{} lines (Δ {}), +{} / −{} binary assets, {} – {}": "@{} : {} PR, {} commits, +{} / −{} lignes (Δ {}), +{} / −{} ressources binaires, {} – {}",
|
||||
"Add {local_n} to My Photos": "Ajouter {local_n} à Mes photos",
|
||||
"Add {} Photo{}": "Ajouter {} photo{}",
|
||||
"Add {} Photo{}, restore {}": "Ajouter {} photo{}, restaurer {}",
|
||||
"Add “{}” to Favorites": "Ajouter « {} » aux favoris",
|
||||
"Added {n} photo{} to My Photos": "{n} photo{} ajoutée(s) à Mes photos",
|
||||
"Added {n} photo{} to “{}”": "{n} photo{} ajoutée(s) à « {} »",
|
||||
"Added {what} to {name}": "{what} ajouté à {name}",
|
||||
"Adding photos… {} of {}": "Ajout des photos… {} sur {}",
|
||||
"All {n} selected photos move by the same amount.": "Les {n} photos sélectionnées se déplacent de la même valeur.",
|
||||
"Already in the library, in Recently Deleted: {} photo{} selected · right-click ▸ Restore, or Delete Permanently to import afresh": "Déjà dans la bibliothèque, dans « Supprimés récemment » : {} photo{} sélectionnée(s) · clic droit → Restaurer, ou Supprimer définitivement pour importer à nouveau",
|
||||
"Already in the library: {} photo{} selected in All Photos": "Déjà dans la bibliothèque : {} photo{} sélectionnée(s) dans Toutes les photos",
|
||||
"Auto ({})": "Automatique ({})",
|
||||
"Auto Import: added {} photo{}": "Importation automatique : {} photo{} ajoutée(s)",
|
||||
"Auto Sync: edits apply to {n} photos": "Synchronisation automatique : les modifications s’appliquent à {n} photos",
|
||||
"Automatic ({} MB)": "Automatique ({} Mo)",
|
||||
"Build 1:1 Previews ({scope})": "Créer les aperçus 1:1 ({scope})",
|
||||
"Build Smart Previews ({scope})": "Créer les aperçus dynamiques ({scope})",
|
||||
"Build Standard-Sized Previews ({scope})": "Créer les aperçus de taille standard ({scope})",
|
||||
"Building previews for {} photos…": "Création des aperçus pour {} photos…",
|
||||
"Click {}:1": "Cliquer sur {}:1",
|
||||
"Couldn't open the editor: {e}": "Impossible d’ouvrir l’éditeur : {e}",
|
||||
"Create {n} Virtual Copies": "Créer {n} copies virtuelles",
|
||||
"Creates {} stacks from {} of {scope}": "Crée {} piles à partir de {} parmi {scope}",
|
||||
"Decoder: {reason}": "Décodeur : {reason}",
|
||||
"Delete \"{label}\"": "Supprimer « {label} »",
|
||||
"Delete \"{label}\" (and the mask)": "Supprimer « {label} » (et le masque)",
|
||||
"Delete {n} Photos": "Supprimer {n} photos",
|
||||
"Delete “{current}”": "Supprimer « {current} »",
|
||||
"Discard Smart Previews ({scope})": "Supprimer les aperçus dynamiques ({scope})",
|
||||
"Done ({what}): {done} photo{plural}": "Terminé ({what}) : {done} photo{plural}",
|
||||
"Duplicate \"{label}\"": "Dupliquer « {label} »",
|
||||
"Example: {example}": "Exemple : {example}",
|
||||
"Exported {n} photo{}": "{n} photo{} exportée(s)",
|
||||
"Exported {ok} of {total} photo{}": "{ok} photo{} exportée(s) sur {total}",
|
||||
"Exported {} point curve preset{}": "{} préréglage{} de courbe de points exporté(s)",
|
||||
"Exported {} preset{}": "{} préréglage{} exporté(s)",
|
||||
"Exporting {} of {total}": "Exportation : {} sur {total}",
|
||||
"Filter bar — {active} active filter{}": "Barre de filtres — {active} filtre{} actif(s)",
|
||||
"Focus {:.0}": "Mise au point {:.0}",
|
||||
"Folder “{}” (and its subfolders)": "Dossier « {} » (et ses sous-dossiers)",
|
||||
"Found {n} missing photo{}; {left} still missing{unsure}": "{n} photo{} manquante(s) retrouvée(s) ; {left} toujours manquante(s){unsure}",
|
||||
"Healed {n} dust spot{}": "{n} tache{} de poussière corrigée(s)",
|
||||
"Import cancelled · {} photo{} added": "Importation annulée · {} photo{} ajoutée(s)",
|
||||
"Import failed: {e}": "Échec de l’importation : {e}",
|
||||
"Imported {n} point curve preset{}": "{n} préréglage{} de courbe de points importé(s)",
|
||||
"Imported {n} preset{}": "{n} préréglage{} importé(s)",
|
||||
"Imported {n} preset{}, {f} file{} not readable": "{n} préréglage{} importé(s), {f} fichier{} illisible(s)",
|
||||
"Imported {profiles} profile{} (Profile browser ▸ their groups)": "{profiles} profil{} importé(s) (Navigateur de profils → leurs groupes)",
|
||||
"Imported {} photo{}": "{} photo{} importée(s)",
|
||||
"Insert at the cursor (also written {})": "Insérer à la position du curseur (également écrit {})",
|
||||
"Label Set: {name}": "Ensemble d’étiquettes : {name}",
|
||||
"LightCraft could not open its window: {e}": "LightCraft n’a pas pu ouvrir sa fenêtre : {e}",
|
||||
"LightCraft could not open its window: {e}\n\nThe log file has the details: {path}": "LightCraft n’a pas pu ouvrir sa fenêtre : {e}\n\nConsultez le fichier journal pour plus de détails : {path}",
|
||||
"Lightroom catalog inspected: {photos} photos, {collections} collections, {missing} missing": "Catalogue Lightroom analysé : {photos} photos, {collections} collections, {missing} manquante(s)",
|
||||
"Lightroom import complete: {imported} photos added": "Importation Lightroom terminée : {imported} photos ajoutées",
|
||||
"Lightroom import complete: {imported} photos added, {failed} failed": "Importation Lightroom terminée : {imported} photos ajoutées, {failed} échec(s)",
|
||||
"Lightroom import complete: {imported} photos added; index warning: {warning}": "Importation Lightroom terminée : {imported} photos ajoutées ; avertissement d’index : {warning}",
|
||||
"Lightroom import failed: {e}{warning}": "Échec de l’importation Lightroom : {e}{warning}",
|
||||
"Lightroom inspection failed: {e}{warning}": "Échec de l’analyse Lightroom : {e}{warning}",
|
||||
"MIT OR Apache-2.0. Fonts: {} (OFL). Icons: original.": "MIT ou Apache-2.0. Polices : {} (OFL). Icônes : originales.",
|
||||
"Matches: {}": "Correspondances : {}",
|
||||
"Merging… {stage} {:.0}%": "Fusion… {stage} {:.0}%",
|
||||
"Move {what} to Recently Deleted?": "Déplacer {what} vers « Supprimés récemment » ?",
|
||||
"Named ({named_n})": "Nommés ({named_n})",
|
||||
"Painting “{k}”: click photos to add or remove it · Esc stops": "Application de « {k} » : cliquez sur les photos pour l’ajouter ou le retirer · Échap pour arrêter",
|
||||
"Paste into {n} photo{} — only settings that were copied are pasted": "Coller dans {n} photo{} — seuls les réglages copiés seront collés",
|
||||
"Preset: {name}": "Préréglage : {name}",
|
||||
"Preview only — editing the camera's embedded JPEG ({})": "Aperçu uniquement — modification du JPEG intégré de l’appareil photo ({})",
|
||||
"Preview only — {}": "Aperçu uniquement — {}",
|
||||
"Previews ready for {done} photo{plural}": "Aperçus prêts pour {done} photo{plural}",
|
||||
"Profile: {}": "Profil : {}",
|
||||
"Proof Copy ({})": "Copie d’épreuve ({})",
|
||||
"Proof Preview · {}": "Aperçu d’épreuve · {}",
|
||||
"Quick Develop · {n} photos": "Développement rapide · {n} photos",
|
||||
"Quick Develop: {name}": "Développement rapide : {name}",
|
||||
"Rated {}": "Noté {}",
|
||||
"Reading Lightroom catalog… {done} of {total}": "Lecture du catalogue Lightroom… {done} sur {total}",
|
||||
"Reading photos… {done} of {total}": "Lecture des photos… {done} sur {total}",
|
||||
"Reading photos… {} of {}": "Lecture des photos… {} sur {}",
|
||||
"Redo {}": "Rétablir {}",
|
||||
"Remove “{name}” and its {count} photo{} from the library?": "Retirer « {name} » et ses {count} photo{} de la bibliothèque ?",
|
||||
"Remove “{}” from Favorites": "Retirer « {} » des favoris",
|
||||
"Removed from {}": "Retiré de {}",
|
||||
"Removed {what} from {name}": "{what} retiré de {name}",
|
||||
"Rename {n} Photos…": "Renommer {n} photos…",
|
||||
"Rename “{name}”": "Renommer « {name} »",
|
||||
"Renames “{from}” on {n} photo{} (keywords below it too). Use | for levels, e.g. Travel|Italy. An existing name merges the two.": "Renomme « {from} » sur {n} photo{} (ainsi que les mots-clés qui en dépendent). Utilisez | pour séparer les niveaux, par ex. Voyages|Italie. Si le nom existe déjà, les deux sont fusionnés.",
|
||||
"Rendering on the CPU: {why}": "Rendu sur le processeur : {why}",
|
||||
"Replace {} with:": "Remplacer {} par :",
|
||||
"Reset {name}": "Réinitialiser {name}",
|
||||
"Reset {} Channel": "Réinitialiser le canal {}",
|
||||
"Restore {}": "Restaurer {}",
|
||||
"Restore {} Photo{}": "Restaurer {} photo{}",
|
||||
"Saved export preset “{}”": "Préréglage d’exportation « {} » enregistré",
|
||||
"Scores {scope} for focus and exposure and finds similar shots taken within seconds of each other (bursts).": "Évalue la mise au point et l’exposition de {scope}, puis repère les prises similaires réalisées à quelques secondes d’intervalle (rafales).",
|
||||
"Show {hidden} hidden location{}": "Afficher {hidden} emplacement{} masqué(s)",
|
||||
"Showing {n} of {}": "Affichage de {n} sur {}",
|
||||
"Smart album: {}": "Album dynamique : {}",
|
||||
"Tagged {n} photo{} from the tracklog": "{n} photo{} géolocalisée(s) à partir du journal de trajet",
|
||||
"The SAM 3 download failed: {e}": "Échec du téléchargement de SAM 3 : {e}",
|
||||
"Undo {}": "Annuler {}",
|
||||
"Unknown tag{s} {} stay{} as typed (see Tags)": "Les étiquettes inconnues{s} {} restent{} telles quelles (voir Étiquettes)",
|
||||
"Updated “{name}”": "« {name} » mis à jour",
|
||||
"Version {} — a clean-room, pure-Rust photo library and raw developer.": "Version {} — bibliothèque photo et développeur RAW en Rust pur, développés indépendamment.",
|
||||
"Version: {}": "Version : {}",
|
||||
"Virtual copy “{name}” of {of}": "Copie virtuelle « {name} » de {of}",
|
||||
"Working on {what} for {} photos…": "Traitement de {what} pour {} photos…",
|
||||
"none (CPU rendering): {why}": "aucun (rendu sur le processeur) : {why}",
|
||||
"the {n} selected photos": "les {n} photos sélectionnées",
|
||||
"the {} photos in view": "les {} photos affichées",
|
||||
"these {count} photos": "ces {count} photos",
|
||||
"{count} smart preview{} · {:.1} MB": "{count} aperçu{0} dynamique{0} · {1:.1} Mo",
|
||||
"{f} folders (and their subfolders)": "{f} dossier(s) (et leurs sous-dossiers)",
|
||||
"{label} Grading": "Étalonnage de {label}",
|
||||
"{label} {d:+} on every selected photo": "{label} {d:+} sur chaque photo sélectionnée",
|
||||
"{label} {index} of {n}": "{label} {index} sur {n}",
|
||||
"{label}, {n} photos": "{label}, {n} photos",
|
||||
"{matching} of {t} photos": "{matching} sur {t} photos",
|
||||
"{matching} photos": "{matching} photos",
|
||||
"{mode} spot {} of {}": "Tache {mode} {} sur {}",
|
||||
"{month}": "{month:02}",
|
||||
"{month} {year}": "{month:02}/{year}",
|
||||
"{msg} ({failed} failed)": "{msg} ({failed} échec(s))",
|
||||
"{name} Label": "Étiquette {name}",
|
||||
"{name} Off": "{name} : désactivé",
|
||||
"{name} On": "{name} : activé",
|
||||
"{name} opened for editing; it is stacked with the original": "{name} ouvert pour modification ; il est empilé avec l’original",
|
||||
"{name} — double-click to reset it": "{name} — double-cliquez pour réinitialiser",
|
||||
"{n} change{} couldn't be written to disk: {e}\nIf you quit now, {} lost.": "Impossible d’écrire {n} modification{} sur le disque : {e}\nSi vous quittez maintenant, {} seront perdues.",
|
||||
"{n} change{} saved in memory but not written to disk: {e}\nLightCraft retries automatically; quitting now would lose {}.": "{n} modification{} enregistrée(s) en mémoire mais non écrite(s) sur le disque : {e}\nLightCraft réessaiera automatiquement ; quitter maintenant entraînerait la perte de {}.",
|
||||
"{n} change{} saved in memory but not written to disk: {e} — LightCraft will retry": "{n} modification{} enregistrée(s) en mémoire mais non écrite(s) sur le disque : {e} — LightCraft réessaiera.",
|
||||
"{n} found · {sel} selected": "{n} trouvé(s) · {sel} sélectionné(s)",
|
||||
"{n} photos": "{n} photos",
|
||||
"{n} photos in {} are hidden by the filters above": "Les filtres ci-dessus masquent {n} photos dans {}",
|
||||
"{n} photo{}": "{n} photo{}",
|
||||
"{n} photo{} match · updates automatically as photos change": "{n} photo{} correspondante(s) · mise à jour automatique lorsque les photos changent",
|
||||
"{n} photo{} now · updates automatically as photos change": "{n} photo{} actuellement · mise à jour automatique lorsque les photos changent",
|
||||
"{pid} (missing)": "{pid} (manquant)",
|
||||
"{sel_n} selected · {counted}": "{sel_n} sélectionné(s) · {counted}",
|
||||
"{stage}… {:.0}%": "{stage}… {:.0}%",
|
||||
"{verb} {n} Photo{}": "{verb} {n} photo{}",
|
||||
"{weekday}, {day}": "{weekday} {day}",
|
||||
"{weekday}, {day} {month} {year}": "{weekday} {day} {month} {year}",
|
||||
"{what} merge added": "Fusion de {what} ajoutée",
|
||||
"{what} merge failed: {e}": "Échec de la fusion de {what} : {e}",
|
||||
"{year}": "{year}",
|
||||
"{{date:…}} directives: {}": "Directives {{date:…}} : {}",
|
||||
"{} and higher": "{} et plus",
|
||||
"{} contributors · {} commits": "{} contributeurs · {} commits",
|
||||
"{} failed": "{} échec(s)",
|
||||
"{} files": "{} fichiers",
|
||||
"{} files and {f} folder{}": "{} fichiers et {f} dossier{}",
|
||||
"{} item{}": "{} élément{}",
|
||||
"{} of 4 guides — drag along lines that should be vertical or horizontal.": "{} guides sur 4 — faites-les glisser le long des lignes qui doivent être verticales ou horizontales.",
|
||||
"{} photos": "{} photos",
|
||||
"{} photos · exposures {} EV": "{} photos · expositions {} EV",
|
||||
"{} photos · {} · {:.0}° × {:.0}°": "{} photos · {} · {:.0}° × {:.0}°",
|
||||
"{} photo{} not readable": "{} photo{} illisible(s)",
|
||||
"{} sample{}": "{} échantillon{}",
|
||||
"{} sec": "{} s",
|
||||
"{} spot(s) on this photo": "{} tache(s) sur cette photo",
|
||||
"{} — show their photos": "{} — afficher leurs photos",
|
||||
"· {dups} already in the library": "· déjà dans la bibliothèque : {dups}",
|
||||
"· {n} photo{}": "· {n} photo{}",
|
||||
"… and {more} more": "… et {more} de plus",
|
||||
"LightCraft can't decode this raw variant yet ({}). You're editing the camera's embedded JPEG preview, which already includes the camera's picture style (e.g. Monochrome) and white balance.": "LightCraft ne peut pas encore décoder cette variante RAW ({}). Vous modifiez l’aperçu JPEG intégré de l’appareil photo, qui inclut déjà le style d’image (par ex. monochrome) et la balance des blancs de l’appareil.",
|
||||
"Filtered: {label}": "Filtré : {label}",
|
||||
"{n} similar photo{} · View ▸ Clear Filters to see all": "{n} photo{} similaire(s) · Affichage → Effacer les filtres pour tout voir",
|
||||
"Moved; {} photo(s) relinked": "Déplacé ; {} photo(s) de nouveau associée(s)",
|
||||
"{} label (click more labels to show any of them)": "Étiquette {} (cliquez sur « autres étiquettes » pour afficher celles de votre choix)",
|
||||
", {} star{}": ", {} étoile{}",
|
||||
", {} label": ", étiquette {}",
|
||||
"Downloads from {host}. Once it has arrived and checked out, LightCraft installs it, {after}.": "Téléchargement depuis {host}. Une fois le téléchargement terminé et vérifié, LightCraft l’installe, {after}.",
|
||||
"{:.1} MB": "{:.1} Mo",
|
||||
"Running on the processor: {}.": "Exécution sur le processeur : {}.",
|
||||
"{} · {}. Kept in the library's “denoise” folder; the oldest ones that no photo uses go first when the limit is reached.": "{} · {}. Conservé dans le dossier « denoise » de la bibliothèque ; lorsque la limite est atteinte, les fichiers les plus anciens inutilisés par les photos sont supprimés en premier.",
|
||||
"Denoising {name}: {done} of {total} tiles{}": "Réduction du bruit de {name} : {done} sur {total} tuile{}",
|
||||
"{size} GB": "{size} Go",
|
||||
"{} of {} from {host}": "{} sur {} depuis {host}",
|
||||
"{} KB": "{} Ko",
|
||||
"{} MB": "{} Mo",
|
||||
"Making the denoised picture… {}%": "Création de l’image débruitée… {}%",
|
||||
"{name} · {terms}": "{name} · {terms}",
|
||||
"{n} {noun}": "{n} {noun}",
|
||||
"Trained on: {provenance}": "Entraîné sur : {provenance}",
|
||||
" · {queued} waiting": " · {queued} en attente",
|
||||
"Shows the model's terms, then downloads {} from {host}, installs it and starts using it. Nothing else is sent.": "Affiche les conditions du modèle, puis télécharge {} depuis {host}, l’installe et commence à l’utiliser. Aucune autre donnée n’est envoyée.",
|
||||
"In line for AI Denoise ({ahead} ahead)…": "En attente de la réduction du bruit par IA ({ahead} devant)…",
|
||||
"Running on {}.": "En cours d’exécution sur {}.",
|
||||
"{file} · {size}": "{file} · {size}",
|
||||
"• {assumption}": "• {assumption}"
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -124,6 +124,7 @@ language_table! {
|
||||
Es, "es", "Español", "Latn", include_str!("../locales/es.json");
|
||||
De, "de", "Deutsch", "Latn", include_str!("../locales/de.json");
|
||||
Ru, "ru", "Русский", "Cyrl", include_str!("../locales/ru.json");
|
||||
Fr, "fr", "Français", "Latn", include_str!("../locales/fr.json");
|
||||
}
|
||||
|
||||
// The settings file stores the BCP-47 code (`"zh-hans"`), never the Rust variant name, so a
|
||||
@@ -508,6 +509,9 @@ mod tests {
|
||||
assert_eq!(Locale::parse_tag("pt-BR"), Some(Locale::PtBr));
|
||||
assert_eq!(Locale::parse_tag("pt_BR.UTF-8"), Some(Locale::PtBr));
|
||||
assert_eq!(Locale::parse_tag("pt"), Some(Locale::PtBr));
|
||||
assert_eq!(Locale::parse_tag("fr"), Some(Locale::Fr));
|
||||
assert_eq!(Locale::parse_tag("fr-FR"), Some(Locale::Fr));
|
||||
assert_eq!(Locale::parse_tag("fr_FR.UTF-8"), Some(Locale::Fr));
|
||||
for tag in ["de", "de-DE", "de_AT.UTF-8", "de-CH"] {
|
||||
assert_eq!(Locale::parse_tag(tag), Some(Locale::De), "{tag}");
|
||||
}
|
||||
@@ -552,6 +556,9 @@ mod tests {
|
||||
set_language(Locale::Ja);
|
||||
assert_eq!(tr_format!("Imported {} photo{}", 12, "s"), "12枚を読み込みました");
|
||||
assert_eq!(tr_format!("Exported {ok} of {total} photo{}", "s", ok = 4, total = 12), "12枚中4枚を書き出しました");
|
||||
set_language(Locale::Fr);
|
||||
assert_eq!(tr_format!("Imported {} photo{}", 12, "s"), "12 photos importée(s)");
|
||||
assert_eq!(tr_format!("Imported {} photo{}", 1, ""), "1 photo importée(s)");
|
||||
// Format specs survive translation: precision, sign, and values a language reorders.
|
||||
for language in Locale::ALL {
|
||||
set_language(*language);
|
||||
@@ -654,6 +661,7 @@ mod tests {
|
||||
("app.language.simplifiedChinese", Locale::ZhHans),
|
||||
("app.language.japanese", Locale::Ja),
|
||||
("app.language.portuguese", Locale::PtBr),
|
||||
("app.language.french", Locale::Fr),
|
||||
("app.language.spanish", Locale::Es),
|
||||
("app.language.german", Locale::De),
|
||||
("app.language.russian", Locale::Ru),
|
||||
|
||||
@@ -19,6 +19,7 @@ pub const LANGUAGE_COMMANDS: &[UiCommand] = &[
|
||||
("app.language.traditionalChinese", crate::i18n::Locale::ZhHant.name(), None, "Edit>Language"),
|
||||
("app.language.japanese", crate::i18n::Locale::Ja.name(), None, "Edit>Language"),
|
||||
("app.language.portuguese", crate::i18n::Locale::PtBr.name(), None, "Edit>Language"),
|
||||
("app.language.french", crate::i18n::Locale::Fr.name(), None, "Edit>Language"),
|
||||
("app.language.spanish", crate::i18n::Locale::Es.name(), None, "Edit>Language"),
|
||||
("app.language.german", crate::i18n::Locale::De.name(), None, "Edit>Language"),
|
||||
("app.language.russian", crate::i18n::Locale::Ru.name(), None, "Edit>Language"),
|
||||
@@ -39,6 +40,7 @@ pub fn language_from_command(id: &str) -> Option<crate::i18n::Locale> {
|
||||
"app.language.traditionalChinese" => Some(crate::i18n::Locale::ZhHant),
|
||||
"app.language.japanese" => Some(crate::i18n::Locale::Ja),
|
||||
"app.language.portuguese" => Some(crate::i18n::Locale::PtBr),
|
||||
"app.language.french" => Some(crate::i18n::Locale::Fr),
|
||||
"app.language.spanish" => Some(crate::i18n::Locale::Es),
|
||||
"app.language.german" => Some(crate::i18n::Locale::De),
|
||||
"app.language.russian" => Some(crate::i18n::Locale::Ru),
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
The interface ships in the language it is written in (English) plus every language in the table in
|
||||
`crates/ui-egui/src/i18n.rs`. Today that is English, Simplified Chinese (`zh-hans`), Traditional
|
||||
Chinese (`zh-hant`, Taiwan), Japanese (`ja`), Brazilian Portuguese (`pt-br`), Spanish (`es`), German (`de`) and Russian (`ru`). This file is the reference for **adding or maintaining a language**; the per-language notes
|
||||
Chinese (`zh-hant`, Taiwan), Japanese (`ja`), Brazilian Portuguese (`pt-br`), Spanish (`es`), German (`de`), Russian (`ru`) and French (`fr`). This file is the reference for **adding or maintaining a language**; the per-language notes
|
||||
are in [`localization-zh-hans.md`](localization-zh-hans.md), [`localization-zh-hant.md`](localization-zh-hant.md),
|
||||
[`localization-ja.md`](localization-ja.md), [`localization-pt-br.md`](localization-pt-br.md), [`localization-es.md`](localization-es.md),
|
||||
[`localization-de.md`](localization-de.md) and [`localization-ru.md`](localization-ru.md).
|
||||
|
||||
+1
-1
@@ -528,7 +528,7 @@ under the UI command that wraps it (a no-op error); the UI command now wins.
|
||||
| LR-BEHAV-TEXTFIELD | Text fields behave alike | P1 | 🟡 | `crates/ui-egui/src/text_field.rs`, `crates/ui-egui/src/panels/topbar.rs`, `crates/ui-egui/src/widgets.rs`, `crates/ui-egui/src/panels/right.rs` (`meta_field`), `crates/ui-egui/src/panels/dialogs.rs`, `crates/ui-egui/src/panels/unnamed.rs` | one shared field: right-click Cut / Copy / Paste / Select All (no Paste in the browser), Esc gives back the text from before the edit, Return / leaving / Esc reported to the caller, optional select-on-focus; agents use `ui.clipboard` (MCP `clipboard`) and `ui.inspect` → `copied`. Used by Search Photos, slider values, the Info panel's metadata fields (multi-line captions), the one-field dialogs (New / Rename Album, New Smart Album, Rename / Merge Keywords, text prompts) and the unnamed faces' name field so far; the other text fields (most dialogs, import, settings, masking, keywords …) still use egui's own and have no menu |
|
||||
| LR-BEHAV-HEADLESS | Headless UI snapshots | P2 | ✅ | `apps/lightcraft-cli/src/main.rs`, `crates/ui-egui/src/headless.rs`, `docs/control-protocol.md` | `snapshot` rasterizes the UI and defaults photo development to the CPU before the first frame, without adapter discovery; scaled dimensions are validated before allocation, and UI zoom preserves the requested physical viewport; JSON-lines control scripts are supported |
|
||||
| LR-BEHAV-ACCESS | Accessibility | P2 | 🟡 | `crates/ui-egui/src/widgets.rs`, `crates/ui-egui/src/panels/grid.rs` | AccessKit (VoiceOver / Narrator / AT-SPI): sliders announce control and value, buttons / icon buttons / dropdowns / section headers / sources their labels and state, grid thumbnails file name, rating, flag and label; the canvas tools (crop, masks) are pointer-only; not audited with a screen reader |
|
||||
| LR-BEHAV-LOCALE | Language options | P2 | ✅ | `cmd:app.language.english`, `cmd:app.language.simplifiedChinese`, `cmd:app.language.traditionalChinese`, `cmd:app.language.japanese`, `cmd:app.language.portuguese`, `cmd:app.language.spanish`, `cmd:app.language.german`, `cmd:app.language.russian` | Edit > Language lists every language in the table and the active one is checked; shared with Settings > General (docs/localization.md) |
|
||||
| LR-BEHAV-LOCALE | Language options | P2 | ✅ | `cmd:app.language.english`, `cmd:app.language.simplifiedChinese`, `cmd:app.language.traditionalChinese`, `cmd:app.language.japanese`, `cmd:app.language.portuguese`, `cmd:app.language.french`, `cmd:app.language.spanish`, `cmd:app.language.german`, `cmd:app.language.russian` | Edit > Language lists every language in the table and the active one is checked; shared with Settings > General (docs/localization.md) |
|
||||
| LR-BEHAV-LOCALIZE | Localisation | P2 | 🟡 | `crates/ui-egui/src/i18n.rs`, `crates/ui-egui/locales/`, `docs/localization.md`, `docs/localization-zh-hans.md`, `docs/localization-zh-hant.md`, `docs/localization-ja.md`, `docs/localization-pt-br.md`, `docs/localization-es.md`, `docs/localization-de.md`, `docs/localization-ru.md` | One table entry per language (code, endonym, ISO 15924 script, catalog): English, Simplified Chinese, Traditional Chinese (Taiwan), Japanese, Brazilian Portuguese, Spanish, German and Russian UI with a persisted language preference and craft-fonts regular/bold faces per script; menus, edit, crop/masks, settings, import/export and primary progress messages. Adding a language is a table entry plus two catalogs. Stock presets/profiles, history steps, library headings, date headings and capture times are localised (user-named items stay verbatim); the German catalog covers every existing catalog key, command/control label and rule-editor label; the other catalogs fall back to English for messages they lack. Technical errors remain English; release notes are translated in German; Traditional Chinese borrows the Simplified Chinese face (no TC face in craft-fonts yet), and the web build embeds the Japanese face in WASM while loading the Simplified Chinese face from a separate font file. |
|
||||
| LR-BEHAV-LEARN | Tutorials | OOS | 🚫 | | |
|
||||
| LR-BEHAV-WHATSNEW | What's new | P2 | ✅ | `cmd:app.whatsNew`, `docs/whats-new.md` | Help ▸ What's New: release highlights |
|
||||
|
||||
Reference in New Issue
Block a user