mirror of
https://github.com/storytold/lightcraft.git
synced 2026-10-24 10:09:01 -06:00
Merge PR #2295: i18n: Indonesian (id) interface language
Conflicts: - crates/ui-egui/src/i18n.rs, crates/ui-egui/src/menus.rs: language table and commands keep sv, fi and id - crates/ui-egui/src/panels/keyword_list.rs: code list gains id; Locale::ALL.len() is 17 - docs/localization.md: language list and note links keep every language - docs/localization-parity.md: header keeps the newer date and both changes; links and revision rows are the union
This commit is contained in:
+3
-2
@@ -49,7 +49,7 @@ Hours are calibrated on this repo's PR history; see
|
||||
| UI/UX fidelity | ~70% | ~85% | 32–54 h | [ui-parity](docs/ui-parity.md) |
|
||||
| File formats (non-raw) | ~70% | ~85% | 30–55 h | [file-format-parity](docs/file-format-parity.md) |
|
||||
| Hardware | ~40% | ~50% | 40–80 h | [hardware-parity](docs/hardware-parity.md) |
|
||||
| Localization | ~55% of the 12 key languages | 7 of 12 present | 130–210 h (+145–255 h new scripts) | [localization-parity](docs/localization-parity.md) |
|
||||
| Localization | ~64% of the 12 key languages | 8 of 12 present | 130–210 h (+135–239 h new scripts) | [localization-parity](docs/localization-parity.md) |
|
||||
| Performance | ~70% | ~80% | 30–50 h | [target-app-parity](docs/target-app-parity.md#by-dimension) |
|
||||
| Stability | ~60% | — | 30–60 h | [target-app-parity](docs/target-app-parity.md#by-dimension) |
|
||||
| Platforms | ~60% | macOS, Windows, Linux, FreeBSD, web | 25–45 h | [target-app-parity](docs/target-app-parity.md#by-dimension) |
|
||||
@@ -90,7 +90,7 @@ while lower-layer errors stay English. Detail: [localization-parity.md](docs/loc
|
||||
| Arabic | ar | 0% | none (no RTL / shaping) |
|
||||
| French | fr | 88% | partial |
|
||||
| Portuguese (Brazil) | pt-br | 85% | partial |
|
||||
| Indonesian | id | 0% | none |
|
||||
| Indonesian | id | 100% (What's New in English) | partial |
|
||||
| Japanese | ja | 87% | partial |
|
||||
| German | de | 91% | partial |
|
||||
| Korean | ko | 0% | none (no Hangul face) |
|
||||
@@ -183,6 +183,7 @@ Ranked toward beta; detail in [docs/roadmap.md](docs/roadmap.md), gaps in [docs/
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-10-19 | minor | Indonesian interface (`id`): every plain and formats message, plus 69 command labels, locale, menu command and tests; What's New left in English; Localization ~55% → ~64% (mean of the 12 key languages), 8 of 12 present |
|
||||
| 2026-10-12 | minor | Italian interface (`it`, #1192): 2,201 of 2,398 messages, locale, menu command and tests; headline numbers unchanged |
|
||||
| 2026-10-13 | minor | Sony ILCA-99M2 camera colour profile in the log; numbers unchanged |
|
||||
| 2026-10-14 | minor | Localization ~52% → ~55% (mean of the 12 key languages): de, es, fr, ja and uk catalogs filled |
|
||||
|
||||
@@ -33,6 +33,7 @@ covers a whole directory), or if a licence file referenced in the Licence column
|
||||
| `crates/ui-egui/locales/uk.json`, `crates/ui-egui/locales/uk-formats.json` | Ukrainian interface catalogs | @dmatviichuk with Codex; PhotoCraft, FilmCraft and VectorCraft translation contributors for reused labels | original translations from English source; 337 initial English-key matches reviewed from [PhotoCraft 69c41f3](https://github.com/storytold/photocraft/blob/69c41f3523e147eb215da8c7b4c29b18b35d1c63/crates/ui-egui/src/i18n/uk.tsv), [FilmCraft 4854c27](https://github.com/storytold/filmcraft/blob/4854c277536fe8118257362304b6a7d82d8e704b/crates/ui-egui/src/i18n/uk.tsv), [VectorCraft 4b44265](https://github.com/storytold/vectorcraft/blob/4b44265965fdd6ffedfd6182a892c1a6c360d344/crates/ui-egui/src/i18n/uk.tsv) | MIT OR Apache-2.0 (`LICENSE-MIT`, `LICENSE-APACHE`, also the source repositories' licences) | 2026-10-09 | adapted to LightCraft photo-development context, completed catalogs, reviewed spelling and placeholders |
|
||||
| `crates/ui-egui/locales/cs.json`, `crates/ui-egui/locales/cs-formats.json` | Czech interface catalogs | @Losminek with AI assistance (Codex) | original work: translations of English source phrases, reviewed against the app UI conventions; no external translation material | MIT OR Apache-2.0 (`LICENSE-MIT`, `LICENSE-APACHE`) | 2026-10-11 | catalog coverage, Czech dates and count-neutral wording; independent scope/terminology review; native-speaker proofreading pending |
|
||||
| `crates/ui-egui/locales/it.json`, `crates/ui-egui/locales/it-formats.json` | Italian interface catalogs | @GabrielePecchioli with Claude Code; PhotoCraft, VectorCraft, PdfCraft and WordCraft translation contributors for reused labels | original translations from English source; 410 initial English-key matches reviewed from [PhotoCraft da3da09](https://github.com/storytold/photocraft/blob/da3da0942c14c1159f40c652afcf33584332c733/crates/ui-egui/src/i18n/it.tsv), [VectorCraft 5432821](https://github.com/storytold/vectorcraft/blob/543282148007bcb5633c493a5374cd26b0339c8d/crates/ui-egui/src/i18n/it.tsv), [PdfCraft e8e275c](https://github.com/storytold/pdfcraft/blob/e8e275cbd40ccd0dc6b56f82b16a575571043702/crates/ui-egui/src/i18n/it.tsv) and the Italian WordCraft catalog ([storytold/wordcraft#598](https://github.com/storytold/wordcraft/pull/598)); 46 of them retranslated where the sibling's meaning didn't fit a photo app | MIT OR Apache-2.0 (`LICENSE-MIT`, `LICENSE-APACHE`, also the source repositories' licences) | 2026-10-12 | adapted to LightCraft photo-development context, count-neutral labels for Italian plural agreement, reviewed placeholders |
|
||||
| `crates/ui-egui/locales/id.json`, `crates/ui-egui/locales/id-formats.json` | Indonesian interface catalogs | @RevDonz with Claude Code; PhotoCraft, VectorCraft, FilmCraft and FigCraft translation contributors for reused labels | original translations from English source; 356 labels match the sibling apps' Indonesian wording, reviewed from [PhotoCraft c39d752](https://github.com/storytold/photocraft/blob/c39d752758155492bbaba71d802cfaa03206fb4a/crates/ui-egui/src/i18n/id.tsv), [VectorCraft 9fe0f03](https://github.com/storytold/vectorcraft/blob/9fe0f03de2bd29e8c86a1179f977c3e651069424/crates/ui-egui/src/i18n/id.tsv), [FilmCraft fae7f8a](https://github.com/storytold/filmcraft/blob/fae7f8a9be09bd74f95fbe08c3d98adc17fe1030/crates/ui-egui/src/i18n/id.tsv) and [FigCraft 8482c3e](https://github.com/storytold/figcraft/blob/8482c3e85bc5f2a430e2f3be2826674872f6d084/crates/ui-egui/locales/id.toml) | MIT OR Apache-2.0 (`LICENSE-MIT`, `LICENSE-APACHE`, also the source repositories' licences) | 2026-10-19 | adapted to LightCraft's photo context, count-neutral nouns, reviewed placeholders |
|
||||
| `crates/ui-egui/locales/ka.json`, `crates/ui-egui/locales/ka-formats.json` | Georgian interface catalogs | Davit Matchakhelidze with Claude; WordCraft, GridCraft, PhotoCraft, FilmCraft and VectorCraft Georgian catalogs for reused labels | original translations from the English source (meaning-based, no vendor localization used); 450 English-key matches reused from the sibling Craft apps' Georgian catalogs | MIT OR Apache-2.0 (`LICENSE-MIT`, `LICENSE-APACHE`) | 2026-10-12 | adapted to LightCraft photo-library and raw-development context; count-neutral numerals; placeholders checked |
|
||||
| `crates/ui-egui/locales/sv.json`, `crates/ui-egui/locales/sv-formats.json` | Swedish interface catalogs | LightCraft contributors | original work: clean-room Swedish translations of English source phrases | MIT OR Apache-2.0 (`LICENSE-MIT`, `LICENSE-APACHE`) | 2026-10-15 | none |
|
||||
| `crates/ui-egui/locales/fi.json`, `crates/ui-egui/locales/fi-formats.json` | Finnish interface catalogs | @roopeg with Claude Code (AI-assisted; native-speaker review by @roopeg) | original work: translations of the English source phrases, using common Finnish photo-editing vocabulary; no external translation material | MIT OR Apache-2.0 (`LICENSE-MIT`, `LICENSE-APACHE`) | 2026-10-17 | count-neutral labels for Finnish partitive agreement, Finnish dates and times (`20.9.2026`, `16:04`), reviewed placeholders |
|
||||
|
||||
@@ -0,0 +1,299 @@
|
||||
{
|
||||
" · {skipped} skipped (file exists)": " · {skipped} dilewati (file sudah ada)",
|
||||
" · {} duplicate{} skipped": " · {} duplikat dilewati{:.0}",
|
||||
" · {} failed: {}": " · {} gagal: {}",
|
||||
" · {} moved": " · {} dipindahkan",
|
||||
" · {} not readable": " · {} tidak dapat dibaca",
|
||||
" · {} restored from Recently Deleted": " · {} dipulihkan dari Baru dihapus",
|
||||
", {failed} file{} not readable": ", {failed} file tidak dapat dibaca{:.0}",
|
||||
"Add {local_n} to My Photos": "Tambahkan {local_n} ke Foto saya",
|
||||
"Add {} Photo{}": "Tambahkan {} foto{:.0}",
|
||||
"Add {} Photo{}, restore {}": "Tambahkan {} foto{:.0}, pulihkan {}",
|
||||
"Add “{}” to Favorites": "Tambahkan “{}” ke Favorit",
|
||||
"Added {n} photo{} to My Photos": "{n} foto{:.0} ditambahkan ke Foto saya",
|
||||
"Added {n} photo{} to “{}”": "{n} foto ditambahkan ke “{1}”{0:.0}",
|
||||
"All {n} selected photos move by the same amount.": "Semua {n} foto yang dipilih digeser dengan selisih waktu yang sama.",
|
||||
"Already in “{}”": "Sudah ada di “{}”",
|
||||
"Auto Sync: edits apply to {n} photos": "Sinkronisasi otomatis: edit diterapkan ke {n} foto",
|
||||
"Automatic ({} MB)": "Otomatis ({} MB)",
|
||||
"Click {}:1": "Klik {}:1",
|
||||
"Color space: Rec. 2020 {curve} (HDR AVIF)": "Ruang warna: Rec. 2020 {curve} (AVIF HDR)",
|
||||
"Create {n} Virtual Copies": "Buat {n} salinan virtual",
|
||||
"Decoder: {reason}": "Dekoder: {reason}",
|
||||
"Delete \"{label}\"": "Hapus \"{label}\"",
|
||||
"Delete \"{label}\" (and the mask)": "Hapus \"{label}\" (beserta maskernya)",
|
||||
"Delete {n} Photos": "Hapus {n} foto",
|
||||
"Delete “{current}”": "Hapus “{current}”",
|
||||
"Duplicate \"{label}\"": "Duplikat \"{label}\"",
|
||||
"Example: {example}": "Contoh: {example}",
|
||||
"Exported {n} photo{}": "{n} foto{:.0} diekspor",
|
||||
"Exported {ok} of {total} photo{}": "{ok} dari {total} foto diekspor{:.0}",
|
||||
"Exported {} point curve preset{}": "{} preset kurva titik{:.0} diekspor",
|
||||
"Exported {} preset{}": "{} preset{:.0} diekspor",
|
||||
"Exporting {} of {total}": "Mengekspor {} dari {total}",
|
||||
"Filter bar — {active} active filter{}": "Bilah filter — {active} filter aktif{:.0}",
|
||||
"Healed {n} dust spot{}": "{n} bintik debu diperbaiki{:.0}",
|
||||
"Imported {n} point curve preset{}": "{n} preset kurva titik diimpor{:.0}",
|
||||
"Imported {n} preset{}": "{n} preset{:.0} diimpor",
|
||||
"Imported {n} preset{}, {f} file{} not readable": "{n} preset diimpor{0:.0}, {f} file tidak dapat dibaca{1:.0}",
|
||||
"Imported {} photo{}": "{} foto{:.0} diimpor",
|
||||
"LightCraft could not open its window: {e}": "LightCraft tidak dapat membuka jendela: {e}",
|
||||
"LightCraft could not open its window: {e}\n\nThe log file has the details: {path}": "LightCraft tidak dapat membuka jendela: {e}\n\nDetailnya ada di file log: {path}",
|
||||
"Matches: {}": "Cocok: {}",
|
||||
"Merging… {stage} {:.0}%": "Menggabungkan… {stage} {:.0}%",
|
||||
"Move {n} photo{} to “{}”": "Pindahkan {n} foto{0:.0} ke “{1}”",
|
||||
"Move {n} photo{} to “{}”?": "Pindahkan {n} foto{0:.0} ke “{1}”?",
|
||||
"Move {what} to Recently Deleted?": "Pindahkan {what} ke Baru dihapus?",
|
||||
"Moved {n} photo{} to “{}”. Edit → Undo moves them back.": "{n} foto dipindahkan ke “{1}”{0:.0}. Pilih Edit → Urungkan untuk mengembalikannya.",
|
||||
"Named ({named_n})": "Bernama ({named_n})",
|
||||
"Paste into {n} photo{} — only settings that were copied are pasted": "Tempel ke {n} foto{:.0} — hanya menempelkan pengaturan yang disalin",
|
||||
"Preset: {name}": "Preset: {name}",
|
||||
"Preview only — editing the camera's embedded JPEG ({})": "Hanya pratinjau — yang diedit adalah JPEG bawaan kamera ({})",
|
||||
"Preview only — {}": "Hanya pratinjau — {}",
|
||||
"Profile: {}": "Profil: {}",
|
||||
"Proof Copy ({})": "Salinan soft proof ({})",
|
||||
"Proof Preview · {}": "Pratinjau soft proof · {}",
|
||||
"Quick Develop · {n} photos": "Olah cepat · {n} foto",
|
||||
"Rated {}": "Diberi rating {}",
|
||||
"Reading Lightroom catalog… {done} of {total}": "Membaca katalog Lightroom… {done} dari {total}",
|
||||
"Reading photos… {done} of {total}": "Membaca foto… {done} dari {total}",
|
||||
"Redo {}": "Ulangi {}",
|
||||
"Remove “{}” from Favorites": "Keluarkan “{}” dari Favorit",
|
||||
"Removed from {}": "Dikeluarkan dari {}",
|
||||
"Rename {n} Photos…": "Ganti nama {n} foto…",
|
||||
"Rename “{name}”": "Ganti nama “{name}”",
|
||||
"Rendering on the CPU: {why}": "Merender dengan CPU: {why}",
|
||||
"Reset {} Channel": "Atur ulang kanal {}",
|
||||
"Restore {}": "Pulihkan {}",
|
||||
"Restore {} Photo{}": "Pulihkan {} foto{:.0}",
|
||||
"Restored {} photo{} from Recently Deleted": "{} foto{:.0} dipulihkan dari Baru dihapus",
|
||||
"Saved export preset “{}”": "Preset ekspor “{}” disimpan",
|
||||
"Show {hidden} hidden location{}": "Tampilkan {hidden} lokasi tersembunyi{:.0}",
|
||||
"Showing {n} of {}": "Menampilkan {n} dari {}",
|
||||
"Smart album: {}": "Album pintar: {}",
|
||||
"The XMP sidecars of {n} photos couldn't be written (is their folder offline?). LightCraft keeps trying.": "File sidecar XMP untuk {n} foto tidak dapat ditulis (apakah foldernya sedang offline?). LightCraft akan terus mencoba.",
|
||||
"Undo {}": "Urungkan {}",
|
||||
"Version {} — a clean-room, pure-Rust photo library and raw developer.": "Versi {} — pustaka foto dan pengolah raw yang dibuat secara clean-room dengan Rust murni.",
|
||||
"Version: {}": "Versi: {}",
|
||||
"none (CPU rendering): {why}": "tidak ada (rendering CPU): {why}",
|
||||
"the {n} selected photos": "{n} foto yang dipilih",
|
||||
"the {} photos in view": "{} foto yang ditampilkan",
|
||||
"these {count} photos": "{count} foto ini",
|
||||
"{count} smart preview{} · {:.1} MB": "{count} pratinjau pintar{0:.0} · {1:.1} MB",
|
||||
"{f} folders (and their subfolders)": "{f} folder (beserta subfoldernya)",
|
||||
"{label} Grading": "Grading {label}",
|
||||
"{label} {d:+} on every selected photo": "{label} {d:+} pada setiap foto yang dipilih",
|
||||
"{label}, {n} photos": "{label}, {n} foto",
|
||||
"{matching} of {t} photos": "{matching} dari {t} foto",
|
||||
"{matching} photos": "{matching} foto",
|
||||
"{mode} spot {} of {}": "{mode}: bintik {} dari {}",
|
||||
"{msg} ({failed} failed)": "{msg} ({failed} gagal)",
|
||||
"{name} Label": "Label {name}",
|
||||
"{name} Off": "{name} nonaktif",
|
||||
"{name} On": "{name} aktif",
|
||||
"{name} — double-click to reset it": "{name} — klik dua kali untuk mengatur ulang",
|
||||
"{n} change{} saved in memory but not written to disk: {e}\nLightCraft retries automatically; quitting now would lose {}.": "{n} perubahan{0:.0} tersimpan di memori, tetapi belum ditulis ke disk: {e}\nLightCraft akan otomatis mencoba lagi; jika Anda keluar sekarang, perubahan tersebut akan hilang.{1:.0}",
|
||||
"{n} found · {sel} selected": "{n} ditemukan · {sel} dipilih",
|
||||
"{n} photos": "{n} foto",
|
||||
"{n} photos in {} are hidden by the filters above": "{n} foto di {} disembunyikan oleh filter di atas",
|
||||
"{n} photo{}": "{n} foto{:.0}",
|
||||
"{n} photo{} match · updates automatically as photos change": "{n} foto cocok{:.0} · diperbarui otomatis saat foto berubah",
|
||||
"{n} photo{} now · updates automatically as photos change": "Saat ini {n} foto{:.0} · diperbarui otomatis saat foto berubah",
|
||||
"{n} selected photos · {pages} pages": "{n} foto dipilih · {pages} halaman",
|
||||
"{sel_n} selected · {counted}": "{sel_n} dipilih · {counted}",
|
||||
"{stage}… {:.0}%": "{stage}… {:.0}%",
|
||||
"{what} merge added": "Hasil penggabungan {what} ditambahkan",
|
||||
"{what} merge failed: {e}": "Penggabungan {what} gagal: {e}",
|
||||
"{} and higher": "{} ke atas",
|
||||
"{} files": "{} file",
|
||||
"{} files and {f} folder{}": "{} file dan {f} folder{:.0}",
|
||||
"{} of 4 guides — drag along lines that should be vertical or horizontal.": "{} dari 4 garis panduan — seret di sepanjang garis yang seharusnya vertikal atau horizontal.",
|
||||
"{} photos": "{} foto",
|
||||
"{} photo{} not readable": "{} foto tidak dapat dibaca{:.0}",
|
||||
"{} spot(s) on this photo": "{} bintik di foto ini",
|
||||
"· {dups} already in the library": "· {dups} sudah ada di pustaka",
|
||||
"· {n} photo{}": "· {n} foto{:.0}",
|
||||
"· {trashed} in Recently Deleted": "· {trashed} di “Baru dihapus”",
|
||||
"… and {more} more": "… dan {more} lainnya",
|
||||
"Import cancelled · {} photo{} added": "Impor dibatalkan · {} foto{:.0} ditambahkan",
|
||||
"Reading photos… {} of {}": "Membaca foto… {} dari {}",
|
||||
"Adding photos… {} of {}": "Menambahkan foto… {} dari {}",
|
||||
" ({} in Recently Deleted)": " ({} di Baru dihapus)",
|
||||
"Already in the library: {} photo{} selected in All Photos": "Sudah ada di pustaka: {} foto{:.0} dipilih di Semua foto",
|
||||
"Already in the library, in Recently Deleted: {} photo{} selected · right-click ▸ Restore, or Delete Permanently to import afresh": "Sudah ada di pustaka, di Baru dihapus: {} foto{:.0} dipilih · klik kanan → Pulihkan, atau Hapus permanen untuk mengimpor ulang",
|
||||
"Auto ({})": "Otomatis ({})",
|
||||
"Build 1:1 Previews ({scope})": "Buat pratinjau 1:1 ({scope})",
|
||||
"Build Smart Previews ({scope})": "Buat pratinjau pintar ({scope})",
|
||||
"Build Standard-Sized Previews ({scope})": "Buat pratinjau ukuran standar ({scope})",
|
||||
"Discard Smart Previews ({scope})": "Buang pratinjau pintar ({scope})",
|
||||
"Lightroom catalog inspected: {photos} photos, {collections} collections, {missing} missing": "Katalog Lightroom diperiksa: {photos} foto, {collections} koleksi, {missing} hilang",
|
||||
"Lightroom import complete: {imported} photos added": "Impor Lightroom selesai: {imported} foto ditambahkan",
|
||||
"Lightroom import complete: {imported} photos added, {failed} failed": "Impor Lightroom selesai: {imported} foto ditambahkan, {failed} gagal",
|
||||
"Lightroom import complete: {imported} photos added; index warning: {warning}": "Impor Lightroom selesai: {imported} foto ditambahkan; peringatan indeks: {warning}",
|
||||
"Lightroom import failed: {e}{warning}": "Impor Lightroom gagal: {e}{warning}",
|
||||
"Lightroom inspection failed: {e}{warning}": "Pemeriksaan Lightroom gagal: {e}{warning}",
|
||||
"Label Set: {name}": "Set label: {name}",
|
||||
"Quick Develop: {name}": "Olah cepat: {name}",
|
||||
"Reset {name}": "Atur ulang {name}",
|
||||
"Updated “{name}”": "“{name}” diperbarui",
|
||||
"{month}": "{month:02}",
|
||||
"{month} {year}": "{month:02}/{year}",
|
||||
"{verb} {n} Photo{}": "{verb} {n} foto{:.0}",
|
||||
"{weekday}, {day}": "{weekday}, {day}",
|
||||
"{weekday}, {day} {month} {year}": "{weekday}, {day:02}/{month:02}/{year}",
|
||||
"{year}": "{year}",
|
||||
"Remove “{name}” and its {count} photo{} from the library?": "Keluarkan “{name}” beserta {count} foto{:.0} di dalamnya dari pustaka?",
|
||||
" ({unsure} with several look-alike files: use Locate)": " ({unsure} memiliki beberapa file serupa: gunakan “Temukan file hilang”)",
|
||||
" · {:.0}% clipped": " · {:.0}% terpotong",
|
||||
" · {failed} couldn't be rendered": " · {failed} gagal dirender",
|
||||
" · {} original{} left at the source": " · {} file asli{:.0} tetap di sumber",
|
||||
" — not carried over: {}{}": " — tidak ikut terbawa: {}{}",
|
||||
"+{} more": "+{} lainnya",
|
||||
"; {kept} already had a location": "; {kept} sudah memiliki lokasi",
|
||||
"; {outside} outside its time range": "; {outside} di luar rentang waktunya",
|
||||
"@{}: {} PRs, {} commits, +{} / −{} lines (Δ {}), +{} / −{} binary assets, {} – {}": "@{}: {} PR, {} commit, +{} / −{} baris (Δ {}), +{} / −{} aset biner, {} – {}",
|
||||
"Added {what} to {name}": "{what} ditambahkan ke {name}",
|
||||
"Auto Import: added {} photo{}": "Impor otomatis: {} foto{:.0} ditambahkan",
|
||||
"Building previews for {} photos…": "Membuat pratinjau untuk {} foto…",
|
||||
"Couldn't open the editor: {e}": "Tidak dapat membuka editor: {e}",
|
||||
"Creates {} stacks from {} of {scope}": "Membuat {} tumpukan dari {} di antara {scope}",
|
||||
"Done ({what}): {done} photo{plural}": "Selesai ({what}): {done} foto{plural:.0}",
|
||||
"Focus {:.0}": "Fokus {:.0}",
|
||||
"Folder “{}” (and its subfolders)": "Folder “{}” (beserta subfoldernya)",
|
||||
"Found {n} missing photo{}; {left} still missing{unsure}": "Ditemukan {n} foto yang hilang{:.0}; {left} masih hilang{unsure}",
|
||||
"Import failed: {e}": "Impor gagal: {e}",
|
||||
"Import warnings ({n}):\n{warnings}": "Peringatan impor ({n}):\n{warnings}",
|
||||
"XMP profile \"{profile}\" was not applied for {path}; colors may differ from Lightroom.": "Profil XMP \"{profile}\" tidak diterapkan untuk {path}; warna mungkin berbeda dari Lightroom.",
|
||||
"Lightroom geometry was not preserved for {path}; {mode} will be recalculated.": "Geometri Lightroom untuk {path} tidak dipertahankan; {mode} akan dihitung ulang.",
|
||||
"Lightroom geometry for {path} was not preserved; saved transform is ignored because Upright is Off.": "Geometri Lightroom untuk {path} tidak dipertahankan; transformasi tersimpan diabaikan karena Tegakkan nonaktif.",
|
||||
"Lightroom geometry for {path} was not preserved; Guided Upright saved transform is unsupported.": "Geometri Lightroom untuk {path} tidak dipertahankan; transformasi Tegakkan terpandu yang tersimpan tidak didukung.",
|
||||
"Lightroom geometry for {path} was not preserved; saved Upright transform is unsupported.": "Geometri Lightroom untuk {path} tidak dipertahankan; transformasi Tegakkan yang tersimpan tidak didukung.",
|
||||
"XMP adjustments were not imported for {path}: {fields}.": "Penyesuaian XMP untuk {path} tidak diimpor: {fields}.",
|
||||
"Imported {profiles} profile{} (Profile browser ▸ their groups)": "{profiles} profil diimpor{:.0} (Penjelajah profil → grup masing-masing)",
|
||||
"Insert at the cursor (also written {})": "Sisipkan di posisi kursor (dapat juga ditulis {})",
|
||||
"MIT OR Apache-2.0. Fonts: {} (OFL). Icons: original.": "MIT OR Apache-2.0. Font: {} (OFL). Ikon: orisinal.",
|
||||
"Painting “{k}”: click photos to add or remove it · Esc stops": "Menerapkan “{k}”: klik foto untuk menambahkan atau menghapusnya · Esc untuk berhenti",
|
||||
"Previews ready for {done} photo{plural}": "Pratinjau untuk {done} foto{plural:.0} sudah siap",
|
||||
"Removed {what} from {name}": "{what} dihapus dari {name}",
|
||||
"Renames “{from}” on {n} photo{} (keywords below it too). Use | for levels, e.g. Travel|Italy. An existing name merges the two.": "Mengganti nama “{from}” di {n} foto{:.0} (termasuk kata kunci di bawahnya). Gunakan | untuk tingkatan, mis. Liburan|Italia. Jika nama sudah ada, keduanya akan digabungkan.",
|
||||
"Replace {} with:": "Ganti {} dengan:",
|
||||
"Scores {scope} for focus and exposure and finds similar shots taken within seconds of each other (bursts).": "Menilai fokus dan eksposur {scope}, lalu mencari bidikan serupa yang diambil berselang beberapa detik (bidikan beruntun).",
|
||||
"Tagged {n} photo{} from the tracklog": "{n} foto diberi lokasi dari log jejak GPS{:.0}",
|
||||
"The SAM 3 download failed: {e}": "Gagal mengunduh SAM 3: {e}",
|
||||
"Unknown tag{s} {} stay{} as typed (see Tags)": "Tag tak dikenal{s:.0} {0} tetap seperti yang diketik{1:.0} (lihat Tag)",
|
||||
"Virtual copy “{name}” of {of}": "Salinan virtual “{name}” dari {of}",
|
||||
"Working on {what} for {} photos…": "Memproses {what} untuk {} foto…",
|
||||
"{label} {index} of {n}": "{label} {index} dari {n}",
|
||||
"{name} opened for editing; it is stacked with the original": "{name} dibuka untuk diedit dan ditumpuk dengan file aslinya",
|
||||
"{n} change{} couldn't be written to disk: {e}\nIf you quit now, {} lost.": "{n} perubahan{0:.0} tidak dapat ditulis ke disk: {e}\nJika Anda keluar sekarang, perubahan tersebut akan hilang{1:.0}.",
|
||||
"{n} change{} saved in memory but not written to disk: {e} — LightCraft will retry": "{n} perubahan{:.0} tersimpan di memori, tetapi belum ditulis ke disk: {e} — LightCraft akan mencoba lagi",
|
||||
"{pid} (missing)": "{pid} (hilang)",
|
||||
"{{date:…}} directives: {}": "Direktif {{date:…}}: {}",
|
||||
"{} contributors · {} commits": "{} kontributor · {} commit",
|
||||
"{} failed": "{} gagal",
|
||||
"{} item{}": "{} item{:.0}",
|
||||
"{} photos · exposures {} EV": "{} foto · eksposur {} EV",
|
||||
"{} photos · {} · {:.0}° × {:.0}°": "{} foto · {} · {:.0}° × {:.0}°",
|
||||
"{} sample{}": "{} sampel{:.0}",
|
||||
"{} sec": "{} dtk",
|
||||
"{} — show their photos": "{} — tampilkan foto orang ini",
|
||||
"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 belum dapat mendekode varian raw ini ({}). Anda sedang mengedit pratinjau JPEG bawaan kamera, yang sudah menyertakan gaya gambar kamera (mis. Monokrom) dan keseimbangan putihnya.",
|
||||
"Filtered: {label}": "Difilter: {label}",
|
||||
"{n} similar photo{} · View ▸ Clear Filters to see all": "{n} foto serupa{:.0} · Tampilan → Hapus filter untuk melihat semua",
|
||||
"Moved; {} photo(s) relinked": "Dipindahkan; {} foto ditautkan ulang",
|
||||
"{} label (click more labels to show any of them)": "Label {} (klik label lain untuk ikut menampilkan foto berlabel tersebut)",
|
||||
", {} star{}": ", {} bintang{:.0}",
|
||||
", {} label": ", label {}",
|
||||
"Downloads from {host}. Once it has arrived and checked out, LightCraft installs it, {after}.": "Diunduh dari {host}. Setelah selesai diunduh dan lolos pemeriksaan, LightCraft akan menginstalnya, {after}.",
|
||||
"{:.1} MB": "{:.1} MB",
|
||||
"Running on the processor: {}.": "Berjalan di prosesor: {}.",
|
||||
"{} · {}. Kept in the library's “denoise” folder; the oldest ones that no photo uses go first when the limit is reached.": "{} · {}. Disimpan di folder “denoise” pustaka; saat batas tercapai, file terlama yang tidak dipakai foto mana pun dihapus lebih dulu.",
|
||||
"Denoising {name}: {done} of {total} tiles{}": "Mengurangi noise {name}: {done} dari {total} petak{}",
|
||||
"{size} GB": "{size} GB",
|
||||
"{} of {} from {host}": "{} / {} dari {host}",
|
||||
"{} KB": "{} KB",
|
||||
"{} MB": "{} MB",
|
||||
"Making the denoised picture… {}%": "Membuat gambar hasil pengurangan noise… {}%",
|
||||
"{name} · {terms}": "{name} · {terms}",
|
||||
"{n} {noun}": "{n} {noun}",
|
||||
"Trained on: {provenance}": "Dilatih dengan: {provenance}",
|
||||
" · {queued} waiting": " · {queued} menunggu",
|
||||
"Shows the model's terms, then downloads {} from {host}, installs it and starts using it. Nothing else is sent.": "Menampilkan ketentuan model, lalu mengunduh {} dari {host}, menginstalnya, dan mulai menggunakannya. Tidak ada data lain yang dikirim.",
|
||||
"In line for AI Denoise ({ahead} ahead)…": "Dalam antrean pengurangan noise AI ({ahead} di depan)…",
|
||||
"Running on {}.": "Berjalan di {}.",
|
||||
"{file} · {size}": "{file} · {size}",
|
||||
"• {assumption}": "• {assumption}",
|
||||
"Put inside “{parent}”": "Masukkan ke “{parent}”",
|
||||
"Delete the keyword “{name}”?": "Hapus kata kunci “{name}”?",
|
||||
"It is taken off {count} photo{}, with the keywords below it. Undo brings it back.": "Kata kunci ini akan dilepas dari {count} foto{:.0}, beserta kata kunci di bawahnya. Urungkan untuk mengembalikannya.",
|
||||
"Create Keyword Tag Inside “{name}”…": "Buat tag kata kunci di dalam “{name}”…",
|
||||
"“{parent}” has a “{name}” already. Merge the two?": "“{parent}” sudah berisi “{name}”. Gabungkan keduanya?",
|
||||
"There is a “{name}” at the top level already. Merge the two?": "Sudah ada “{name}” di tingkat teratas. Gabungkan keduanya?",
|
||||
"Added “{keyword}” to {n} photo{}": "“{keyword}” ditambahkan ke {n} foto{:.0}",
|
||||
"On {have} of {of} selected photos": "Pada {have} dari {of} foto yang dipilih",
|
||||
"Remove “{name}”": "Hapus “{name}”",
|
||||
"There is a keyword set “{name}” already": "Set kata kunci “{name}” sudah ada",
|
||||
"Added {n} keyword{}": "{n} kata kunci ditambahkan{:.0}",
|
||||
"; {n} gained synonyms": "; {n} mendapat sinonim baru",
|
||||
"Exported {n} keyword{}": "{n} kata kunci diekspor{:.0}",
|
||||
" — Capture One won't import a list with ; , < or > in a keyword: {names}": " — Capture One tidak akan mengimpor daftar yang kata kuncinya mengandung ; , < atau >: {names}",
|
||||
" — left out, as a keyword list can't hold them: {names}": " — tidak disertakan karena tidak dapat dimasukkan ke daftar kata kunci: {names}",
|
||||
"{done} of {total}": "{done} dari {total}",
|
||||
"{done} of {total} MB": "{done} dari {total} MB",
|
||||
"{pct} %": "{pct} %",
|
||||
"+{n} more": "+{n} lainnya",
|
||||
"Create the keyword “{name}”": "Buat kata kunci “{name}”",
|
||||
"new, inside {parent}": "baru, di dalam {parent}",
|
||||
"Keywords of {n} selected photos": "Kata kunci {n} foto yang dipilih",
|
||||
"Removed “{name}” from {n} photos. Edit ▸ Undo puts it back.": "“{name}” dihapus dari {n} foto. Edit → Urungkan akan mengembalikannya.",
|
||||
"1 task is still running: {names}. Quitting stops it.": "1 tugas masih berjalan: {names}. Jika keluar sekarang, tugas ini akan dihentikan.",
|
||||
"{n} tasks are still running: {names}. Quitting stops them.": "{n} tugas masih berjalan: {names}. Jika keluar sekarang, semua tugas ini akan dihentikan.",
|
||||
"{what} merge cancelled": "Penggabungan {what} dibatalkan",
|
||||
"{n} Local photo{} skipped: albums hold library photos (Add to My Photos first)": "{n} foto Lokal{:.0} dilewati: album hanya dapat berisi foto pustaka (tambahkan ke Foto saya terlebih dahulu)",
|
||||
"New Folder in “{name}”": "Folder baru di “{name}”",
|
||||
"Moved {} photo(s)": "{} foto dipindahkan",
|
||||
"not added to Apple Photos: {e}": "tidak ditambahkan ke Apple Photos: {e}",
|
||||
"{n} added to Apple Photos album “{album}”": "{n} ditambahkan ke album Apple Photos “{album}”",
|
||||
"{n} added to Apple Photos": "{n} ditambahkan ke Apple Photos",
|
||||
"{n} photos opened for editing; each is stacked with its original": "{n} foto dibuka untuk diedit; masing-masing ditumpuk dengan file aslinya",
|
||||
" in {g} group{}": " dalam {g} grup{:.0}",
|
||||
" · kept, not applied: {}": " · dipertahankan, tidak diterapkan: {}",
|
||||
" — kept but not applied: {}": " — disimpan, tetapi tidak diterapkan: {}",
|
||||
"Apply to “{mask}” on Selected Photos": "Terapkan ke “{mask}” pada foto yang dipilih",
|
||||
"Delete the effect preset “{name}”?": "Hapus preset efek “{name}”?",
|
||||
"Delete these {n} effect presets?": "Hapus {n} preset efek ini?",
|
||||
"Delete {n} effect preset{}? This can't be undone.": "Hapus {n} preset efek{:.0}? Tindakan ini tidak dapat diurungkan.",
|
||||
"Effect: {name}": "Efek: {name}",
|
||||
"Exported {} effect preset{}": "{} preset efek diekspor{:.0}",
|
||||
"Imported {e} mask effect{} (Masking ▸ Effect)": "{e} efek masker{:.0} diimpor (Masker → Efek)",
|
||||
"Update “{name}” with Current Settings": "Perbarui “{name}” dengan pengaturan saat ini",
|
||||
"{n} preset{}": "{n} preset{:.0}",
|
||||
"{name} opened in the other editor": "{name} dibuka di editor lain",
|
||||
"{n} originals opened in the other editor": "{n} file asli dibuka di editor lain",
|
||||
"· {in_source} identical copies": "· {in_source} salinan identik",
|
||||
"{count} more warnings.": "{count} peringatan lainnya.",
|
||||
"{photos} catalog records processed; {collections} collections.": "{photos} entri katalog diproses; {collections} koleksi.",
|
||||
"{missing} originals are missing. Their catalog records are available; use Find Missing Photos to relink them.": "{missing} file asli hilang. Data katalognya masih tersedia; gunakan “Cari foto hilang” untuk menautkannya ulang.",
|
||||
"Applied {name}": "{name} diterapkan",
|
||||
"Delete “{name}”?": "Hapus “{name}”?",
|
||||
"Updated {name}": "{name} diperbarui",
|
||||
"Exported to {path}": "Diekspor ke {path}",
|
||||
"Saved template {name}": "Templat {name} disimpan",
|
||||
"Imported {name}": "{name} diimpor",
|
||||
"Skipped {problem}": "Dilewati: {problem}",
|
||||
"…and {more} more": "…dan {more} lainnya",
|
||||
"Template preview: {name}": "Pratinjau templat: {name}",
|
||||
"{n} photos in view · {slides} slides · {time}": "{n} foto dalam tampilan · {slides} slide · {time}",
|
||||
"{n} pages": "{n} halaman",
|
||||
"{n} JPEG files": "{n} file JPEG",
|
||||
"{s} s of AV1 video": "Video AV1 {s} detik",
|
||||
"Slideshow exported: {what}": "Tayangan slide diekspor: {what}",
|
||||
" · {n} skipped (could not be rendered)": " · {n} dilewati (tidak dapat dirender)",
|
||||
"{n} raws can now be developed from their raw data": "{n} file raw kini dapat diolah dari data raw-nya",
|
||||
"LightCraft stopped unexpectedly: {e}\n\nThe log file has the details: {path}": "LightCraft berhenti tiba-tiba: {e}\n\nDetailnya ada di file log: {path}",
|
||||
"LightCraft stopped unexpectedly: {e}": "LightCraft berhenti tiba-tiba: {e}",
|
||||
"Renames {n} face{} across the library. The files are not changed.": "Mengganti nama {n} wajah{:.0} di seluruh pustaka. File tidak diubah.",
|
||||
"“{to}” is already a person. Combining them makes one person; Undo separates them again.": "“{to}” sudah terdaftar sebagai orang. Jika digabungkan, keduanya menjadi satu orang; Urungkan akan memisahkannya lagi.",
|
||||
"{what} merge added at {mp}: its full size, {full}, needs more memory than this computer has": "Hasil penggabungan {what} ditambahkan dengan resolusi {mp}: resolusi penuhnya ({full}) memerlukan memori melebihi kapasitas komputer ini",
|
||||
"{what} merge added at {mp}, the largest a panorama can be (its full size is {full})": "Hasil penggabungan {what} ditambahkan dengan resolusi {mp}, resolusi maksimum untuk panorama (resolusi penuhnya {full})"
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -132,6 +132,7 @@ language_table! {
|
||||
Ka, "ka", "ქართული", "Geor", include_str!("../locales/ka.json");
|
||||
Sv, "sv", "Svenska", "Latn", include_str!("../locales/sv.json");
|
||||
Fi, "fi", "Suomi", "Latn", include_str!("../locales/fi.json");
|
||||
Id, "id", "Bahasa Indonesia", "Latn", include_str!("../locales/id.json");
|
||||
}
|
||||
|
||||
// The settings file stores the BCP-47 code (`"zh-hans"`), never the Rust variant name, so a
|
||||
@@ -558,6 +559,45 @@ mod tests {
|
||||
set_language(Locale::En);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn indonesian_switches_persists_formats_dates_and_preserves_values() {
|
||||
use crate::control::{ControlRequest, Outcome};
|
||||
let mut app = crate::LightcraftApp::new(lightcraft_engine::Session::with_demo(), Default::default());
|
||||
app.run("app.language.indonesian", serde_json::json!({})).unwrap();
|
||||
assert_eq!(app.ui.language, Locale::Id);
|
||||
assert_eq!(Locale::Id.name(), "Bahasa Indonesia");
|
||||
assert_eq!(Locale::Id.script(), "Latn");
|
||||
assert_eq!(crate::menubar::checked(&app, "app.language.indonesian"), Some(true));
|
||||
assert_eq!(tr("Exposure"), "Eksposur");
|
||||
assert_eq!(tr("My Photos"), "Foto saya");
|
||||
assert_eq!(date_group_label("2026-09-20", false), "Minggu, 20/09/2026");
|
||||
assert_eq!(date_group_label("2026-09-20", true), "Minggu, 20");
|
||||
assert_eq!(date_group_label("2026-09", false), "09/2026");
|
||||
assert_eq!(date_group_label("2026", false), "2026");
|
||||
assert_eq!(display_time("2026-09-20T16:04:05"), "Minggu, 20/09/2026 16:04:05");
|
||||
// Indonesian keeps a noun unchanged after a count ("1 foto", "22 foto"), so the English
|
||||
// plural suffix is consumed and never shows.
|
||||
for n in [0, 1, 2, 5, 11, 22] {
|
||||
assert_eq!(tr_format!("Imported {} photo{}", n, if n == 1 { "" } else { "s" }), format!("{n} foto diimpor"));
|
||||
}
|
||||
let name = String::from("Color 1234.56 {title} 日本語");
|
||||
assert_eq!(tr_format!("Added {n} photo{} to “{}”", "s", name, n = 22), format!("22 foto ditambahkan ke “{name}”"));
|
||||
assert_eq!(builtin_label("Warm Glow", false), "Warm Glow");
|
||||
assert_eq!(tr("photo-{title}.jpg"), "photo-{title}.jpg");
|
||||
let saved = serde_json::to_string(&app.ui).unwrap();
|
||||
assert!(saved.contains(r#""language":"id""#));
|
||||
assert_eq!(serde_json::from_str::<crate::state::UiState>(&saved).unwrap().language, Locale::Id);
|
||||
let ctx = egui::Context::default();
|
||||
for tag in ["id", "id-ID", "id_ID.UTF-8", "id-Latn-ID"] {
|
||||
assert_eq!(Locale::parse_tag(tag), Some(Locale::Id));
|
||||
let (request, _) = ControlRequest::new("ui.set", serde_json::json!({"language": tag}));
|
||||
let Outcome::Done(reply) = crate::control::handle(&mut app, &ctx, &request) else { panic!("expected reply") };
|
||||
assert_eq!(reply["ok"], true);
|
||||
assert_eq!(language(), Locale::Id);
|
||||
}
|
||||
set_language(Locale::En);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sentence_case_keeps_georgian_lowercase() {
|
||||
assert_eq!(upper_first("its input is not an image"), "Its input is not an image");
|
||||
@@ -870,6 +910,7 @@ mod tests {
|
||||
("app.language.georgian", Locale::Ka),
|
||||
("app.language.swedish", Locale::Sv),
|
||||
("app.language.finnish", Locale::Fi),
|
||||
("app.language.indonesian", Locale::Id),
|
||||
];
|
||||
// One command per language, and every command reachable from the menu table.
|
||||
assert_eq!(commands.len(), Locale::ALL.len());
|
||||
|
||||
@@ -30,6 +30,7 @@ pub const LANGUAGE_COMMANDS: &[UiCommand] = &[
|
||||
("app.language.georgian", crate::i18n::Locale::Ka.name(), None, "Edit>Language"),
|
||||
("app.language.swedish", crate::i18n::Locale::Sv.name(), None, "Edit>Language"),
|
||||
("app.language.finnish", crate::i18n::Locale::Fi.name(), None, "Edit>Language"),
|
||||
("app.language.indonesian", crate::i18n::Locale::Id.name(), None, "Edit>Language"),
|
||||
];
|
||||
|
||||
/// Every UI command: the languages, then everything else. `xtask parity` reads both tables from
|
||||
@@ -58,6 +59,7 @@ pub fn language_from_command(id: &str) -> Option<crate::i18n::Locale> {
|
||||
"app.language.georgian" => Some(crate::i18n::Locale::Ka),
|
||||
"app.language.swedish" => Some(crate::i18n::Locale::Sv),
|
||||
"app.language.finnish" => Some(crate::i18n::Locale::Fi),
|
||||
"app.language.indonesian" => Some(crate::i18n::Locale::Id),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -621,13 +621,13 @@ mod tests {
|
||||
"Export Keywords…",
|
||||
];
|
||||
let dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("locales");
|
||||
for code in ["de", "es", "fr", "pt-br", "ru", "uk", "it", "ka", "ja", "zh-hans", "zh-hant", "pl", "cs", "sv", "fi"] {
|
||||
for code in ["de", "es", "fr", "pt-br", "ru", "uk", "it", "ka", "ja", "zh-hans", "zh-hant", "pl", "cs", "sv", "fi", "id"] {
|
||||
let text = std::fs::read_to_string(dir.join(format!("{code}.json"))).unwrap();
|
||||
let catalog: std::collections::HashMap<String, String> = serde_json::from_str(&text).unwrap();
|
||||
for label in labels {
|
||||
assert!(catalog.contains_key(label), "{code}: “{label}”");
|
||||
}
|
||||
}
|
||||
assert_eq!(Locale::ALL.len(), 16, "a language added: list its file above");
|
||||
assert_eq!(Locale::ALL.len(), 17, "a language added: list its file above");
|
||||
}
|
||||
}
|
||||
|
||||
+3
-2
@@ -1,6 +1,6 @@
|
||||
# Gaps: where LightCraft falls short of Lightroom
|
||||
|
||||
> **Last reviewed:** 2026-10-11 · **Last updated:** 2026-10-15 · **Change:** minor (gap 15: Print Page Options — page numbers, page info, crop marks)
|
||||
> **Last reviewed:** 2026-10-11 · **Last updated:** 2026-10-19 · **Change:** minor (gap 21: Indonesian interface shipped, every message but What's New)
|
||||
|
||||
Every known shortfall, one entry each, ranked by user impact (how many Lightroom users hit it, and
|
||||
how hard it blocks them), then by effort. **Agents pick work from the top** (the first entry nobody is
|
||||
@@ -35,7 +35,7 @@ Hours are Opus 5.5 agent wall-clock hours (see [target-app-parity.md](target-app
|
||||
| 18 | **Video**: playback, trim, global edits, export | VID rows 0% | users who mix stills and clips | 25–45 | [target-app-parity](target-app-parity.md#features) |
|
||||
| 19 | **Plug-in ecosystem**: no Lightroom SDK equivalent (export / publish plug-ins, metadata plug-ins) | ⬜ | pro workflows built on plug-ins (LR/Enfuse, Jeffrey's exporters, Negative Lab Pro) | 40–80 + owner decision | [target-app-parity](target-app-parity.md#by-dimension) |
|
||||
| 20 | **Long-tail raw formats**: compressed SRW, ARQ pixel shift, IIQ, Hasselblad compression, X3F, CRW, MRW, ERF, KDC, DCR, MEF, GPR, old FinePix | raw-parity.md | small user share each | 45–85 | [raw-parity](raw-parity.md) |
|
||||
| 21 | **Localization**: 9 of 15 shipped languages partial (de, es, fr, ja, uk now 97–99% of catalog messages, awaiting native review; pt-BR, ru, zh-hans, zh-hant 74–92%), lower-layer errors English; Hindi, Arabic, Indonesian, Korean, Vietnamese absent; no RTL or complex shaping | measured from catalogs | non-English users see mixed English | 40–70 (shipped to full); 145–255 (five new) | [localization-parity](localization-parity.md) |
|
||||
| 21 | **Localization**: 10 of 16 shipped languages partial (de, es, fr, ja, uk now 97–99% of catalog messages and id every message but What's New, awaiting native review; pt-BR, ru, zh-hans, zh-hant 74–92%), lower-layer errors English; Hindi, Arabic, Korean, Vietnamese absent; no RTL or complex shaping | measured from catalogs | non-English users see mixed English | 40–70 (shipped to full); 135–239 (four new) | [localization-parity](localization-parity.md) |
|
||||
| 23 | **Accessibility**: AccessKit tree audited by a test; canvas handles, spots and mask pins by keyboard; left: brush and red-eye by keyboard, a session with a real screen reader | LR-BEHAV-ACCESS 🟡 | blind and low-vision users | 2–4 | [ui-parity](ui-parity.md) |
|
||||
| 22 | **Pen pressure on macOS / Linux tablets** (brush size and flow follow pressure where winit reports a pen force), OS monitor profiles on Windows (Linux reads colord's, macOS the screen's), follow-window colour on Linux / Windows | hardware-parity.md | brush users with tablets; multi-monitor setups | 11–22 | [hardware-parity](hardware-parity.md) |
|
||||
| 24 | **Brush live preview and masking feel** (#517, #518); Feather / Edge mask refinement (15.5) | issues | masking feels slower than Lightroom | 8–12 | [ui-parity](ui-parity.md) |
|
||||
@@ -77,6 +77,7 @@ Beta-blocking gaps (B) total **~230–430 h**; with the stability and platform w
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-10-19 | minor | Gap 21: Indonesian (`id`) shipped with every catalog message but What's New; four new languages left (Hindi, Arabic, Korean, Vietnamese), 135–239 h |
|
||||
| 2026-10-18 | patch | Gap 1: six X-Trans CMOS 4 Fujifilm bodies (X-T30 …) take the X-T3's spectral matrices instead of the neutral matrix |
|
||||
| 2026-10-15 | minor | Gap 15 shrinks: the Page panel's Page Options (Page Numbers, Page Info, Crop Marks) print on Single Image and Contact Sheet pages; identity plate, watermark, photo info, Cut Guides, direct printing and JPEG output remain |
|
||||
| 2026-10-14 | minor | Gap 26: at 100k photos stack and album lookups are indexed, so an "In a Stack" or "Album" smart album counts in ~14 ms (was 0.6–2.7 s); open time unchanged |
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
# LightCraft in Indonesian
|
||||
|
||||
Choose **Edit → Language → Bahasa Indonesia** or **Settings → General → Language**. The choice applies
|
||||
at once and is saved for the next launch (`language: "id"` in `ui.json`); the control command is
|
||||
`app.language.indonesian`. `LIGHTCRAFT_LANGUAGE` selects it for headless runs and accepts `id`, `id-ID`
|
||||
and `id_ID.UTF-8`; the saved value is always `id`. LightCraft does not follow the system language, for
|
||||
Indonesian as for every other language.
|
||||
|
||||
The Indonesian catalogs cover every plain and formats message the other catalogs have (2,258 + 297),
|
||||
plus 69 command labels no catalog translated yet: menus, shortcuts, library, editing, crop, masks,
|
||||
people, import/export, print, slideshow, settings, built-in presets and profiles, history, date
|
||||
headings, status messages and the smart-album rule editor. The embedded release notes (What's New)
|
||||
stay in English. Technical errors from lower layers stay in English, as in the other languages.
|
||||
The catalogs were written with an agent from the meaning of the English labels and reviewed for
|
||||
natural, standard app Indonesian; 356 labels reuse the Indonesian wording of the sibling apps
|
||||
(PhotoCraft, VectorCraft, FilmCraft, FigCraft) so the suite reads the same. A native speaker's pass
|
||||
is welcome.
|
||||
|
||||
File names, command ids, template placeholders and albums, presets or metadata you named yourself are
|
||||
not translated.
|
||||
|
||||
## Style
|
||||
|
||||
- Sentence case everywhere, as in the English; names, brands and abbreviations keep their capitals.
|
||||
- Buttons and menu commands use the bare verb (Simpan, Hapus, Ekspor, Pangkas); progress lines use
|
||||
me- with an ellipsis (Mengimpor…); finished-state toasts put the subject first (`{n} foto diekspor`).
|
||||
- The user is addressed as *Anda*, only where a sentence needs a subject; never *kamu*.
|
||||
- Indonesian keeps a noun unchanged after a count (`3 foto`), so English plural endings are dropped
|
||||
with `{:.0}`.
|
||||
- Dates read `Minggu, 20/09/2026` (`{weekday}, {day:02}/{month:02}/{year}`), months `09/2026`.
|
||||
- Delete is **Hapus**; remove from a container (album, stack, favorites) is **Keluarkan dari …**.
|
||||
Select is **Pilih**; the Pick flag is **Pilihan**.
|
||||
- `▸` and `▾` are written `→` and `⌄`, as in the other catalogs.
|
||||
|
||||
## Terminology
|
||||
|
||||
| Source | Indonesian |
|
||||
|---|---|
|
||||
| Develop | Olah |
|
||||
| File / Edit / View | File / Edit / Tampilan |
|
||||
| Settings / General / Language | Pengaturan / Umum / Bahasa |
|
||||
| Import / Export | Impor / Ekspor |
|
||||
| Photos / Albums / Folders | Foto / Album / Folder |
|
||||
| Smart Album | Album pintar |
|
||||
| Crop | Pangkas |
|
||||
| Masks / Masking | Masker |
|
||||
| Exposure / Contrast | Eksposur / Kontras |
|
||||
| Highlights / Shadows / Whites / Blacks | Sorotan / Bayangan / Putih / Hitam |
|
||||
| Temperature / Tint | Suhu / Rona |
|
||||
| Vibrance / Saturation | Vibrance / Saturasi |
|
||||
| Clarity / Texture / Dehaze | Kejernihan / Tekstur / Hilangkan kabut |
|
||||
| Sharpening / Noise Reduction | Penajaman / Pengurangan noise |
|
||||
| Vignette / Grain | Vinyet / Butiran |
|
||||
| White Balance / Tone Curve | Keseimbangan putih / Kurva tone |
|
||||
| Lens Corrections | Koreksi lensa |
|
||||
| Presets / Profile | Preset / Profil |
|
||||
| Keywords / Rating | Kata kunci / Rating |
|
||||
| Flag / Pick / Reject | Tanda / Pilihan / Tolak |
|
||||
| Stack / Virtual Copy | Tumpukan / Salinan virtual |
|
||||
| History / Recently Deleted | Riwayat / Baru dihapus |
|
||||
| Compare / Before / After | Bandingkan / Sebelum / Sesudah |
|
||||
| Slideshow / Print / Template | Tayangan slide / Cetak / Templat |
|
||||
| People | Orang |
|
||||
@@ -1,12 +1,12 @@
|
||||
# Localization parity
|
||||
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-17 · **Change:** minor (Finnish interface catalog added; Italian: every interface string translated, native-speaker corrections; previously minor: de, es, fr, ja, uk catalogs filled; re-measured; Italian and Georgian interface catalogs added) · **Target:** Adobe Lightroom Classic 15.5 / Lightroom 9.6
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-19 · **Change:** minor (Indonesian and Finnish interface catalogs added; Italian: every interface string translated, native-speaker corrections; previously minor: de, es, fr, ja, uk catalogs filled; re-measured; Italian and Georgian interface catalogs added) · **Target:** Adobe Lightroom Classic 15.5 / Lightroom 9.6
|
||||
|
||||
How far each interface language is from `full`. How to add or maintain a language is in
|
||||
[localization.md](localization.md); per-language notes are in `localization-<code>.md`
|
||||
([zh-hans](localization-zh-hans.md), [zh-hant](localization-zh-hant.md), [ja](localization-ja.md),
|
||||
[pt-br](localization-pt-br.md), [es](localization-es.md), [de](localization-de.md),
|
||||
[ru](localization-ru.md), [fi](localization-fi.md), [ka](localization-ka.md)).
|
||||
[ru](localization-ru.md), [fi](localization-fi.md), [ka](localization-ka.md), [id](localization-id.md)).
|
||||
|
||||
## The target
|
||||
|
||||
@@ -52,7 +52,7 @@ that is promising but is not recorded as review, so the column says `no (communi
|
||||
| 5 | Arabic | `ar` | 0 (0%) | none | **RTL layout and Arabic shaping missing** | no | none (target: not shipped) | 60–110 h (RTL mirroring 30–50 h + shaping, shared with Hindi) |
|
||||
| 6 | French | `fr` | 2,315 / 2,398 (97%; 2026-10-12, the rest are words spelled the same) | as zh-hans | Latin | no (community edits) | partial | 2–4 h (native review, lower-layer errors) |
|
||||
| 7 | Portuguese (Brazil) | `pt-br` | 1,966 / 2,304 (85%) | as zh-hans | Latin | no (community edits) | partial | 6–10 h |
|
||||
| 8 | Indonesian | `id` | 0 (0%) | none | Latin (Inter covers it) | no | none (target: not shipped) | 10–16 h |
|
||||
| 8 | Indonesian | `id` | 2,555 / 2,555 (100%; 2026-10-19: every plain and formats message any catalog has, plus 69 command labels; What's New left in English) | as zh-hans | Latin (Inter covers it) | no (written with an agent; native-speaker pass pending) | partial (target: not shipped) | 2–4 h (native review, lower-layer errors) |
|
||||
| 9 | Japanese | `ja` | 2,383 / 2,398 (99%; 2026-10-12) | as zh-hans; vertical export watermarks | Jpan via craft-fonts (BIZ UDPGothic / UDMincho); IME through winit | no (community edits) | partial | 2–4 h (native review, lower-layer errors) |
|
||||
| 10 | German | `de` | 2,338 / 2,398 (97%; 2026-10-12, the rest are words spelled the same) | as zh-hans; What's New translated line by line | Latin | no (community edits) | partial | 2–4 h (native review, lower-layer errors) |
|
||||
| 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 |
|
||||
@@ -94,6 +94,7 @@ Target languages LightCraft lacks: Korean, Dutch, Polish, Swedish, Norwegian Bok
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-10-19 | minor | Indonesian interface catalog (`id`): every plain and formats message any catalog has, plus 69 command labels; What's New left in English |
|
||||
| 2026-10-17 | minor | Finnish interface catalog (`fi`): 2,610 of 3,308 messages (2,313 plain + 297 formats), What's New left in English |
|
||||
| 2026-10-15 | trivial | Italian (`it`): 339 interface messages and 60 format strings that were missing or still in English translated (2,628 of 3,278; only What's New left in English); native-speaker corrections: Exposure → *Esposizione*, Sharpening → *Nitidezza*, Preset → *Preset*, blurry → *sfocate* |
|
||||
| 2026-10-12 | minor | Italian interface catalog (`it`): 2,201 of 2,398 messages, What's New left in English |
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
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`), Russian (`ru`), French (`fr`), Ukrainian (`uk`), Czech (`cs`), Georgian (`ka`), Swedish (`sv`) and Finnish (`fi`). 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`), French (`fr`), Ukrainian (`uk`), Czech (`cs`), Georgian (`ka`), Swedish (`sv`), Finnish (`fi`) and Indonesian (`id`). 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), [`localization-ru.md`](localization-ru.md),
|
||||
[`localization-cs.md`](localization-cs.md), [`localization-fi.md`](localization-fi.md) and [`localization-ka.md`](localization-ka.md).
|
||||
[`localization-cs.md`](localization-cs.md), [`localization-fi.md`](localization-fi.md), [`localization-ka.md`](localization-ka.md) and [`localization-id.md`](localization-id.md).
|
||||
|
||||
## Adding a language
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ phase #85, duplicate Local entries #22, black GPU exports on an Intel iGPU #78).
|
||||
| UI/UX fidelity | ~85% | ~70% | 32–54 h | [ui-parity.md](ui-parity.md) |
|
||||
| File formats (non-raw: images, sidecars, presets, catalogs) | ~85% | ~70% | 30–55 h | [file-format-parity.md](file-format-parity.md) |
|
||||
| Hardware | ~50% | ~40% | 40–80 h (+ tethering and printing, counted under Classic modules) | [hardware-parity.md](hardware-parity.md) |
|
||||
| Localization (12 key languages) | 7 of 12 present | ~55% (mean of the 12, measured) | 130–210 h for the target's set; +145–255 h for Hindi, Arabic, Indonesian, Vietnamese, Korean | [localization-parity.md](localization-parity.md) |
|
||||
| Localization (12 key languages) | 8 of 12 present | ~64% (mean of the 12, measured) | 130–210 h for the target's set; +135–239 h for Hindi, Arabic, Vietnamese, Korean | [localization-parity.md](localization-parity.md) |
|
||||
| Performance | ~80% | ~70% | 30–50 h | 24 MP GPU slider 3.9 ms, export 0.3 s (measured, [gpu-pipeline.md](gpu-pipeline.md)); 85k library opens in 1.7–4.7 s; 100k test pending |
|
||||
| Stability | — | ~60% | 30–60 h | never-crash lints and guards workspace-wide, crash-tested journal, 2,561 tests; but CI runs tests only on FreeBSD, user reports keep finding bugs in ✅ areas |
|
||||
| Platforms | macOS, Windows (x64 / x86 / ARM64), Linux (AppImage, deb, rpm, Flatpak, Nix), FreeBSD, web | ~60% | 25–45 h | macOS is where it is tested; Windows installer UI unverified on Windows (#79); web experimental (CPU only) |
|
||||
@@ -136,12 +136,12 @@ valued from the model-by-model measurement in [raw-parity.md](raw-parity.md):
|
||||
| UI/UX fidelity | 8% | 70% |
|
||||
| File formats (non-raw) | 6% | 70% |
|
||||
| Hardware | 3% | 40% |
|
||||
| Localization | 3% | 55% |
|
||||
| Localization | 3% | 64% |
|
||||
| Performance | 6% | 70% |
|
||||
| Stability | 8% | 60% |
|
||||
| Platforms | 4% | 60% |
|
||||
| Ecosystem / plug-ins | 2% | 15% |
|
||||
| **Weighted sum** | 100% | **61.2% ≈ 61%** (range 56–66%) |
|
||||
| **Weighted sum** | 100% | **61.5% ≈ 61%** (range 56–66%) |
|
||||
|
||||
Mainstream comes out lower than full: its scope is the raw-develop core, where LightCraft is weakest
|
||||
(camera colour, CR3 coverage), and its discounts are multiplicative, while the full sum is lifted by
|
||||
@@ -300,6 +300,7 @@ P2 items 12–25 h; look tuning, performance, packaging, hardening 25–45 h.
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-10-19 | minor | Localization ~55% → ~64% (mean of the 12 key languages): Indonesian (`id`) catalog, every message but What's New; full target 61.2% → 61.5% (still ~61%) |
|
||||
| 2026-10-14 | minor | Localization ~52% → ~55% (mean of the 12 key languages): de, es, fr, ja and uk catalogs filled |
|
||||
| 2026-10-12 | minor | UI/UX remaining 34–58 h → 32–54 h (canvas tools by keyboard); headline numbers unchanged |
|
||||
| 2026-10-14 | minor | Merge and HDR: merge 100% → 88% (LR-MERGE-HDR ✅ → 🟡 after testing on real 67 MP brackets; gap 29); area percentages unchanged |
|
||||
|
||||
Reference in New Issue
Block a user