From b273f8e6087ae9f20ebfc2f4fb3708fd263f0171 Mon Sep 17 00:00:00 2001 From: FredApps <153173854+FredApps@users.noreply.github.com> Date: Sun, 11 Oct 2026 00:53:36 +0200 Subject: [PATCH 001/350] #798: read large Lightroom catalogs by page Generated with Codex. --- crates/engine/src/lightroom_catalog.rs | 37 ++++- crates/engine/src/lightroom_sqlite.rs | 220 ++++++++++++++++++++++++- docs/gaps.md | 2 +- docs/lightroom-catalog-import.md | 13 +- docs/parity-checklist.md | 2 +- 5 files changed, 257 insertions(+), 17 deletions(-) diff --git a/crates/engine/src/lightroom_catalog.rs b/crates/engine/src/lightroom_catalog.rs index 6c1c7724d..a727491fb 100644 --- a/crates/engine/src/lightroom_catalog.rs +++ b/crates/engine/src/lightroom_catalog.rs @@ -8,7 +8,7 @@ use std::sync::{ atomic::{AtomicBool, AtomicUsize, Ordering}, }; -use crate::lightroom_sqlite::{Database, LiveTable, Value as SqlValue}; +use crate::lightroom_sqlite::{Database, FileSource, LiveTable, Value as SqlValue}; use lightcraft_catalog::{Album, Flag, Op, Photo, PhotoId, Source}; use lightcraft_geom::{Affine, Orientation, Point, Rect}; use serde::{Deserialize, Serialize}; @@ -352,15 +352,15 @@ pub fn read_with_progress(path: &Path, cancel: &AtomicBool, total: &AtomicUsize, let before = std::fs::metadata(path).map_err(|e| e.to_string())?; let wal_path = PathBuf::from(format!("{}-wal", path.display())); let wal_before = std::fs::metadata(&wal_path).ok().map(|m| (m.len(), m.modified().ok())); - let main = bytes(path)?; + let main = FileSource::open(path)?; let wal = match std::fs::metadata(&wal_path) { Ok(_) => bytes(&wal_path)?, Err(e) if e.kind() == std::io::ErrorKind::NotFound => Vec::new(), Err(e) => return Err(e.to_string()), }; - let wal_len = committed_wal_len(&main, &wal)?; + let wal_len = committed_wal_len(main.header(), &wal)?; ensure_read_active(cancel)?; - let db = Database::open_with_wal(main, &wal[..wal_len]).map_err(|e| format!("invalid SQLite catalog: {e:?}"))?; + let db = Database::open_file_with_wal(main, &wal[..wal_len]).map_err(|e| format!("invalid SQLite catalog: {e:?}"))?; let after = std::fs::metadata(path).map_err(|e| e.to_string())?; let wal_after = std::fs::metadata(&wal_path).ok().map(|m| (m.len(), m.modified().ok())); if before.len() != after.len() || before.modified().ok() != after.modified().ok() || wal_before != wal_after { @@ -471,6 +471,11 @@ pub fn read_with_progress(path: &Path, cancel: &AtomicBool, total: &AtomicUsize, }); } ensure_read_active(cancel)?; + reader.db.ensure_unchanged()?; + let wal_after = std::fs::metadata(&wal_path).ok().map(|m| (m.len(), m.modified().ok())); + if wal_before != wal_after { + return Err("catalog changed during reading; close Lightroom and retry".into()); + } Ok(out) } @@ -1302,6 +1307,30 @@ mod tests { assert_eq!(catalog.photos[0].uuid, "fixture-image"); assert_eq!(number(&catalog.photos[0].image, "rating"), 5); assert!(catalog.photos[0].path.ends_with("test.ARW")); + // Put the required image table beyond the old 1 GiB cutoff without allocating it. + // A main-file-sized allocation would defeat the purpose of the page-backed reader. + // The large fixture relies on Unix sparse-file behavior; small parity runs everywhere. + #[cfg(unix)] + { + let far_offset = 1u64 << 30; + schema.last_mut().unwrap()[3] = I((far_offset / 2048 + 1) as i64); + leaf(&mut bytes[..2048], 100, &schema); + use std::io::{Seek, SeekFrom, Write}; + let mut sparse = std::fs::OpenOptions::new().write(true).truncate(true).open(&path).unwrap(); + sparse.write_all(&bytes).unwrap(); + sparse.set_len(far_offset + 2048).unwrap(); + sparse.seek(SeekFrom::Start(far_offset)).unwrap(); + sparse.write_all(&bytes[4 * 2048..5 * 2048]).unwrap(); + drop(sparse); + let large = read(&path).unwrap(); + assert_eq!(serde_json::to_value(&large.photos).unwrap(), serde_json::to_value(&catalog.photos).unwrap()); + let mut session = crate::Session::new(); + session.execute("library.importLightroom", &json!({"path": path.to_string_lossy()})).unwrap(); + assert_eq!(session.catalog.len(), 1); + assert_eq!(session.catalog.photos().next().unwrap().rating, 5); + session.execute("edit.undo", &json!({})).unwrap(); + assert!(session.catalog.is_empty()); + } std::fs::write(&path, b"bad catalog").unwrap(); assert!(read(&path).is_err()); std::fs::remove_file(path).unwrap(); diff --git a/crates/engine/src/lightroom_sqlite.rs b/crates/engine/src/lightroom_sqlite.rs index 900fe4a26..f00cb111f 100644 --- a/crates/engine/src/lightroom_sqlite.rs +++ b/crates/engine/src/lightroom_sqlite.rs @@ -6,7 +6,79 @@ //! than a SQL engine. It never writes its input and has no SQLite runtime //! dependency. +use std::borrow::Cow; use std::collections::{HashMap, HashSet}; +use std::fs::{File, Metadata}; +use std::io::{Read, Seek, SeekFrom}; +use std::path::{Path, PathBuf}; +use std::sync::Mutex; + +const MAX_DATABASE_BYTES: u64 = 16 << 30; + +/// A bounded, read-only page source. Only referenced pages are loaded, never the whole file. +pub struct FileSource { + file: Mutex, + path: PathBuf, + before: Metadata, + header: Vec, +} + +impl FileSource { + pub fn open(path: &Path) -> Result { + if !std::fs::metadata(path).map_err(|e| e.to_string())?.is_file() { + return Err("SQLite catalog must be a regular file".into()); + } + let mut file = File::open(path).map_err(|e| e.to_string())?; + let before = file.metadata().map_err(|e| e.to_string())?; + if !before.is_file() { + return Err("SQLite catalog must be a regular file".into()); + } + if before.len() > MAX_DATABASE_BYTES { + return Err("catalog exceeds 16 GiB import limit".into()); + } + let mut header = vec![0; 100]; + file.read_exact(&mut header).map_err(|e| format!("cannot read SQLite header: {e}"))?; + let source = Self { file: Mutex::new(file), path: path.into(), before, header }; + source.ensure_unchanged()?; + Ok(source) + } + + pub fn header(&self) -> &[u8] { + &self.header + } + + pub fn ensure_unchanged(&self) -> Result<(), String> { + let file = self.file.lock().map_err(|_| "SQLite page source lock poisoned")?; + let handle = file.metadata().map_err(|e| e.to_string())?; + let path = std::fs::metadata(&self.path).map_err(|_| "catalog changed during reading; close Lightroom and retry")?; + if !same_metadata(&self.before, &handle) || !same_metadata(&self.before, &path) { + return Err("catalog changed during reading; close Lightroom and retry".into()); + } + Ok(()) + } + + fn page(&self, page_id: u32, size: usize) -> Result, String> { + let start = u64::from(page_id).checked_sub(1).and_then(|n| n.checked_mul(size as u64)).ok_or("page offset overflow")?; + if start.checked_add(size as u64).is_none_or(|end| end > self.before.len()) { + return Err(format!("page {page_id} is truncated")); + } + let mut out = vec![0; size]; + let mut file = self.file.lock().map_err(|_| "SQLite page source lock poisoned")?; + file.seek(SeekFrom::Start(start)).and_then(|_| file.read_exact(&mut out)).map_err(|e| format!("cannot read SQLite page {page_id}: {e}"))?; + Ok(out) + } +} + +fn same_metadata(a: &Metadata, b: &Metadata) -> bool { + #[cfg(unix)] + { + use std::os::unix::fs::MetadataExt; + if a.dev() != b.dev() || a.ino() != b.ino() { + return false; + } + } + a.len() == b.len() && a.modified().ok() == b.modified().ok() && a.created().ok() == b.created().ok() +} const MAX_PAGE_ID: u32 = 16_777_216; const MAX_COLUMNS: usize = 16_384; @@ -44,6 +116,7 @@ pub struct LiveTable { /// Read-only SQLite database image, with a committed WAL overlay if supplied. pub struct Database { main: Vec, + file: Option, overlay: HashMap>, page_size: usize, reserved: usize, @@ -84,17 +157,34 @@ impl Database { /// The WAL argument must include its 32-byte header and only complete /// frames through a commit. Frames are overlaid by page number, with the /// final commit's database-size field defining the visible page count. + #[cfg(test)] pub fn open_with_wal(main: Vec, committed_wal: &[u8]) -> Result { + Self::open(main, None, committed_wal) + } + + pub fn open_file_with_wal(source: FileSource, committed_wal: &[u8]) -> Result { + Self::open(source.header().to_vec(), Some(source), committed_wal) + } + + pub fn ensure_unchanged(&self) -> Result<(), String> { + if let Some(file) = &self.file { + file.ensure_unchanged()?; + } + Ok(()) + } + + fn open(main: Vec, file: Option, committed_wal: &[u8]) -> Result { let main_header = main.get(..100).ok_or("truncated SQLite header")?; if main_header.get(..16) != Some(b"SQLite format 3\0") { return Err("invalid SQLite header signature".into()); } let page_size = sqlite_page_size(be_u16(main_header, 16)?)?; validate_header_fields(main_header, page_size)?; - if main.len() < page_size || !main.len().is_multiple_of(page_size) { + let main_len = file.as_ref().map_or(main.len() as u64, |source| source.before.len()); + if main_len < page_size as u64 || !main_len.is_multiple_of(page_size as u64) { return Err("SQLite image is not a whole number of pages".into()); } - let main_pages = u32::try_from(main.len() / page_size).map_err(|_| "SQLite image is too large")?; + let main_pages = u32::try_from(main_len / page_size as u64).map_err(|_| "SQLite image is too large")?; if main_pages == 0 || main_pages > MAX_PAGE_ID { return Err("invalid SQLite image page count".into()); } @@ -140,7 +230,7 @@ impl Database { _ => return Err("unsupported SQLite text encoding".into()), }; - let mut db = Self { main, overlay, page_size, reserved, encoding, page_count, tables: Vec::new(), rowid_aliases: HashMap::new() }; + let mut db = Self { main, file, overlay, page_size, reserved, encoding, page_count, tables: Vec::new(), rowid_aliases: HashMap::new() }; let schema = db.parse_schema()?; db.tables = schema.tables; db.rowid_aliases = schema.aliases; @@ -166,17 +256,20 @@ impl Database { Ok(state.out) } - fn page(&self, page_id: u32) -> Result<&[u8], String> { + fn page(&self, page_id: u32) -> Result, String> { if page_id == 0 || page_id > self.page_count { return Err(format!("page {page_id} is outside database")); } if let Some(page) = self.overlay.get(&page_id) { - return Ok(page); + return Ok(Cow::Borrowed(page)); + } + if let Some(file) = &self.file { + return file.page(page_id, self.page_size).map(Cow::Owned); } let id = usize::try_from(page_id).map_err(|_| "page number does not fit host")?; let start = id.checked_sub(1).and_then(|n| n.checked_mul(self.page_size)).ok_or("page offset overflow")?; let end = start.checked_add(self.page_size).ok_or("page offset overflow")?; - self.main.get(start..end).ok_or_else(|| format!("page {page_id} is truncated")) + self.main.get(start..end).map(Cow::Borrowed).ok_or_else(|| format!("page {page_id} is truncated")) } fn visit_table(&self, page_id: u32, ncols: usize, alias: Option, depth: usize, state: &mut WalkState) -> Result<(), String> { @@ -219,7 +312,7 @@ impl Database { if state.payload_total > MAX_TABLE_PAYLOAD { return Err("SQLite table payload exceeds bounded import size".into()); } - let payload = self.payload(page, at, payload_len)?; + let payload = self.payload(&page, at, payload_len)?; let mut values = decode_record(&payload, ncols, self.encoding)?; if let Some(index) = alias { if index >= values.len() { @@ -325,7 +418,7 @@ impl Database { out.extend_from_slice(overflow.get(4..end).ok_or("truncated SQLite overflow page")?); remaining -= take; if remaining > 0 { - next = be_u32_at(overflow, 0)?; + next = be_u32_at(&overflow, 0)?; } } Ok(out) @@ -871,6 +964,72 @@ fn be_u32_at(bytes: &[u8], at: usize) -> Result { mod tests { use super::*; + struct Scratch(PathBuf); + impl Scratch { + fn new(bytes: &[u8]) -> Self { + static NEXT: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0); + let n = NEXT.fetch_add(1, std::sync::atomic::Ordering::Relaxed); + let path = std::env::temp_dir().join(format!("lightcraft-page-source-{}-{n}.lrcat", std::process::id())); + std::fs::write(&path, bytes).unwrap(); + Self(path) + } + } + impl Drop for Scratch { + fn drop(&mut self) { + let _ = std::fs::remove_file(&self.0); + } + } + + fn file_backed(mut db: Database) -> (Scratch, Database) { + let scratch = Scratch::new(&db.main); + db.file = Some(FileSource::open(&scratch.0).unwrap()); + db.main.truncate(100); + (scratch, db) + } + + #[test] + fn file_source_bounds_and_mutation_detection() { + let scratch = Scratch::new(&[0; 512]); + let source = FileSource::open(&scratch.0).unwrap(); + assert_eq!(source.page(1, 512).unwrap().len(), 512); + assert!(source.page(2, 512).unwrap_err().contains("truncated")); + File::options().write(true).open(&scratch.0).unwrap().set_len(100).unwrap(); + assert!(source.page(1, 512).is_err()); + assert!(source.ensure_unchanged().unwrap_err().contains("changed during reading")); + drop(source); + // Unix set_len creates a hole. Do not reserve a 16 GiB normal file on Windows. + #[cfg(unix)] + { + File::options().write(true).open(&scratch.0).unwrap().set_len(MAX_DATABASE_BYTES + 1).unwrap(); + assert_eq!(FileSource::open(&scratch.0).err().unwrap(), "catalog exceeds 16 GiB import limit"); + } + } + + #[cfg(unix)] + #[test] + fn file_source_detects_same_sized_path_replacement() { + let original = Scratch::new(&[0; 512]); + let replacement = Scratch::new(&[0; 512]); + let source = FileSource::open(&original.0).unwrap(); + std::fs::rename(&replacement.0, &original.0).unwrap(); + assert!(source.ensure_unchanged().unwrap_err().contains("changed during reading")); + } + + #[test] + fn file_source_detects_same_length_content_changes() { + let scratch = Scratch::new(&[0; 512]); + let source = FileSource::open(&scratch.0).unwrap(); + std::fs::write(&scratch.0, [1; 512]).unwrap(); + // Make the timestamp change deterministic even on filesystems with coarse timestamps. + File::options() + .write(true) + .open(&scratch.0) + .unwrap() + .set_modified(source.before.modified().unwrap() + std::time::Duration::from_secs(2)) + .unwrap(); + assert!(source.ensure_unchanged().unwrap_err().contains("changed during reading")); + } + fn varint(mut value: u64) -> Vec { let mut out = vec![u8::try_from(value & 0x7f).unwrap_or(0)]; value >>= 7; @@ -996,6 +1155,40 @@ mod tests { assert!(tables.iter().any(|table| table.name == "t")); let rows = db.read_table(2, 2).unwrap(); assert_eq!(rows.first().and_then(|row| row.values.first()), Some(&Value::Integer(1))); + let scratch = Scratch::new(&db.main); + let file_db = Database::open_file_with_wal(FileSource::open(&scratch.0).unwrap(), &[]).unwrap(); + assert_eq!(file_db.live_tables().unwrap(), tables); + assert_eq!(file_db.read_table(2, 2).unwrap(), rows); + assert_eq!(file_db.main.len(), 100); + file_db.ensure_unchanged().unwrap(); + // The same committed WAL page overrides the lazily read main page. + let mut wal = vec![0; 32 + 24 + 512]; + wal[..4].copy_from_slice(&0x377f0682u32.to_be_bytes()); + wal[4..8].copy_from_slice(&3_007_000u32.to_be_bytes()); + wal[8..12].copy_from_slice(&512u32.to_be_bytes()); + wal[32..36].copy_from_slice(&2u32.to_be_bytes()); + wal[36..40].copy_from_slice(&2u32.to_be_bytes()); + leaf(&mut wal[56..], 0, 2, &[3, 0, 15, b'y']); + let memory_wal = Database::open_with_wal(db.main.clone(), &wal).unwrap(); + let file_wal = Database::open_file_with_wal(FileSource::open(&scratch.0).unwrap(), &wal).unwrap(); + assert_eq!(memory_wal.read_table(2, 2).unwrap(), file_wal.read_table(2, 2).unwrap()); + assert_eq!(file_wal.read_table(2, 2).unwrap()[0].values[0], Value::Integer(2)); + let mut malformed = db.main.clone(); + malformed.push(0); + let partial = Scratch::new(&malformed); + assert_eq!( + Database::open_file_with_wal(FileSource::open(&partial.0).unwrap(), &[]).err().unwrap(), + "SQLite image is not a whole number of pages" + ); + let mut malformed = db.main.clone(); + malformed[24..28].copy_from_slice(&1u32.to_be_bytes()); + malformed[92..96].copy_from_slice(&1u32.to_be_bytes()); + malformed[28..32].copy_from_slice(&3u32.to_be_bytes()); + let oversized = Scratch::new(&malformed); + assert_eq!( + Database::open_file_with_wal(FileSource::open(&oversized.0).unwrap(), &[]).err().unwrap(), + "SQLite header page count exceeds image" + ); } #[test] @@ -1012,6 +1205,7 @@ mod tests { leaf(&mut main[1024..1536], 0, 1, &[2, 0]); leaf(&mut main[1536..], 0, 2, &[2, 0]); let db = Database { + file: None, main, overlay: HashMap::new(), page_size: 512, @@ -1043,6 +1237,7 @@ mod tests { let mut aliases = HashMap::new(); aliases.insert(1, 0); let db = Database { + file: None, main, overlay: HashMap::new(), page_size: 512, @@ -1063,6 +1258,7 @@ mod tests { main[103..105].copy_from_slice(&1u16.to_be_bytes()); main[108..110].copy_from_slice(&490u16.to_be_bytes()); let db = Database { + file: None, main, overlay: HashMap::new(), page_size: 512, @@ -1073,6 +1269,8 @@ mod tests { rowid_aliases: HashMap::new(), }; assert!(db.read_table(1, 1).is_err()); + let (_scratch, db) = file_backed(db); + assert!(db.read_table(1, 1).is_err()); } #[test] @@ -1085,6 +1283,7 @@ mod tests { let mut main = vec![0u8; 2 * 512]; let db = Database { + file: None, main: std::mem::take(&mut main), overlay: HashMap::new(), page_size: 512, @@ -1111,6 +1310,10 @@ mod tests { assert_eq!(bytes.len(), 600); assert_eq!(&bytes[..92], &[b'x'; 92]); assert_eq!(&bytes[92..], &[b'y'; 508]); + let (_scratch, mut db) = file_backed(db); + db.overlay.clear(); + let bytes = db.payload(&cell_page, 0, 600).unwrap(); + assert_eq!(&bytes[92..], &[b'y'; 508]); } #[test] @@ -1134,6 +1337,7 @@ mod tests { let mut page = vec![0u8; 512]; page[16..18].copy_from_slice(&512u16.to_be_bytes()); let db = Database { + file: None, main: vec![0; 512], overlay: HashMap::new(), page_size: 512, diff --git a/docs/gaps.md b/docs/gaps.md index 64b1cb8ac..98cc17548 100644 --- a/docs/gaps.md +++ b/docs/gaps.md @@ -27,7 +27,7 @@ Hours are Opus 5.5 agent wall-clock hours (see [target-app-parity.md](target-app | 10 B | **Per-model verification thin, plus cheap per-body decode fixes**: 234 of 1,446 Adobe models verified (16%), ~40% of photographers on a verified body; Nikon 5 bodies verified, Canon 11. Cheap fixes: Z 6II packed 14-bit NEF (#769, PR #671), Sony A100 / F828 regression (#702), DSLR-A200…A390 / A850 12-bit ARW (#535) | measured: [raw/coverage.tsv](raw/coverage.tsv) | per-body bugs (levels, crops, WB) surface only from users | 25–45 | [raw-parity](raw-parity.md#by-maker-measured) | | 11 | **Enhance: Raw Details, Super Resolution; AI denoise without shippable weights or X-Trans** | ENH rows 0%; denoise Bayer only, RawNIND weights GPL and opt-in | Fujifilm users get no AI denoise; nobody gets it out of the box | 30–60 + model decision | [raw-parity](raw-parity.md#demosaic-levels-crops-and-lens-metadata) | | 12 | **Content-aware / generative remove, detect distractions, reflections removal** | REM rows 75%; patch synthesis missing | cleanup work goes back to Photoshop | 25–45 (+ generative model) | [target-app-parity](target-app-parity.md#ai) | -| 13 | **Lightroom catalog migration is one-way and approximate**: unsupported Adobe profiles / AI settings archived, history kept as data | lightroom-catalog-import.md | switching users lose some looks | 8–12 | [file-format-parity](file-format-parity.md) | +| 13 | **Lightroom catalog migration is one-way and approximate**: unsupported Adobe profiles / AI settings archived, history kept as data; main-file pages read on demand up to 16 GiB, with dense-table and WAL bounds retained (#798) | lightroom-catalog-import.md | switching users lose some looks | 8–12 | [file-format-parity](file-format-parity.md) | | 14 | **HDR display** (EDR / Windows HDR); HLG; HDR settings from `crs` XMP | HDR rows 70%; LR-VIEW-HDR-DISPLAY ⬜ | HDR editing works blind on HDR monitors | 12–25 | [hardware-parity](hardware-parity.md) | | 15 | **Print module**: custom packages, printer colour management (contact-sheet PDF only) | LRC-PRINT rows | Classic users who print | 25–40 | [target-app-parity](target-app-parity.md#features) | | 16 | **Map view, Book, Slideshow module, publish services** | LRC-MAP / BOOK / SS rows ⬜ | Classic users; publish services matter for Flickr / SmugMug workflows | 60–100 | [target-app-parity](target-app-parity.md#features) | diff --git a/docs/lightroom-catalog-import.md b/docs/lightroom-catalog-import.md index 0c18a6521..3ae13c75e 100644 --- a/docs/lightroom-catalog-import.md +++ b/docs/lightroom-catalog-import.md @@ -28,9 +28,16 @@ retained. Oldest managed archives are retired; legacy `.json` archives remain un `Interop/lightroom-index.json` records imported identities. Source catalogs and originals are never overwritten. -Native import is bounded to a 1 GiB database/WAL, 16 MiB XMP packets and one million rows per -table. The in-tree, read-only Rust SQLite B-tree reader follows SQLite’s public file-format -specification; it introduces no dependency or C runtime. Table payloads are capped at 256 MiB. +Native import reads referenced database pages on demand (at most 64 KiB per page), rather than +loading the whole `.lrcat`. Database files are capped at 16 GiB and 16,777,216 pages; the WAL +remains capped at 1 GiB. Tables still have a 256 MiB encoded-payload budget and one million rows, +individual records are capped at 64 MiB, and XMP packets at 16 MiB. These limits can still reject +large catalogs with dense tables; file size alone no longer determines the memory allocation. +The open file and source path are checked again after all tables are read. Close Lightroom before +importing: metadata checks detect ordinary concurrent changes, but are not SQLite snapshot isolation. + +The in-tree, read-only Rust SQLite B-tree reader follows SQLite's public file-format +specification; it introduces no dependency or C runtime. Optional history, keyword and collection tables that exceed limits are skipped with warnings; required photo tables still report errors. Unrelated unsupported schemas are ignored. A needed WITHOUT ROWID or virtual table produces an explicit error, handled as a warning when optional. diff --git a/docs/parity-checklist.md b/docs/parity-checklist.md index 099411089..2b6cf4814 100644 --- a/docs/parity-checklist.md +++ b/docs/parity-checklist.md @@ -679,7 +679,7 @@ From `08-lightroom-classic-extras.md` (Classic-only features) and part 2 of `06- | LRC-LIB-SURVEY | Survey view | P2 | ✅ | `cmd:view.survey` | N | | LRC-LIB-REFVIEW | Reference view | P2 | ✅ | `cmd:view.reference`, `cmd:photo.setReference`, `crates/ui-egui/src/panels/compare.rs` (`show_reference`) | View ▸ Reference View (⇧R): the reference photo beside the active one (edited with the Edit panel); photo menu ▸ Set as Reference Photo | | LRC-LIB-CATALOG-PANEL | Catalog sets | P1 | ✅ | `cmd:library.source` (`missing`) | all, recently added, picks, recently deleted, missing photos (when any) | -| LRC-LIB-CATALOG-IMPORT | Native Lightroom Classic catalog import | P1 | 🟡 | `cmd:library.inspectLightroom`, `cmd:library.importLightroom`, `crates/engine/src/lightroom_catalog.rs`, `docs/lightroom-catalog-import.md` | read-only `.lrcat` plus committed WAL pages, in-tree read-only Rust SQLite B-tree reader; background inspection/import with progress/cancellation, per-open library identity checks; originals in place, ratings/flags/labels, XMP, hierarchical keywords, collection sets/regular collections, virtual copies, mapped develop settings; stable reimport identities, undo, missing-file placeholders, existing edits preserved. Best-effort deduplicated recovery archives retain settings/history/snapshots/collection rules (32 MiB each, eight archives/128 MiB aggregate); archive limits/write failures and optional-table limits warn without blocking photo import; unrelated unsupported tables and opaque SQL BLOBs skipped. Custom white balance on relative-WB raws (`RAW` in Lightroom's terms) stays As Shot and is reported, since the catalog keeps no as-shot white to shift from (issue #510). Adobe rendering, AI data and native history replay remain incomplete; no writes to Lightroom catalogs | +| LRC-LIB-CATALOG-IMPORT | Native Lightroom Classic catalog import | P1 | 🟡 | `cmd:library.inspectLightroom`, `cmd:library.importLightroom`, `crates/engine/src/lightroom_catalog.rs`, `docs/lightroom-catalog-import.md` | read-only `.lrcat` plus committed WAL pages, in-tree read-only Rust SQLite B-tree reader; on-demand main-file pages up to 16 GiB with existing table/record bounds (WAL still capped at 1 GiB, issue #798); background inspection/import with progress/cancellation, per-open library identity checks; originals in place, ratings/flags/labels, XMP, hierarchical keywords, collection sets/regular collections, virtual copies, mapped develop settings; stable reimport identities, undo, missing-file placeholders, existing edits preserved. Best-effort deduplicated recovery archives retain settings/history/snapshots/collection rules (32 MiB each, eight archives/128 MiB aggregate); archive limits/write failures and optional-table limits warn without blocking photo import; unrelated unsupported tables and opaque SQL BLOBs skipped. Custom white balance on relative-WB raws (`RAW` in Lightroom's terms) stays As Shot and is reported, since the catalog keeps no as-shot white to shift from (issue #510). Adobe rendering, AI data and native history replay remain incomplete; no writes to Lightroom catalogs | | LRC-LIB-CATALOG-LOCK | Catalog open in one program at a time | P1 | ✅ | `cmd:app.openLibrary`, `crates/catalog/src/lock.rs`, `crates/engine/src/library.rs` (`open_library`) | exclusive OS lock on `catalog.lock` for the session (app and `lightcraft-cli --library`); a second opener is refused with who has it (`catalog.lock.owner`: program, process, computer); released by the OS on a crash, so never stale; file systems without locks open unprotected with a warning (the app's notices, `library.info` → `settingsWarnings`, and the CLI's stderr; issue #171); no read-only mode; the browser build (OPFS) has no guard across tabs yet. A library that can't be opened at launch (locked, unreadable, newer format, drive missing) shows a window — Try Again, Choose Another Library…, Continue Without Saving (then a banner; nothing written), Quit — instead of a silent demo session (`crates/ui-egui/src/panels/library_problem.rs`) | | LRC-LIB-FOLDERS | Disk folder tree | P1 | ✅ | `cmd:library.browse`, `cmd:folder.rename`, `cmd:folder.move`, `crates/ui-egui/src/panels/left.rs` (`local_section`, `folder_tree`) | standard places + the browsed folder + Browse Folder…, each an expandable tree of subfolders, breadcrumb navigation; context menu: Rename Folder…, Move Folder To…, Show in Finder (on disk, photos relinked; one undo step each: undo / redo move the folder back and forth, refused when the destination is taken) | | LRC-LIB-LIBFOLDERS | Library folders | P1 | ✅ | `cmd:library.folders`, `cmd:library.source` (`libraryFolder`), `cmd:library.filter` (`libraryFolder`), `cmd:library.removeFolder`, `cmd:folder.rename`, `cmd:folder.move`, `cmd:folder.label`, `cmd:folder.scanChanges`, `cmd:folder.synchronize`, `crates/catalog/src/folders.rs`, `crates/engine/src/sync.rs`, `crates/ui-egui/src/sync.rs`, `crates/ui-egui/src/panels/left.rs` (`folders_section`, `folder_menu_for_library`, `row_menu`), `crates/ui-egui/src/tests_panels.rs` | sidebar Folders: the folders the library's photos were imported from, with photo counts (subfolders included), as another way to explore the library next to By Date and Keywords; Local stays the way to browse any folder on disk. Each disk is a row of its own and starts open: a drive letter, a Windows share (`\\server\share`, `\\?\UNC\…`, `\\wsl$\…`), a macOS share or disk (`/Volumes/tokyo`), a Linux mount (`/media`, `/run/media`, `/mnt`, gvfs `smb-share:…`, `/net/`), NFS (`/Network/Servers/`), else “This Computer” — told apart from the stored paths alone, so an offline share lists like a mounted one and the sidebar never waits on a network. Only folders that hold imported photos are listed (browsed, deleted and demo photos don't count); every folder is a row of its own (`Users` → `me` → `Pictures`), and a folder that holds nothing itself and leads to one folder starts open; every level indents one step more than its parent however deep it goes: the whole sidebar (Albums, Local, By Date, Folders, Keywords) scrolls sideways when its widest row is wider than the panel (rows are measured one frame behind; Create Album and the counts stay at the visible edge); a name that does not fit ends in an ellipsis at the count (the full name on hover; a row asks for room for at most 140 pt of its name, so depth, not one long name, makes the sidebar scroll), as does the grid title; selection and hover bars end at the panel's edge; click makes the folder the source, like an album or a Local folder (its photos and those of the folders inside it fill the grid, titled “photos/travel”; the filter bar narrows it further; `library.source` `libraryFolder` + `path`; kept with the library's view), and its row is always opened into view; the shown folder follows a rename or move and their undo (engine-tested; the sidebar test covers rename), is dropped back to All Photos when it is removed or no longer holds a photo, and a smart album made from the view keeps it, also when its rules are edited (the editor has no folder field). Only a folder that shows exactly its own photos can be shown (not the startup disk, not `/Volumes`-like folders above disks, not an empty one). A row that would cover other disks' photos too (the startup disk, `/Volumes`, `/mnt`…) only opens. Right-click (row or triangle): Rename Folder…, Move Folder To…, Show in Finder (on disk, photos relinked, as in Local), Set Color Label ▸ (the five colours with their custom names, None, Edit Label Names…; `folder.label`, one undo step; the row shows the label's dot before its count and says it with its name; kept in the catalog as a folder record under the folder's identity, so it follows Rename / Move and their undo and redo, the folders inside going along), Synchronize Folder… (the dialog opens at once and scans the folder and the folders inside it on a worker thread — the look for new files beside parallel checks of the library's photos — then offers Import new photos (checked; files only browsed in Local count as new), Relink photos whose file was renamed or moved within the folder (checked; matched by content — a Duplicate's too — or, for a photo with no hash on record such as one from a Lightroom catalog, by file size and dimensions when exactly one file agrees), Remove missing photos from the library (to Recently Deleted) and Read metadata updates from XMP sidecars (saved after the photo came in or was last edited here, and saying something the library doesn't; the sidecar wins), with counts and skipped duplicates / unreadable files; `folder.scanChanges` / `folder.synchronize`, which acts on exactly the scan shown — a scan whose folder's photos changed meanwhile is refused and made again in the background — and is one undo step, also with a full history; a folder that isn't there (an unplugged disk) is reported as such, not as every photo missing; a whole disk or a folder holding disks needs `disk: true`; Esc stops the scan; Synchronize hands everything to a worker thread — the import, the checks that moved and missing files are still as found, the sidecar reads — and commits its steps between frames, shown in the activity stack with ✕ to stop, so no file is touched on the UI thread) and Remove from Library… (asks; moves the folder's photos to Recently Deleted, one undo step, no file touched); a disk row (not the startup disk) offers Set Color Label ▸, Synchronize Folder… and Remove Disk from Library… (the command needs `disk: true` for a whole disk or a folder spanning several). Limits: names are compared as written (macOS `/Volumes/tokyo` vs `/Volumes/TOKYO` are two disks; `/Volumes/Macintosh HD/…` and `/…` two rows); no disk capacity / online status; no “include subfolders” switch (a folder always includes the ones inside it); creating a folder and moving photos between folders are not here; folders can't be filtered or sorted by label, and a label stays with the old path when the folder is moved outside LightCraft (Find Missing relinks photos, not folder records); Synchronize has no “show import dialog first” or “show missing photos” option, and only knows when a photo came in or was last developed here: a rating, label or metadata change made here (auto-write off) after another app saved the sidecar is listed as an update, and reading it restores the sidecar's older value (reading is never the default); the walk for new files isn't cancelled midway and its depth/entry limits are only logged | From d6c29aaf254bb26c8bb3451c18d2de59cf9e946f Mon Sep 17 00:00:00 2001 From: Andrew Frahn Date: Mon, 12 Oct 2026 04:18:59 +1100 Subject: [PATCH 002/350] LR-IMP-FORMATS: decode Minolta MRW (packed 12-bit and 16-bit words, RGGB / GBRG) The \0MRM block container: PRD sensor size, storage and Bayer cell; WBG as-shot gains in cell order; TTW TIFF for Exif and orientation. Black 0, white from the saturation plateau. 4 CC0 samples pinned in RAW_SAMPLES; DiMAGE 7, 7Hi, A1, A2, A200 and Dynax / Maxxum 7D verified. Also fixes clippy::chunks_exact_to_as_chunks in pipeline/spots.rs. Sources: public prose description of the MRW layout (Dalibor Jelinek's MRW notes) and own black-box analysis of the CC0 samples. Co-Authored-By: Claude Opus 5.5 (1M context) --- ROADMAP.md | 8 +- crates/engine/src/files.rs | 4 +- crates/meta/src/container.rs | 9 ++ crates/meta/src/lib.rs | 1 + crates/meta/src/mrw.rs | 93 ++++++++++++++ crates/pipeline/src/spots.rs | 4 +- crates/raw/src/lib.rs | 8 +- crates/raw/src/preview.rs | 3 +- crates/raw/src/vendor/mod.rs | 1 + crates/raw/src/vendor/mrw.rs | 230 +++++++++++++++++++++++++++++++++++ crates/raw/tests/corpus.rs | 48 ++++++++ docs/gaps.md | 7 +- docs/parity-checklist.md | 5 +- docs/raw-parity.md | 22 ++-- docs/raw/coverage.py | 4 +- docs/raw/coverage.tsv | 22 ++-- docs/raw/evidence.tsv | 6 + docs/target-app-parity.md | 5 +- xtask/src/main.rs | 20 +++ 19 files changed, 461 insertions(+), 39 deletions(-) create mode 100644 crates/meta/src/mrw.rs create mode 100644 crates/raw/src/vendor/mrw.rs diff --git a/ROADMAP.md b/ROADMAP.md index c804c36fc..909113f9e 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -2,7 +2,7 @@ **Stage: alpha** · next: beta, ~14 points and ~340–600 h away -> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-11 · **Change:** minor (EOS R5 Mark II CR3 verified; RAW decoding 77%) · **Target:** Adobe Lightroom Classic 15.5 / Lightroom 9.6 +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-12 · **Change:** minor (Minolta MRW decoded, 6 bodies verified) · **Target:** Adobe Lightroom Classic 15.5 / Lightroom 9.6 One-page summary of how close LightCraft is to Adobe Lightroom. Agents: read this, then pick work from [docs/gaps.md](docs/gaps.md). The full assessment, method and evidence are in @@ -45,7 +45,7 @@ Hours are calibrated on this repo's PR history; see | Dimension | Ready | Breadth | Remaining | Doc | |---|---:|---:|---:|---| | Features | ~61% | ~77% (checklist 81.1%) | 600–1,100 h | [target-app-parity](docs/target-app-parity.md#features) | -| ↳ RAW cameras, colour, lens profiles | ~56% | 81% of 1,446 Adobe models decode, 16% verified | 255–480 h | [raw-parity](docs/raw-parity.md) | +| ↳ RAW cameras, colour, lens profiles | ~56% | 82% of 1,446 Adobe models decode, 17% verified | 255–480 h | [raw-parity](docs/raw-parity.md) | | UI/UX fidelity | ~70% | ~85% | 40–70 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) | @@ -114,6 +114,9 @@ Ranked toward beta; detail in [docs/roadmap.md](docs/roadmap.md), gaps in [docs/ ## Progress log +- 2026-10-12: Minolta / Konica Minolta MRW decodes from sensor data (12-bit packed and 16-bit words, + RGGB and GBRG, as-shot WB from `WBG`); DiMAGE 7, 7Hi, A1, A2, A200 and Dynax / Maxxum 7D verified on + CC0 files. 241 models verified, 222 preview-only; headline numbers unchanged. - 2026-10-11: Canon EOS R5 Mark II C-RAW decodes from sensor data (57% of its files opened as a preview): the CRX QP map's first-symbol literal and limited-length escape; four CC0 R5 Mark II files pinned, the QP maps of 33,665 private C-RAW files decode exactly ([cr3.md](docs/cr3.md)). 235 models @@ -161,6 +164,7 @@ Ranked toward beta; detail in [docs/roadmap.md](docs/roadmap.md), gaps in [docs/ | Date | Change | Summary | |---|---|---| +| 2026-10-12 | minor | Minolta MRW decoded: 6 more verified models (241), 11 fewer preview-only; headline numbers unchanged | | 2026-10-11 | minor | EOS R5 Mark II CR3 verified: CR3 on four verified bodies, RAW decoding 76% → 77%; headline numbers unchanged | | 2026-10-10 | minor | RAW measured model by model; RAW decode and colour as explicit rows: full 59% → 61%, mainstream 51% → 49%, essentials 63% → 64%; beta ~14 points | | 2026-10-10 | minor | Full ready restored to the additive weighted sum (~59%; method aligned with the standard, no new evidence); hours per audience; beta ~16 points away | diff --git a/crates/engine/src/files.rs b/crates/engine/src/files.rs index c48aaff77..a5f03e476 100644 --- a/crates/engine/src/files.rs +++ b/crates/engine/src/files.rs @@ -1825,8 +1825,8 @@ mod tests { } } - /// Recognised raw containers we don't decode (Minolta MRW here: the preview's first byte is - /// overwritten in the file) import as preview only with the JPEG's size, instead of failing. + /// Recognised raw containers we can't decode (an MRW whose block header is damaged here; its preview's first + /// byte is overwritten, as in real MRW files) import as preview only with the JPEG's size, instead of failing. #[test] fn undecodable_container_with_a_preview_imports_as_preview_only() { let px: Vec = (0..40 * 30).flat_map(|i| [(i % 251) as u8, 128, 200]).collect(); diff --git a/crates/meta/src/container.rs b/crates/meta/src/container.rs index 8dda6b55d..3ac60907f 100644 --- a/crates/meta/src/container.rs +++ b/crates/meta/src/container.rs @@ -7,6 +7,7 @@ //! - WebP (RIFF container spec): `EXIF`, `XMP `, `ICCP` chunks. //! - TIFF-based files (TIFF, DNG and most raws): the whole file is the Exif block; XMP (700), ICC (34675) and //! IPTC (33723) from IFD0. +//! - Minolta MRW (see [`crate::mrw`]): the `TTW` block is the Exif block. //! - Canon CR3 (ISO base media file, see [`crate::cr3`]): `CMT1`/`CMT2`/`CMT4` merged into one Exif block; the //! XMP `uuid` box. @@ -36,6 +37,14 @@ pub fn embedded(bytes: &[u8]) -> Embedded { _ => Embedded::default(), }; } + if let Some(m) = crate::mrw::parse(bytes) { + // Minolta MRW: the `TTW` block is a complete TIFF with the Exif data + return m + .block(b"TTW") + .filter(|t| Tiff::parse(t).is_ok()) + .map(|t| Embedded { exif: Some(t.to_vec()), ..Default::default() }) + .unwrap_or_default(); + } if let Some(c) = crate::cr3::parse_cr3(bytes) { return Embedded { exif: crate::cr3::merged_exif(&c), xmp: c.xmp.map(|b| String::from_utf8_lossy(b).into_owned()), ..Default::default() }; } diff --git a/crates/meta/src/lib.rs b/crates/meta/src/lib.rs index 31a35cc65..52bf211fe 100644 --- a/crates/meta/src/lib.rs +++ b/crates/meta/src/lib.rs @@ -17,6 +17,7 @@ mod datetime; mod exif; mod gpx; mod iptc; +pub mod mrw; pub mod tags; mod xmp; mod xmp_merge; diff --git a/crates/meta/src/mrw.rs b/crates/meta/src/mrw.rs new file mode 100644 index 000000000..ef641c44d --- /dev/null +++ b/crates/meta/src/mrw.rs @@ -0,0 +1,93 @@ +//! Minolta / Konica Minolta MRW block container. +//! +//! Sources: the public prose description of the MRW layout (Dalibor Jelínek's MRW notes) and our own black-box +//! analysis of the CC0 samples on raw.pixls.us. The file starts with `\0MRM` and a big-endian `u32` length; the +//! sensor data begins right after that many bytes (at `8 + length`). In between is a sequence of blocks, each a +//! four-byte name (`\0PRD`, `\0TTW`, `\0WBG`, `\0RIF`, `\0PAD`), a big-endian `u32` length and that many bytes. +//! `\0TTW` holds a complete big-endian TIFF (IFD0, Exif, maker note) whose offsets are relative to the block. + +/// The blocks and the offset of the sensor data in an MRW file. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Mrw<'a> { + /// `(name without the leading NUL, contents)`, in file order. + pub blocks: Vec<([u8; 3], &'a [u8])>, + /// Absolute offset of the sensor data. + pub data_offset: usize, +} + +impl<'a> Mrw<'a> { + /// The first block called `name` (e.g. `b"PRD"`). + pub fn block(&self, name: &[u8; 3]) -> Option<&'a [u8]> { + self.blocks.iter().find(|(n, _)| n == name).map(|(_, d)| *d) + } +} + +/// At most this many blocks are walked (real files have four or five). +const MAX_BLOCKS: usize = 64; + +fn be32(b: &[u8], at: usize) -> Option { + let s = b.get(at..at.checked_add(4)?)?; + Some(u32::from_be_bytes([s[0], s[1], s[2], s[3]]) as usize) +} + +/// Parse the block list of an MRW file. `None` when the magic is missing or the header length points past the +/// file; a block that runs past the header is dropped together with everything after it. +pub fn parse(bytes: &[u8]) -> Option> { + if !bytes.starts_with(b"\0MRM") { + return None; + } + let data_offset = be32(bytes, 4)?.checked_add(8).filter(|&o| o <= bytes.len())?; + let mut blocks = Vec::new(); + let mut at = 8usize; + while blocks.len() < MAX_BLOCKS && at.saturating_add(8) <= data_offset { + let (Some(name), Some(len)) = (bytes.get(at..at + 4), be32(bytes, at + 4)) else { break }; + let start = at + 8; + let Some(end) = start.checked_add(len).filter(|&e| e <= data_offset) else { break }; + let Some(data) = bytes.get(start..end) else { break }; + if name[0] == 0 { + blocks.push(([name[1], name[2], name[3]], data)); + } + at = end; + } + Some(Mrw { blocks, data_offset }) +} + +#[cfg(test)] +mod tests { + use super::*; + + fn block(name: &[u8; 3], data: &[u8]) -> Vec { + let mut v = vec![0]; + v.extend_from_slice(name); + v.extend_from_slice(&(data.len() as u32).to_be_bytes()); + v.extend_from_slice(data); + v + } + + #[test] + fn walks_blocks_and_finds_the_data() { + let mut body = block(b"PRD", &[1, 2, 3]); + body.extend(block(b"WBG", &[4; 12])); + let mut f = b"\0MRM".to_vec(); + f.extend_from_slice(&(body.len() as u32).to_be_bytes()); + f.extend_from_slice(&body); + f.extend_from_slice(&[9, 9]); + let m = parse(&f).unwrap(); + assert_eq!(m.block(b"PRD"), Some(&[1u8, 2, 3][..])); + assert_eq!(m.block(b"WBG").map(<[u8]>::len), Some(12)); + assert_eq!(m.block(b"TTW"), None); + assert_eq!(m.data_offset, f.len() - 2); + } + + #[test] + fn hostile_lengths_never_panic() { + assert_eq!(parse(b"\0MRM"), None); + assert_eq!(parse(b"\0MRM\xff\xff\xff\xff"), None); + // a block claiming more than the header holds is dropped + let f = b"\0MRM\0\0\0\x0c\0PRD\xff\xff\xff\xff\0\0\0\0"; + assert_eq!(parse(f).map(|m| m.blocks.len()), Some(0)); + for n in 0..f.len() { + let _ = parse(&f[..n]); + } + } +} diff --git a/crates/pipeline/src/spots.rs b/crates/pipeline/src/spots.rs index 483f83f3c..f8b3fbbdf 100644 --- a/crates/pipeline/src/spots.rs +++ b/crates/pipeline/src/spots.rs @@ -247,8 +247,8 @@ fn fill_box(src: &mut [[f32; 3]], tgt: &[[f32; 3]], alpha: &[f32], bw: usize, bh let flat: Vec = tgt.iter().flatten().copied().collect(); let out = lightcraft_inpaint::complete(bw, bh, 3, &flat, &hole, &lightcraft_inpaint::CompleteParams::default()) .unwrap_or_else(|| lightcraft_inpaint::membrane_fill(bw, bh, 3, &flat, &hole)); - for (d, v) in src.iter_mut().zip(out.chunks_exact(3)) { - *d = [v[0], v[1], v[2]]; + for (d, v) in src.iter_mut().zip(out.as_chunks::<3>().0) { + *d = *v; } } diff --git a/crates/raw/src/lib.rs b/crates/raw/src/lib.rs index 8a09a9edb..fb7ac3c35 100644 --- a/crates/raw/src/lib.rs +++ b/crates/raw/src/lib.rs @@ -100,7 +100,7 @@ pub enum RawFormat { Srw, /// Canon CRW (CIFF heap), the bodies before the CR2 era. Crw, - /// Minolta MRW (`\0MRM` block container). + /// Minolta MRW (`\0MRM` block container, `vendor::mrw`). Mrw, /// Sigma / Foveon X3F (`FOVb`). X3f, @@ -131,6 +131,7 @@ impl RawFormat { | RawFormat::CfaTiff | RawFormat::Srw | RawFormat::KodakDcs + | RawFormat::Mrw ) } } @@ -370,6 +371,7 @@ fn decode_with(bytes: &[u8], mode: Mode) -> Result { RawFormat::CfaTiff => dng::decode_as(bytes, mode, RawFormat::CfaTiff).map(lift_clipped), RawFormat::Srw => vendor::srw::decode(bytes, mode), RawFormat::KodakDcs => vendor::kodak::decode(bytes, mode), + RawFormat::Mrw => vendor::mrw::decode(bytes, mode), RawFormat::OtherTiff => Err(RawError::Unsupported(other_tiff_reason(bytes))), other => Err(RawError::Unsupported(format!("{other:?} files are not decoded yet"))), } @@ -1002,10 +1004,10 @@ mod tests { assert_eq!(probe(b"II\x1a\0\0\0HEAPCCDR\0\0"), Some(RawFormat::Crw)); assert_eq!(probe(b"\0MRM\0\x01\0\0"), Some(RawFormat::Mrw)); assert_eq!(probe(b"FOVb\x02\0\x02\0"), Some(RawFormat::X3f)); - for f in [RawFormat::Crw, RawFormat::Mrw, RawFormat::X3f] { + for f in [RawFormat::Crw, RawFormat::X3f] { assert!(!f.is_supported()); } - assert!(matches!(decode(b"\0MRM\0\x01\0\0"), Err(RawError::Unsupported(w)) if w.contains("Mrw"))); + assert!(matches!(decode(b"FOVb\x02\0\x02\0"), Err(RawError::Unsupported(w)) if w.contains("X3f"))); // too short for the CIFF signature assert_eq!(probe(b"II\x1a\0\0\0HEAP"), None); } diff --git a/crates/raw/src/preview.rs b/crates/raw/src/preview.rs index 4660b737f..e3e882690 100644 --- a/crates/raw/src/preview.rs +++ b/crates/raw/src/preview.rs @@ -616,7 +616,8 @@ mod tests { f.extend_from_slice(part); f.extend_from_slice(&[0u8; 7]); } - assert!(crate::probe(&f).is_some_and(|p| !p.is_supported()), "{head:?}"); + // MRW decodes; its preview is still found by the scan + assert!(crate::probe(&f).is_some_and(|p| !p.is_supported() || p == crate::RawFormat::Mrw), "{head:?}"); assert_eq!(embedded_preview(&f).as_deref(), Some(&big[..]), "{head:?}"); for n in (0..f.len()).step_by(11) { let _ = embedded_preview(&f[..n]); diff --git a/crates/raw/src/vendor/mod.rs b/crates/raw/src/vendor/mod.rs index b7bef1471..62c1b2161 100644 --- a/crates/raw/src/vendor/mod.rs +++ b/crates/raw/src/vendor/mod.rs @@ -11,6 +11,7 @@ pub mod cr3; pub mod crx; pub(crate) mod crx_wavelet; pub mod kodak; +pub mod mrw; pub mod nef; pub mod nefc; pub mod orf; diff --git a/crates/raw/src/vendor/mrw.rs b/crates/raw/src/vendor/mrw.rs new file mode 100644 index 000000000..25d19204e --- /dev/null +++ b/crates/raw/src/vendor/mrw.rs @@ -0,0 +1,230 @@ +//! Minolta / Konica Minolta MRW: a block container (see [`lightcraft_meta::mrw`]) around a 12-bit Bayer mosaic. +//! +//! Sources: the public prose description of the MRW layout (Dalibor Jelínek's MRW notes) and our own black-box +//! analysis of the eight CC0 MRW samples on raw.pixls.us (DiMAGE 7, 7Hi, A1, A2, A200, Dynax / Maxxum / ALPHA-7 +//! Digital); every number below was measured on them. +//! +//! - `PRD` (24 bytes, big-endian): 8 ASCII version bytes, sensor rows and columns (`u16` each), image rows and +//! columns, data size (12 or 16 bits per stored sample), pixel size (12), storage method (`0x59` = 12-bit +//! packed: two samples in three bytes, most significant bits first; `0x52` = one 12-bit sample per big-endian +//! 16-bit word), two unknown bytes and the Bayer layout as a `u16` (`1` = RGGB, `4` = GBRG). The sensor data +//! starts after the header and is exactly sensor rows x columns samples in every sample. +//! - The sensor frame is 8 columns and 6 to 8 rows larger than the image size, but every edge holds picture (no +//! masked border), so the whole frame is the active area and the image size is the default crop. +//! - Black is 0: the darkest samples are 0 in every packed file and 13..34 in the unpacked ones, with no offset +//! left to subtract. White is the saturation plateau where the frame has one (3964 on the A1, 3965 on a clipped +//! DiMAGE 7, 4020 on the A200, 4076 on the 7D), else 4095. +//! - The layout code was checked against the embedded preview: with `1` the two greens are the equal (0,1) and +//! (1,0) positions; in the A200 (`4`) the greens are (0,0) and (1,1), and only red at (1,0) reproduces the +//! preview's red-dominated colour. +//! - `WBG` (12 bytes): four scale bytes, then four big-endian `u16` coefficients in the order of the Bayer cell +//! read row by row (RGGB: R G G B, GBRG: G B R G). Red over green and blue over green are the as-shot gains; +//! applied to the raw channel means they reproduce the preview's colour balance within the colour matrix's +//! reach on all eight samples. +//! - `TTW` is a TIFF with IFD0 (orientation), Exif and the maker note; the preview JPEG sits in it with its first +//! byte overwritten (see `preview::scan_for_jpeg`). +use crate::{BlackLevel, Cfa, ColorData, Mode, OpcodeLists, RawData, RawError, RawFormat, RawImage, Rect, Result, unpack}; +use lightcraft_geom::Orientation; +use lightcraft_tiff::{Tiff, tags as t}; + +/// Storage method codes in `PRD`. +const PACKED_12: u8 = 0x59; +const WORDS_16: u8 = 0x52; + +/// What `PRD` says about the sensor data. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +struct Prd { + sensor: (usize, usize), + image: (usize, usize), + packed: bool, + cfa: &'static str, +} + +fn be16(b: &[u8], at: usize) -> Option { + b.get(at..at + 2).map(|s| u16::from_be_bytes([s[0], s[1]])) +} + +fn prd(b: &[u8]) -> Result { + let u = |at| be16(b, at).map(usize::from).ok_or_else(|| RawError::Corrupt("Mrw PRD block too short".into())); + let (sh, sw, ih, iw) = (u(8)?, u(10)?, u(12)?, u(14)?); + let (size, storage) = (b.get(16).copied(), b.get(18).copied()); + let packed = match (size, storage) { + (Some(12), Some(PACKED_12)) => true, + (Some(16), Some(WORDS_16)) => false, + _ => return Err(RawError::Unsupported(format!("Mrw storage {size:?}/{storage:?} is not decoded yet"))), + }; + let cfa = match u(22)? { + 1 => "RGGB", + 4 => "GBRG", + other => return Err(RawError::Unsupported(format!("Mrw Bayer layout {other}"))), + }; + if sw == 0 || sh == 0 || (packed && sw % 2 != 0) { + return Err(RawError::Corrupt("Mrw sensor size".into())); + } + Ok(Prd { sensor: (sw, sh), image: (iw.min(sw), ih.min(sh)), packed, cfa }) +} + +pub(crate) fn decode(bytes: &[u8], mode: Mode) -> Result { + let m = lightcraft_meta::mrw::parse(bytes).ok_or_else(|| RawError::Corrupt("Mrw block header".into()))?; + let p = prd(m.block(b"PRD").ok_or_else(|| RawError::Unsupported("Mrw file without a PRD block".into()))?)?; + let (w, h) = p.sensor; + let n = w.checked_mul(h).filter(|n| *n <= crate::MAX_SAMPLES).ok_or(RawError::Limit("image too large"))?; + let need = if p.packed { n / 2 * 3 } else { n * 2 }; + let src = bytes + .get(m.data_offset..) + .and_then(|s| s.get(..need)) + .ok_or_else(|| RawError::Corrupt(format!("Mrw sensor data truncated (needs {need} bytes)")))?; + let cfa = Cfa::bayer_static(p.cfa); + let (data, white) = if mode == Mode::Full { + let mut d = vec![0u16; n]; + if p.packed { + unpack::unpack_msb(src, 12, &mut d); + } else { + unpack::read_u16s(src, lightcraft_tiff::ByteOrder::Big, &mut d); + for v in &mut d { + *v = (*v).min(4095); + } + } + let white = super::white_from_data(&d, 12); + (RawData::U16(d), white) + } else { + (RawData::U16(Vec::new()), 4095.0) + }; + let wb = m.block(b"WBG").and_then(|b| wb_from(b, &cfa)); + let tiff = m.block(b"TTW").and_then(|b| Tiff::parse(b).ok()); + let mut metadata = tiff.as_ref().map(lightcraft_meta::from_tiff).unwrap_or_default(); + metadata.width = Some(p.image.0 as u32); + metadata.height = Some(p.image.1 as u32); + let orientation = tiff.as_ref().and_then(|t| t.ifds.first()).and_then(|i| i.u16(t::ORIENTATION)).unwrap_or(1); + let img = RawImage { + format: RawFormat::Mrw, + width: w, + height: h, + cpp: 1, + data, + cfa: Some(cfa), + bits: 12, + black: BlackLevel::uniform(0.0), + white: vec![white], + active_area: Rect::new(0, 0, w, h), + crop: Rect::new(0, 0, p.image.0, p.image.1), + orientation: Orientation::from_exif(orientation), + color: ColorData::default(), + wb_multipliers: wb, + linearized: false, + opcodes: OpcodeLists::default(), + metadata, + }; + img.validate_for(mode)?; + Ok(img) +} + +/// As-shot gains from `WBG`: four coefficients in Bayer-cell order after four scale bytes. +fn wb_from(b: &[u8], cfa: &Cfa) -> Option<[f32; 3]> { + let mut sum = [0f32; 3]; + let mut count = [0f32; 3]; + for (i, &c) in cfa.pattern.iter().enumerate().take(4) { + let v = f32::from(be16(b, 4 + 2 * i)?); + let k = usize::from(c).min(2); + sum[k] += v; + count[k] += 1.0; + } + if count.contains(&0.0) || sum.iter().any(|&s| s <= 0.0) { + return None; + } + let mean = |k: usize| sum[k] / count[k]; + Some([mean(0) / mean(1), 1.0, mean(2) / mean(1)]) +} + +#[cfg(test)] +pub(crate) mod tests { + use super::*; + + /// A synthetic MRW: `PRD` with the given storage, `WBG`, a `TTW` TIFF with orientation 6, then the samples. + pub(crate) fn sample(w: u16, h: u16, packed: bool, layout: u16, wbg: [u16; 4], samples: &[u16]) -> Vec { + let mut prd = b"21810002".to_vec(); + for v in [h, w, h - 2, w - 2] { + prd.extend_from_slice(&v.to_be_bytes()); + } + prd.extend_from_slice(&[if packed { 12 } else { 16 }, 12, if packed { PACKED_12 } else { WORDS_16 }, 0, 0, 0]); + prd.extend_from_slice(&layout.to_be_bytes()); + let mut wb = vec![2u8; 4]; + for v in wbg { + wb.extend_from_slice(&v.to_be_bytes()); + } + let mut ifd0 = lightcraft_tiff::IfdBuilder::new(); + ifd0.set(t::MAKE, lightcraft_tiff::Value::Ascii("Minolta Co., Ltd.".into())); + ifd0.set(t::ORIENTATION, lightcraft_tiff::Value::Short(vec![6])); + let ttw = lightcraft_tiff::TiffWriter::default().write(&[ifd0]).unwrap(); + let mut body = Vec::new(); + for (name, data) in [(b"PRD", &prd), (b"WBG", &wb), (b"TTW", &ttw)] { + body.push(0); + body.extend_from_slice(name); + body.extend_from_slice(&(data.len() as u32).to_be_bytes()); + body.extend_from_slice(data); + } + let mut f = b"\0MRM".to_vec(); + f.extend_from_slice(&(body.len() as u32).to_be_bytes()); + f.extend_from_slice(&body); + if packed { + for p in samples.chunks(2) { + let (a, b) = (p[0], p.get(1).copied().unwrap_or(0)); + f.extend_from_slice(&[(a >> 4) as u8, ((a & 15) << 4) as u8 | (b >> 8) as u8, b as u8]); + } + } else { + for v in samples { + f.extend_from_slice(&v.to_be_bytes()); + } + } + f + } + + #[test] + fn decodes_packed_and_word_storage() { + let (w, h) = (8u16, 6u16); + let px: Vec = (0..48).map(|i| (i * 85) as u16 % 4096).collect(); + for packed in [true, false] { + let f = sample(w, h, packed, 1, [408, 256, 256, 450], &px); + assert_eq!(crate::probe(&f), Some(RawFormat::Mrw)); + let r = crate::decode(&f).unwrap(); + assert_eq!((r.width, r.height, r.bits), (8, 6, 12)); + assert_eq!(r.data, RawData::U16(px.clone()), "packed {packed}"); + assert_eq!(r.cfa.as_ref().map(Cfa::name).as_deref(), Some("RGGB")); + assert_eq!(r.crop, Rect::new(0, 0, 6, 4)); + assert_eq!(r.orientation, Orientation::from_exif(6)); + assert_eq!(r.metadata.make.as_deref(), Some("Minolta Co., Ltd.")); + let wb = r.wb_multipliers.unwrap(); + assert!((wb[0] - 408.0 / 256.0).abs() < 1e-6 && (wb[2] - 450.0 / 256.0).abs() < 1e-6, "{wb:?}"); + assert_eq!(crate::probe_info(&f).unwrap(), r.info()); + } + } + + /// GBRG (layout 4): the coefficients follow the cell, so the second is blue and the third red. + #[test] + fn gbrg_white_balance_follows_the_cell() { + let f = sample(4, 4, true, 4, [255, 416, 480, 255], &[100; 16]); + let r = crate::decode(&f).unwrap(); + assert_eq!(r.cfa.as_ref().map(Cfa::name).as_deref(), Some("GBRG")); + let wb = r.wb_multipliers.unwrap(); + assert!((wb[0] - 480.0 / 255.0).abs() < 1e-6 && (wb[2] - 416.0 / 255.0).abs() < 1e-6, "{wb:?}"); + } + + /// Truncations and corrupted header bytes give errors, never panics. + #[test] + fn malformed_files_never_panic() { + let f = sample(8, 6, true, 1, [408, 256, 256, 450], &[7; 48]); + for n in 0..f.len() { + assert!(crate::decode(&f[..n]).is_err() || n == f.len()); + } + for i in 8..f.len().min(120) { + for v in [0u8, 0xff, 0x52, 0x59] { + let mut g = f.clone(); + g[i] = v; + let _ = crate::decode(&g); + let _ = crate::probe_info(&g); + } + } + assert!(matches!(crate::decode(b"\0MRM\0\x01\0\0"), Err(RawError::Corrupt(_)))); + assert!(matches!(crate::decode(b"\0MRM\0\0\0\0"), Err(RawError::Unsupported(w)) if w.contains("Mrw"))); + } +} diff --git a/crates/raw/tests/corpus.rs b/crates/raw/tests/corpus.rs index 5ca4777b7..7d21d72b0 100644 --- a/crates/raw/tests/corpus.rs +++ b/crates/raw/tests/corpus.rs @@ -1133,3 +1133,51 @@ fn fuji_embedded_lens_tables_follow_the_validated_models() { } eprintln!("Fuji lens tables: {checked} RAFs, {warped} warps, {vignetted} vignette gains"); } + +/// Minolta MRW (`crates/raw/src/vendor/mrw.rs`): packed and 16-bit-word storage, RGGB and GBRG cells, the image +/// size as the crop, the `WBG` gains in cell order and an embedded preview. Skips files that are absent. +#[test] +fn corpus_minolta_mrw() { + let root = corpus_root().join("raw"); + let mut checked = 0; + // (file, sensor size, crop size, cell, white, red gain, blue gain) + for (name, sensor, crop, cell, white, r, b) in [ + ("mrw-minolta-dimage7hi-words16.mrw", (2568, 1928), (2560, 1920), "RGGB", 4095.0, 411.0 / 256.0, 343.0 / 256.0), + ("mrw-minolta-dimage-a1.mrw", (2568, 1928), (2560, 1920), "RGGB", 3964.0, 341.0 / 256.0, 539.0 / 256.0), + ("mrw-minolta-dimage-a200-gbrg.mrw", (3280, 2454), (3264, 2448), "GBRG", 4020.0, 480.0 / 255.0, 416.0 / 255.0), + ("mrw-minolta-dynax7d.mrw", (3016, 2008), (3008, 2000), "RGGB", 4076.0, 435.0 / 256.0, 435.0 / 256.0), + ] { + let Ok(bytes) = std::fs::read(root.join(name)) else { + eprintln!("skip: {name} absent"); + continue; + }; + assert_eq!(probe(&bytes), Some(RawFormat::Mrw), "{name}"); + let img = decode(&bytes).unwrap_or_else(|e| panic!("{name}: {e}")); + assert_eq!(((img.width, img.height), img.bits), (sensor, 12), "{name}"); + assert_eq!((img.crop.width, img.crop.height), crop, "{name}"); + assert_eq!(img.cfa.as_ref().map(|c| c.name()).as_deref(), Some(cell), "{name}"); + assert!((img.white_at(0) - white).abs() <= 8.0, "{name}: white {}", img.white_at(0)); + assert_eq!(img.black.mean(), 0.0, "{name}"); + let wb = img.wb_multipliers.unwrap_or_else(|| panic!("{name}: no white balance")); + assert!((wb[0] - r).abs() < 1e-4 && (wb[2] - b).abs() < 1e-4, "{name}: {wb:?}"); + assert!(img.metadata.make.as_deref().is_some_and(|m| m.to_ascii_uppercase().contains("MINOLTA")), "{name}: {:?}", img.metadata.make); + // the two greens of the cell agree (a wrong cell or a packing slip would split them) + let lightcraft_raw::RawData::U16(d) = &img.data else { panic!("float data") }; + let (w, h) = sensor; + let mean = |y0: usize, x0: usize| { + let (mut s, mut n) = (0f64, 0f64); + for y in (y0..h).step_by(2) { + for x in (x0..w).step_by(2) { + s += f64::from(d[y * w + x]); + n += 1.0; + } + } + s / n + }; + let (g1, g2) = if cell == "RGGB" { (mean(0, 1), mean(1, 0)) } else { (mean(0, 0), mean(1, 1)) }; + assert!((g1 - g2).abs() < 0.02 * g1, "{name}: greens {g1} vs {g2}"); + assert!(embedded_preview(&bytes).is_some(), "{name}: no preview"); + checked += 1; + } + eprintln!("MRW: {checked} corpus files checked"); +} diff --git a/docs/gaps.md b/docs/gaps.md index 7c4f56223..1b229d6bf 100644 --- a/docs/gaps.md +++ b/docs/gaps.md @@ -1,6 +1,6 @@ # Gaps: where LightCraft falls short of Lightroom -> **Last reviewed:** 2026-10-11 · **Last updated:** 2026-10-11 · **Change:** minor (CR3 entry names the EOS R7 C-RAW fix and the refused CRX variants; CI and Windows / Linux entries note the 0.6.0 riscv64 build; camera colour: tone curve from black-and-white camera JPEGs; Compare and Reference get sharp zoom windows; gap 4 shrinks; gap 14: the HDR switch is read from crs XMP; gaps 2 and 10: EOS R5 Mark II CR3 verified) · **Target:** Adobe Lightroom Classic 15.5 / Lightroom 9.6 +> **Last reviewed:** 2026-10-11 · **Last updated:** 2026-10-12 · **Change:** minor (gap 20: Minolta MRW decodes; CR3 entry names the EOS R7 C-RAW fix and the refused CRX variants; CI and Windows / Linux entries note the 0.6.0 riscv64 build; camera colour: tone curve from black-and-white camera JPEGs; Compare and Reference get sharp zoom windows; gap 4 shrinks; gap 14: the HDR switch is read from crs XMP; gaps 2 and 10: EOS R5 Mark II CR3 verified) · **Target:** Adobe Lightroom Classic 15.5 / Lightroom 9.6 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 @@ -24,7 +24,7 @@ Hours are Opus 5.5 agent wall-clock hours (see [target-app-parity.md](target-app | 7 | **Nikon High Efficiency NEF** (HE / HE★ on Z 8, Z 9, Z 6III, Z f, Z50II, Z5II when set to HE) | named and preview only (#193); needs a pure-Rust JPEG XS decoder | +1.1 points (only shots taken in HE; lossless works on the same bodies); low gain per hour (~0.04), so not a beta blocker | 20–40 | [raw-parity](raw-parity.md) | | 8 B | **No lens profile database** (LR-EDIT-OPTICS-PROFILE): only DNG opcodes, RW2 in-file distortion and Sony ILCE-7RM4A distortion | Adobe ships 3,635 lens profiles; we never use them | distortion / vignetting correction is a default step for many | 40–80 + calibration shots | [raw-parity](raw-parity.md#lens-profiles) | | 9 B | **Tests don't run in CI on macOS, Windows or Linux x64**: only FreeBSD runs `cargo test`; the others build packages | `.github/workflows/` (freebsd, packaging-lint, release, windows-arm64); the linux-riscv64 release job added in 0.6.0 (#844) runs only `lightcraft-cli --version` under QEMU | regressions reach users on the main platforms; `cargo xtask ci` runs only locally | 6–12 | [target-app-parity](target-app-parity.md#by-dimension) | -| 10 B | **Per-model verification thin, plus cheap per-body decode fixes**: 235 of 1,446 Adobe models verified (16%), ~42% of photographers on a verified body; Nikon 5 bodies verified, Canon 12. Cheap fixes: Z 6II packed 14-bit NEF (#769, PR #671), Sony A100 / F828 regression (#702), DSLR-A200…A390 / A850 12-bit ARW (#535) | measured: [raw/coverage.tsv](raw/coverage.tsv) | per-body bugs (levels, crops, WB) surface only from users | 25–45 | [raw-parity](raw-parity.md#by-maker-measured) | +| 10 B | **Per-model verification thin, plus cheap per-body decode fixes**: 241 of 1,446 Adobe models verified (17%), ~42% of photographers on a verified body; Nikon 5 bodies verified, Canon 12. Cheap fixes: Z 6II packed 14-bit NEF (#769, PR #671), Sony A100 / F828 regression (#702), DSLR-A200…A390 / A850 12-bit ARW (#535) | measured: [raw/coverage.tsv](raw/coverage.tsv) | per-body bugs (levels, crops, WB) surface only from users | 25–45 | [raw-parity](raw-parity.md#by-maker-measured) | | 11 | **Enhance: Raw Details, Super Resolution; AI denoise without shippable weights or X-Trans** | ENH rows 0%; denoise Bayer only, RawNIND weights GPL and opt-in | Fujifilm users get no AI denoise; nobody gets it out of the box | 30–60 + model decision | [raw-parity](raw-parity.md#demosaic-levels-crops-and-lens-metadata) | | 12 | **Content-aware / generative remove, detect distractions, reflections removal** | REM rows 75%; patch synthesis missing | cleanup work goes back to Photoshop | 25–45 (+ generative model) | [target-app-parity](target-app-parity.md#ai) | | 13 | **Lightroom catalog migration is one-way and approximate**: unsupported Adobe profiles / AI settings archived, history kept as data | lightroom-catalog-import.md | switching users lose some looks | 8–12 | [file-format-parity](file-format-parity.md) | @@ -34,7 +34,7 @@ Hours are Opus 5.5 agent wall-clock hours (see [target-app-parity.md](target-app | 17 | **Tethered capture** | ⬜ | studio photographers | 25–45 + cameras | [hardware-parity](hardware-parity.md) | | 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) | +| 20 | **Long-tail raw formats**: compressed SRW, ARQ pixel shift, IIQ, Hasselblad compression, X3F, CRW, ERF, KDC, DCR, MEF, GPR, old FinePix (MRW decodes since 2026-10-12) | raw-parity.md | small user share each | 40–80 | [raw-parity](raw-parity.md) | | 21 | **Localization**: 9 of 15 shipped languages partial (74–99% of catalog messages), lower-layer errors English; Hindi, Arabic, Indonesian, Korean, Vietnamese absent; no RTL or complex shaping | measured from catalogs | non-English users see mixed English | 55–90 (shipped to full); 145–255 (five new) | [localization-parity](localization-parity.md) | | 22 | **Pen pressure**, OS monitor profiles, follow-window colour | hardware-parity.md | brush users with tablets; multi-monitor setups | 11–22 | [hardware-parity](hardware-parity.md) | | 23 | **Accessibility** audit with screen readers; canvas tools keyboard-reachable | LR-BEHAV-ACCESS 🟡 | blind and low-vision users | 10–20 | [ui-parity](ui-parity.md) | @@ -72,6 +72,7 @@ Beta-blocking gaps (B) total **~230–430 h**; with the stability and platform w | Date | Change | Summary | |---|---|---| +| 2026-10-12 | minor | Gap 20 shrinks: Minolta MRW decodes (`vendor/mrw.rs`), 6 bodies verified; gap 10 count 235 → 241 | | 2026-10-11 | minor | Reviewed against main after 0.6.0: CR3 entry names the CRX variants `crx.rs` still refuses and the R7 / R6 Mark II C-RAW state (decoding, not verified, so the measured numbers don't move); CI and Windows / Linux entries note the riscv64 release build (#844); R7 fix added to Closed recently. Panel docking (UI.9, #869) closes no listed gap | | 2026-10-11 | minor | Camera colour entry: raws with a black-and-white camera JPEG take its tone curve (#577); gap not closed | | 2026-10-11 | minor | Gap 4: Compare and Reference views get zoom windows per pane (1:1 was a 2,560 px render magnified); overlays and soft proofing remain, 8–15 h → 4–8 h | diff --git a/docs/parity-checklist.md b/docs/parity-checklist.md index 77ae26e4c..3848901d3 100644 --- a/docs/parity-checklist.md +++ b/docs/parity-checklist.md @@ -1,6 +1,6 @@ # Lightroom parity checklist -> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-11 · **Change:** minor (rapid slider entry; LR-PROF-CAMERACOLOR: tone curve from black-and-white camera JPEGs; LR-VIEW-ZOOM, LR-VIEW-COMPARE: Compare and Reference zoom windows; LR-IMP-FORMATS, LR-IMP-CAMERA-COVERAGE: EOS R5 Mark II CR3 decodes; renamed from `parity.md`; Top gaps moved to gaps.md, shortcut notes to ui-parity.md; filesystem history retry/Undo/Redo evidence; renamed from `parity.md`; Top gaps moved to gaps.md, shortcut notes to ui-parity.md) · **Target:** Adobe Lightroom Classic 15.5 / Lightroom 9.6 +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-12 · **Change:** minor (LR-IMP-FORMATS: Minolta MRW decodes; rapid slider entry; LR-PROF-CAMERACOLOR: tone curve from black-and-white camera JPEGs; LR-VIEW-ZOOM, LR-VIEW-COMPARE: Compare and Reference zoom windows; LR-IMP-FORMATS, LR-IMP-CAMERA-COVERAGE: EOS R5 Mark II CR3 decodes; renamed from `parity.md`; Top gaps moved to gaps.md, shortcut notes to ui-parity.md; filesystem history retry/Undo/Redo evidence; renamed from `parity.md`; Top gaps moved to gaps.md, shortcut notes to ui-parity.md) · **Target:** Adobe Lightroom Classic 15.5 / Lightroom 9.6 The measured, row-by-row checklist: one row per Lightroom feature, menu item and shortcut, what we have and what is missing. It answers *does the feature exist?* (feature breadth). Whether it is good @@ -80,7 +80,7 @@ differences and missing bindings are in [ui-parity.md](ui-parity.md#shortcuts). | LR-IMP-PROFILES | Import profiles & presets | P1 | ✅ | `cmd:file.importPresets`, `cmd:preset.import`, `cmd:profile.import`, `crates/engine/src/preset_import.rs`, `crates/engine/src/preset_luminar.rs` | presets: .lcpreset, XMP, classic .lrtemplate, photos carrying edits ("DNG presets"), Luminar looks (.lmp, .mplumpack collections; sliders with a counterpart), .zip bundles, folders (folder → group), drag & drop (an `.xmp` dropped together with its photo is that photo's sidecar and is not imported as a preset, issue #936); masks carried over; unmapped settings reported (fields that only describe the preset or photo, e.g. `Cluster`, `SortName`, `SupportsAmount2`, the as-shot white, empty Point Color slots, are not); profiles: .cube 3D LUTs (one toast reports both halves; a LUT that fails is named with its reason); Adobe profile formats deliberately unsupported | | LR-IMP-LOCAL | Work on files in place | P0 | ✅ | `cmd:library.browse`, `cmd:photo.addToLibrary`, `cmd:library.import` (mode add), `cmd:local.addRoot`, `cmd:local.hide`, `cmd:local.restoreHidden`, `crates/engine/src/cmd/browse.rs`, `crates/ui-egui/src/panels/left.rs` (`local_section`), `crates/ui-egui/src/panels/grid.rs` (`folder_header`) | Local: browse Pictures / Desktop / Downloads / Home or any folder without adding it (breadcrumb, Include subfolders, Add N to My Photos); browsed photos stay out of All Photos, albums and counts (album commands skip them and the album menus say to Add to My Photos first, issue #684); folders picked with Browse Folder… (or Keep in Local / Add to Local on a folder row) stay listed across restarts, and browsing a folder inside a listed one highlights it inside that tree (opened down to it, siblings reachable) instead of adding a root; edits go to XMP sidecars; importing promotes them; right-click a top-level location → Remove from Local hides the shortcut only (nothing on disk or in the catalog changes), saved with the UI state, and “Show N hidden locations” (or Browse Folder… on it) brings it back; a folder is one location however its path is spelled (`/` or `\`, trailing separator, `.`/`..`, drive-letter case; `folder_key` in `crates/catalog/src/query.rs`); browsed photos nobody changed are forgotten once their folder has not been browsed for 30 days (Settings → Performance → Local folders, 0 = never; checked when the library opens, or `cmd:library.forgetLocal` with `dryRun`; files and sidecars stay, browsing again brings them back; see `crates/catalog/src/local.rs` for what counts as a change) | | LR-IMP-SIDECAR-SPLIT | Separate XMP sidecar variants | P2 | ⬜ | `cmd:library.xmpPreferences` | sidecar naming option exists (stem/full), no split sidecars | -| LR-IMP-FORMATS | Supported formats | P0 | 🟡 | `crates/codecs/src/lib.rs`, `crates/raw/src/lib.rs`, `crates/raw/src/jxl.rs` | JPEG, PNG, TIFF (1- to 64-bit integer, 16- to 64-bit float, incl. bilevel and CCITT fax), WebP, JXL, PSD, GIF, BMP (lossy wide-gamut JXL decodes to the right colours: jxl-oxide desaturated XYB rendered to P3/Rec. 2020, worked around in `crates/codecs/src/jxl.rs`); DNG (incl. lossy / Smart Preview DNG and DNG 1.7 JPEG XL tiles/strips: lossless ones decode bit-exactly on synthetic CFA and LinearRaw files, lossy ones are restored to the declared linear primaries without clipping or gamut mapping, checked on one real file with 108 lossy tiles, and any tile that fails to decode makes the file preview-only; DNG 1.7 row/column-interleaved rasters (`RowInterleaveFactor` / `ColumnInterleaveFactor`) are undone before the mosaic is read, so a file from Adobe's converter with a 2×2 interleave no longer decodes as four scaled-down copies in the wrong colours; a dimension the factor does not divide decodes with short trailing fields; verified on 4 real ILCE-6400 JPEG XL DNGs rendering bit-identical to their non-interleaved twins, factors above 2 rest on the plain reading of the tag; a single-chunk JPEG XL preview IFD is offered as the embedded preview; a DNG whose samples pile up at one value well below its stated `WhiteLevel`, as a camera app's 12-bit Bayer DNG that states 4095 and clips at 3567, has those samples raised to the white level on decode, so highlight reconstruction sees the clipped areas instead of white balance tinting them magenta, issue #548, `crates/raw/src/saturation.rs`), CR2 (colour-filter layout from the file's `CR2CFAPattern` tag, issue #85), ARW (pre-2017 bodies: white balance and black level from the encrypted `SR2SubIFD`, issue #148, its `WB_RGGBLevels` being the white balance the camera applied, issue #535; the DSLR-A900's packed 12-bit strip, two pixels per three bytes, read only when the strip is exactly 1.5 bytes per pixel, with its camera-JPEG window centred, checked on one CC0 file (A850 unmeasured); downsized Sony lossless YCbCr 4:2:0 / 4:2:2 tiles decoded to linear RGB, verified on private ILCE-7M4 3:2 & 4:3 examples including 16-bit full-resolution export; Sony DSC-R1 .SR2 decodes, its big-endian 16-bit words read in the order that fits the sample range, checked on the CC0 3221 sample; its crop and white balance live in the SR2SubIFD and are not read yet; ARW6 Compressed / Compressed (HQ) of the ILCE-7RM6 (`crates/raw/src/vendor/arw6.rs`, `crates/raw/src/llvc.rs`; 12-bit codes exact against a black-box oracle on 8 CC0 files, FF over the full frame, APS-C in the interior (LibRaw's own edge rows differ); output through our own companding curve, measured from CC0 lossless / ARW6 pairs; geometry checked against the camera JPEG, `docs/arw6-compression.md`; the ILCE-7M5 writes the same codec, unverified)), NEF (uncompressed, lossless and lossy compressed 12/14-bit, `crates/raw/src/vendor/nefc.rs`), RAF (uncompressed, lossless/lossy compressed Bayer and X-Trans; `crates/raw/src/vendor/rafc.rs`, full sensor verification on 13 bodies, `docs/raf-compression.md`), RW2 / Leica RWL / Panasonic RAW in every raw format (compressed 4 and 6, the prefix-coded strips of format 8 from the GH6 on, packed 2/5/7, the 16-bit words of the 2005–2007 bodies; black levels, in-camera aspect crops and mapped-out defect pixels; 178 CC0 files from 118 bodies checked, `crates/raw/src/vendor/rw2.rs`), PEF, ORF (uncompressed; colour-filter layout from the file's Exif `CFAPattern`; 12.8 bit/px 16-byte blocks of ten 12-bit samples + a zero pad byte, E-300 / E-330 / E-500 verified on CC0 files, E-M5 Mark II / PEN-F high-res files decode smooth but CFA and black unverified), Kodak DCS520C TIFF (a two-component 12-bit lossless JPEG strip, the two components the even and odd columns; the file's `GrayResponseCurve` table linearises the companded samples to 12 bits, black measured per CFA position, white balance from the `KodakIFD`; `RawFormat::KodakDcs`, `crates/raw/src/vendor/kodak.rs`, checked on the one CC0 sample against its IFD0 thumbnail), Hasselblad 3FR and FFF (a TIFF without a DNG version tag that describes its CFA IFD, levels, crop and white balance with DNG's tags; `RawFormat::CfaTiff`, read by `dng::decode_as`, RGGB when the file states no `CFAPattern`): uncompressed (X1D, X1D II, X2D, CFV 100C) and Hasselblad's lossless JPEG with scan selection value 8 (every FFF; H3D, H4D and CFV-50c 3FR), `ljpeg::decode_hasselblad`, its rule measured on 14 CC0 files with the ljpeg-explorer tool, Samsung SRW without compression (NX5, NX10, NX11 and the NX20-generation bodies NX20, NX200, NX210, NX1000 and NX1100 as 12-bit packed samples in either bit order, EX1 and WB2000 as 16-bit words; layout, camera-JPEG framing, levels and white balance from the maker note, `crates/raw/src/vendor/srw.rs`; median ΔE vs the camera JPEG 2.2–7.6 on 11 of the 12 files from 10 bodies checked, 10.7 (5.7 registered) on the backlit WB2000 sample). 12-bit NEF black level: maker note `0x003d` is in 14-bit units (D750, D780, D850, D7500, Z 50 checked). Lossy type 2 NEF curves of version `0x44 0x40` (D780, D6, Z 5, Z 6, Z 7, Z 7_2) span a quarter of the sample range, read from the table's own point spacing. Import probes (`probe_info`) of compressed NEFs decode only the first 128 rows, the ones the masked-trailing-column test reads in both the probe and the full decode (the D5100 and D7000 write 8 masked columns at 0 with no maker-note tag for them, compressed and uncompressed alike), instead of the whole Huffman stream: ~3 ms instead of the full decode time per file (386 ms on a 24 MP D750 file), issue #708. CR3 lossless CRX Bayer and version 0x100/0x200 C-RAW decodes to sensor pixels with timed white balance, black/white levels and file crop (the shot's aspect ratio from the maker note's `AspectInfo`); full sensor samples match the reference on M50/R100/R8 (`crates/raw/tests/cr3_corpus.rs`, `docs/cr3.md`). EOS R5 Mark II C-RAW and RAW decode too (the QP map's first-symbol literal and 23-zero escape, odd-height Bayer planes): 4 CC0 files pinned, every QP map of 33,665 private C-RAW files decodes exactly, and full-frame images match the camera JPEG. Unsupported coding variants retain metadata and use the embedded JPEG when available; HEVC preview decoding remains unsupported. Missing: CR3 unverified CRX variants, compressed ORF, compressed Samsung SRW (NX1, NX30, NX300, NX500, NX2000, NX3000, NX3300, NX mini: preview only with the reason), NEFs labelled compressed (34713) but stored uncompressed without a `0x0096` table (Z 6 packed 14-bit, D850 12-bit uncompressed), Nikon High Efficiency NEF (HE / HE★ from the Z 8, Z 9, Z 6III and Z f: compression 34713 with a JPEG XS codestream and no `0x0096` table; no public specification, so preview only with the reason "Nikon High Efficiency NEF", issue #193; Lossless compressed NEFs from the same bodies decode), NEF "lossy after split" (preview only: imported with `preview_only` = the decoder's reason, rendered as a rendered JPEG, flagged by a grid badge and loupe/Edit/Info notices, `previewOnly` in `catalog.query`; Reload clears it once the file decodes), TIFF-based raws whose raw data sits in a private block (Phase One / Leaf IIQ, Canon EOS-1D / 1Ds and the Kodak DCS Pro / DCS760C TIFFs (compression 65000): IFD0 is only a reduced RGB image next to a much larger declared picture) are recognised from that structure and import as `preview_only` with the reason, instead of opening as a thumbnail-sized ordinary image (`thumbnail_shell` in `crates/raw/src/lib.rs`), Recognised raws LightCraft cannot decode open as `preview_only` with any usable embedded JPEG, also Canon CRW, Minolta MRW and Sigma X3F (containers recognised by magic, preview found by a structural JPEG scan), Kodak KDC (IFD0 without `ImageWidth`), Leaf MOS and Epson ERF (scan), and any decode failure of a recognised raw, not only an unsupported variant; ones with no JPEG still fail with "without an embedded preview", AVIF decode (HEIC decodes only behind the non-default `heif` feature, which the release packages enable: `crates/heif`, heic-rs for the container and HEVC (bit-exact against libde265 on iPhone tiles) plus our own colour conversion, matching libheif within 1 code value on iPhone-style grids (VUI full range, Display P3 ICC, nclx, 10-bit, irot/imir/clap, gain map/depth ignored); 4:2:0/monochrome only, 4:2:2/4:4:4 Canon/Sony HIF refused; same policy as PhotoCraft), palette (indexed-colour) TIFF (refused by the `tiff` crate) | +| LR-IMP-FORMATS | Supported formats | P0 | 🟡 | `crates/codecs/src/lib.rs`, `crates/raw/src/lib.rs`, `crates/raw/src/jxl.rs` | JPEG, PNG, TIFF (1- to 64-bit integer, 16- to 64-bit float, incl. bilevel and CCITT fax), WebP, JXL, PSD, GIF, BMP (lossy wide-gamut JXL decodes to the right colours: jxl-oxide desaturated XYB rendered to P3/Rec. 2020, worked around in `crates/codecs/src/jxl.rs`); DNG (incl. lossy / Smart Preview DNG and DNG 1.7 JPEG XL tiles/strips: lossless ones decode bit-exactly on synthetic CFA and LinearRaw files, lossy ones are restored to the declared linear primaries without clipping or gamut mapping, checked on one real file with 108 lossy tiles, and any tile that fails to decode makes the file preview-only; DNG 1.7 row/column-interleaved rasters (`RowInterleaveFactor` / `ColumnInterleaveFactor`) are undone before the mosaic is read, so a file from Adobe's converter with a 2×2 interleave no longer decodes as four scaled-down copies in the wrong colours; a dimension the factor does not divide decodes with short trailing fields; verified on 4 real ILCE-6400 JPEG XL DNGs rendering bit-identical to their non-interleaved twins, factors above 2 rest on the plain reading of the tag; a single-chunk JPEG XL preview IFD is offered as the embedded preview; a DNG whose samples pile up at one value well below its stated `WhiteLevel`, as a camera app's 12-bit Bayer DNG that states 4095 and clips at 3567, has those samples raised to the white level on decode, so highlight reconstruction sees the clipped areas instead of white balance tinting them magenta, issue #548, `crates/raw/src/saturation.rs`), CR2 (colour-filter layout from the file's `CR2CFAPattern` tag, issue #85), ARW (pre-2017 bodies: white balance and black level from the encrypted `SR2SubIFD`, issue #148, its `WB_RGGBLevels` being the white balance the camera applied, issue #535; the DSLR-A900's packed 12-bit strip, two pixels per three bytes, read only when the strip is exactly 1.5 bytes per pixel, with its camera-JPEG window centred, checked on one CC0 file (A850 unmeasured); downsized Sony lossless YCbCr 4:2:0 / 4:2:2 tiles decoded to linear RGB, verified on private ILCE-7M4 3:2 & 4:3 examples including 16-bit full-resolution export; Sony DSC-R1 .SR2 decodes, its big-endian 16-bit words read in the order that fits the sample range, checked on the CC0 3221 sample; its crop and white balance live in the SR2SubIFD and are not read yet; ARW6 Compressed / Compressed (HQ) of the ILCE-7RM6 (`crates/raw/src/vendor/arw6.rs`, `crates/raw/src/llvc.rs`; 12-bit codes exact against a black-box oracle on 8 CC0 files, FF over the full frame, APS-C in the interior (LibRaw's own edge rows differ); output through our own companding curve, measured from CC0 lossless / ARW6 pairs; geometry checked against the camera JPEG, `docs/arw6-compression.md`; the ILCE-7M5 writes the same codec, unverified)), NEF (uncompressed, lossless and lossy compressed 12/14-bit, `crates/raw/src/vendor/nefc.rs`), RAF (uncompressed, lossless/lossy compressed Bayer and X-Trans; `crates/raw/src/vendor/rafc.rs`, full sensor verification on 13 bodies, `docs/raf-compression.md`), RW2 / Leica RWL / Panasonic RAW in every raw format (compressed 4 and 6, the prefix-coded strips of format 8 from the GH6 on, packed 2/5/7, the 16-bit words of the 2005–2007 bodies; black levels, in-camera aspect crops and mapped-out defect pixels; 178 CC0 files from 118 bodies checked, `crates/raw/src/vendor/rw2.rs`), PEF, ORF (uncompressed; colour-filter layout from the file's Exif `CFAPattern`; 12.8 bit/px 16-byte blocks of ten 12-bit samples + a zero pad byte, E-300 / E-330 / E-500 verified on CC0 files, E-M5 Mark II / PEN-F high-res files decode smooth but CFA and black unverified), Kodak DCS520C TIFF (a two-component 12-bit lossless JPEG strip, the two components the even and odd columns; the file's `GrayResponseCurve` table linearises the companded samples to 12 bits, black measured per CFA position, white balance from the `KodakIFD`; `RawFormat::KodakDcs`, `crates/raw/src/vendor/kodak.rs`, checked on the one CC0 sample against its IFD0 thumbnail), Hasselblad 3FR and FFF (a TIFF without a DNG version tag that describes its CFA IFD, levels, crop and white balance with DNG's tags; `RawFormat::CfaTiff`, read by `dng::decode_as`, RGGB when the file states no `CFAPattern`): uncompressed (X1D, X1D II, X2D, CFV 100C) and Hasselblad's lossless JPEG with scan selection value 8 (every FFF; H3D, H4D and CFV-50c 3FR), `ljpeg::decode_hasselblad`, its rule measured on 14 CC0 files with the ljpeg-explorer tool, Minolta / Konica Minolta MRW (the `\0MRM` block container: `PRD` sensor size, 12-bit packed or 16-bit-word storage and the RGGB / GBRG cell, `WBG` gains in cell order, the `TTW` TIFF for Exif and orientation, black 0 and white from the saturation plateau; `crates/raw/src/vendor/mrw.rs`, DiMAGE 7, 7Hi, A1, A2, A200 and Dynax / Maxxum 7D checked on CC0 files against their previews), Samsung SRW without compression (NX5, NX10, NX11 and the NX20-generation bodies NX20, NX200, NX210, NX1000 and NX1100 as 12-bit packed samples in either bit order, EX1 and WB2000 as 16-bit words; layout, camera-JPEG framing, levels and white balance from the maker note, `crates/raw/src/vendor/srw.rs`; median ΔE vs the camera JPEG 2.2–7.6 on 11 of the 12 files from 10 bodies checked, 10.7 (5.7 registered) on the backlit WB2000 sample). 12-bit NEF black level: maker note `0x003d` is in 14-bit units (D750, D780, D850, D7500, Z 50 checked). Lossy type 2 NEF curves of version `0x44 0x40` (D780, D6, Z 5, Z 6, Z 7, Z 7_2) span a quarter of the sample range, read from the table's own point spacing. Import probes (`probe_info`) of compressed NEFs decode only the first 128 rows, the ones the masked-trailing-column test reads in both the probe and the full decode (the D5100 and D7000 write 8 masked columns at 0 with no maker-note tag for them, compressed and uncompressed alike), instead of the whole Huffman stream: ~3 ms instead of the full decode time per file (386 ms on a 24 MP D750 file), issue #708. CR3 lossless CRX Bayer and version 0x100/0x200 C-RAW decodes to sensor pixels with timed white balance, black/white levels and file crop (the shot's aspect ratio from the maker note's `AspectInfo`); full sensor samples match the reference on M50/R100/R8 (`crates/raw/tests/cr3_corpus.rs`, `docs/cr3.md`). EOS R5 Mark II C-RAW and RAW decode too (the QP map's first-symbol literal and 23-zero escape, odd-height Bayer planes): 4 CC0 files pinned, every QP map of 33,665 private C-RAW files decodes exactly, and full-frame images match the camera JPEG. Unsupported coding variants retain metadata and use the embedded JPEG when available; HEVC preview decoding remains unsupported. Missing: CR3 unverified CRX variants, compressed ORF, compressed Samsung SRW (NX1, NX30, NX300, NX500, NX2000, NX3000, NX3300, NX mini: preview only with the reason), NEFs labelled compressed (34713) but stored uncompressed without a `0x0096` table (Z 6 packed 14-bit, D850 12-bit uncompressed), Nikon High Efficiency NEF (HE / HE★ from the Z 8, Z 9, Z 6III and Z f: compression 34713 with a JPEG XS codestream and no `0x0096` table; no public specification, so preview only with the reason "Nikon High Efficiency NEF", issue #193; Lossless compressed NEFs from the same bodies decode), NEF "lossy after split" (preview only: imported with `preview_only` = the decoder's reason, rendered as a rendered JPEG, flagged by a grid badge and loupe/Edit/Info notices, `previewOnly` in `catalog.query`; Reload clears it once the file decodes), TIFF-based raws whose raw data sits in a private block (Phase One / Leaf IIQ, Canon EOS-1D / 1Ds and the Kodak DCS Pro / DCS760C TIFFs (compression 65000): IFD0 is only a reduced RGB image next to a much larger declared picture) are recognised from that structure and import as `preview_only` with the reason, instead of opening as a thumbnail-sized ordinary image (`thumbnail_shell` in `crates/raw/src/lib.rs`), Recognised raws LightCraft cannot decode open as `preview_only` with any usable embedded JPEG, also Canon CRW and Sigma X3F (containers recognised by magic, preview found by a structural JPEG scan), Kodak KDC (IFD0 without `ImageWidth`), Leaf MOS and Epson ERF (scan), and any decode failure of a recognised raw, not only an unsupported variant; ones with no JPEG still fail with "without an embedded preview", AVIF decode (HEIC decodes only behind the non-default `heif` feature, which the release packages enable: `crates/heif`, heic-rs for the container and HEVC (bit-exact against libde265 on iPhone tiles) plus our own colour conversion, matching libheif within 1 code value on iPhone-style grids (VUI full range, Display P3 ICC, nclx, 10-bit, irot/imir/clap, gain map/depth ignored); 4:2:0/monochrome only, 4:2:2/4:4:4 Canon/Sony HIF refused; same policy as PhotoCraft), palette (indexed-colour) TIFF (refused by the `tiff` crate) | | LR-IMP-CAMERA-COVERAGE | Camera coverage, verified per model | P0 | 🟡 | `crates/raw/tests/corpus.rs`, `xtask/src/main.rs` | a supported container is not the same as every camera that writes it decoding correctly: ~55 CC0 corpus files plus 6 exact-sensor CR3 cases and 4 pinned EOS R5 Mark II files (plus ~60 NEFs checked by hand and 178 Panasonic / Leica RW2, RWL and RAW files from 118 bodies, checked against each file's own JPEG) against the >1,000 models Lightroom lists; per-model differences still surface (e.g. the CR2 colour-filter layout differed by model until it was read from the file's own tag, issue #85, checked on 35 CR2 bodies; CR2 black levels were read from border columns light already reaches, left of `SensorInfo`'s border, so CR2s rendered dark with crushed shadows (EOS 6D: 2591 instead of 2047), now measured from the masked columns only, checked on 8 corpus bodies; pre-2017 Sony ARWs opened green until their scrambled white balance / black level were read, issue #148, checked on 16 ARWs from 15 Sony bodies; their white balance now comes from the encrypted `SR2SubIFD`'s `WB_RGGBLevels`, the gains the camera applied, which 14 bodies (DSLR-A450 … A700, NEX-3/5/C3, SLT-A33/A35/A55, ILCE-6001, UMC-R10C) had no other source for and which the maker-note estimate read before missed by up to 100 % on preset shots, issue #535, checked against ExifTool on 100 decoded ARWs from 87 Sony bodies; the encrypted SR2 black level is now read from its directory entry (the DSLR-A450/A500/A550/A700 read 354–975 instead of 512), checked on 126 ARWs from 97 Sony bodies, and downsized lossless M/S ARWs use their measured black level 1024 instead of 512, checked on 12 files from 4 bodies, issue #535, and on a fifth, the ILCE-7CM2 (issue #697: 0.5.0 rendered its lossless M file with that 512 pedestal, the darkest half of a dusk scene +11 L* and blue, the lamplight white; its darkest 0.1 % per channel sits at 1017/1020/1024, and with 1024 the render is within +3 L* of the camera JPEG; the body's compressed and uncompressed "M-size" files are Bayer at 4736×3132 with black 512, two public ones in the corpus); pre-2017 Sony bodies shot in the camera's 16:9 mode (ILCE-7SM2, DSLR-A580) now get the 16:9 crop of their camera JPEG instead of the whole 3:2 frame with padding columns, issue #535; Canon PowerShot and EOS M CR2s whose `ColorData` is stored as bytes opened green until the bytes were read as 16-bit words, 25 files from 25 bodies checked). Compressed RAF sensor arrays verified on 13 Fujifilm bodies (`docs/raf-compression.md`). ILCE-7RM6 ARW6 12-bit codes verified on 8 CC0 files (FF and APS-C, both compression modes). Sony ILCE-7CR (61 MP): lossless compressed L and M and compressed ARW2 samples of one scene in the corpus (black level, default crop, as-shot gains, lossless vs compressed mosaic agreement, fitted camera look), and all nine public codings (also uncompressed, small and APS-C crop) decode and fit. Grow the CC0 corpus per model and test each sample decodes with plausible colour. Nikon CropArea and untagged-preview colour-space regression tests; private Z 8 crop verified; the Nikon D4, which records no CropArea, gets its image area and white level measured on 148 NEFs against the camera JPEG (optical-black stripes and magenta clipped highlights gone). | | LR-IMP-PREVIEW-READ | Preview reads the header, not the raw | P0 | ✅ | `crates/raw/src/preview.rs` (`bounded_preview`, `embedded_preview_from_range`), `crates/engine/src/files.rs` (`preview_window`), `docs/raw-preview-reads.md` | a grid thumbnail and a loupe preview of an unedited raw show the camera's embedded JPEG, which sits near the start of the file (a 24 MP Fuji RAF keeps its 5.6 MB JPEG in a 56 MB file), so the preview loader reads the header and that JPEG instead of the whole file: 56.5 MB → 5.9 MB and ~10 s → 0.96 s measured on one real RAF over a GVFS/SMB Wi-Fi share (byte-identical preview pixels; `LIGHTCRAFT_PROFILE=1` reports the bytes); the RAF pointer is read from its fixed header fields, formats whose preview only the whole file reveals (CR3 boxes, TIFF pointer tags past the prefix, CRW/MRW/X3F scans) keep the whole-file path, and a lying pointer, a short read or a file that changes underneath us falls back to it rather than losing the preview. An unedited raw's **grid thumbnail is that camera JPEG itself**, so no sensor decode is scheduled behind it (`Session::embedded_thumb_is_final`, `grid::skips_the_real_render`): drawing a 512 px thumbnail used to decode the whole raw — 45 s a photo at 1.2 MB/s, 8.3 GB for a 149-raw folder — and the queue it built delayed the render the user was waiting for; a cached render as stand-in, an edited photo and a raw without an embedded JPEG still render | | LR-IMP-CULL-AT-IMPORT | Culling analysis at import | P2 | 🟡 | `cmd:photo.analyze` | run Assisted Culling on the imported photos (they're selected after an import); not automatic | @@ -787,6 +787,7 @@ Latin stays upright. Advanced Japanese composition remains open. Regression cove | Date | Change | Summary | |---|---|---| +| 2026-10-12 | minor | LR-IMP-FORMATS: Minolta MRW decodes from sensor data (`vendor/mrw.rs`), no longer preview-only | | 2026-10-11 | minor | KEY-SLIDER-TYPE: honor immediate Return/Escape and keep typed keys in the value editor; add regression references | | 2026-10-11 | minor | LR-PROF-CAMERACOLOR: raws with a black-and-white camera JPEG take its tone curve (issue #577) | | 2026-10-11 | minor | LR-VIEW-ZOOM and LR-VIEW-COMPARE: Compare and Reference are sharp at 1:1 (zoom windows per pane, two originals kept decoded while they are open); statuses unchanged | diff --git a/docs/raw-parity.md b/docs/raw-parity.md index 2b4b9efb5..49cfa73d1 100644 --- a/docs/raw-parity.md +++ b/docs/raw-parity.md @@ -1,6 +1,6 @@ # RAW parity: cameras, formats, demosaic, colour and lens profiles -> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-11 · **Change:** minor (EOS R5 Mark II decoded and verified: CRX QP-map escape, odd-height planes) · **Target:** Adobe Lightroom Classic 15.5 / Lightroom 9.6 (Camera Raw 18.7) +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-12 · **Change:** minor (Minolta MRW decoded: 6 bodies verified) · **Target:** Adobe Lightroom Classic 15.5 / Lightroom 9.6 (Camera Raw 18.7) Raw processing is the deepest single dimension of Lightroom parity: a photographer whose camera does not decode, or decodes with the wrong colour, cannot switch. This document measures it model by @@ -14,9 +14,9 @@ ranked in [gaps.md](gaps.md). Details per format: [cr3.md](cr3.md), | Measure | Value | Kind | |---|---:|---| | Adobe-listed camera models | **1,446** | measured: [raw/adobe-cameras.tsv](raw/adobe-cameras.tsv) | -| Decoded from sensor data and **verified** on a real file | **235** (16%) | measured: [raw/evidence.tsv](raw/evidence.tsv) | -| Decoder path should handle it, **unverified** | **942** (65%) | measured from the format rules (632 of them DNG, mostly phones) | -| **Preview-only** (embedded JPEG) | **233** (16%) | measured | +| Decoded from sensor data and **verified** on a real file | **241** (17%) | measured: [raw/evidence.tsv](raw/evidence.tsv) | +| Decoder path should handle it, **unverified** | **947** (65%) | measured from the format rules (632 of them DNG, mostly phones) | +| **Preview-only** (embedded JPEG) | **222** (15%) | measured | | **Unsupported** (not imported, refused or decodes wrongly) | **36** (2%) | measured | | Models added since 2017 (Camera Raw 10+): verified / unverified / preview / unsupported | 82 / 640 / 24 / 8 of 754 | measured | | **Share of photographers whose camera fully works** (decodes from sensor data), use-weighted | **~85%** | estimated: measured classes × written usage weights × per-format confidence | @@ -41,7 +41,7 @@ committed table is stale. `lightcraft_engine::import::EXTENSIONS`, and `KNOWN_UNSUPPORTED` in `crates/raw/tests/corpus.rs`. Doc claims were not used. - **Verified** means a real file from that body decoded from sensor data in: the corpus test over the - `RAW_SAMPLES` manifest (`xtask/src/main.rs`, 101 CC0 files; bodies whose sample is in + `RAW_SAMPLES` manifest (`xtask/src/main.rs`, 105 CC0 files; bodies whose sample is in `KNOWN_UNSUPPORTED` excluded), `crates/raw/tests/cr3_corpus.rs` (3 bodies exact against an external decoder; the EOS R5 Mark II pinned, with a QP-map check of 33,665 private files), the RAF reference check ([raf-compression.md](raf-compression.md)), and the raw.pixls.us bulk checks recorded in issue @@ -80,8 +80,8 @@ committed table is stale. | Casio | 26 | 0 | 26 | 0 | 0 | — (DNG) | | DJI | 21 | 0 | 21 | 0 | 0 | — (DNG) | | OM Digital Solutions | 7 | 0 | 0 | 7 | 0 | **compressed ORF** | -| Kodak, Konica Minolta, Epson, Sigma, GoPro, Contax, others | 56 | 0 | 14 | 27 | 15 | DCR, GPR not imported; KDC, MRW, ERF, X3F preview | -| **All** | **1,446** | **235 (16%)** | **942 (65%)** | **233 (16%)** | **36 (2%)** | | +| Kodak, Konica Minolta, Epson, Sigma, GoPro, Contax, others | 56 | 6 | 19 | 16 | 15 | DCR, GPR not imported; KDC, ERF, X3F preview (MRW decodes) | +| **All** | **1,446** | **241 (17%)** | **947 (65%)** | **222 (15%)** | **36 (2%)** | | ## By use (estimated) @@ -97,7 +97,7 @@ committed table is stale. | Pentax / Ricoh | 1.5% | 94% | 14% | | | Leica | 1% | 95% | 5% | | | DJI | 1% | 95% | 0% | | -| Medium format and others | 0.5% | 23% | 0% | IIQ, 3FR, X3F | +| Medium format and others | 0.5% | 28% | 3% | IIQ, 3FR, X3F | | **Weighted** | 100% | **85%** | **42%** | | About 5 in 6 raw photographers' cameras decode, but only about 2 in 5 use a body we have actually @@ -144,7 +144,8 @@ checked, and Canon, the largest bucket, is the weakest of the big four. | DNG | GoPro GPR (VC-5) | ⬜ | refused | | 3FR / FFF | DNG-like layouts | 🟡 | decoded when uncompressed or LJ92 | | 3FR / FFF | Hasselblad compression | ⬜ | preview | -| IIQ, MOS, MRW, ERF, KDC, X3F | all | ⬜ | preview | +| MRW | 12-bit packed, 16-bit words; RGGB and GBRG | ✅ | 4 CC0 corpus files (DiMAGE 7Hi, A1, A200, Dynax 7D) plus DiMAGE 7 and A2 checked against their previews; `vendor/mrw.rs` | +| IIQ, MOS, ERF, KDC, X3F | all | ⬜ | preview | | DCR, MEF, MFW, DXO, GPR, TIFF raws | all | ⬜ | not imported | ### Compressed ORF: a clean-room starting point @@ -251,7 +252,7 @@ works, from [raw/usage-weights.tsv](raw/usage-weights.tsv). | 7 | Sony A100 and DSC-F828 regression (#702) | +0.1 | 1–2 | ~0.07 | samples on raw.pixls.us | | 8 | Canon CRW (2000–2004 bodies) | +1.2 by the uniform tail weight, far less by real use | 6–12 | ≤ 0.1 | samples | | 9 | Nikon HE / HE★ NEF (Z 8, Z 9, Z 6III, Z f, Z50II, Z5II set to HE) | +1.1 | 20–40 | ~0.04 | a pure-Rust JPEG XS decoder | -| 10 | Compressed SRW, Hasselblad 3FR, IIQ, X3F, MRW, KDC, ERF, DCR, MEF, GPR | +0.6 together | 45–85 | ~0.01 | samples; low use | +| 10 | Compressed SRW, Hasselblad 3FR, IIQ, X3F, KDC, ERF, DCR, MEF, GPR (MRW done) | +0.6 together | 45–85 | ~0.01 | samples; low use | Beyond decoding: @@ -266,6 +267,7 @@ Beyond decoding: | Date | Change | Summary | |---|---|---| +| 2026-10-12 | minor | Minolta MRW decoded (`vendor/mrw.rs`): DiMAGE 7, 7Hi, A1, A2, A200 and Dynax / Maxxum 7D verified; 241 verified, 947 unverified, 222 preview | | 2026-10-10 | minor | Compressed ORF: pointer to the two Olympus patents that describe the method, as a clean-room starting point | | 2026-10-11 | minor | EOS R5 Mark II verified (CRX QP-map first literal and limited-length escape, odd-height Bayer planes; 4 CC0 files pinned, QP maps of 33,665 private files): 235 verified, 942 unverified; use-weighted 85% (42% on verified bodies); decoding 77%, RAW readiness unchanged at ~56% | | 2026-10-10 (later) | major | Model-by-model measurement against Adobe's published list (1,446 models: 234 verified, 943 unverified, 233 preview, 36 unsupported); `docs/raw/` data and re-measure script; use-weighted share 84% (40% on verified bodies); variant matrix; colour and lens sections with scores; ranked next cameras; RAW readiness ~56% from written parts | diff --git a/docs/raw/coverage.py b/docs/raw/coverage.py index c635c993a..c267a2573 100644 --- a/docs/raw/coverage.py +++ b/docs/raw/coverage.py @@ -83,7 +83,9 @@ def classify(maker, camera, ext_field): return "preview", "SRW", "compressed SRW is not decoded" return "unverified", "SRW", "uncompressed / packed SRW" e = es[0] if es else "" - if e in ("CRW", "3FR", "FFF", "IIQ", "MOS", "ERF", "KDC", "MRW", "X3F", "RAW", "ORI"): + if e == "MRW": + return "unverified", "MRW", "MRW decoder (12-bit packed, 16-bit words)" + if e in ("CRW", "3FR", "FFF", "IIQ", "MOS", "ERF", "KDC", "X3F", "RAW", "ORI"): return "preview", e, f"{e} is opened from its embedded JPEG only" return "unsupported", e, f"{e or 'unknown'} is not imported" diff --git a/docs/raw/coverage.tsv b/docs/raw/coverage.tsv index cc0dc1e66..3d7e28d5d 100644 --- a/docs/raw/coverage.tsv +++ b/docs/raw/coverage.tsv @@ -552,17 +552,17 @@ Kodak EasyShare Z1015 IS KDC 2008 preview KDC is opened from its embedded JPEG o Kodak EasyShare Z980 KDC 2008 preview KDC is opened from its embedded JPEG only Kodak EasyShare Z981 RAW 2010 preview RAW is opened from its embedded JPEG only Kodak EasyShare Z990 RAW 2010 preview RAW is opened from its embedded JPEG only -Konica Minolta Alpha-5 Digital (China) MRW 2005 preview MRW is opened from its embedded JPEG only -Konica Minolta Alpha Sweet Digital (Japan) MRW 2005 preview MRW is opened from its embedded JPEG only -Konica Minolta DiMAGE 5 MRW 2003 preview MRW is opened from its embedded JPEG only -Konica Minolta DiMAGE 7 MRW 2003 preview MRW is opened from its embedded JPEG only -Konica Minolta DiMAGE 7i MRW 2003 preview MRW is opened from its embedded JPEG only -Konica Minolta DiMAGE 7Hi MRW 2003 preview MRW is opened from its embedded JPEG only -Konica Minolta DiMAGE A1 MRW 2003 preview MRW is opened from its embedded JPEG only -Konica Minolta DiMAGE A2 MRW 2003 preview MRW is opened from its embedded JPEG only -Konica Minolta DiMAGE A200 MRW 2003 preview MRW is opened from its embedded JPEG only -Konica Minolta Maxxum 5D Dynax 5D MRW 2005 preview MRW is opened from its embedded JPEG only -Konica Minolta Maxxum 7D Dynax 7D MRW 2003 preview MRW is opened from its embedded JPEG only +Konica Minolta Alpha-5 Digital (China) MRW 2005 unverified MRW decoder (12-bit packed, 16-bit words) +Konica Minolta Alpha Sweet Digital (Japan) MRW 2005 unverified MRW decoder (12-bit packed, 16-bit words) +Konica Minolta DiMAGE 5 MRW 2003 unverified MRW decoder (12-bit packed, 16-bit words) +Konica Minolta DiMAGE 7 MRW 2003 verified raw.pixls.us check: CC0 sample decoded and its WB / CFA matched to the embedded preview (vendor/mrw.rs) +Konica Minolta DiMAGE 7i MRW 2003 unverified MRW decoder (12-bit packed, 16-bit words) +Konica Minolta DiMAGE 7Hi MRW 2003 verified corpus: crates/raw/tests/corpus.rs (xtask RAW_SAMPLES) +Konica Minolta DiMAGE A1 MRW 2003 verified corpus: crates/raw/tests/corpus.rs (xtask RAW_SAMPLES) +Konica Minolta DiMAGE A2 MRW 2003 verified raw.pixls.us check: CC0 sample decoded and its WB / CFA matched to the embedded preview (vendor/mrw.rs) +Konica Minolta DiMAGE A200 MRW 2003 verified corpus: crates/raw/tests/corpus.rs (xtask RAW_SAMPLES) +Konica Minolta Maxxum 5D Dynax 5D MRW 2005 unverified MRW decoder (12-bit packed, 16-bit words) +Konica Minolta Maxxum 7D Dynax 7D MRW 2003 verified corpus: crates/raw/tests/corpus.rs (xtask RAW_SAMPLES) Leaf AFi II 6 MOS 2008 preview MOS is opened from its embedded JPEG only Leaf AFi II 7 MOS 2008 preview MOS is opened from its embedded JPEG only Leaf Aptus 17 MOS 2007 preview MOS is opened from its embedded JPEG only diff --git a/docs/raw/evidence.tsv b/docs/raw/evidence.tsv index 74340fcf7..8272405c9 100644 --- a/docs/raw/evidence.tsv +++ b/docs/raw/evidence.tsv @@ -248,3 +248,9 @@ Sony RX1R II (DSC-RX1RM2) verified issue #535: raw.pixls.us bulk check of all 10 Sony ZV-1 (DCZV1/B) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool) Sony ZV-E1 verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool) Sony ZV-E10 verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool) +Konica Minolta DiMAGE 7Hi verified corpus: crates/raw/tests/corpus.rs (xtask RAW_SAMPLES) +Konica Minolta DiMAGE A1 verified corpus: crates/raw/tests/corpus.rs (xtask RAW_SAMPLES) +Konica Minolta DiMAGE A200 verified corpus: crates/raw/tests/corpus.rs (xtask RAW_SAMPLES) +Konica Minolta Maxxum 7D Dynax 7D verified corpus: crates/raw/tests/corpus.rs (xtask RAW_SAMPLES) +Konica Minolta DiMAGE 7 verified raw.pixls.us check: CC0 sample decoded and its WB / CFA matched to the embedded preview (vendor/mrw.rs) +Konica Minolta DiMAGE A2 verified raw.pixls.us check: CC0 sample decoded and its WB / CFA matched to the embedded preview (vendor/mrw.rs) diff --git a/docs/target-app-parity.md b/docs/target-app-parity.md index c90c1ead1..ecf3f3f93 100644 --- a/docs/target-app-parity.md +++ b/docs/target-app-parity.md @@ -1,6 +1,6 @@ # Target-app parity: LightCraft vs Adobe Lightroom -> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-11 · **Change:** minor (EOS R5 Mark II CR3 verified: RAW decoding 76% → 77%; headline numbers unchanged) · **Target:** Adobe Lightroom Classic 15.5 (August 2026) and Lightroom 9.6 (desktop) +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-12 · **Change:** minor (Minolta MRW decoded: 6 models verified; headline numbers unchanged) · **Target:** Adobe Lightroom Classic 15.5 (August 2026) and Lightroom 9.6 (desktop) The authoritative assessment of how close LightCraft is to Lightroom. The row-by-row checklist is [parity-checklist.md](parity-checklist.md); the ranked work list is [gaps.md](gaps.md); deep areas @@ -47,7 +47,7 @@ phase #85, duplicate Local entries #22, black GPU exports on an Intel iGPU #78). | Dimension | Breadth | Ready for real work | Remaining | Doc | |---|---:|---:|---:|---| | Features (weighted areas below) | ~77% (checklist 81.1%, measured) | ~61% | 600–1,100 h | [Features](#features) | -| ↳ RAW cameras, colour and lens profiles (part of features) | 81% of Adobe's 1,446 models decode (16% verified), measured | ~56% | 255–480 h | [raw-parity.md](raw-parity.md) | +| ↳ RAW cameras, colour and lens profiles (part of features) | 82% of Adobe's 1,446 models decode (17% verified), measured | ~56% | 255–480 h | [raw-parity.md](raw-parity.md) | | UI/UX fidelity | ~85% | ~70% | 40–70 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) | @@ -297,6 +297,7 @@ P2 items 12–25 h; look tuning, performance, packaging, hardening 25–45 h. | Date | Change | Summary | |---|---|---| +| 2026-10-12 | minor | Minolta MRW decoded (raw-parity.md): 241 models verified, 222 preview-only; use-weighted shares and the rounded numbers unchanged | | 2026-10-11 | minor | EOS R5 Mark II CR3 verified (raw-parity.md): use-weighted share whose camera decodes 84% → 85%, RAW decoding 76% → 77%; full 60.6% → 60.7%, mainstream depth 71.8% → 72.1%, essentials depth 77.4% → 77.5%; the rounded numbers (~61%, ~49%, ~64%) are unchanged | | 2026-10-10 | minor | RAW measured model by model (raw-parity.md): RAW decoding (76%) and colour (35%) are explicit rows of the full sum (59% → 61%); mainstream uses the use-weighted 84% plus a ×0.85 colour discount (51% → 49%); essentials uses 84% × colour 0.75 (63% → 64%); beta ~14 points | | 2026-10-10 | minor | Full number restored to an additive weighted sum over the dimensions (~59%; method aligned with the standard, no new evidence); hours to ~95% for each of the three audiences; beta distance ~16 points | diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 08ef435c5..e330f4e18 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -885,6 +885,26 @@ const RAW_SAMPLES: &[(&str, &str, &str)] = &[ "https://raw.pixls.us/getfile.php/4204/nice/Leica%20-%20D-Lux%207%20-%204:3.RWL", "4f6db6492da83f7f2a5012591e370557249d1ed44d4c948784016605b799327c", ), + ( + "mrw-minolta-dimage7hi-words16.mrw", + "https://raw.pixls.us/data/Minolta/DiMAGE%207Hi/RAW_MINOLTA_DIMAGE_7HI.MRW", + "2919a05757197a5424e02970c016893bca5aa29363a67b62b1a4b36326a10f6a", + ), + ( + "mrw-minolta-dimage-a1.mrw", + "https://raw.pixls.us/data/Minolta/DiMAGE%20A1/RAW_MINOLTA_A1.MRW", + "bde1e2cd788e49c9bef20dfdd41be948fb02c2ee198c6b0959a67a3f79fd41c9", + ), + ( + "mrw-minolta-dimage-a200-gbrg.mrw", + "https://raw.pixls.us/data/Minolta/DiMAGE%20A200/RAW_MINOLTA_DIMAGE_A200.MRW", + "2a95f6af2168e536dfb6d02b47e3b6119b35b497eebf179d7c20a6e496c26641", + ), + ( + "mrw-minolta-dynax7d.mrw", + "https://raw.pixls.us/data/Minolta/Dynax%207D/PICT3410.MRW", + "713819e33e5302ec864d576d57223cfc8dcf46e8d45e0ae744d1fec40290a89f", + ), ]; fn cmd_corpus(download: bool) -> Result<(), String> { From 7361cb222cfb373f5254e956fa93a1711c2dfa72 Mon Sep 17 00:00:00 2001 From: Andrew Frahn Date: Mon, 12 Oct 2026 06:15:53 +1100 Subject: [PATCH 003/350] LR-IMP-FORMATS: MRW gets the file-local look fitted to its preview Co-Authored-By: Claude Opus 5.5 (1M context) --- crates/catalog/src/model.rs | 3 ++- crates/engine/src/camera_preview.rs | 2 ++ docs/camera-preview-colour.md | 4 ++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/crates/catalog/src/model.rs b/crates/catalog/src/model.rs index abeaadad4..83f5c3262 100644 --- a/crates/catalog/src/model.rs +++ b/crates/catalog/src/model.rs @@ -313,7 +313,7 @@ pub struct Analysis { /// file's white balance is edited relative to its as-shot look or in Kelvin depends on the camera: /// [`relative_wb_camera`]. pub fn relative_wb_format(format: &str) -> bool { - ["ARW", "NEF", "NRW", "RW2", "RWL", "RAW", "RAF", "CR3", "CR2", "PEF", "SRW", "ORF"].iter().any(|f| format.eq_ignore_ascii_case(f)) + ["ARW", "NEF", "NRW", "RW2", "RWL", "RAW", "RAF", "CR3", "CR2", "PEF", "SRW", "ORF", "MRW"].iter().any(|f| format.eq_ignore_ascii_case(f)) } /// Whether a raw of `format` shot on `camera` (Exif make and model, as [`Meta::camera`] keeps them) is developed @@ -564,6 +564,7 @@ mod edited_tests { ("a.cr2", "CR2", true), ("a.pef", "pef", true), ("a.orf", "ORF", true), + ("a.mrw", "MRW", true), ("a.dng", "DNG", false), ] { let mut p = Photo::new(PhotoId(1), Source::Demo { scene: 0 }, name, format, 10, 10, "2026-10-01T00:00:00"); diff --git a/crates/engine/src/camera_preview.rs b/crates/engine/src/camera_preview.rs index 858f3b4cf..a6d5312db 100644 --- a/crates/engine/src/camera_preview.rs +++ b/crates/engine/src/camera_preview.rs @@ -58,6 +58,7 @@ pub(crate) fn file_local_look(format: RawFormat) -> bool { | RawFormat::Pef | RawFormat::Srw | RawFormat::Orf + | RawFormat::Mrw ) } @@ -1885,6 +1886,7 @@ mod tests { RawFormat::Pef, RawFormat::Srw, RawFormat::Orf, + RawFormat::Mrw, ]; assert!(local.into_iter().all(file_local_look)); // DNG carries its own colour model diff --git a/docs/camera-preview-colour.md b/docs/camera-preview-colour.md index b24d9bf75..db7637d21 100644 --- a/docs/camera-preview-colour.md +++ b/docs/camera-preview-colour.md @@ -1,6 +1,6 @@ -# Sony ARW, Nikon NEF, Panasonic RW2, Fujifilm RAF, Canon CR3/CR2, Pentax PEF, Samsung SRW and Olympus ORF starting look +# Sony ARW, Nikon NEF, Panasonic RW2, Fujifilm RAF, Canon CR3/CR2, Pentax PEF, Samsung SRW, Olympus ORF and Minolta MRW starting look -ARW, NEF, RW2, RAF, CR3, CR2, PEF, SRW and ORF decoding supply sensor data and camera white-balance multipliers, but currently no measured camera colour matrix. Treating camera RGB as linear sRGB produces a dark, muted default rendering. The loader now estimates a file-local starting look from that file's embedded camera JPEG, only when a usable camera matrix is absent. All output pixels still come from the RAW sensor data; there is no JPEG replacement or uniform saturation boost. +ARW, NEF, RW2, RAF, CR3, CR2, PEF, SRW, ORF and MRW decoding supply sensor data and camera white-balance multipliers, but currently no measured camera colour matrix. Treating camera RGB as linear sRGB produces a dark, muted default rendering. The loader now estimates a file-local starting look from that file's embedded camera JPEG, only when a usable camera matrix is absent. All output pixels still come from the RAW sensor data; there is no JPEG replacement or uniform saturation boost. ## Colour and tone are separate From 8bdde1ad7bd9dd2332698f6b4482ef7d6dcffb6d Mon Sep 17 00:00:00 2001 From: Vikram Bhaskaran Date: Tue, 13 Oct 2026 01:24:21 +1100 Subject: [PATCH 004/350] Ignore hidden and empty masks when sizing develop planes. --- crates/pipeline/src/local.rs | 61 ++++++++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 17 deletions(-) diff --git a/crates/pipeline/src/local.rs b/crates/pipeline/src/local.rs index ce3994cd8..c0eb7f1fd 100644 --- a/crates/pipeline/src/local.rs +++ b/crates/pipeline/src/local.rs @@ -454,9 +454,13 @@ pub struct PlaneSigmas { pub fn plane_sigmas(s: &DevelopSettings, px_per_long: f64, q: Quality) -> PlaneSigmas { let ppl = px_per_long as f32; - let local_any = |f: fn(&lightcraft_develop::LocalAdjustments) -> f64| s.masks.iter().any(|m| f(&m.adjust) != 0.0); - let tone_active = - s.light.highlights != 0.0 || s.light.shadows != 0.0 || s.masks.iter().any(|m| m.adjust.highlights != 0.0 || m.adjust.shadows != 0.0); + // A hidden mask, or one with no components, does not change the picture. Its sliders must + // not pick the tone base Clarity reads (#1214). + let live = |m: &&lightcraft_develop::Mask| m.visible && !m.components.is_empty(); + let local_any = |f: fn(&lightcraft_develop::LocalAdjustments) -> f64| s.masks.iter().filter(live).any(|m| f(&m.adjust) != 0.0); + let tone_active = s.light.highlights != 0.0 + || s.light.shadows != 0.0 + || s.masks.iter().filter(live).any(|m| m.adjust.highlights != 0.0 || m.adjust.shadows != 0.0); // Edge-aware base at ~1.5% of the long edge (EV² epsilon: edges of > ~0.6 EV are preserved) // From V2 it is taken of the median at 0.15%: lines and texture finer than that are detail, // not tone (#632). @@ -471,10 +475,10 @@ pub fn plane_sigmas(s: &DevelopSettings, px_per_long: f64, q: Quality) -> PlaneS || local_any(|a| a.texture) || local_any(|a| a.sharpness) || local_any(|a| a.noise) - || s.masks.iter().any(|m| m.adjust.defringe > 0.0)) + || s.masks.iter().filter(live).any(|m| m.adjust.defringe > 0.0)) .then(|| (0.0018 * ppl).max(0.6)); let dark = (s.effects.dehaze != 0.0 || local_any(|a| a.dehaze)).then(|| (0.02 * ppl).max(1.0)); - let chroma = (local_any(|a| a.moire) || s.masks.iter().any(|m| m.adjust.noise > 0.0)).then(|| (CHROMA_SIGMA * ppl).max(1.0)); + let chroma = (local_any(|a| a.moire) || s.masks.iter().filter(live).any(|m| m.adjust.noise > 0.0)).then(|| (CHROMA_SIGMA * ppl).max(1.0)); let base_detail = if base.is_some() { tone_base_detail(s, px_per_long) } else { 0 }; PlaneSigmas { base, base_detail, clarity, texture, dark, chroma } } @@ -601,22 +605,45 @@ mod tests { } #[test] - fn exposure_doubles() { + fn a_hidden_or_empty_mask_does_not_request_the_tone_base() { + use lightcraft_develop::{Mask, MaskComponent, MaskOp, MaskShape}; + use lightcraft_geom::Point; + let shape = MaskShape::Linear { start: Point::new(0.0, 0.0), end: Point::new(1.0, 0.0) }; + let component = MaskComponent { name: None, op: MaskOp::Add, invert: false, shape }; let mut s = DevelopSettings::default(); - s.light.exposure = 1.0; - let mut img = Rgb32f::filled(2, 2, [0.1, 0.2, 0.3]); - scene_linear_pre(&mut img, &SourceInfo::default(), &s); - assert!((img.get(1, 1)[2] - 0.6).abs() < 1e-5); + s.masks.push(Mask { + visible: false, + components: vec![component], + adjust: lightcraft_develop::LocalAdjustments { highlights: 40.0, ..Default::default() }, + ..Default::default() + }); + assert!(plane_sigmas(&s, 2000.0, Quality::Full).base.is_none()); + s.masks[0].visible = true; + s.masks[0].components.clear(); + assert!(plane_sigmas(&s, 2000.0, Quality::Full).base.is_none()); + s.masks[0].components.push(MaskComponent { + name: None, + op: MaskOp::Add, + invert: false, + shape: MaskShape::Linear { start: Point::new(0.0, 0.0), end: Point::new(1.0, 0.0) }, + }); + assert!(plane_sigmas(&s, 2000.0, Quality::Full).base.is_some()); } -} - -#[cfg(test)] -mod fast_tests { - use super::*; #[test] - fn fast_guided_close_to_reference() { - let p = Plane::from_fn(160, 120, |x, y| ((x as f32 * 0.13).sin() + (y as f32 * 0.07).cos()) * 2.0 + if x > 80 { 1.5 } else { 0.0 }); + fn nr_contrast_keeps_fine_texture() { + let src = Rgb32f::from_fn(48, 16, |x, y| { + let n = if (x + y) % 2 == 0 { 0.12 } else { -0.12 }; + [0.3 + n; 3] + }); + let mut flat = DevelopSettings::default(); + flat.detail.nr_luminance = 100.0; + let mut held = flat.clone(); + held.detail.nr_contrast = 100.0; + let mut a = src.clone(); + let mut b = src.clone(); + denoise(&mut a, &flat, 48, 48); + denoise(&mut b, &held, 48, + if x > 80 { 1.5 } else { 0.0 }); let a = guided(&p, 12.0, 0.3); let b = guided_fast(&p, 12.0, 0.3); let err: f32 = a.data.iter().zip(&b.data).map(|(u, v)| (u - v).abs()).sum::() / a.len() as f32; From 71fb91daebbd3e6d5f699f4ff71b10bb084e7554 Mon Sep 17 00:00:00 2001 From: radialmonster Date: Mon, 12 Oct 2026 12:30:55 -0400 Subject: [PATCH 005/350] LR-IMP-FORMATS: RW2 format 8 decodes tiled images (DC-S1RM2 high-resolution mode, tag 0x0043 = 2) (#1276) The high-resolution mode of the DC-S1RM2 (16296 x 10856) tiles the image in two rows of four. Tag 0x0045 holds (x, y) u16 pairs per tile (y was always 0 in single-row files, where the old 32-bit reading gave the same numbers), and tag 0x0043 is the number of tile rows. The decoder now takes each tile's position from the lists, checks that the tiles lie inside the image, do not overlap and cover it exactly, and that 0x0043 equals the number of distinct tile tops. Tiles are decoded like strips. Other tag values are still refused. --- crates/raw/src/vendor/rw2.rs | 145 +++++++++++++++++++++++++++-------- 1 file changed, 112 insertions(+), 33 deletions(-) diff --git a/crates/raw/src/vendor/rw2.rs b/crates/raw/src/vendor/rw2.rs index 0a64c9e44..d7e872253 100644 --- a/crates/raw/src/vendor/rw2.rs +++ b/crates/raw/src/vendor/rw2.rs @@ -48,8 +48,12 @@ //! apart with red and blue between them]; each is //! predicted from the same site of the previous cell, the first cell of a row pair from the first cell of the //! previous pair, 0 at the top [the strips decode to the camera JPEG's image without seams]. The streams end a -//! few padding rows before their stated length. Tags `0x0039`–`0x003f`, `0x0041` and `0x0043` carry the same -//! values in every sample; files with other values are reported as unsupported rather than guessed at. +//! few padding rows before their stated length. Tags `0x0039`–`0x003f` and `0x0041` carry the same +//! values in every sample; files with other values are reported as unsupported rather than guessed at. The high-resolution +//! mode of the DC-S1RM2 (16296 × 10856, `0x0043` = 2) tiles the image in two rows of four: `0x0045` then lists (x, y) +//! `u16` pairs (y is 0 in single-row files, so the 32-bit reading used for them is the same numbers), the tiles are +//! 5632 and 5224 rows high and are decoded exactly like strips [the tiles' areas add up to the sensor, and `0x0043` equals +//! the number of distinct tile tops in every sample]; the decoder takes the geometry from the lists, not from the body. //! //! Levels and geometry: //! @@ -130,7 +134,7 @@ const STRIP_BITS: u16 = 0x0046; const STRIP_WIDTHS: u16 = 0x0047; const STRIP_HEIGHTS: u16 = 0x0048; /// Format-8 tags of unknown meaning and the values every sample carries (as `u16` arrays). -const FORMAT8_FIXED: [(u16, &[u16]); 9] = [ +const FORMAT8_FIXED: [(u16, &[u16]); 8] = [ (0x0039, &[6, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1]), (0x003a, &[6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), (0x003b, &[65535]), @@ -139,8 +143,9 @@ const FORMAT8_FIXED: [(u16, &[u16]); 9] = [ (0x003e, &[0]), (0x003f, &[0]), (0x0041, &[17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), - (0x0043, &[1]), ]; +/// Format-8 tile rows (ExifTool: no name): 1 for a single row of strips, 2 for the 16296 × 10856 high-resolution mode. +const TILE_ROWS: u16 = 0x0043; /// The camera's lens distortion correction (ExifTool name: DistortionInfo); see the module docs. const DISTORTION_INFO: u16 = 0x0119; /// Fixed-point one of the distortion coefficients and zoom. @@ -149,7 +154,7 @@ const DISTORTION_ONE: f64 = 32768.0; const DISTORTION_SAMPLES: usize = 64; /// Largest error of the fitted inverse (relative to the half diagonal) accepted: real lenses fit within 1.2e-4. const DISTORTION_MAX_FIT_ERROR: f64 = 1e-3; -/// Most strips seen in a file is 3 (the 12008 × 8008 high-resolution mode). +/// Most strips seen in a file is 8 (the 16296 × 10856 high-resolution mode: 4 columns by 2 rows of tiles). const MAX_STRIPS: usize = 64; const CHUNK: usize = 0x4000; @@ -348,6 +353,15 @@ fn u16_array(ifd: &Ifd, tag: u16, order: ByteOrder) -> Option> { } } +/// The format-8 tile origins (tag `0x0045`): a count, then (x, y) pairs of `u16`. +fn origins(ifd: &Ifd, order: ByteOrder) -> Result> { + let a = u16_array(ifd, STRIP_LEFT, order).ok_or_else(|| RawError::Corrupt("RW2 format 8 without tag 0x0045".into()))?; + let n = a.first().map_or(0, |&n| n as usize); + let at = |i: usize| a.get(i).map(|&v| v as usize); + let values: Option> = (0..n).map(|i| Some((at(1 + 2 * i)?, at(2 + 2 * i)?))).collect(); + values.filter(|v| !v.is_empty() && v.len() <= MAX_STRIPS).ok_or_else(|| RawError::Corrupt("RW2 format 8: bad list in tag 0x0045".into())) +} + /// A format-8 `u16` list (count, then the values; `wide`: 32-bit values as low/high pairs). fn list(ifd: &Ifd, tag: u16, order: ByteOrder, wide: bool) -> Result> { let a = u16_array(ifd, tag, order).ok_or_else(|| RawError::Corrupt(format!("RW2 format 8 without tag {tag:#06x}")))?; @@ -357,15 +371,17 @@ fn list(ifd: &Ifd, tag: u16, order: ByteOrder, wide: bool) -> Result> { values.filter(|v| !v.is_empty() && v.len() <= MAX_STRIPS).ok_or_else(|| RawError::Corrupt(format!("RW2 format 8: bad list in tag {tag:#06x}"))) } -/// One format-8 strip: its bit stream and placement. +/// One format-8 strip or tile: its bit stream and placement. struct Strip<'a> { data: &'a [u8], + left: usize, + top: usize, width: usize, height: usize, bits: u64, } -/// The format-8 strips (tiling the full width, top to bottom) and code table. +/// The format-8 strips or tiles (together covering the whole image exactly once) and code table. fn format8<'a>(ifd: &Ifd, order: ByteOrder, bytes: &'a [u8], w: usize, h: usize) -> Result<(Vec>, Huffman)> { for (tag, want) in FORMAT8_FIXED { if let Some(v) = u16_array(ifd, tag, order) @@ -374,26 +390,40 @@ fn format8<'a>(ifd: &Ifd, order: ByteOrder, bytes: &'a [u8], w: usize, h: usize) return Err(RawError::Unsupported(format!("Panasonic raw format 8 with tag {tag:#06x} = {v:?}"))); } } - let (offsets, lefts, bits) = (list(ifd, STRIP_OFFSETS, order, true)?, list(ifd, STRIP_LEFT, order, true)?, list(ifd, STRIP_BITS, order, true)?); + let (offsets, origins, bits) = (list(ifd, STRIP_OFFSETS, order, true)?, origins(ifd, order)?, list(ifd, STRIP_BITS, order, true)?); let (widths, heights) = (list(ifd, STRIP_WIDTHS, order, false)?, list(ifd, STRIP_HEIGHTS, order, false)?); let n = offsets.len(); - if [lefts.len(), bits.len(), widths.len(), heights.len()].iter().any(|&l| l != n) { + if [origins.len(), bits.len(), widths.len(), heights.len()].iter().any(|&l| l != n) { return Err(RawError::Corrupt("RW2 format 8: strip lists of different lengths".into())); } let mut strips = Vec::with_capacity(n); - let mut x = 0usize; + let mut area = 0usize; for i in 0..n { - let (left, width, height) = (lefts[i] as usize, widths[i] as usize, heights[i] as usize); + let ((left, top), width, height) = (origins[i], widths[i] as usize, heights[i] as usize); let len = usize::try_from(bits[i].div_ceil(8)).unwrap_or(usize::MAX); let data = usize::try_from(offsets[i]).ok().and_then(|o| bytes.get(o..o.checked_add(len)?)); - let Some(data) = data.filter(|_| left == x && width > 0 && height == h) else { + let inside = width > 0 && height > 0 && left + width <= w && top + height <= h; + let Some(data) = data.filter(|_| inside) else { return Err(RawError::Corrupt(format!("RW2 format 8: strip {i} outside the image or file"))); }; - x += width; - strips.push(Strip { data, width, height, bits: bits[i] }); + area += width * height; + strips.push(Strip { data, left, top, width, height, bits: bits[i] }); } - if x != w { - return Err(RawError::Corrupt(format!("RW2 format 8: strips cover {x} of {w} columns"))); + // inside the image, no two overlapping and the areas adding up to the image: every sample has exactly one strip + let overlap = strips.iter().enumerate().any(|(i, a)| { + strips[i + 1..].iter().any(|b| a.left < b.left + b.width && b.left < a.left + a.width && a.top < b.top + b.height && b.top < a.top + a.height) + }); + if overlap || area != w * h { + return Err(RawError::Corrupt(format!("RW2 format 8: strips cover {area} of {} samples", w * h))); + } + // tag 0x0043 counts the rows of tiles; a file that says otherwise is not one we understand + let mut tops: Vec = strips.iter().map(|s| s.top).collect(); + tops.sort_unstable(); + tops.dedup(); + if let Some(v) = u16_array(ifd, TILE_ROWS, order) + && v != [tops.len() as u16] + { + return Err(RawError::Unsupported(format!("Panasonic raw format 8 with tag {TILE_ROWS:#06x} = {v:?} for {} tile rows", tops.len()))); } let codes = u16_array(ifd, HUFFMAN_CODES, order).unwrap_or_default(); let pairs: Vec<(u32, u32)> = match (codes.first(), codes.get(1..35)) { @@ -454,12 +484,21 @@ fn decode_strip(s: &Strip, codes: &Huffman, mut rows: Vec<&mut [u16]>) -> Result fn decode_strips(strips: &[Strip], codes: &Huffman, w: usize, out: &mut [u16]) -> Result<()> { let mut parts: Vec> = strips.iter().map(|s| Vec::with_capacity(s.height)).collect(); - for row in out.chunks_mut(w) { - let mut rest = row; - for (s, rows) in strips.iter().zip(parts.iter_mut()) { - let (part, tail) = rest.split_at_mut(s.width.min(rest.len())); - rows.push(part); + for (y, row) in out.chunks_mut(w).enumerate() { + // the strips crossing this row, left to right, each take their columns off its front + let mut here: Vec = (0..strips.len()).filter(|&i| strips.get(i).is_some_and(|s| s.top <= y && y < s.top + s.height)).collect(); + here.sort_by_key(|&i| strips.get(i).map_or(0, |s| s.left)); + let (mut rest, mut x) = (row, 0usize); + for i in here { + let Some(s) = strips.get(i) else { continue }; + let skip = s.left.saturating_sub(x).min(rest.len()); + let (_, tail) = rest.split_at_mut(skip); + let (part, tail) = tail.split_at_mut(s.width.min(tail.len())); + if let Some(rows) = parts.get_mut(i) { + rows.push(part); + } rest = tail; + x = s.left + s.width; } } strips.par_iter().zip(parts).try_for_each(|(s, rows)| decode_strip(s, codes, rows)) @@ -1196,16 +1235,33 @@ mod tests { /// A format-8 file with the given strip widths; `tweak` edits the tags before writing. fn format8_file(w: usize, h: usize, px: &[u16], widths: &[usize], table: &[(u32, u32); 17], tweak: &dyn Fn(&mut Vec<(u16, Value)>)) -> Vec { + format8_tiled_file(w, px, widths, &[h], table, tweak) + } + + /// A format-8 file tiled in rows of the given heights, each cut into the given widths. + fn format8_tiled_file( + w: usize, + px: &[u16], + widths: &[usize], + rows: &[usize], + table: &[(u32, u32); 17], + tweak: &dyn Fn(&mut Vec<(u16, Value)>), + ) -> Vec { + let h: usize = rows.iter().sum(); let mut payload = vec![]; - let mut strips = vec![]; // (offset in payload, bits, left, width) - let mut left = 0; - for &sw in widths { - let sub: Vec = (0..h).flat_map(|y| px[y * w + left..y * w + left + sw].to_vec()).collect(); - let (data, bits) = encode_strip(&sub, sw, h, table, 2); - strips.push((payload.len(), bits, left, sw)); - payload.extend(data); - payload.resize(payload.len().div_ceil(16) * 16, 0); - left += sw; + let mut strips = vec![]; // (offset in payload, bits, left, width, top, height) + let mut top = 0; + for &th in rows { + let mut left = 0; + for &sw in widths { + let sub: Vec = (top..top + th).flat_map(|y| px[y * w + left..y * w + left + sw].to_vec()).collect(); + let (data, bits) = encode_strip(&sub, sw, th, table, 2); + strips.push((payload.len(), bits, left, sw, top, th)); + payload.extend(data); + payload.resize(payload.len().div_ceil(16) * 16, 0); + left += sw; + } + top += th; } let u16s = |v: Vec| undefined(&v); let wide = |v: Vec| u16s(std::iter::once(v.len() as u16).chain(v.iter().flat_map(|&x| [x as u16, (x >> 16) as u16])).collect()); @@ -1216,10 +1272,11 @@ mod tests { for (tag, v) in FORMAT8_FIXED { tags.push(if v.len() == 1 { short(tag, v[0]) } else { (tag, u16s(v.to_vec())) }); } - tags.push((STRIP_LEFT, wide(strips.iter().map(|s| s.2 as u64).collect()))); + tags.push(short(TILE_ROWS, rows.len() as u16)); + tags.push((STRIP_LEFT, u16s(std::iter::once(strips.len() as u16).chain(strips.iter().flat_map(|s| [s.2 as u16, s.4 as u16])).collect()))); tags.push((STRIP_BITS, wide(strips.iter().map(|s| s.1).collect()))); tags.push((STRIP_WIDTHS, narrow(strips.iter().map(|s| s.3 as u64).collect()))); - tags.push((STRIP_HEIGHTS, narrow(vec![h as u64; strips.len()]))); + tags.push((STRIP_HEIGHTS, narrow(strips.iter().map(|s| s.5 as u64).collect()))); tweak(&mut tags); let offsets: Vec = strips.iter().map(|s| s.0).collect(); file(w as u16, h as u16, &tags, &payload, &|off| { @@ -1240,6 +1297,23 @@ mod tests { } } + #[test] + fn format8_tiles_in_two_rows_round_trip() { + // the DC-S1RM2 high-resolution mode: four columns by two rows of tiles, tag 0x0043 = 2 + let (w, h) = (96usize, 40usize); + let px = image(w, h, 520, 16000); + for (widths, rows) in [(vec![24, 24, 24, 24], vec![24, 16]), (vec![40, 56], vec![20, 20]), (vec![96], vec![8, 32])] { + let bytes = format8_tiled_file(w, &px, &widths, &rows, &TABLE14, &|_| {}); + let r = crate::decode(&bytes).unwrap_or_else(|e| panic!("{widths:?} x {rows:?}: {e}")); + assert_eq!(samples(&r), px, "{widths:?} x {rows:?}"); + assert_eq!(crate::probe_info(&bytes).unwrap(), r.info()); + } + // a tile row count that disagrees with the tiles, or tiles that leave a gap, are refused + let case = |tag: u16, v: Value| crate::decode(&format8_tiled_file(w, &px, &[48, 48], &[20, 20], &TABLE14, &|t| replace(t, tag, v.clone()))); + assert!(case(TILE_ROWS, Value::Short(vec![1])).is_err_and(|e| matches!(e, RawError::Unsupported(_)))); + assert!(case(STRIP_HEIGHTS, undefined(&[4, 20, 20, 20, 12])).is_err_and(|e| matches!(e, RawError::Corrupt(_)))); + } + #[test] fn format8_cell_is_coded_column_by_column() { // One 2×2 cell coded by hand (not with `encode_strip`, which shares the decoder's site order): the values @@ -1256,7 +1330,12 @@ mod tests { let mut data: Vec = bits.chunks(8).map(|b| b.iter().enumerate().fold(0u8, |a, (i, &x)| a | (x as u8) << i)).collect(); data.extend([0; 8]); let (mut top, mut bottom) = ([0u16; 2], [0u16; 2]); - decode_strip(&Strip { data: &data, width: 2, height: 2, bits: n }, &code_table(&TABLE14).unwrap(), vec![&mut top, &mut bottom]).unwrap(); + decode_strip( + &Strip { data: &data, left: 0, top: 0, width: 2, height: 2, bits: n }, + &code_table(&TABLE14).unwrap(), + vec![&mut top, &mut bottom], + ) + .unwrap(); assert_eq!((top, bottom), ([1, 3], [2, 4]), "top-left, bottom-left, top-right, bottom-right"); } From d3e56df54a12c3dff9e00cbddded42b1da451592 Mon Sep 17 00:00:00 2001 From: null 00000111 <287216888+s17sh70x2jfl031ag@users.noreply.github.com> Date: Mon, 12 Oct 2026 23:50:09 -0700 Subject: [PATCH 006/350] Add a security policy --- SECURITY.md | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000..6d7340dd5 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,54 @@ +# Security Policy + +LightCraft reads camera raw files, image formats, metadata and sidecars, imports other photo catalogs, downloads and runs machine-learning models, and exposes CLI, JSON control, and MCP automation. Treat files, paths, metadata, catalogs, model files, automation requests, and command parameters as potentially malicious. + +## Reporting a vulnerability + +Please give the repository maintainers a reasonable opportunity to investigate and coordinate a fix before publishing exploitable details, proof-of-concept code, or weaponized files. + +This repository does not currently document a dedicated private security email or private reporting channel. Contact the repository maintainers through the repository owner/maintainer channels already listed in the project, provide only a minimal non-exploitable summary in public, and ask for an appropriate private transfer method before sharing sensitive details. Do not open a public issue containing a working exploit, secret, sensitive crash dump, or malicious attachment. + +If no private channel can be established, withhold weaponized material and report the smallest safe description that allows maintainers to make contact. + +## What to include + +A useful report includes: + +- affected LightCraft version, commit, or release artifact; +- operating system, architecture, build profile (desktop or web), and relevant feature flags; +- the affected component or path; +- security impact and required attacker access; +- exact reproduction steps; +- expected behavior and actual behavior; +- crash logs, backtraces, sanitizer output, or resource measurements when applicable; +- whether the problem reproduces from a clean checkout; +- any known workaround or containment. + +Remove credentials, personal paths, private photos, and unrelated system information from logs. + +## Malicious test files + +Do not attach a potentially harmful or non-redistributable file to a public issue. Initially provide its format, size, cryptographic hash, observed effect, provenance category (for example, synthetic or fuzz-generated), and the command needed to reproduce the problem. Coordinate a private transfer method with maintainers before sending the sample. + +Test files accepted into the repository must be minimized, free of personal or proprietary data, legally redistributable, and documented with the expected failure behavior. A fixed parser defect should receive a permanent regression test whenever safe and practical. + +## Scope + +Security reports may cover: + +- camera raw, DNG, TIFF, HEIF, JPEG and other image decoding, and EXIF/XMP metadata and sidecar parsing; +- decompression bombs, oversized dimensions, integer overflow, memory exhaustion, recursion, or hangs; +- the LightCraft catalog, and importing other catalogs and libraries (such as Lightroom catalogs); +- import/export and filesystem path handling, including traversal, symlinks, and unsafe overwrite or move behavior; +- downloading, verifying, unpacking and running machine-learning models (denoise, faces, masks); +- engine command validation and serialization/deserialization; +- the desktop control channel, the MCP server, and the MCP-to-app connection; +- the WebAssembly build; +- GPU resource validation or driver-facing input handling; +- dependencies, CI, packaging, signing, checksums, and release artifact integrity. + +General bugs without a security impact should use the project's normal issue and contribution process. + +## Current limitations + +The control channel (`lightcraft --control PORT`) listens on loopback only and has no authentication, so any local process can drive the app while it is enabled; only enable it when you need it ([control-protocol.md](docs/control-protocol.md)). From 2247b9a3863a90844410b2aa0de13655ecce73ec Mon Sep 17 00:00:00 2001 From: "DUY Tran Nhat (SAE-KIDS)" Date: Tue, 13 Oct 2026 15:42:57 +0700 Subject: [PATCH 007/350] i18n(vi): translate app shell and navigation Co-authored-by: Cursor --- crates/ui-egui/locales/vi.json | 126 +++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 crates/ui-egui/locales/vi.json diff --git a/crates/ui-egui/locales/vi.json b/crates/ui-egui/locales/vi.json new file mode 100644 index 000000000..427a54b90 --- /dev/null +++ b/crates/ui-egui/locales/vi.json @@ -0,0 +1,126 @@ +{ + "AI Denoise": "Khử nhiễu AI", + "About": "Giới thiệu", + "About LightCraft": "Giới thiệu LightCraft", + "All": "Tất cả", + "Appearance": "Giao diện", + "Appearance Mode": "Chế độ giao diện", + "Appearance Settings…": "Cài đặt giao diện…", + "Apply": "Áp dụng", + "ArtCraft Website": "Trang web ArtCraft", + "Auto": "Tự động", + "Back": "Quay lại", + "Back Up Library…": "Sao lưu thư viện…", + "Cancel": "Hủy", + "Choose Edit Settings to Copy…": "Chọn cài đặt chỉnh sửa để sao chép…", + "Clear": "Xóa", + "Close": "Đóng", + "Copy": "Sao chép", + "Copy Edit Settings": "Sao chép cài đặt chỉnh sửa", + "Cut": "Cắt", + "Cycle Info Overlay": "Chuyển lớp phủ thông tin", + "Dark Theme": "Chủ đề tối", + "Delete": "Xóa", + "Deselect": "Bỏ chọn", + "Desktop": "Màn hình chính", + "Display": "Màn hình", + "Display theme": "Chủ đề hiển thị", + "Done": "Xong", + "Downloads": "Tải xuống", + "Duplicate": "Nhân bản", + "Edit": "Chỉnh sửa", + "Edit settings copied": "Đã sao chép cài đặt chỉnh sửa", + "English": "English", + "Enter Full Screen": "Vào toàn màn hình", + "Exit": "Thoát", + "Export Keywords…": "Xuất từ khóa…", + "Export Presets…": "Xuất thiết lập sẵn…", + "Export with Previous": "Xuất với lần trước", + "Export…": "Xuất…", + "Faces": "Khuôn mặt", + "File": "Tệp", + "Filter Bar": "Thanh bộ lọc", + "Find…": "Tìm…", + "Full Screen Preview": "Xem trước toàn màn hình", + "General": "Chung", + "Help": "Trợ giúp", + "Home": "Thư mục Nhà", + "Import": "Nhập", + "Import Keywords…": "Nhập từ khóa…", + "Import Lightroom Catalog…": "Nhập catalog Lightroom…", + "Import Photos…": "Nhập ảnh…", + "Import Profiles & Presets…": "Nhập hồ sơ và thiết lập sẵn…", + "Import from Folder…": "Nhập từ thư mục…", + "In-memory session: these settings last until LightCraft quits.": "Phiên trong bộ nhớ: các cài đặt này chỉ tồn tại đến khi LightCraft thoát.", + "Info": "Thông tin", + "Interface": "Giao diện", + "Interface language": "Ngôn ngữ giao diện", + "Join the ArtCraft Discord…": "Tham gia Discord ArtCraft…", + "Keyboard Shortcuts": "Phím tắt", + "Keyboard shortcuts": "Phím tắt", + "Language": "Ngôn ngữ", + "Library Preferences": "Tùy chọn thư viện", + "Light Theme": "Chủ đề sáng", + "LightCraft Help": "Trợ giúp LightCraft", + "LightCraft Website": "Trang web LightCraft", + "LightCraft on GitHub": "LightCraft trên GitHub", + "Lights Out": "Tắt đèn", + "Manual": "Thủ công", + "Menu": "Trình đơn", + "Minimize": "Thu nhỏ", + "More": "Thêm", + "New Folder…": "Thư mục mới…", + "New Library…": "Thư viện mới…", + "No": "Không", + "None": "Không có", + "OK": "OK", + "Off": "Tắt", + "Open Library…": "Mở thư viện…", + "Open Log Folder": "Mở thư mục nhật ký", + "Open…": "Mở…", + "Panels": "Các bảng", + "Paste": "Dán", + "Paste Edit Settings": "Dán cài đặt chỉnh sửa", + "Paste Selected Settings…": "Dán cài đặt đã chọn…", + "Performance": "Hiệu năng", + "Photo": "Ảnh", + "Preferences": "Tùy chọn", + "Preferences…": "Tùy chọn…", + "Quit": "Thoát", + "Quit LightCraft": "Thoát LightCraft", + "Redo": "Làm lại", + "Remove": "Gỡ", + "Rename": "Đổi tên", + "Reset": "Đặt lại", + "Reset Panel Layout": "Đặt lại bố cục bảng", + "Restore Library from Backup…": "Khôi phục thư viện từ bản sao lưu…", + "Save": "Lưu", + "Search": "Tìm kiếm", + "Second Window": "Cửa sổ thứ hai", + "Select All": "Chọn tất cả", + "Selected": "Đã chọn", + "Send Feedback…": "Gửi phản hồi…", + "Settings": "Cài đặt", + "Show": "Hiện", + "Show Clipping": "Hiện vùng cắt tông", + "Show Original": "Hiện bản gốc", + "Show Photo Counts": "Hiện số lượng ảnh", + "Show in Finder": "Hiện trong trình quản lý tệp", + "Switch light / dark theme": "Chuyển chủ đề sáng / tối", + "System Info…": "Thông tin hệ thống…", + "Theme": "Chủ đề", + "Toggle Zoom": "Bật/tắt thu phóng", + "Tools": "Công cụ", + "Undo": "Hoàn tác", + "View": "Xem", + "What's New": "Có gì mới", + "Window": "Cửa sổ", + "XMP Sidecar Preferences": "Tùy chọn tệp sidecar XMP", + "Yes": "Có", + "Zoom 100%": "Thu phóng 100%", + "Zoom In": "Phóng to", + "Zoom Out": "Thu nhỏ", + "Zoom to Fit": "Thu phóng vừa khung", + "日本語": "日本語", + "繁體中文(台灣)": "繁體中文(台灣)" +} From 815febed6abbfc1844038e58b91d6e9ecf5a25db Mon Sep 17 00:00:00 2001 From: "DUY Tran Nhat (SAE-KIDS)" Date: Tue, 13 Oct 2026 15:43:54 +0700 Subject: [PATCH 008/350] i18n(vi): translate library and photo navigation Co-authored-by: Cursor --- crates/ui-egui/locales/vi.json | 144 +++++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) diff --git a/crates/ui-egui/locales/vi.json b/crates/ui-egui/locales/vi.json index 427a54b90..baa630410 100644 --- a/crates/ui-egui/locales/vi.json +++ b/crates/ui-egui/locales/vi.json @@ -1,26 +1,82 @@ { + " (library default)": " (mặc định thư viện)", + "A folder is already being synchronized": "Một thư mục đang được đồng bộ", + "A folder is being synchronized": "Một thư mục đang được đồng bộ", "AI Denoise": "Khử nhiễu AI", "About": "Giới thiệu", "About LightCraft": "Giới thiệu LightCraft", + "Add Folder to Local": "Thêm thư mục vào Cục bộ", + "Add Selected Photos": "Thêm ảnh đã chọn", + "Add to Album": "Thêm vào album", + "Add to All Selected Photos": "Thêm vào mọi ảnh đã chọn", + "Add to Apple Photos": "Thêm vào Ảnh Apple", + "Add to My Photos": "Thêm vào Ảnh của tôi", + "Add to My Photos First": "Thêm vào Ảnh của tôi trước", + "Add to Selected Photos": "Thêm vào ảnh đã chọn", + "Add to Target Album": "Thêm vào album đích", + "Adding Lightroom photos…": "Đang thêm ảnh Lightroom…", + "Adding photos…": "Đang thêm ảnh…", + "Adding to Apple Photos": "Đang thêm vào Ảnh Apple", + "Adding to Apple Photos…": "Đang thêm vào Ảnh Apple…", + "Album": "Album", + "Albums": "Album", + "Albums hold library photos: Add to My Photos first": "Album chứa ảnh thư viện: hãy Thêm vào Ảnh của tôi trước", "All": "Tất cả", + "All Photos": "Tất cả ảnh", "Appearance": "Giao diện", "Appearance Mode": "Chế độ giao diện", "Appearance Settings…": "Cài đặt giao diện…", "Apply": "Áp dụng", "ArtCraft Website": "Trang web ArtCraft", "Auto": "Tự động", + "Auto Advance: move to the next photo after rating or flagging": "Tự chuyển tiếp: sang ảnh tiếp theo sau khi xếp hạng hoặc gắn cờ", + "Auto-Stack by Capture Time": "Tự xếp chồng theo thời gian chụp", + "Auto-Stack by Capture Time…": "Tự xếp chồng theo thời gian chụp…", + "Auto-Tag Photos from Tracklog": "Tự gắn thẻ ảnh từ nhật ký hành trình", "Back": "Quay lại", "Back Up Library…": "Sao lưu thư viện…", + "Back to Grid": "Quay lại lưới", + "Browse Folder": "Duyệt thư mục", + "Browse Folder…": "Duyệt thư mục…", "Cancel": "Hủy", + "Cancel Pending Photo Action": "Hủy thao tác ảnh đang chờ", + "Captured": "Đã chụp", + "Catalog Statistics": "Thống kê catalog", + "Choose Another Library…": "Chọn thư viện khác…", "Choose Edit Settings to Copy…": "Chọn cài đặt chỉnh sửa để sao chép…", + "Choose Folder…": "Chọn thư mục…", + "Choose a photo in the grid or filmstrip": "Chọn một ảnh trên lưới hoặc dải phim", + "Choose an album…": "Chọn một album…", "Clear": "Xóa", + "Clear Quick Collection": "Xóa Bộ sưu tập nhanh", "Close": "Đóng", + "Collapse All Stacks": "Thu gọn mọi chồng", + "Collapse Stack": "Thu gọn chồng", + "Compare": "So sánh", + "Compare needs at least two photos": "So sánh cần ít nhất hai ảnh", + "Confirm before moving photos to Recently Deleted": "Xác nhận trước khi chuyển ảnh vào Đã xóa gần đây", "Copy": "Sao chép", "Copy Edit Settings": "Sao chép cài đặt chỉnh sửa", + "Copy Name": "Tên bản sao", + "Create Album": "Tạo album", + "Create Album…": "Tạo album…", + "Create Folder": "Tạo thư mục", + "Create Folder…": "Tạo thư mục…", + "Create Smart Album": "Tạo album thông minh", + "Create Smart Album from Filter…": "Tạo album thông minh từ bộ lọc…", + "Create Smart Album…": "Tạo album thông minh…", + "Create Stack": "Tạo chồng", + "Create Virtual Copy": "Tạo bản sao ảo", "Cut": "Cắt", "Cycle Info Overlay": "Chuyển lớp phủ thông tin", "Dark Theme": "Chủ đề tối", + "Date": "Ngày", "Delete": "Xóa", + "Delete Album": "Xóa album", + "Delete Photo": "Xóa ảnh", + "Delete Photos": "Xóa ảnh", + "Denoise Photos": "Khử nhiễu ảnh", + "Denoise all photos with an Amount": "Khử nhiễu mọi ảnh có Độ mạnh", "Deselect": "Bỏ chọn", "Desktop": "Màn hình chính", "Display": "Màn hình", @@ -29,49 +85,123 @@ "Downloads": "Tải xuống", "Duplicate": "Nhân bản", "Edit": "Chỉnh sửa", + "Edit Smart Album": "Chỉnh sửa album thông minh", + "Edit Smart Album…": "Chỉnh sửa album thông minh…", "Edit settings copied": "Đã sao chép cài đặt chỉnh sửa", + "Edited": "Đã chỉnh sửa", + "Empty Recently Deleted": "Dọn Đã xóa gần đây", "English": "English", "Enter Full Screen": "Vào toàn màn hình", "Exit": "Thoát", + "Expand All Stacks": "Mở rộng mọi chồng", + "Expand Stack": "Mở rộng chồng", + "Expand/Collapse Stack": "Mở rộng/Thu gọn chồng", "Export Keywords…": "Xuất từ khóa…", "Export Presets…": "Xuất thiết lập sẵn…", "Export with Previous": "Xuất với lần trước", "Export…": "Xuất…", "Faces": "Khuôn mặt", + "Favorites": "Yêu thích", "File": "Tệp", + "Fill Location": "Điền vị trí", + "Fill Location from GPS": "Điền vị trí từ GPS", + "Filmstrip": "Dải phim", + "Filmstrip (/)": "Dải phim (/)", + "Filter": "Bộ lọc", "Filter Bar": "Thanh bộ lọc", + "Find Missing Photos": "Tìm ảnh bị thiếu", + "Find Missing Photos…": "Tìm ảnh bị thiếu…", + "Find Similar Photos": "Tìm ảnh tương tự", "Find…": "Tìm…", + "Flag": "Gắn cờ", + "Folder": "Thư mục", + "Folders": "Thư mục", + "Forget Unchanged Local Photos": "Quên ảnh cục bộ không đổi", + "Forget unchanged photos": "Quên ảnh không đổi", "Full Screen Preview": "Xem trước toàn màn hình", "General": "Chung", + "Generated demo photo": "Ảnh demo được tạo", + "Grid": "Lưới", + "Grid Info": "Thông tin lưới", + "Group into Stack": "Gom thành chồng", "Help": "Trợ giúp", "Home": "Thư mục Nhà", "Import": "Nhập", "Import Keywords…": "Nhập từ khóa…", + "Import Lightroom Catalog": "Nhập catalog Lightroom", "Import Lightroom Catalog…": "Nhập catalog Lightroom…", + "Import Photos": "Nhập ảnh", "Import Photos…": "Nhập ảnh…", "Import Profiles & Presets…": "Nhập hồ sơ và thiết lập sẵn…", "Import from Folder…": "Nhập từ thư mục…", + "Import new photos": "Nhập ảnh mới", + "Imported": "Đã nhập", + "Imported Photos": "Ảnh đã nhập", + "Importing Lightroom Catalog": "Đang nhập catalog Lightroom", + "Importing Lightroom catalog": "Đang nhập catalog Lightroom", + "In Recently Deleted": "Trong Đã xóa gần đây", + "In a Stack": "Trong chồng", + "In library": "Trong thư viện", "In-memory session: these settings last until LightCraft quits.": "Phiên trong bộ nhớ: các cài đặt này chỉ tồn tại đến khi LightCraft thoát.", + "Include selected photos": "Bao gồm ảnh đã chọn", + "Include subfolders": "Bao gồm thư mục con", "Info": "Thông tin", + "Inspect Lightroom Catalog": "Kiểm tra catalog Lightroom", + "Inspect Photo": "Kiểm tra ảnh", + "Inspecting Lightroom Catalog": "Đang kiểm tra catalog Lightroom", "Interface": "Giao diện", "Interface language": "Ngôn ngữ giao diện", + "Into one folder": "Vào một thư mục", "Join the ArtCraft Discord…": "Tham gia Discord ArtCraft…", "Keyboard Shortcuts": "Phím tắt", "Keyboard shortcuts": "Phím tắt", "Language": "Ngôn ngữ", + "Last loupe render": "Lần kết xuất kính lúp gần nhất", + "Library": "Thư viện", + "Library Folders": "Thư mục thư viện", + "Library Info": "Thông tin thư viện", + "Library Originals": "Bản gốc thư viện", "Library Preferences": "Tùy chọn thư viện", + "Library State": "Trạng thái thư viện", + "Library name": "Tên thư viện", + "Library saved": "Đã lưu thư viện", "Light Theme": "Chủ đề sáng", "LightCraft Help": "Trợ giúp LightCraft", "LightCraft Website": "Trang web LightCraft", + "LightCraft couldn't open the library at": "LightCraft không mở được thư viện tại", "LightCraft on GitHub": "LightCraft trên GitHub", + "Lightroom Classic Catalog": "Catalog Lightroom Classic", "Lights Out": "Tắt đèn", + "List Albums": "Liệt kê album", + "List this folder in Local from now on": "Liệt kê thư mục này trong Cục bộ từ nay", + "Local folders": "Thư mục cục bộ", + "Local library — no cloud account needed": "Thư viện cục bộ — không cần tài khoản đám mây", + "Locate Missing Files…": "Định vị tệp bị thiếu…", + "Locate Missing File…": "Định vị tệp bị thiếu…", + "Locate Photo": "Định vị ảnh", + "Location": "Vị trí", + "Looking for photos…": "Đang tìm ảnh…", + "Make Candidate the Select": "Đặt ảnh ứng viên thành ảnh được chọn", "Manual": "Thủ công", "Menu": "Trình đơn", "Minimize": "Thu nhỏ", + "Missing Photos": "Ảnh bị thiếu", "More": "Thêm", + "Move Album": "Di chuyển album", + "Move Down in Stack": "Di chuyển xuống trong chồng", + "Move Folder": "Di chuyển thư mục", + "Move Folder To…": "Di chuyển thư mục tới…", + "Move Selected Photos Here": "Di chuyển ảnh đã chọn vào đây", + "Move Up in Stack": "Di chuyển lên trong chồng", + "My Photos": "Ảnh của tôi", + "My Photos Panel": "Bảng Ảnh của tôi", + "New Album…": "Album mới…", "New Folder…": "Thư mục mới…", "New Library…": "Thư viện mới…", + "New Smart Album from Filter…": "Album thông minh mới từ bộ lọc…", + "New Smart Album…": "Album thông minh mới…", "No": "Không", + "No photos": "Không có ảnh", "None": "Không có", "OK": "OK", "Off": "Tắt", @@ -82,13 +212,17 @@ "Paste": "Dán", "Paste Edit Settings": "Dán cài đặt chỉnh sửa", "Paste Selected Settings…": "Dán cài đặt đã chọn…", + "People": "Người", "Performance": "Hiệu năng", "Photo": "Ảnh", + "Photo Grid": "Lưới ảnh", "Preferences": "Tùy chọn", "Preferences…": "Tùy chọn…", "Quit": "Thoát", "Quit LightCraft": "Thoát LightCraft", + "Recently Deleted": "Đã xóa gần đây", "Redo": "Làm lại", + "Reference View": "Xem tham chiếu", "Remove": "Gỡ", "Rename": "Đổi tên", "Reset": "Đặt lại", @@ -106,12 +240,22 @@ "Show Original": "Hiện bản gốc", "Show Photo Counts": "Hiện số lượng ảnh", "Show in Finder": "Hiện trong trình quản lý tệp", + "Slideshow": "Trình chiếu", + "Smart Album": "Album thông minh", + "Square Grid": "Lưới vuông", + "Stack": "Chồng", + "Stacks": "Chồng", + "Survey": "Khảo sát", + "Swap Compare Photos": "Đổi chỗ ảnh so sánh", "Switch light / dark theme": "Chuyển chủ đề sáng / tối", + "Synchronize Folder": "Đồng bộ thư mục", + "Synchronize Folder…": "Đồng bộ thư mục…", "System Info…": "Thông tin hệ thống…", "Theme": "Chủ đề", "Toggle Zoom": "Bật/tắt thu phóng", "Tools": "Công cụ", "Undo": "Hoàn tác", + "Unedited": "Chưa chỉnh sửa", "View": "Xem", "What's New": "Có gì mới", "Window": "Cửa sổ", From 662ddbd2a6bfc851635e91bdb18b458b2d99ee4a Mon Sep 17 00:00:00 2001 From: "DUY Tran Nhat (SAE-KIDS)" Date: Tue, 13 Oct 2026 15:45:32 +0700 Subject: [PATCH 009/350] i18n(vi): translate organization and metadata workflows Co-authored-by: Cursor --- crates/ui-egui/locales/vi.json | 324 +++++++++++++++++++++++++++++++++ 1 file changed, 324 insertions(+) diff --git a/crates/ui-egui/locales/vi.json b/crates/ui-egui/locales/vi.json index baa630410..14cc5a1c5 100644 --- a/crates/ui-egui/locales/vi.json +++ b/crates/ui-egui/locales/vi.json @@ -1,12 +1,18 @@ { " (library default)": " (mặc định thư viện)", + ", picked": ", đã chọn", + ", rejected": ", đã loại", + "0: nothing is rejected.": "0: không loại gì.", "A folder is already being synchronized": "Một thư mục đang được đồng bộ", "A folder is being synchronized": "Một thư mục đang được đồng bộ", + "A keyword set needs a name": "Bộ từ khóa cần một tên", "AI Denoise": "Khử nhiễu AI", "About": "Giới thiệu", "About LightCraft": "Giới thiệu LightCraft", + "Add Face Model…": "Thêm mô hình khuôn mặt…", "Add Folder to Local": "Thêm thư mục vào Cục bộ", "Add Selected Photos": "Thêm ảnh đã chọn", + "Add keyword": "Thêm từ khóa", "Add to Album": "Thêm vào album", "Add to All Selected Photos": "Thêm vào mọi ảnh đã chọn", "Add to Apple Photos": "Thêm vào Ảnh Apple", @@ -22,69 +28,131 @@ "Albums": "Album", "Albums hold library photos: Add to My Photos first": "Album chứa ảnh thư viện: hãy Thêm vào Ảnh của tôi trước", "All": "Tất cả", + "All Metadata": "Tất cả siêu dữ liệu", + "All Metadata…": "Tất cả siêu dữ liệu…", "All Photos": "Tất cả ảnh", + "Alt Text": "Văn bản thay thế", + "Any Searchable Text": "Mọi văn bản tìm được", + "Any keyword": "Mọi từ khóa", + "Aperture": "Khẩu độ", "Appearance": "Giao diện", "Appearance Mode": "Chế độ giao diện", "Appearance Settings…": "Cài đặt giao diện…", "Apply": "Áp dụng", + "Apply Color Label Set": "Áp dụng bộ nhãn màu", + "Apply Metadata Preset": "Áp dụng thiết lập sẵn siêu dữ liệu", "ArtCraft Website": "Trang web ArtCraft", + "Aspect Ratio": "Tỷ lệ khung hình", + "Assisted Culling": "Sàng lọc hỗ trợ", "Auto": "Tự động", + "Auto Advance after rating or flagging": "Tự chuyển tiếp sau khi xếp hạng hoặc gắn cờ", "Auto Advance: move to the next photo after rating or flagging": "Tự chuyển tiếp: sang ảnh tiếp theo sau khi xếp hạng hoặc gắn cờ", "Auto-Stack by Capture Time": "Tự xếp chồng theo thời gian chụp", "Auto-Stack by Capture Time…": "Tự xếp chồng theo thời gian chụp…", "Auto-Tag Photos from Tracklog": "Tự gắn thẻ ảnh từ nhật ký hành trình", + "Auto-Tag from Tracklog": "Tự gắn thẻ từ nhật ký hành trình", + "Auto-Tag from Tracklog…": "Tự gắn thẻ từ nhật ký hành trình…", "Back": "Quay lại", "Back Up Library…": "Sao lưu thư viện…", "Back to Grid": "Quay lại lưới", + "Back to this person": "Quay lại người này", + "Best of Similar Shots": "Ảnh đẹp nhất trong nhóm tương tự", + "Black & White": "Đen trắng", + "Blue": "Lam", + "Blue label": "Nhãn lam", "Browse Folder": "Duyệt thư mục", "Browse Folder…": "Duyệt thư mục…", + "Camera": "Máy ảnh", + "Camera Info": "Thông tin máy ảnh", "Cancel": "Hủy", + "Cancel Face Model Download": "Hủy tải mô hình khuôn mặt", "Cancel Pending Photo Action": "Hủy thao tác ảnh đang chờ", + "Caption": "Chú thích", + "Capture Date": "Ngày chụp", "Captured": "Đã chụp", "Catalog Statistics": "Thống kê catalog", "Choose Another Library…": "Chọn thư viện khác…", "Choose Edit Settings to Copy…": "Chọn cài đặt chỉnh sửa để sao chép…", + "Choose Face Recognition Model": "Chọn mô hình nhận diện khuôn mặt", "Choose Folder…": "Chọn thư mục…", + "Choose a model below (Use) to start.": "Chọn một mô hình bên dưới (Dùng) để bắt đầu.", "Choose a photo in the grid or filmstrip": "Chọn một ảnh trên lưới hoặc dải phim", "Choose an album…": "Chọn một album…", + "City": "Thành phố", "Clear": "Xóa", "Clear Quick Collection": "Xóa Bộ sưu tập nhanh", + "Clear rating": "Xóa xếp hạng", + "Clear rating and advance": "Xóa xếp hạng và chuyển tiếp", + "Click to restore · double-click to rename": "Nhấp để khôi phục · nhấp đúp để đổi tên", "Close": "Đóng", "Collapse All Stacks": "Thu gọn mọi chồng", "Collapse Stack": "Thu gọn chồng", + "Color Label": "Nhãn màu", + "Color Label Names": "Tên nhãn màu", + "Color Label Sets": "Bộ nhãn màu", + "Color label cleared": "Đã xóa nhãn màu", "Compare": "So sánh", "Compare needs at least two photos": "So sánh cần ít nhất hai ảnh", "Confirm before moving photos to Recently Deleted": "Xác nhận trước khi chuyển ảnh vào Đã xóa gần đây", "Copy": "Sao chép", "Copy Edit Settings": "Sao chép cài đặt chỉnh sửa", + "Copy Metadata": "Sao chép siêu dữ liệu", "Copy Name": "Tên bản sao", + "Copyright": "Bản quyền", + "Copyright Info URL": "URL thông tin bản quyền", + "Copyright Status": "Trạng thái bản quyền", + "Copyrighted": "Có bản quyền", + "Country": "Quốc gia", "Create Album": "Tạo album", "Create Album…": "Tạo album…", "Create Folder": "Tạo thư mục", "Create Folder…": "Tạo thư mục…", + "Create Keyword Tag": "Tạo thẻ từ khóa", "Create Smart Album": "Tạo album thông minh", "Create Smart Album from Filter…": "Tạo album thông minh từ bộ lọc…", "Create Smart Album…": "Tạo album thông minh…", "Create Stack": "Tạo chồng", "Create Virtual Copy": "Tạo bản sao ảo", + "Creator": "Người tạo", + "Creator metadata": "Siêu dữ liệu người tạo", + "Cropped": "Đã cắt", "Cut": "Cắt", "Cycle Info Overlay": "Chuyển lớp phủ thông tin", "Dark Theme": "Chủ đề tối", "Date": "Ngày", + "Day": "Ngày", + "Decrease Rating": "Giảm xếp hạng", "Delete": "Xóa", "Delete Album": "Xóa album", + "Delete Color Label Set": "Xóa bộ nhãn màu", + "Delete Keyword": "Xóa từ khóa", + "Delete Keyword Set": "Xóa bộ từ khóa", + "Delete Keyword…": "Xóa từ khóa…", + "Delete Metadata Preset": "Xóa thiết lập sẵn siêu dữ liệu", "Delete Photo": "Xóa ảnh", "Delete Photos": "Xóa ảnh", "Denoise Photos": "Khử nhiễu ảnh", "Denoise all photos with an Amount": "Khử nhiễu mọi ảnh có Độ mạnh", + "Description": "Mô tả", "Deselect": "Bỏ chọn", "Desktop": "Màn hình chính", + "Detect Faces": "Phát hiện khuôn mặt", + "Develop": "Phát triển", "Display": "Màn hình", "Display theme": "Chủ đề hiển thị", "Done": "Xong", + "Download Face Model": "Tải mô hình khuôn mặt", "Downloads": "Tải xuống", "Duplicate": "Nhân bản", "Edit": "Chỉnh sửa", + "Edit Color Label Names": "Sửa tên nhãn màu", + "Edit Color Label Names…": "Sửa tên nhãn màu…", + "Edit Date": "Ngày chỉnh sửa", + "Edit Keyword Set": "Sửa bộ từ khóa", + "Edit Keyword Tag": "Sửa thẻ từ khóa", + "Edit Keyword Tag…": "Sửa thẻ từ khóa…", + "Edit Label Names": "Sửa tên nhãn", + "Edit Label Names…": "Sửa tên nhãn…", "Edit Smart Album": "Chỉnh sửa album thông minh", "Edit Smart Album…": "Chỉnh sửa album thông minh…", "Edit settings copied": "Đã sao chép cài đặt chỉnh sửa", @@ -92,41 +160,80 @@ "Empty Recently Deleted": "Dọn Đã xóa gần đây", "English": "English", "Enter Full Screen": "Vào toàn màn hình", + "Evaluate Face Recognition": "Đánh giá nhận diện khuôn mặt", + "Every EXIF, GPS and XMP field in the file": "Mọi trường EXIF, GPS và XMP trong tệp", "Exit": "Thoát", "Expand All Stacks": "Mở rộng mọi chồng", "Expand Stack": "Mở rộng chồng", "Expand/Collapse Stack": "Mở rộng/Thu gọn chồng", + "Export Containing Keywords": "Xuất từ khóa chứa", + "Export Keywords": "Xuất từ khóa", "Export Keywords…": "Xuất từ khóa…", "Export Presets…": "Xuất thiết lập sẵn…", + "Export Synonyms": "Xuất từ đồng nghĩa", "Export with Previous": "Xuất với lần trước", "Export…": "Xuất…", + "Face Boxes": "Khung khuôn mặt", + "Face Model Downloads": "Tải mô hình khuôn mặt", + "Face Models": "Mô hình khuôn mặt", + "Face Recognition On/Off": "Bật/tắt nhận diện khuôn mặt", + "Face boxes": "Khung khuôn mặt", + "Face detector": "Bộ phát hiện khuôn mặt", + "Face recognition": "Nhận diện khuôn mặt", "Faces": "Khuôn mặt", + "Faces of a Person": "Khuôn mặt của một người", "Favorites": "Yêu thích", "File": "Tệp", + "File Extension": "Phần mở rộng tệp", + "File Format": "Định dạng tệp", + "File Path": "Đường dẫn tệp", + "File Type": "Loại tệp", + "Filename": "Tên tệp", "Fill Location": "Điền vị trí", "Fill Location from GPS": "Điền vị trí từ GPS", "Filmstrip": "Dải phim", "Filmstrip (/)": "Dải phim (/)", "Filter": "Bộ lọc", "Filter Bar": "Thanh bộ lọc", + "Filter Keywords": "Lọc từ khóa", "Find Missing Photos": "Tìm ảnh bị thiếu", "Find Missing Photos…": "Tìm ảnh bị thiếu…", "Find Similar Photos": "Tìm ảnh tương tự", + "Finding faces": "Đang tìm khuôn mặt", "Find…": "Tìm…", + "Five stars": "Năm sao", + "Fix the marked rules to save this album.": "Sửa các quy tắc đã đánh dấu để lưu album này.", "Flag": "Gắn cờ", + "Flag as Pick": "Gắn cờ Đã chọn", + "Flag as Reject": "Gắn cờ Đã loại", + "Flagged as Pick": "Đã gắn cờ Đã chọn", + "Flagged as Reject": "Đã gắn cờ Đã loại", + "Focal Length": "Tiêu cự", + "Focus (assisted culling)": "Lấy nét (sàng lọc hỗ trợ)", "Folder": "Thư mục", + "Folder name (renamed on disk; its photos follow)": "Tên thư mục (đổi tên trên đĩa; ảnh theo thư mục)", "Folders": "Thư mục", "Forget Unchanged Local Photos": "Quên ảnh cục bộ không đổi", "Forget unchanged photos": "Quên ảnh không đổi", + "Fr": "T6", + "Friday": "Thứ Sáu", "Full Screen Preview": "Xem trước toàn màn hình", "General": "Chung", "Generated demo photo": "Ảnh demo được tạo", + "Green": "Lục", + "Green label": "Nhãn lục", "Grid": "Lưới", "Grid Info": "Thông tin lưới", "Group into Stack": "Gom thành chồng", + "Has Edits": "Có chỉnh sửa", + "Has GPS": "Có GPS", "Help": "Trợ giúp", "Home": "Thư mục Nhà", + "ISO Speed": "Tốc độ ISO", + "Image": "Ảnh", "Import": "Nhập", + "Import Date": "Ngày nhập", + "Import Keywords": "Nhập từ khóa", "Import Keywords…": "Nhập từ khóa…", "Import Lightroom Catalog": "Nhập catalog Lightroom", "Import Lightroom Catalog…": "Nhập catalog Lightroom…", @@ -139,24 +246,51 @@ "Imported Photos": "Ảnh đã nhập", "Importing Lightroom Catalog": "Đang nhập catalog Lightroom", "Importing Lightroom catalog": "Đang nhập catalog Lightroom", + "In Color": "Màu", "In Recently Deleted": "Trong Đã xóa gần đây", "In a Stack": "Trong chồng", "In library": "Trong thư viện", "In-memory session: these settings last until LightCraft quits.": "Phiên trong bộ nhớ: các cài đặt này chỉ tồn tại đến khi LightCraft thoát.", "Include selected photos": "Bao gồm ảnh đã chọn", "Include subfolders": "Bao gồm thư mục con", + "Increase Rating": "Tăng xếp hạng", + "Index Faces": "Lập chỉ mục khuôn mặt", + "Index Faces in the Background": "Lập chỉ mục khuôn mặt nền", "Info": "Thông tin", + "Inspect Face Model File": "Kiểm tra tệp mô hình khuôn mặt", "Inspect Lightroom Catalog": "Kiểm tra catalog Lightroom", "Inspect Photo": "Kiểm tra ảnh", "Inspecting Lightroom Catalog": "Đang kiểm tra catalog Lightroom", + "Install Face Model": "Cài mô hình khuôn mặt", "Interface": "Giao diện", "Interface language": "Ngôn ngữ giao diện", "Into one folder": "Vào một thư mục", + "It tests this album, so testing it back would loop": "Nó kiểm tra album này, nên kiểm tra ngược lại sẽ tạo vòng lặp", "Join the ArtCraft Discord…": "Tham gia Discord ArtCraft…", "Keyboard Shortcuts": "Phím tắt", "Keyboard shortcuts": "Phím tắt", + "Keyword": "Từ khóa", + "Keyword Count": "Số từ khóa", + "Keyword List": "Danh sách từ khóa", + "Keyword Lists": "Danh sách từ khóa", + "Keyword Name": "Tên từ khóa", + "Keyword Painter": "Cọ từ khóa", + "Keyword Set": "Bộ từ khóa", + "Keyword Sets": "Bộ từ khóa", + "Keyword Suggestions": "Gợi ý từ khóa", + "Keyword Tag Options": "Tùy chọn thẻ từ khóa", + "Keyword to paint": "Từ khóa để tô", + "Keywords": "Từ khóa", + "Keywords & People": "Từ khóa và Người", + "Keywords (K)": "Từ khóa (K)", + "Keywords (⌥1–⌥9)": "Từ khóa (⌥1–⌥9)", + "Keywords you add appear here; ⌥1–⌥9 apply them.": "Từ khóa bạn thêm hiện ở đây; ⌥1–⌥9 áp dụng chúng.", + "Label": "Nhãn", + "Label Set": "Bộ nhãn", + "Landscape (wide)": "Ngang (rộng)", "Language": "Ngôn ngữ", "Last loupe render": "Lần kết xuất kính lúp gần nhất", + "Lens": "Ống kính", "Library": "Thư viện", "Library Folders": "Thư mục thư viện", "Library Info": "Thông tin thư viện", @@ -168,6 +302,7 @@ "Light Theme": "Chủ đề sáng", "LightCraft Help": "Trợ giúp LightCraft", "LightCraft Website": "Trang web LightCraft", + "LightCraft could not start": "LightCraft không thể khởi động", "LightCraft couldn't open the library at": "LightCraft không mở được thư viện tại", "LightCraft on GitHub": "LightCraft trên GitHub", "Lightroom Classic Catalog": "Catalog Lightroom Classic", @@ -180,12 +315,23 @@ "Locate Missing File…": "Định vị tệp bị thiếu…", "Locate Photo": "Định vị ảnh", "Location": "Vị trí", + "Long Edge": "Cạnh dài", "Looking for photos…": "Đang tìm ảnh…", "Make Candidate the Select": "Đặt ảnh ứng viên thành ảnh được chọn", "Manual": "Thủ công", + "Megapixels": "Megapixel", "Menu": "Trình đơn", + "Merge Keywords": "Gộp từ khóa", + "Metadata": "Siêu dữ liệu", + "Metadata Preset": "Thiết lập sẵn siêu dữ liệu", + "Metadata Presets": "Thiết lập sẵn siêu dữ liệu", + "Metadata preset": "Thiết lập sẵn siêu dữ liệu", + "Metadata read": "Đã đọc siêu dữ liệu", "Minimize": "Thu nhỏ", "Missing Photos": "Ảnh bị thiếu", + "Mo": "T2", + "Monday": "Thứ Hai", + "Month": "Tháng", "More": "Thêm", "Move Album": "Di chuyển album", "Move Down in Stack": "Di chuyển xuống trong chồng", @@ -195,76 +341,254 @@ "Move Up in Stack": "Di chuyển lên trong chồng", "My Photos": "Ảnh của tôi", "My Photos Panel": "Bảng Ảnh của tôi", + "Name Face": "Đặt tên khuôn mặt", + "Name Faces": "Đặt tên khuôn mặt", + "Named": "Đã đặt tên", + "Named People": "Người đã đặt tên", "New Album…": "Album mới…", "New Folder…": "Thư mục mới…", "New Library…": "Thư viện mới…", + "New Smart Album": "Album thông minh mới", "New Smart Album from Filter…": "Album thông minh mới từ bộ lọc…", "New Smart Album…": "Album thông minh mới…", "No": "Không", + "No Label": "Không nhãn", + "No Stars": "Không sao", + "No albums match": "Không có album khớp", + "No albums yet": "Chưa có album", + "No keywords are exported": "Không xuất từ khóa nào", + "No keywords match": "Không có từ khóa khớp", + "No keywords yet": "Chưa có từ khóa", + "No metadata found": "Không tìm thấy siêu dữ liệu", + "No named people in these photos": "Không có người được đặt tên trong các ảnh này", + "No named people yet": "Chưa có người được đặt tên", + "No photo has it; the keywords below it go too.": "Không ảnh nào có nó; các từ khóa bên dưới cũng bị gỡ.", "No photos": "Không có ảnh", "None": "Không có", "OK": "OK", "Off": "Tắt", + "On NixOS, start it from `nix develop`.": "Trên NixOS, hãy khởi chạy từ `nix develop`.", "Open Library…": "Mở thư viện…", "Open Log Folder": "Mở thư mục nhật ký", "Open…": "Mở…", "Panels": "Các bảng", "Paste": "Dán", "Paste Edit Settings": "Dán cài đặt chỉnh sửa", + "Paste Metadata": "Dán siêu dữ liệu", "Paste Selected Settings…": "Dán cài đặt đã chọn…", "People": "Người", + "People Count": "Số người", + "Percentage": "Phần trăm", "Performance": "Hiệu năng", + "Person": "Người", "Photo": "Ảnh", "Photo Grid": "Lưới ảnh", + "Pick": "Đã chọn", + "Pick Flag": "Cờ chọn", + "Pick a colour on the photo with the eyedropper.": "Chọn màu trên ảnh bằng ống nhỏ giọt.", + "Pick a date": "Chọn ngày", + "Picked": "Đã chọn", + "Picks": "Ảnh đã chọn", + "Portrait (tall)": "Dọc (cao)", "Preferences": "Tùy chọn", "Preferences…": "Tùy chọn…", + "Public Domain": "Phạm vi công cộng", + "Purge Unused Keywords": "Dọn từ khóa không dùng", + "Purple": "Tím", + "Put New Keywords Inside This Keyword": "Đặt từ khóa mới vào trong từ khóa này", "Quit": "Thoát", "Quit LightCraft": "Thoát LightCraft", + "Rating": "Xếp hạng", + "Rating cleared": "Đã xóa xếp hạng", + "Ratings & flags": "Xếp hạng và cờ", + "Raw": "Raw", + "Read Metadata from File": "Đọc siêu dữ liệu từ tệp", + "Read metadata updates from XMP sidecars": "Đọc cập nhật siêu dữ liệu từ sidecar XMP", + "Recent Keywords": "Từ khóa gần đây", + "Recent Keywords is built in: choose another name": "Từ khóa gần đây là bộ sẵn: hãy chọn tên khác", "Recently Deleted": "Đã xóa gần đây", + "Recognise faces (experimental)": "Nhận diện khuôn mặt (thử nghiệm)", + "Red": "Đỏ", + "Red label": "Nhãn đỏ", "Redo": "Làm lại", "Reference View": "Xem tham chiếu", + "Reject": "Đã loại", + "Reject below focus": "Loại ảnh dưới ngưỡng lấy nét", + "Rejected": "Đã loại", + "Rejects": "Ảnh đã loại", + "Relink photos whose file was renamed or moved": "Liên kết lại ảnh có tệp đã đổi tên hoặc di chuyển", "Remove": "Gỡ", + "Remove Face Box": "Gỡ khung khuôn mặt", + "Remove Face Model": "Gỡ mô hình khuôn mặt", + "Remove this face box (undo with Edit ▸ Undo)": "Gỡ khung khuôn mặt này (hoàn tác bằng Chỉnh sửa ▸ Hoàn tác)", "Rename": "Đổi tên", + "Rename Album": "Đổi tên album", + "Rename Component": "Đổi tên thành phần", + "Rename Folder": "Đổi tên thư mục", + "Rename Folder…": "Đổi tên thư mục…", + "Rename Keyword": "Đổi tên từ khóa", + "Rename Keyword…": "Đổi tên từ khóa…", + "Rename Mask": "Đổi tên mặt nạ", + "Rename Photos": "Đổi tên ảnh", + "Rename Photos…": "Đổi tên ảnh…", + "Rename Preset": "Đổi tên thiết lập sẵn", + "Rename Preview": "Đổi tên bản xem trước", + "Rename Template Tags": "Thẻ mẫu đổi tên", + "Rename Version": "Đổi tên phiên bản", + "Rename…": "Đổi tên…", "Reset": "Đặt lại", "Reset Panel Layout": "Đặt lại bố cục bảng", + "Resize Face Box": "Đổi kích thước khung khuôn mặt", "Restore Library from Backup…": "Khôi phục thư viện từ bản sao lưu…", + "Sa": "T7", + "Saturday": "Thứ Bảy", "Save": "Lưu", + "Save Color Label Set": "Lưu bộ nhãn màu", + "Save Current Keywords as Set…": "Lưu từ khóa hiện tại thành bộ…", + "Save Keyword Set": "Lưu bộ từ khóa", + "Save Metadata Preset": "Lưu thiết lập sẵn siêu dữ liệu", + "Save Metadata Preset…": "Lưu thiết lập sẵn siêu dữ liệu…", + "Save Metadata to File": "Lưu siêu dữ liệu vào tệp", + "Save as Smart Album…": "Lưu thành album thông minh…", "Search": "Tìm kiếm", + "Search albums": "Tìm album", "Second Window": "Cửa sổ thứ hai", "Select All": "Chọn tất cả", + "Select by Flag, Rating or Label": "Chọn theo cờ, xếp hạng hoặc nhãn", + "Select photos to give them keywords.": "Chọn ảnh để gán từ khóa.", "Selected": "Đã chọn", "Send Feedback…": "Gửi phản hồi…", + "Sequence number, counting from the start number": "Số thứ tự, đếm từ số bắt đầu", + "Set Color Label": "Đặt nhãn màu", + "Set Flag": "Đặt cờ", + "Set Rating": "Đặt xếp hạng", "Settings": "Cài đặt", + "Short Edge": "Cạnh ngắn", "Show": "Hiện", "Show Clipping": "Hiện vùng cắt tông", "Show Original": "Hiện bản gốc", + "Show Person": "Hiện người", "Show Photo Counts": "Hiện số lượng ảnh", + "Show Photos with Keyword": "Hiện ảnh có từ khóa", "Show in Finder": "Hiện trong trình quản lý tệp", + "Show ratings, flags and edit badges": "Hiện xếp hạng, cờ và huy hiệu chỉnh sửa", + "Show the template tags; click one to insert it": "Hiện thẻ mẫu; nhấp để chèn", + "Shutter Speed": "Tốc độ cửa trập", + "Size": "Kích thước", "Slideshow": "Trình chiếu", "Smart Album": "Album thông minh", + "Smart Album Rule Fields": "Trường quy tắc album thông minh", + "Some rules need fixing (Edit Smart Album…):": "Một số quy tắc cần sửa (Chỉnh sửa album thông minh…):", + "Source": "Nguồn", + "Square": "Vuông", "Square Grid": "Lưới vuông", "Stack": "Chồng", "Stacks": "Chồng", + "Star rating (0–5)": "Xếp hạng sao (0–5)", + "Start at": "Bắt đầu tại", + "Start number": "Số bắt đầu", + "Starting": "Đang bắt đầu", + "Starting…": "Đang bắt đầu…", + "Startup": "Khởi động", + "State / Province": "Bang / Tỉnh", + "Su": "CN", + "Suggest Names for Faces": "Gợi ý tên cho khuôn mặt", + "Sunday": "Chủ Nhật", "Survey": "Khảo sát", "Swap Compare Photos": "Đổi chỗ ảnh so sánh", "Switch light / dark theme": "Chuyển chủ đề sáng / tối", "Synchronize Folder": "Đồng bộ thư mục", "Synchronize Folder…": "Đồng bộ thư mục…", + "Synonyms": "Từ đồng nghĩa", "System Info…": "Thông tin hệ thống…", + "Tags": "Thẻ", + "Test Face Model": "Thử mô hình khuôn mặt", + "Th": "T5", "Theme": "Chủ đề", + "This group is empty: add a rule or remove it.": "Nhóm này trống: thêm quy tắc hoặc xóa nhóm.", + "This is the album you're editing": "Đây là album bạn đang chỉnh sửa", + "Thursday": "Thứ Năm", + "Title": "Tiêu đề", + "Title metadata": "Siêu dữ liệu tiêu đề", + "Toggle Keyword from Set": "Bật/tắt từ khóa từ bộ", "Toggle Zoom": "Bật/tắt thu phóng", "Tools": "Công cụ", + "Treatment": "Xử lý màu", + "Tu": "T3", + "Tuesday": "Thứ Ba", "Undo": "Hoàn tác", "Unedited": "Chưa chỉnh sửa", + "Unflag": "Bỏ cờ", + "Unflagged": "Không gắn cờ", + "Unknown": "Không rõ", + "Unnamed Faces": "Khuôn mặt chưa đặt tên", + "Use Keyword Set": "Dùng bộ từ khóa", + "Video": "Video", + "Video Duration": "Thời lượng video", "View": "Xem", + "Vintage": "Vintage", + "Virtual Copy": "Bản sao ảo", + "Waiting to start…": "Đang chờ bắt đầu…", + "We": "T4", + "Wednesday": "Thứ Tư", "What's New": "Có gì mới", "Window": "Cửa sổ", "XMP Sidecar Preferences": "Tùy chọn tệp sidecar XMP", + "Year": "Năm", + "Yellow": "Vàng", + "Yellow label": "Nhãn vàng", "Yes": "Có", "Zoom 100%": "Thu phóng 100%", "Zoom In": "Phóng to", "Zoom Out": "Thu nhỏ", "Zoom to Fit": "Thu phóng vừa khung", + "are empty": "trống", + "aren't empty": "không trống", + "can't be tested that way": "không thể kiểm tra theo cách đó", + "can't match any rating from 0 to 5": "không khớp xếp hạng nào từ 0 đến 5", + "can't test a folder; choose an album in it": "không thể kiểm tra thư mục; hãy chọn album bên trong", + "contains": "chứa", + "copyrighted": "có bản quyền", + "doesn't contain": "không chứa", + "ends with": "kết thúc bằng", + "has the first date after the second": "ngày đầu sau ngày thứ hai", + "is": "là", + "is <": "<", + "is >": ">", + "is after": "sau", + "is before": "trước", + "is between": "nằm giữa", + "is empty": "trống", + "is in the last": "trong vòng", + "is unknown": "không rõ", + "is yes or no": "là có hoặc không", + "is ≤": "≤", + "is ≥": "≥", + "isn't": "không phải", + "isn't a field rules know": "không phải trường quy tắc biết", + "isn't empty": "không trống", + "isn't in the last": "không trong vòng", + "isn't one of the choices": "không phải một trong các lựa chọn", + "names an album that no longer exists": "chỉ album không còn tồn tại", + "needs a date like 2026, 2026-08 or 2026-08-14": "cần ngày như 2026, 2026-08 hoặc 2026-08-14", + "needs a number": "cần một số", + "needs a number more than 0": "cần số lớn hơn 0", + "needs a time like 1/250 or 2": "cần thời gian như 1/250 hoặc 2", + "needs an album": "cần một album", + "needs hours, days, weeks, months or years": "cần giờ, ngày, tuần, tháng hoặc năm", + "needs something to look for (or use “are empty”)": "cần nội dung để tìm (hoặc dùng “trống”)", + "needs something to look for (or use “aren't empty”)": "cần nội dung để tìm (hoặc dùng “không trống”)", + "needs something to look for (or use “is empty”)": "cần nội dung để tìm (hoặc dùng “trống”)", + "needs something to look for (or use “isn't empty”)": "cần nội dung để tìm (hoặc dùng “không trống”)", + "needs text": "cần văn bản", + "needs two values": "cần hai giá trị", + "pick": "đã chọn", + "reject": "đã loại", + "smart album value|No": "Không", + "smart album value|Yes": "Có", + "starts using it for AI Denoise": "bắt đầu dùng nó cho Khử nhiễu AI", + "starts with": "bắt đầu bằng", + "would make this album include itself through other smart albums": "sẽ khiến album này bao gồm chính nó qua album thông minh khác", "日本語": "日本語", "繁體中文(台灣)": "繁體中文(台灣)" } From 1fb7bad0932487f5a37b08e6eac8d4aa58853ae0 Mon Sep 17 00:00:00 2001 From: "DUY Tran Nhat (SAE-KIDS)" Date: Tue, 13 Oct 2026 15:54:00 +0700 Subject: [PATCH 010/350] i18n(vi): translate import workflows --- crates/ui-egui/locales/vi.json | 72 ++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/crates/ui-egui/locales/vi.json b/crates/ui-egui/locales/vi.json index 14cc5a1c5..574964369 100644 --- a/crates/ui-egui/locales/vi.json +++ b/crates/ui-egui/locales/vi.json @@ -3,6 +3,7 @@ ", picked": ", đã chọn", ", rejected": ", đã loại", "0: nothing is rejected.": "0: không loại gì.", + "1620 × 1080 preview, and import with their metadata: capture time, camera, lens, exposure, GPS and XMP. Their raw": "xem trước 1620 × 1080 và nhập kèm metadata: thời gian chụp, máy ảnh, ống kính, phơi sáng, GPS và XMP. Raw của chúng", "A folder is already being synchronized": "Một thư mục đang được đồng bộ", "A folder is being synchronized": "Một thư mục đang được đồng bộ", "A keyword set needs a name": "Bộ từ khóa cần một tên", @@ -12,6 +13,8 @@ "Add Face Model…": "Thêm mô hình khuôn mặt…", "Add Folder to Local": "Thêm thư mục vào Cục bộ", "Add Selected Photos": "Thêm ảnh đã chọn", + "Add in place": "Thêm tại chỗ", + "Add in place: the library references the files where they are; nothing is copied or moved.": "Thêm tại chỗ: thư viện tham chiếu tệp ở vị trí hiện tại; không sao chép hay di chuyển gì.", "Add keyword": "Thêm từ khóa", "Add to Album": "Thêm vào album", "Add to All Selected Photos": "Thêm vào mọi ảnh đã chọn", @@ -20,6 +23,7 @@ "Add to My Photos First": "Thêm vào Ảnh của tôi trước", "Add to Selected Photos": "Thêm vào ảnh đã chọn", "Add to Target Album": "Thêm vào album đích", + "Added to photos you import that don't already have it.": "Được thêm vào ảnh bạn nhập nếu chưa có.", "Adding Lightroom photos…": "Đang thêm ảnh Lightroom…", "Adding photos…": "Đang thêm ảnh…", "Adding to Apple Photos": "Đang thêm vào Ảnh Apple", @@ -31,6 +35,7 @@ "All Metadata": "Tất cả siêu dữ liệu", "All Metadata…": "Tất cả siêu dữ liệu…", "All Photos": "Tất cả ảnh", + "All the photos imported from this disk are included.": "Tất cả ảnh nhập từ đĩa này đều được bao gồm.", "Alt Text": "Văn bản thay thế", "Any Searchable Text": "Mọi văn bản tìm được", "Any keyword": "Mọi từ khóa", @@ -47,6 +52,9 @@ "Auto": "Tự động", "Auto Advance after rating or flagging": "Tự chuyển tiếp sau khi xếp hạng hoặc gắn cờ", "Auto Advance: move to the next photo after rating or flagging": "Tự chuyển tiếp: sang ảnh tiếp theo sau khi xếp hạng hoặc gắn cờ", + "Auto Import": "Tự nhập", + "Auto Import Now": "Tự nhập ngay", + "Auto Import Settings": "Cài đặt tự nhập", "Auto-Stack by Capture Time": "Tự xếp chồng theo thời gian chụp", "Auto-Stack by Capture Time…": "Tự xếp chồng theo thời gian chụp…", "Auto-Tag Photos from Tracklog": "Tự gắn thẻ ảnh từ nhật ký hành trình", @@ -64,6 +72,7 @@ "Browse Folder…": "Duyệt thư mục…", "Camera": "Máy ảnh", "Camera Info": "Thông tin máy ảnh", + "Cameras and Cards": "Máy ảnh và thẻ nhớ", "Cancel": "Hủy", "Cancel Face Model Download": "Hủy tải mô hình khuôn mặt", "Cancel Pending Photo Action": "Hủy thao tác ảnh đang chờ", @@ -94,10 +103,16 @@ "Compare": "So sánh", "Compare needs at least two photos": "So sánh cần ít nhất hai ảnh", "Confirm before moving photos to Recently Deleted": "Xác nhận trước khi chuyển ảnh vào Đã xóa gần đây", + "Convert to DNG": "Chuyển sang DNG", + "Convert to DNG, Copy as DNG, Photo Merge and smart previews no longer write straight to the final file (issue": "Chuyển sang DNG, Sao chép dạng DNG, Photo Merge và smart preview không còn ghi thẳng vào tệp cuối (issue", "Copy": "Sao chép", "Copy Edit Settings": "Sao chép cài đặt chỉnh sửa", "Copy Metadata": "Sao chép siêu dữ liệu", "Copy Name": "Tên bản sao", + "Copy as DNG": "Sao chép thành DNG", + "Copy into the library (else use the files where they are)": "Sao chép vào thư viện (không thì dùng tệp tại chỗ)", + "Copy the files (into the library's Originals/, or a folder you choose)": "Sao chép tệp (vào Originals/ của thư viện, hoặc thư mục bạn chọn)", + "Copy: the files are copied to the folder below and the library uses the copies; the originals are left as they are.": "Sao chép: tệp được sao chép vào thư mục bên dưới và thư viện dùng bản sao; bản gốc giữ nguyên.", "Copyright": "Bản quyền", "Copyright Info URL": "URL thông tin bản quyền", "Copyright Status": "Trạng thái bản quyền", @@ -125,6 +140,7 @@ "Delete": "Xóa", "Delete Album": "Xóa album", "Delete Color Label Set": "Xóa bộ nhãn màu", + "Delete Imported Profile": "Xóa hồ sơ đã nhập", "Delete Keyword": "Xóa từ khóa", "Delete Keyword Set": "Xóa bộ từ khóa", "Delete Keyword…": "Xóa từ khóa…", @@ -144,6 +160,9 @@ "Download Face Model": "Tải mô hình khuôn mặt", "Downloads": "Tải xuống", "Duplicate": "Nhân bản", + "Duplicate Component": "Nhân bản thành phần", + "Duplicate Mask": "Nhân bản mặt nạ", + "Duplicate and Invert Mask": "Nhân bản và đảo mặt nạ", "Edit": "Chỉnh sửa", "Edit Color Label Names": "Sửa tên nhãn màu", "Edit Color Label Names…": "Sửa tên nhãn màu…", @@ -182,6 +201,7 @@ "Face recognition": "Nhận diện khuôn mặt", "Faces": "Khuôn mặt", "Faces of a Person": "Khuôn mặt của một người", + "Faster exports and card imports, with the same protection for what can't be recreated (issue #134): exports,": "Xuất và nhập thẻ nhanh hơn, với cùng mức bảo vệ cho dữ liệu không thể tạo lại (issue #134): xuất,", "Favorites": "Yêu thích", "File": "Tệp", "File Extension": "Phần mở rộng tệp", @@ -189,6 +209,7 @@ "File Path": "Đường dẫn tệp", "File Type": "Loại tệp", "Filename": "Tên tệp", + "Files with the same content as another file in this import: only the first is imported.": "Tệp trùng nội dung với tệp khác trong lần nhập này: chỉ tệp đầu được nhập.", "Fill Location": "Điền vị trí", "Fill Location from GPS": "Điền vị trí từ GPS", "Filmstrip": "Dải phim", @@ -199,6 +220,7 @@ "Find Missing Photos": "Tìm ảnh bị thiếu", "Find Missing Photos…": "Tìm ảnh bị thiếu…", "Find Similar Photos": "Tìm ảnh tương tự", + "Find photos added to or missing from this folder on disk, and XMP sidecars changed by other apps": "Tìm ảnh được thêm hoặc thiếu trong thư mục trên đĩa, và sidecar XMP bị ứng dụng khác sửa", "Finding faces": "Đang tìm khuôn mặt", "Find…": "Tìm…", "Five stars": "Năm sao", @@ -230,6 +252,7 @@ "Help": "Trợ giúp", "Home": "Thư mục Nhà", "ISO Speed": "Tốc độ ISO", + "If file exists": "Nếu tệp đã tồn tại", "Image": "Ảnh", "Import": "Nhập", "Import Date": "Ngày nhập", @@ -239,13 +262,27 @@ "Import Lightroom Catalog…": "Nhập catalog Lightroom…", "Import Photos": "Nhập ảnh", "Import Photos…": "Nhập ảnh…", + "Import Point Curve Presets": "Nhập thiết lập sẵn đường cong điểm", + "Import Point Curve Presets…": "Nhập thiết lập sẵn đường cong điểm…", + "Import Presets": "Nhập thiết lập sẵn", + "Import Presets…": "Nhập thiết lập sẵn…", + "Import Profiles": "Nhập hồ sơ", "Import Profiles & Presets…": "Nhập hồ sơ và thiết lập sẵn…", + "Import as new": "Nhập như mới", + "Import from Device": "Nhập từ thiết bị", "Import from Folder…": "Nhập từ thư mục…", "Import new photos": "Nhập ảnh mới", + "Import photos with File → Import Photos… (Cmd+Shift+I), or drop them here": "Nhập ảnh bằng Tệp → Nhập ảnh… (Cmd+Shift+I), hoặc thả vào đây", + "Import presets from other editors: XMP presets, classic `.lrtemplate` files, \"DNG presets\" from mobile apps and `.zip`": "Nhập thiết lập sẵn từ trình soạn khác: preset XMP, tệp `.lrtemplate` cổ điển, \"DNG presets\" từ app di động và `.zip`", + "Import ▸ Copy verifies every copy, like Move (issue #96): each file is written as a new file, synced to disk and": "Nhập ▸ Sao chép xác minh mọi bản sao, như Di chuyển (issue #96): mỗi tệp ghi thành tệp mới, đồng bộ ra đĩa và", + "Import ▸ Move: photos go into the destination (with the same folders and renaming as Copy, e.g.": "Nhập ▸ Di chuyển: ảnh vào đích (cùng thư mục và đổi tên như Sao chép, ví dụ", + "Import: copy to any folder, by day / by month / one folder, rename on import, metadata preset, Copy as DNG.": "Nhập: sao chép vào thư mục bất kỳ, theo ngày / theo tháng / một thư mục, đổi tên khi nhập, thiết lập metadata, Sao chép dạng DNG.", "Imported": "Đã nhập", "Imported Photos": "Ảnh đã nhập", + "Importing": "Đang nhập", "Importing Lightroom Catalog": "Đang nhập catalog Lightroom", "Importing Lightroom catalog": "Đang nhập catalog Lightroom", + "Importing scans the source for photos; it doesn't add the folder to Local (use Local → Browse Folder… to work in a folder without importing).": "Nhập quét nguồn để tìm ảnh; không thêm thư mục vào Local (dùng Local → Duyệt thư mục… để làm việc trong thư mục mà không nhập).", "In Color": "Màu", "In Recently Deleted": "Trong Đã xóa gần đây", "In a Stack": "Trong chồng", @@ -306,6 +343,7 @@ "LightCraft couldn't open the library at": "LightCraft không mở được thư viện tại", "LightCraft on GitHub": "LightCraft trên GitHub", "Lightroom Classic Catalog": "Catalog Lightroom Classic", + "Lightroom import cancelled": "Đã hủy nhập Lightroom", "Lights Out": "Tắt đèn", "List Albums": "Liệt kê album", "List this folder in Local from now on": "Liệt kê thư mục này trong Cục bộ từ nay", @@ -317,6 +355,7 @@ "Location": "Vị trí", "Long Edge": "Cạnh dài", "Looking for photos…": "Đang tìm ảnh…", + "Luminar looks: `.lmp` files and `.mplumpack` collections import as presets (grouped by collection); the sliders": "Giao diện Luminar: tệp `.lmp` và bộ sưu tập `.mplumpack` nhập thành thiết lập sẵn (nhóm theo bộ sưu tập); các thanh trượt", "Make Candidate the Select": "Đặt ảnh ứng viên thành ảnh được chọn", "Manual": "Thủ công", "Megapixels": "Megapixel", @@ -339,6 +378,10 @@ "Move Folder To…": "Di chuyển thư mục tới…", "Move Selected Photos Here": "Di chuyển ảnh đã chọn vào đây", "Move Up in Stack": "Di chuyển lên trong chồng", + "Move the files (into the library's Originals/, or a folder you choose), removing them from the source": "Di chuyển tệp (vào Originals/ của thư viện hoặc thư mục bạn chọn), gỡ khỏi nguồn", + "Move: the files are moved to the folder below; each original (and its XMP sidecar) is removed from the source only after its copy is verified. Duplicates and files that fail stay where they are.": "Di chuyển: tệp chuyển vào thư mục bên dưới; mỗi bản gốc (và sidecar XMP) chỉ bị gỡ khỏi nguồn sau khi bản sao được xác minh. Trùng lặp và tệp lỗi giữ nguyên vị trí.", + "Moves every photo imported from this disk to Recently Deleted; no file is touched": "Chuyển mọi ảnh nhập từ đĩa này sang Đã xóa gần đây; không đụng tệp", + "Moves the photos imported from this folder to Recently Deleted; no file is touched": "Chuyển ảnh nhập từ thư mục này sang Đã xóa gần đây; không đụng tệp", "My Photos": "Ảnh của tôi", "My Photos Panel": "Bảng Ảnh của tôi", "Name Face": "Đặt tên khuôn mặt", @@ -356,6 +399,7 @@ "No Stars": "Không sao", "No albums match": "Không có album khớp", "No albums yet": "Chưa có album", + "No imported folders yet": "Chưa có thư mục đã nhập", "No keywords are exported": "Không xuất từ khóa nào", "No keywords match": "Không có từ khóa khớp", "No keywords yet": "Chưa có từ khóa", @@ -383,6 +427,8 @@ "Person": "Người", "Photo": "Ảnh", "Photo Grid": "Lưới ảnh", + "Photos that arrive in this folder (tethering, a scanner, a sync app) are added as soon as they're complete.": "Ảnh đến thư mục này (tethering, máy quét, app đồng bộ) được thêm ngay khi hoàn tất.", + "Photos); importing (also by drag and drop), Find Missing Photos, Build / Discard Smart Previews, the Rename preview,": "Ảnh); nhập (cả kéo thả), Tìm ảnh thiếu, Tạo / Hủy Smart Preview, xem trước Đổi tên,", "Pick": "Đã chọn", "Pick Flag": "Cờ chọn", "Pick a colour on the photo with the eyedropper.": "Chọn màu trên ảnh bằng ống nhỏ giọt.", @@ -404,6 +450,7 @@ "Raw": "Raw", "Read Metadata from File": "Đọc siêu dữ liệu từ tệp", "Read metadata updates from XMP sidecars": "Đọc cập nhật siêu dữ liệu từ sidecar XMP", + "Reading photos…": "Đang đọc ảnh…", "Recent Keywords": "Từ khóa gần đây", "Recent Keywords is built in: choose another name": "Từ khóa gần đây là bộ sẵn: hãy chọn tên khác", "Recently Deleted": "Đã xóa gần đây", @@ -437,9 +484,12 @@ "Rename Version": "Đổi tên phiên bản", "Rename…": "Đổi tên…", "Reset": "Đặt lại", + "Reset Before to Import State": "Đặt lại Before về trạng thái nhập", "Reset Panel Layout": "Đặt lại bố cục bảng", "Resize Face Box": "Đổi kích thước khung khuôn mặt", "Restore Library from Backup…": "Khôi phục thư viện từ bản sao lưu…", + "Restore keeps their edits; Import as new deletes the old record first.": "Khôi phục giữ chỉnh sửa; Nhập như mới xóa bản ghi cũ trước.", + "Review Import": "Xem lại nhập", "Sa": "T7", "Saturday": "Thứ Bảy", "Save": "Lưu", @@ -450,6 +500,7 @@ "Save Metadata Preset…": "Lưu thiết lập sẵn siêu dữ liệu…", "Save Metadata to File": "Lưu siêu dữ liệu vào tệp", "Save as Smart Album…": "Lưu thành album thông minh…", + "Saving Lightroom import index…": "Đang lưu chỉ mục nhập Lightroom…", "Search": "Tìm kiếm", "Search albums": "Tìm album", "Second Window": "Cửa sổ thứ hai", @@ -470,6 +521,7 @@ "Show Person": "Hiện người", "Show Photo Counts": "Hiện số lượng ảnh", "Show Photos with Keyword": "Hiện ảnh có từ khóa", + "Show destination gamut warning": "Hiện cảnh báo gamut đích", "Show in Finder": "Hiện trong trình quản lý tệp", "Show ratings, flags and edit badges": "Hiện xếp hạng, cờ và huy hiệu chỉnh sửa", "Show the template tags; click one to insert it": "Hiện thẻ mẫu; nhấp để chèn", @@ -504,8 +556,10 @@ "Tags": "Thẻ", "Test Face Model": "Thử mô hình khuôn mặt", "Th": "T5", + "The import reads the catalog without changing it and adds its photos, edits, keywords and collections to the library open now.": "Nhập đọc catalog không đổi nó và thêm ảnh, chỉnh sửa, từ khóa và bộ sưu tập vào thư viện đang mở.", "Theme": "Chủ đề", "This group is empty: add a rule or remove it.": "Nhóm này trống: thêm quy tắc hoặc xóa nhóm.", + "This is a Lightroom catalog, not a LightCraft library. Import it into a LightCraft library instead?": "Đây là catalog Lightroom, không phải thư viện LightCraft. Nhập vào thư viện LightCraft thay vì?", "This is the album you're editing": "Đây là album bạn đang chỉnh sửa", "Thursday": "Thứ Năm", "Title": "Tiêu đề", @@ -528,7 +582,9 @@ "View": "Xem", "Vintage": "Vintage", "Virtual Copy": "Bản sao ảo", + "Wait for the import to finish": "Đợi nhập hoàn tất", "Waiting to start…": "Đang chờ bắt đầu…", + "Watched-folder auto import; Convert to DNG; Duplicate; Build Standard / 1:1 / Smart Previews.": "Tự động nhập thư mục theo dõi; Chuyển sang DNG; Nhân bản; Tạo Standard / 1:1 / Smart Preview.", "We": "T4", "Wednesday": "Thứ Tư", "What's New": "Có gì mới", @@ -542,16 +598,25 @@ "Zoom In": "Phóng to", "Zoom Out": "Thu nhỏ", "Zoom to Fit": "Thu phóng vừa khung", + "and every imported photo as one zip, and File ▸ Restore Library from Backup… brings it back (the current library": "và mọi ảnh đã nhập thành một zip, và Tệp ▸ Khôi phục thư viện từ bản sao lưu… đưa lại (thư viện hiện tại", "are empty": "trống", "aren't empty": "không trống", + "camera no longer gets baked in. Photos already imported as \"preview only\" switch over on Reload. (Files that": "máy ảnh không còn bị nướng vào. Ảnh đã nhập \"chỉ xem trước\" chuyển sang khi Tải lại. (Tệp", "can't be tested that way": "không thể kiểm tra theo cách đó", "can't match any rating from 0 to 5": "không khớp xếp hạng nào từ 0 đến 5", "can't test a folder; choose an album in it": "không thể kiểm tra thư mục; hãy chọn album bên trong", "contains": "chứa", + "copy is verified and in the library. Duplicates and files that fail stay where they were.": "bản sao được xác minh và có trong thư viện. Trùng lặp và tệp lỗi giữ nguyên chỗ.", "copyrighted": "có bản quyền", + "data is not decoded yet, so they stay preview-only. For CR3s imported earlier, Photo ▸ Reload from Disk (now in": "dữ liệu chưa giải mã, nên vẫn chỉ xem trước. Với CR3 nhập trước đó, Ảnh ▸ Tải lại từ đĩa (giờ trong", "doesn't contain": "không chứa", "ends with": "kết thúc bằng", + "export. The catalog, XMP sidecars, settings, DNGs, merges, smart previews and the copies an import makes are still": "xuất. Catalog, sidecar XMP, cài đặt, DNG, merge, smart preview và bản sao khi nhập vẫn", "has the first date after the second": "ngày đầu sau ngày thứ hai", + "how to restore it or delete it permanently and import it afresh. (For a fresh start on a photo, Reset Edits,": "cách khôi phục hoặc xóa vĩnh viễn và nhập lại. (Để bắt đầu lại trên ảnh, Đặt lại chỉnh sửa,", + "import — so \"import complete\" means the copies are good before you format the card — and a name that is taken": "nhập — nên \"nhập xong\" nghĩa là bản sao ổn trước khi format thẻ — và tên đã được dùng", + "imported as \"preview only\" switch over on Reload.": "đã nhập \"chỉ xem trước\" chuyển sang khi Tải lại.", + "imported earlier switch over with Photo ▸ Reload from Disk.": "nhập trước đó chuyển sang với Ảnh ▸ Tải lại từ đĩa.", "is": "là", "is <": "<", "is >": ">", @@ -569,6 +634,7 @@ "isn't empty": "không trống", "isn't in the last": "không trong vòng", "isn't one of the choices": "không phải một trong các lựa chọn", + "longer just says \"duplicate skipped\": it opens the side panel on Recently Deleted with the photo selected and says": "không chỉ nói \"bỏ qua trùng\": mở bảng bên ở Đã xóa gần đây với ảnh được chọn và nói", "names an album that no longer exists": "chỉ album không còn tồn tại", "needs a date like 2026, 2026-08 or 2026-08-14": "cần ngày như 2026, 2026-08 hoặc 2026-08-14", "needs a number": "cần một số", @@ -582,13 +648,19 @@ "needs something to look for (or use “isn't empty”)": "cần nội dung để tìm (hoặc dùng “không trống”)", "needs text": "cần văn bản", "needs two values": "cần hai giá trị", + "never leaves a truncated file; the XMP sidecar of an \"Original\" export follows the \"If file exists\" choice too.": "không bao giờ để tệp cắt cụt; sidecar XMP của xuất \"Original\" cũng theo lựa chọn \"Nếu tệp đã tồn tại\".", + "on the card after Review Import is reported instead of being imported with stale details. Checking an export path": "trên thẻ sau Xem lại nhập được báo thay vì nhập với chi tiết cũ. Kiểm tra đường dẫn xuất", "pick": "đã chọn", "reject": "đã loại", "smart album value|No": "Không", "smart album value|Yes": "Có", "starts using it for AI Denoise": "bắt đầu dùng nó cho Khử nhiễu AI", "starts with": "bắt đầu bằng", + "synced. Import ▸ Copy now checks each copy against the content hash taken while scanning the card instead of": "đồng bộ. Nhập ▸ Sao chép giờ kiểm tra mỗi bản sao với hash nội dung lấy khi quét thẻ thay vì", + "the Local folder tree and Auto Import read the disk on worker threads too. The import progress window has Cancel.": "cây thư mục Local và Tự động nhập cũng đọc đĩa trên worker thread. Cửa sổ tiến trình nhập có Hủy.", + "the camera; mapped-out sensor defects are filled in. `.rwl` and `.raw` files are imported too. Photos already": "máy ảnh; điểm lỗi cảm biến được lấp. Tệp `.rwl` và `.raw` cũng được nhập. Ảnh đã", "would make this album include itself through other smart albums": "sẽ khiến album này bao gồm chính nó qua album thông minh khác", + "{date} is the capture time; a photo without one uses the time it was imported.": "{date} là thời gian chụp; ảnh không có thì dùng thời gian nhập.", "日本語": "日本語", "繁體中文(台灣)": "繁體中文(台灣)" } From 67722fb6374d5c1e2201f0345cc10c1bb850b329 Mon Sep 17 00:00:00 2001 From: "DUY Tran Nhat (SAE-KIDS)" Date: Tue, 13 Oct 2026 15:54:00 +0700 Subject: [PATCH 011/350] i18n(vi): translate light and color controls --- crates/ui-egui/locales/vi.json | 108 +++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/crates/ui-egui/locales/vi.json b/crates/ui-egui/locales/vi.json index 574964369..a707d86a7 100644 --- a/crates/ui-egui/locales/vi.json +++ b/crates/ui-egui/locales/vi.json @@ -4,6 +4,7 @@ ", rejected": ", đã loại", "0: nothing is rejected.": "0: không loại gì.", "1620 × 1080 preview, and import with their metadata: capture time, camera, lens, exposure, GPS and XMP. Their raw": "xem trước 1620 × 1080 và nhập kèm metadata: thời gian chụp, máy ảnh, ống kính, phơi sáng, GPS và XMP. Raw của chúng", + "A blank template keeps the original names.": "Mẫu trống giữ tên gốc.", "A folder is already being synchronized": "Một thư mục đang được đồng bộ", "A folder is being synchronized": "Một thư mục đang được đồng bộ", "A keyword set needs a name": "Bộ từ khóa cần một tên", @@ -12,6 +13,7 @@ "About LightCraft": "Giới thiệu LightCraft", "Add Face Model…": "Thêm mô hình khuôn mặt…", "Add Folder to Local": "Thêm thư mục vào Cục bộ", + "Add Point Color Sample": "Thêm mẫu Point Color", "Add Selected Photos": "Thêm ảnh đã chọn", "Add in place": "Thêm tại chỗ", "Add in place: the library references the files where they are; nothing is copied or moved.": "Thêm tại chỗ: thư viện tham chiếu tệp ở vị trí hiện tại; không sao chép hay di chuyển gì.", @@ -46,28 +48,47 @@ "Apply": "Áp dụng", "Apply Color Label Set": "Áp dụng bộ nhãn màu", "Apply Metadata Preset": "Áp dụng thiết lập sẵn siêu dữ liệu", + "Aqua Hue": "Hue ngọc lam", + "Aqua Luminance": "Độ sáng ngọc lam", + "Aqua Saturation": "Độ bão hòa ngọc lam", "ArtCraft Website": "Trang web ArtCraft", + "As Shot": "Như khi chụp", + "As shot": "Như khi chụp", "Aspect Ratio": "Tỷ lệ khung hình", "Assisted Culling": "Sàng lọc hỗ trợ", "Auto": "Tự động", "Auto Advance after rating or flagging": "Tự chuyển tiếp sau khi xếp hạng hoặc gắn cờ", "Auto Advance: move to the next photo after rating or flagging": "Tự chuyển tiếp: sang ảnh tiếp theo sau khi xếp hạng hoặc gắn cờ", + "Auto B&W Mix": "Tự trộn B&W", "Auto Import": "Tự nhập", "Auto Import Now": "Tự nhập ngay", "Auto Import Settings": "Cài đặt tự nhập", + "Auto Sync: edits apply to every selected photo. Auto B&W mix. Automatic versions.": "Auto Sync: chỉnh sửa áp dụng cho mọi ảnh đã chọn. Auto B&W mix. Phiên bản tự động.", "Auto-Stack by Capture Time": "Tự xếp chồng theo thời gian chụp", "Auto-Stack by Capture Time…": "Tự xếp chồng theo thời gian chụp…", "Auto-Tag Photos from Tracklog": "Tự gắn thẻ ảnh từ nhật ký hành trình", "Auto-Tag from Tracklog": "Tự gắn thẻ từ nhật ký hành trình", "Auto-Tag from Tracklog…": "Tự gắn thẻ từ nhật ký hành trình…", + "B&W Mix": "Trộn B&W", + "B&W Mixer": "Bộ trộn B&W", "Back": "Quay lại", "Back Up Library…": "Sao lưu thư viện…", "Back to Grid": "Quay lại lưới", "Back to this person": "Quay lại người này", + "Balance": "Cân bằng", "Best of Similar Shots": "Ảnh đẹp nhất trong nhóm tương tự", "Black & White": "Đen trắng", + "Blacks": "Vùng đen", + "Blending": "Hòa trộn", "Blue": "Lam", + "Blue Hour Boost": "Tăng giờ xanh", + "Blue Hue": "Hue xanh lam", + "Blue Luminance": "Độ sáng xanh lam", + "Blue Primary": "Xanh lam chính", + "Blue Saturation": "Độ bão hòa xanh lam", + "Blue channel": "Kênh xanh lam", "Blue label": "Nhãn lam", + "Blue/Yellow Fringe": "Viền xanh lam/vàng", "Browse Folder": "Duyệt thư mục", "Browse Folder…": "Duyệt thư mục…", "Camera": "Máy ảnh", @@ -94,15 +115,19 @@ "Clear rating and advance": "Xóa xếp hạng và chuyển tiếp", "Click to restore · double-click to rename": "Nhấp để khôi phục · nhấp đúp để đổi tên", "Close": "Đóng", + "Cloudy": "Nhiều mây", "Collapse All Stacks": "Thu gọn mọi chồng", "Collapse Stack": "Thu gọn chồng", + "Color Grading": "Phân cấp màu", "Color Label": "Nhãn màu", "Color Label Names": "Tên nhãn màu", "Color Label Sets": "Bộ nhãn màu", + "Color Mixer": "Bộ trộn màu", "Color label cleared": "Đã xóa nhãn màu", "Compare": "So sánh", "Compare needs at least two photos": "So sánh cần ít nhất hai ảnh", "Confirm before moving photos to Recently Deleted": "Xác nhận trước khi chuyển ảnh vào Đã xóa gần đây", + "Contrast": "Tương phản", "Convert to DNG": "Chuyển sang DNG", "Convert to DNG, Copy as DNG, Photo Merge and smart previews no longer write straight to the final file (issue": "Chuyển sang DNG, Sao chép dạng DNG, Photo Merge và smart preview không còn ghi thẳng vào tệp cuối (issue", "Copy": "Sao chép", @@ -131,11 +156,13 @@ "Creator": "Người tạo", "Creator metadata": "Siêu dữ liệu người tạo", "Cropped": "Đã cắt", + "Custom template…": "Mẫu tùy chỉnh…", "Cut": "Cắt", "Cycle Info Overlay": "Chuyển lớp phủ thông tin", "Dark Theme": "Chủ đề tối", "Date": "Ngày", "Day": "Ngày", + "Daylight": "Ánh sáng ban ngày", "Decrease Rating": "Giảm xếp hạng", "Delete": "Xóa", "Delete Album": "Xóa album", @@ -147,6 +174,8 @@ "Delete Metadata Preset": "Xóa thiết lập sẵn siêu dữ liệu", "Delete Photo": "Xóa ảnh", "Delete Photos": "Xóa ảnh", + "Delete Point Color": "Xóa Point Color", + "Delete Point Color Sample": "Xóa mẫu Point Color", "Denoise Photos": "Khử nhiễu ảnh", "Denoise all photos with an Amount": "Khử nhiễu mọi ảnh có Độ mạnh", "Description": "Mô tả", @@ -192,6 +221,8 @@ "Export Synonyms": "Xuất từ đồng nghĩa", "Export with Previous": "Xuất với lần trước", "Export…": "Xuất…", + "Exposure": "Phơi sáng", + "Exposure (shutter · aperture · ISO)": "Phơi sáng (cửa trập · khẩu độ · ISO)", "Face Boxes": "Khung khuôn mặt", "Face Model Downloads": "Tải mô hình khuôn mặt", "Face Models": "Mô hình khuôn mặt", @@ -230,6 +261,8 @@ "Flag as Reject": "Gắn cờ Đã loại", "Flagged as Pick": "Đã gắn cờ Đã chọn", "Flagged as Reject": "Đã gắn cờ Đã loại", + "Flash": "Đèn flash", + "Fluorescent": "Huỳnh quang", "Focal Length": "Tiêu cự", "Focus (assisted culling)": "Lấy nét (sàng lọc hỗ trợ)", "Folder": "Thư mục", @@ -242,7 +275,18 @@ "Full Screen Preview": "Xem trước toàn màn hình", "General": "Chung", "Generated demo photo": "Ảnh demo được tạo", + "Global Hue": "Sắc độ toàn cục", + "Global Luminance": "Độ sáng toàn cục", + "Global Saturation": "Độ bão hòa toàn cục", "Green": "Lục", + "Green Amount": "Lượng xanh lá", + "Green Hue": "Sắc xanh lá", + "Green Hue High": "Sắc xanh lá cao", + "Green Hue Low": "Sắc xanh lá thấp", + "Green Luminance": "Độ sáng xanh lá", + "Green Primary": "Màu gốc xanh lá", + "Green Saturation": "Độ bão hòa xanh lá", + "Green channel": "Kênh xanh lá", "Green label": "Nhãn lục", "Grid": "Lưới", "Grid Info": "Thông tin lưới", @@ -250,7 +294,16 @@ "Has Edits": "Có chỉnh sửa", "Has GPS": "Có GPS", "Help": "Trợ giúp", + "High Contrast B&W": "B&W tương phản cao", + "Highlight": "Vùng sáng", + "Highlights": "Vùng sáng", + "Highlights Hue": "Sắc vùng sáng", + "Highlights Luminance": "Độ sáng vùng sáng", + "Highlights Saturation": "Độ bão hòa vùng sáng", + "Highlights split": "Tách vùng sáng", "Home": "Thư mục Nhà", + "Hue": "Sắc độ", + "Hue Range": "Dải sắc độ", "ISO Speed": "Tốc độ ISO", "If file exists": "Nếu tệp đã tồn tại", "Image": "Ảnh", @@ -294,6 +347,7 @@ "Index Faces": "Lập chỉ mục khuôn mặt", "Index Faces in the Background": "Lập chỉ mục khuôn mặt nền", "Info": "Thông tin", + "Info Overlay: Exposure": "Lớp phủ thông tin: Phơi sáng", "Inspect Face Model File": "Kiểm tra tệp mô hình khuôn mặt", "Inspect Lightroom Catalog": "Kiểm tra catalog Lightroom", "Inspect Photo": "Kiểm tra ảnh", @@ -355,9 +409,17 @@ "Location": "Vị trí", "Long Edge": "Cạnh dài", "Looking for photos…": "Đang tìm ảnh…", + "Luminance": "Độ sáng", + "Luminance Range": "Dải độ sáng", "Luminar looks: `.lmp` files and `.mplumpack` collections import as presets (grouped by collection); the sliders": "Giao diện Luminar: tệp `.lmp` và bộ sưu tập `.mplumpack` nhập thành thiết lập sẵn (nhóm theo bộ sưu tập); các thanh trượt", + "Magenta": "Đỏ tím", + "Magenta Hue": "Sắc đỏ tím", + "Magenta Luminance": "Độ sáng đỏ tím", + "Magenta Saturation": "Độ bão hòa đỏ tím", "Make Candidate the Select": "Đặt ảnh ứng viên thành ảnh được chọn", "Manual": "Thủ công", + "Match Total Exposures": "Khớp tổng phơi sáng", + "Medium Contrast": "Tương phản trung bình", "Megapixels": "Megapixel", "Menu": "Trình đơn", "Merge Keywords": "Gộp từ khóa", @@ -366,6 +428,11 @@ "Metadata Presets": "Thiết lập sẵn siêu dữ liệu", "Metadata preset": "Thiết lập sẵn siêu dữ liệu", "Metadata read": "Đã đọc siêu dữ liệu", + "Midtones": "Vùng trung tính", + "Midtones Hue": "Sắc vùng trung tính", + "Midtones Luminance": "Độ sáng vùng trung tính", + "Midtones Saturation": "Độ bão hòa vùng trung tính", + "Midtones split": "Tách vùng trung tính", "Minimize": "Thu nhỏ", "Missing Photos": "Ảnh bị thiếu", "Mo": "T2", @@ -399,6 +466,7 @@ "No Stars": "Không sao", "No albums match": "Không có album khớp", "No albums yet": "Chưa có album", + "No exposure information": "Không có thông tin phơi sáng", "No imported folders yet": "Chưa có thư mục đã nhập", "No keywords are exported": "Không xuất từ khóa nào", "No keywords match": "Không có từ khóa khớp", @@ -415,6 +483,9 @@ "Open Library…": "Mở thư viện…", "Open Log Folder": "Mở thư mục nhật ký", "Open…": "Mở…", + "Orange Hue": "Sắc cam", + "Orange Luminance": "Độ sáng cam", + "Orange Saturation": "Độ bão hòa cam", "Panels": "Các bảng", "Paste": "Dán", "Paste Edit Settings": "Dán cài đặt chỉnh sửa", @@ -435,12 +506,19 @@ "Pick a date": "Chọn ngày", "Picked": "Đã chọn", "Picks": "Ảnh đã chọn", + "Point Color": "Màu điểm", "Portrait (tall)": "Dọc (cao)", "Preferences": "Tùy chọn", "Preferences…": "Tùy chọn…", "Public Domain": "Phạm vi công cộng", "Purge Unused Keywords": "Dọn từ khóa không dùng", "Purple": "Tím", + "Purple Amount": "Lượng tím", + "Purple Hue": "Sắc tím", + "Purple Hue High": "Sắc tím cao", + "Purple Hue Low": "Sắc tím thấp", + "Purple Luminance": "Độ sáng tím", + "Purple Saturation": "Độ bão hòa tím", "Put New Keywords Inside This Keyword": "Đặt từ khóa mới vào trong từ khóa này", "Quit": "Thoát", "Quit LightCraft": "Thoát LightCraft", @@ -456,9 +534,14 @@ "Recently Deleted": "Đã xóa gần đây", "Recognise faces (experimental)": "Nhận diện khuôn mặt (thử nghiệm)", "Red": "Đỏ", + "Red Hue": "Sắc đỏ", + "Red Luminance": "Độ sáng đỏ", + "Red Primary": "Màu gốc đỏ", + "Red Saturation": "Độ bão hòa đỏ", "Red label": "Nhãn đỏ", "Redo": "Làm lại", "Reference View": "Xem tham chiếu", + "Refine Saturation": "Tinh chỉnh độ bão hòa", "Reject": "Đã loại", "Reject below focus": "Loại ảnh dưới ngưỡng lấy nét", "Rejected": "Đã loại", @@ -491,6 +574,8 @@ "Restore keeps their edits; Import as new deletes the old record first.": "Khôi phục giữ chỉnh sửa; Nhập như mới xóa bản ghi cũ trước.", "Review Import": "Xem lại nhập", "Sa": "T7", + "Saturation": "Độ bão hòa", + "Saturation Range": "Dải độ bão hòa", "Saturday": "Thứ Bảy", "Save": "Lưu", "Save Color Label Set": "Lưu bộ nhãn màu", @@ -505,6 +590,7 @@ "Search albums": "Tìm album", "Second Window": "Cửa sổ thứ hai", "Select All": "Chọn tất cả", + "Select Luminance Range": "Chọn dải độ sáng", "Select by Flag, Rating or Label": "Chọn theo cờ, xếp hạng hoặc nhãn", "Select photos to give them keywords.": "Chọn ảnh để gán từ khóa.", "Selected": "Đã chọn", @@ -514,9 +600,17 @@ "Set Flag": "Đặt cờ", "Set Rating": "Đặt xếp hạng", "Settings": "Cài đặt", + "Shadow": "Vùng tối", + "Shadows": "Vùng tối", + "Shadows Hue": "Sắc vùng tối", + "Shadows Luminance": "Độ sáng vùng tối", + "Shadows Saturation": "Độ bão hòa vùng tối", + "Shadows Tint": "Tông vùng tối", + "Shadows split": "Tách vùng tối", "Short Edge": "Cạnh ngắn", "Show": "Hiện", "Show Clipping": "Hiện vùng cắt tông", + "Show Luminance Map": "Hiện bản đồ độ sáng", "Show Original": "Hiện bản gốc", "Show Person": "Hiện người", "Show Photo Counts": "Hiện số lượng ảnh", @@ -543,6 +637,7 @@ "Starting…": "Đang bắt đầu…", "Startup": "Khởi động", "State / Province": "Bang / Tỉnh", + "Strong Contrast": "Tương phản mạnh", "Su": "CN", "Suggest Names for Faces": "Gợi ý tên cho khuôn mặt", "Sunday": "Chủ Nhật", @@ -554,6 +649,10 @@ "Synonyms": "Từ đồng nghĩa", "System Info…": "Thông tin hệ thống…", "Tags": "Thẻ", + "Temp": "Nhiệt", + "Temperature": "Nhiệt độ", + "Template": "Mẫu", + "Temporary session — your library isn't open, and nothing you do here is saved.": "Phiên tạm — thư viện chưa mở và không lưu gì bạn làm ở đây.", "Test Face Model": "Thử mô hình khuôn mặt", "Th": "T5", "The import reads the catalog without changing it and adds its photos, edits, keywords and collections to the library open now.": "Nhập đọc catalog không đổi nó và thêm ảnh, chỉnh sửa, từ khóa và bộ sưu tập vào thư viện đang mở.", @@ -562,6 +661,7 @@ "This is a Lightroom catalog, not a LightCraft library. Import it into a LightCraft library instead?": "Đây là catalog Lightroom, không phải thư viện LightCraft. Nhập vào thư viện LightCraft thay vì?", "This is the album you're editing": "Đây là album bạn đang chỉnh sửa", "Thursday": "Thứ Năm", + "Tint": "Tông", "Title": "Tiêu đề", "Title metadata": "Siêu dữ liệu tiêu đề", "Toggle Keyword from Set": "Bật/tắt từ khóa từ bộ", @@ -577,6 +677,7 @@ "Unknown": "Không rõ", "Unnamed Faces": "Khuôn mặt chưa đặt tên", "Use Keyword Set": "Dùng bộ từ khóa", + "Vibrance": "Độ rực rỡ", "Video": "Video", "Video Duration": "Thời lượng video", "View": "Xem", @@ -588,10 +689,17 @@ "We": "T4", "Wednesday": "Thứ Tư", "What's New": "Có gì mới", + "White Balance": "Cân bằng trắng", + "White Balance Selector": "Bộ chọn cân bằng trắng", + "White Balance Selector (W)": "Bộ chọn cân bằng trắng (W)", + "Whites": "Vùng trắng", "Window": "Cửa sổ", "XMP Sidecar Preferences": "Tùy chọn tệp sidecar XMP", "Year": "Năm", "Yellow": "Vàng", + "Yellow Hue": "Sắc vàng", + "Yellow Luminance": "Độ sáng vàng", + "Yellow Saturation": "Độ bão hòa vàng", "Yellow label": "Nhãn vàng", "Yes": "Có", "Zoom 100%": "Thu phóng 100%", From 462c47dc739e5c71c4f12bd8b827063ae17e859d Mon Sep 17 00:00:00 2001 From: "DUY Tran Nhat (SAE-KIDS)" Date: Tue, 13 Oct 2026 15:54:00 +0700 Subject: [PATCH 012/350] i18n(vi): translate effects and tone controls --- crates/ui-egui/locales/vi.json | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/crates/ui-egui/locales/vi.json b/crates/ui-egui/locales/vi.json index a707d86a7..52991210a 100644 --- a/crates/ui-egui/locales/vi.json +++ b/crates/ui-egui/locales/vi.json @@ -48,6 +48,7 @@ "Apply": "Áp dụng", "Apply Color Label Set": "Áp dụng bộ nhãn màu", "Apply Metadata Preset": "Áp dụng thiết lập sẵn siêu dữ liệu", + "Apply Point Curve Preset": "Áp dụng thiết lập sẵn đường cong điểm", "Aqua Hue": "Hue ngọc lam", "Aqua Luminance": "Độ sáng ngọc lam", "Aqua Saturation": "Độ bão hòa ngọc lam", @@ -109,6 +110,7 @@ "Choose a photo in the grid or filmstrip": "Chọn một ảnh trên lưới hoặc dải phim", "Choose an album…": "Chọn một album…", "City": "Thành phố", + "Clarity": "Độ rõ", "Clear": "Xóa", "Clear Quick Collection": "Xóa Bộ sưu tập nhanh", "Clear rating": "Xóa xếp hạng", @@ -156,14 +158,18 @@ "Creator": "Người tạo", "Creator metadata": "Siêu dữ liệu người tạo", "Cropped": "Đã cắt", + "Curve": "Đường cong", "Custom template…": "Mẫu tùy chỉnh…", "Cut": "Cắt", "Cycle Info Overlay": "Chuyển lớp phủ thông tin", "Dark Theme": "Chủ đề tối", + "Darks": "Vùng tối vừa", "Date": "Ngày", "Day": "Ngày", "Daylight": "Ánh sáng ban ngày", + "Decrease Brush Feather": "Giảm lông cọ", "Decrease Rating": "Giảm xếp hạng", + "Dehaze": "Khử sương mù", "Delete": "Xóa", "Delete Album": "Xóa album", "Delete Color Label Set": "Xóa bộ nhãn màu", @@ -176,6 +182,7 @@ "Delete Photos": "Xóa ảnh", "Delete Point Color": "Xóa Point Color", "Delete Point Color Sample": "Xóa mẫu Point Color", + "Delete Point Curve Preset": "Xóa thiết lập sẵn đường cong điểm", "Denoise Photos": "Khử nhiễu ảnh", "Denoise all photos with an Amount": "Khử nhiễu mọi ảnh có Độ mạnh", "Description": "Mô tả", @@ -217,6 +224,8 @@ "Export Containing Keywords": "Xuất từ khóa chứa", "Export Keywords": "Xuất từ khóa", "Export Keywords…": "Xuất từ khóa…", + "Export Point Curve Presets": "Xuất thiết lập sẵn đường cong điểm", + "Export Point Curve Presets…": "Xuất thiết lập sẵn đường cong điểm…", "Export Presets…": "Xuất thiết lập sẵn…", "Export Synonyms": "Xuất từ đồng nghĩa", "Export with Previous": "Xuất với lần trước", @@ -234,6 +243,7 @@ "Faces of a Person": "Khuôn mặt của một người", "Faster exports and card imports, with the same protection for what can't be recreated (issue #134): exports,": "Xuất và nhập thẻ nhanh hơn, với cùng mức bảo vệ cho dữ liệu không thể tạo lại (issue #134): xuất,", "Favorites": "Yêu thích", + "Feather": "Lông", "File": "Tệp", "File Extension": "Phần mở rộng tệp", "File Format": "Định dạng tệp", @@ -278,6 +288,7 @@ "Global Hue": "Sắc độ toàn cục", "Global Luminance": "Độ sáng toàn cục", "Global Saturation": "Độ bão hòa toàn cục", + "Grain": "Hạt", "Green": "Lục", "Green Amount": "Lượng xanh lá", "Green Hue": "Sắc xanh lá", @@ -343,6 +354,7 @@ "In-memory session: these settings last until LightCraft quits.": "Phiên trong bộ nhớ: các cài đặt này chỉ tồn tại đến khi LightCraft thoát.", "Include selected photos": "Bao gồm ảnh đã chọn", "Include subfolders": "Bao gồm thư mục con", + "Increase Brush Feather": "Tăng độ mềm cọ", "Increase Rating": "Tăng xếp hạng", "Index Faces": "Lập chỉ mục khuôn mặt", "Index Faces in the Background": "Lập chỉ mục khuôn mặt nền", @@ -398,6 +410,7 @@ "LightCraft on GitHub": "LightCraft trên GitHub", "Lightroom Classic Catalog": "Catalog Lightroom Classic", "Lightroom import cancelled": "Đã hủy nhập Lightroom", + "Lights": "Đèn", "Lights Out": "Tắt đèn", "List Albums": "Liệt kê album", "List this folder in Local from now on": "Liệt kê thư mục này trong Cục bộ từ nay", @@ -428,6 +441,7 @@ "Metadata Presets": "Thiết lập sẵn siêu dữ liệu", "Metadata preset": "Thiết lập sẵn siêu dữ liệu", "Metadata read": "Đã đọc siêu dữ liệu", + "Midpoint": "Điểm giữa", "Midtones": "Vùng trung tính", "Midtones Hue": "Sắc vùng trung tính", "Midtones Luminance": "Độ sáng vùng trung tính", @@ -487,6 +501,7 @@ "Orange Luminance": "Độ sáng cam", "Orange Saturation": "Độ bão hòa cam", "Panels": "Các bảng", + "Parametric curve": "Đường cong tham số", "Paste": "Dán", "Paste Edit Settings": "Dán cài đặt chỉnh sửa", "Paste Metadata": "Dán siêu dữ liệu", @@ -507,6 +522,9 @@ "Picked": "Đã chọn", "Picks": "Ảnh đã chọn", "Point Color": "Màu điểm", + "Point Curve": "Đường cong điểm", + "Point Curve Presets": "Thiết lập sẵn đường cong điểm", + "Point curve": "Đường cong điểm", "Portrait (tall)": "Dọc (cao)", "Preferences": "Tùy chọn", "Preferences…": "Tùy chọn…", @@ -567,12 +585,17 @@ "Rename Version": "Đổi tên phiên bản", "Rename…": "Đổi tên…", "Reset": "Đặt lại", + "Reset All Curves": "Đặt lại tất cả đường cong", "Reset Before to Import State": "Đặt lại Before về trạng thái nhập", "Reset Panel Layout": "Đặt lại bố cục bảng", + "Reset Parametric Curve": "Đặt lại đường cong tham số", + "Reset Tone Curve": "Đặt lại đường cong tông màu", "Resize Face Box": "Đổi kích thước khung khuôn mặt", "Restore Library from Backup…": "Khôi phục thư viện từ bản sao lưu…", "Restore keeps their edits; Import as new deletes the old record first.": "Khôi phục giữ chỉnh sửa; Nhập như mới xóa bản ghi cũ trước.", "Review Import": "Xem lại nhập", + "Roughness": "Độ thô", + "Roundness": "Độ tròn", "Sa": "T7", "Saturation": "Độ bão hòa", "Saturation Range": "Dải độ bão hòa", @@ -584,6 +607,8 @@ "Save Metadata Preset": "Lưu thiết lập sẵn siêu dữ liệu", "Save Metadata Preset…": "Lưu thiết lập sẵn siêu dữ liệu…", "Save Metadata to File": "Lưu siêu dữ liệu vào tệp", + "Save Point Curve Preset": "Lưu thiết lập sẵn đường cong điểm", + "Save Point Curve…": "Lưu đường cong điểm…", "Save as Smart Album…": "Lưu thành album thông minh…", "Saving Lightroom import index…": "Đang lưu chỉ mục nhập Lightroom…", "Search": "Tìm kiếm", @@ -598,6 +623,7 @@ "Sequence number, counting from the start number": "Số thứ tự, đếm từ số bắt đầu", "Set Color Label": "Đặt nhãn màu", "Set Flag": "Đặt cờ", + "Set Point Curve": "Đặt đường cong điểm", "Set Rating": "Đặt xếp hạng", "Settings": "Cài đặt", "Shadow": "Vùng tối", @@ -649,11 +675,13 @@ "Synonyms": "Từ đồng nghĩa", "System Info…": "Thông tin hệ thống…", "Tags": "Thẻ", + "Targeted adjustment: drag up/down on the photo to adjust the curve there": "Chỉnh có mục tiêu: kéo lên/xuống trên ảnh để chỉnh đường cong tại đó", "Temp": "Nhiệt", "Temperature": "Nhiệt độ", "Template": "Mẫu", "Temporary session — your library isn't open, and nothing you do here is saved.": "Phiên tạm — thư viện chưa mở và không lưu gì bạn làm ở đây.", "Test Face Model": "Thử mô hình khuôn mặt", + "Texture": "Kết cấu", "Th": "T5", "The import reads the catalog without changing it and adds its photos, edits, keywords and collections to the library open now.": "Nhập đọc catalog không đổi nó và thêm ảnh, chỉnh sửa, từ khóa và bộ sưu tập vào thư viện đang mở.", "Theme": "Chủ đề", @@ -666,6 +694,7 @@ "Title metadata": "Siêu dữ liệu tiêu đề", "Toggle Keyword from Set": "Bật/tắt từ khóa từ bộ", "Toggle Zoom": "Bật/tắt thu phóng", + "Tone Curve": "Đường cong tông màu", "Tools": "Công cụ", "Treatment": "Xử lý màu", "Tu": "T3", @@ -681,6 +710,7 @@ "Video": "Video", "Video Duration": "Thời lượng video", "View": "Xem", + "Vignette": "Tối góc", "Vintage": "Vintage", "Virtual Copy": "Bản sao ảo", "Wait for the import to finish": "Đợi nhập hoàn tất", From dfa63f2b4dc4b33fbfd48ccef7ee4b22ca9c5fd7 Mon Sep 17 00:00:00 2001 From: "DUY Tran Nhat (SAE-KIDS)" Date: Tue, 13 Oct 2026 15:54:00 +0700 Subject: [PATCH 013/350] i18n(vi): translate crop geometry and detail controls --- crates/ui-egui/locales/vi.json | 102 +++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/crates/ui-egui/locales/vi.json b/crates/ui-egui/locales/vi.json index 52991210a..402f4f6ca 100644 --- a/crates/ui-egui/locales/vi.json +++ b/crates/ui-egui/locales/vi.json @@ -9,11 +9,17 @@ "A folder is being synchronized": "Một thư mục đang được đồng bộ", "A keyword set needs a name": "Bộ từ khóa cần một tên", "AI Denoise": "Khử nhiễu AI", + "AI Denoise Model": "Mô hình khử nhiễu AI", + "AI Denoise is enabled on the requesting photo": "Khử nhiễu AI đã bật trên ảnh yêu cầu", + "AI Denoise is off: press Use on a model.": "Khử nhiễu AI đang tắt: nhấn Dùng trên một mô hình.", + "AI Denoise needs a model. Install one in Settings.": "Khử nhiễu AI cần một mô hình. Hãy cài trong Cài đặt.", "About": "Giới thiệu", "About LightCraft": "Giới thiệu LightCraft", + "Add Catchlight": "Thêm điểm sáng mắt", "Add Face Model…": "Thêm mô hình khuôn mặt…", "Add Folder to Local": "Thêm thư mục vào Cục bộ", "Add Point Color Sample": "Thêm mẫu Point Color", + "Add Red Eye Correction": "Thêm sửa mắt đỏ", "Add Selected Photos": "Thêm ảnh đã chọn", "Add in place": "Thêm tại chỗ", "Add in place: the library references the files where they are; nothing is copied or moved.": "Thêm tại chỗ: thư viện tham chiếu tệp ở vị trí hiện tại; không sao chép hay di chuyển gì.", @@ -30,6 +36,7 @@ "Adding photos…": "Đang thêm ảnh…", "Adding to Apple Photos": "Đang thêm vào Ảnh Apple", "Adding to Apple Photos…": "Đang thêm vào Ảnh Apple…", + "After installation, AI Denoise will turn on for the requesting photo.": "Sau khi cài, Khử nhiễu AI sẽ bật cho ảnh yêu cầu.", "Album": "Album", "Albums": "Album", "Albums hold library photos: Add to My Photos first": "Album chứa ảnh thư viện: hãy Thêm vào Ảnh của tôi trước", @@ -55,15 +62,18 @@ "ArtCraft Website": "Trang web ArtCraft", "As Shot": "Như khi chụp", "As shot": "Như khi chụp", + "Aspect": "Tỷ lệ", "Aspect Ratio": "Tỷ lệ khung hình", "Assisted Culling": "Sàng lọc hỗ trợ", "Auto": "Tự động", "Auto Advance after rating or flagging": "Tự chuyển tiếp sau khi xếp hạng hoặc gắn cờ", "Auto Advance: move to the next photo after rating or flagging": "Tự chuyển tiếp: sang ảnh tiếp theo sau khi xếp hạng hoặc gắn cờ", "Auto B&W Mix": "Tự trộn B&W", + "Auto Crop": "Tự cắt", "Auto Import": "Tự nhập", "Auto Import Now": "Tự nhập ngay", "Auto Import Settings": "Cài đặt tự nhập", + "Auto Straighten": "Tự chỉnh thẳng", "Auto Sync: edits apply to every selected photo. Auto B&W mix. Automatic versions.": "Auto Sync: chỉnh sửa áp dụng cho mọi ảnh đã chọn. Auto B&W mix. Phiên bản tự động.", "Auto-Stack by Capture Time": "Tự xếp chồng theo thời gian chụp", "Auto-Stack by Capture Time…": "Tự xếp chồng theo thời gian chụp…", @@ -90,19 +100,24 @@ "Blue channel": "Kênh xanh lam", "Blue label": "Nhãn lam", "Blue/Yellow Fringe": "Viền xanh lam/vàng", + "Boundary Warp": "Biến dạng biên", "Browse Folder": "Duyệt thư mục", "Browse Folder…": "Duyệt thư mục…", "Camera": "Máy ảnh", "Camera Info": "Thông tin máy ảnh", "Cameras and Cards": "Máy ảnh và thẻ nhớ", "Cancel": "Hủy", + "Cancel Denoise": "Hủy khử nhiễu", + "Cancel Denoise Model Download": "Hủy tải mô hình khử nhiễu", "Cancel Face Model Download": "Hủy tải mô hình khuôn mặt", "Cancel Pending Photo Action": "Hủy thao tác ảnh đang chờ", "Caption": "Chú thích", "Capture Date": "Ngày chụp", "Captured": "Đã chụp", "Catalog Statistics": "Thống kê catalog", + "Catchlight": "Điểm sáng mắt", "Choose Another Library…": "Chọn thư viện khác…", + "Choose Denoise Model": "Chọn mô hình khử nhiễu", "Choose Edit Settings to Copy…": "Chọn cài đặt chỉnh sửa để sao chép…", "Choose Face Recognition Model": "Chọn mô hình nhận diện khuôn mặt", "Choose Folder…": "Chọn thư mục…", @@ -112,6 +127,7 @@ "City": "Thành phố", "Clarity": "Độ rõ", "Clear": "Xóa", + "Clear Denoise Cache": "Xóa bộ nhớ đệm khử nhiễu", "Clear Quick Collection": "Xóa Bộ sưu tập nhanh", "Clear rating": "Xóa xếp hạng", "Clear rating and advance": "Xóa xếp hạng và chuyển tiếp", @@ -125,10 +141,12 @@ "Color Label Names": "Tên nhãn màu", "Color Label Sets": "Bộ nhãn màu", "Color Mixer": "Bộ trộn màu", + "Color Noise Reduction": "Giảm nhiễu màu", "Color label cleared": "Đã xóa nhãn màu", "Compare": "So sánh", "Compare needs at least two photos": "So sánh cần ít nhất hai ảnh", "Confirm before moving photos to Recently Deleted": "Xác nhận trước khi chuyển ảnh vào Đã xóa gần đây", + "Constrain Crop": "Giới hạn cắt", "Contrast": "Tương phản", "Convert to DNG": "Chuyển sang DNG", "Convert to DNG, Copy as DNG, Photo Merge and smart previews no longer write straight to the final file (issue": "Chuyển sang DNG, Sao chép dạng DNG, Photo Merge và smart preview không còn ghi thẳng vào tệp cuối (issue", @@ -157,10 +175,17 @@ "Create Virtual Copy": "Tạo bản sao ảo", "Creator": "Người tạo", "Creator metadata": "Siêu dữ liệu người tạo", + "Crop": "Cắt", + "Crop & Rotate": "Cắt và xoay", + "Crop & Rotate (C)": "Cắt và xoay (C)", + "Crop Aspect": "Tỷ lệ cắt", + "Crop, Rotate, Geometry": "Cắt, xoay, hình học", "Cropped": "Đã cắt", "Curve": "Đường cong", "Custom template…": "Mẫu tùy chỉnh…", "Cut": "Cắt", + "Cycle Crop Overlay": "Chuyển lớp phủ cắt", + "Cycle Crop Overlay Orientation": "Chuyển hướng lớp phủ cắt", "Cycle Info Overlay": "Chuyển lớp phủ thông tin", "Dark Theme": "Chủ đề tối", "Darks": "Vùng tối vừa", @@ -169,6 +194,7 @@ "Daylight": "Ánh sáng ban ngày", "Decrease Brush Feather": "Giảm lông cọ", "Decrease Rating": "Giảm xếp hạng", + "Defringe": "Khử viền màu", "Dehaze": "Khử sương mù", "Delete": "Xóa", "Delete Album": "Xóa album", @@ -183,18 +209,32 @@ "Delete Point Color": "Xóa Point Color", "Delete Point Color Sample": "Xóa mẫu Point Color", "Delete Point Curve Preset": "Xóa thiết lập sẵn đường cong điểm", + "Delete Red Eye": "Xóa mắt đỏ", + "Delete Red Eye Correction": "Xóa sửa mắt đỏ", + "Denoise Model Downloads": "Tải mô hình khử nhiễu", + "Denoise Models": "Mô hình khử nhiễu", "Denoise Photos": "Khử nhiễu ảnh", + "Denoise Pump": "Bơm khử nhiễu", + "Denoise Settings": "Cài đặt khử nhiễu", + "Denoise Status": "Trạng thái khử nhiễu", "Denoise all photos with an Amount": "Khử nhiễu mọi ảnh có Độ mạnh", "Description": "Mô tả", "Deselect": "Bỏ chọn", "Desktop": "Màn hình chính", + "Detail": "Chi tiết", + "Detail (D)": "Chi tiết (D)", + "Details": "Chi tiết", "Detect Faces": "Phát hiện khuôn mặt", "Develop": "Phát triển", "Display": "Màn hình", "Display theme": "Chủ đề hiển thị", + "Distortion": "Méoc", "Done": "Xong", + "Download Denoise Model": "Tải mô hình khử nhiễu", "Download Face Model": "Tải mô hình khuôn mặt", "Downloads": "Tải xuống", + "Drag Crop Handle": "Kéo tay nắm cắt", + "Drag over an eye on the photo; the pupil inside is found automatically.": "Kéo qua mắt trên ảnh; đồng tử bên trong được tìm tự động.", "Duplicate": "Nhân bản", "Duplicate Component": "Nhân bản thành phần", "Duplicate Mask": "Nhân bản mặt nạ", @@ -213,6 +253,7 @@ "Edit settings copied": "Đã sao chép cài đặt chỉnh sửa", "Edited": "Đã chỉnh sửa", "Empty Recently Deleted": "Dọn Đã xóa gần đây", + "Enable Lens Corrections": "Bật hiệu chỉnh ống kính", "English": "English", "Enter Full Screen": "Vào toàn màn hình", "Evaluate Face Recognition": "Đánh giá nhận diện khuôn mặt", @@ -272,6 +313,8 @@ "Flagged as Pick": "Đã gắn cờ Đã chọn", "Flagged as Reject": "Đã gắn cờ Đã loại", "Flash": "Đèn flash", + "Flip Horizontal": "Lật ngang", + "Flip Vertical": "Lật dọc", "Fluorescent": "Huỳnh quang", "Focal Length": "Tiêu cự", "Focus (assisted culling)": "Lấy nét (sàng lọc hỗ trợ)", @@ -285,6 +328,7 @@ "Full Screen Preview": "Xem trước toàn màn hình", "General": "Chung", "Generated demo photo": "Ảnh demo được tạo", + "Geometry": "Hình học", "Global Hue": "Sắc độ toàn cục", "Global Luminance": "Độ sáng toàn cục", "Global Saturation": "Độ bão hòa toàn cục", @@ -302,6 +346,9 @@ "Grid": "Lưới", "Grid Info": "Thông tin lưới", "Group into Stack": "Gom thành chồng", + "Guided": "Có hướng dẫn", + "Guided Upright": "Chỉnh thẳng có hướng dẫn", + "Guided Upright Guides": "Đường hướng dẫn chỉnh thẳng", "Has Edits": "Có chỉnh sửa", "Has GPS": "Có GPS", "Help": "Trợ giúp", @@ -313,6 +360,9 @@ "Highlights Saturation": "Độ bão hòa vùng sáng", "Highlights split": "Tách vùng sáng", "Home": "Thư mục Nhà", + "Horizontal": "Ngang", + "Horizontal inset (% of short edge)": "Lùi ngang (% cạnh ngắn)", + "Horizontal text": "Chữ ngang", "Hue": "Sắc độ", "Hue Range": "Dải sắc độ", "ISO Speed": "Tốc độ ISO", @@ -360,11 +410,14 @@ "Index Faces in the Background": "Lập chỉ mục khuôn mặt nền", "Info": "Thông tin", "Info Overlay: Exposure": "Lớp phủ thông tin: Phơi sáng", + "Inspect Denoise Model": "Kiểm tra mô hình khử nhiễu", "Inspect Face Model File": "Kiểm tra tệp mô hình khuôn mặt", "Inspect Lightroom Catalog": "Kiểm tra catalog Lightroom", "Inspect Photo": "Kiểm tra ảnh", "Inspecting Lightroom Catalog": "Đang kiểm tra catalog Lightroom", + "Install Denoise Model": "Cài mô hình khử nhiễu", "Install Face Model": "Cài mô hình khuôn mặt", + "Install a denoise model to enable AI Denoise on this photo": "Cài mô hình khử nhiễu để bật AI Khử nhiễu cho ảnh này", "Interface": "Giao diện", "Interface language": "Ngôn ngữ giao diện", "Into one folder": "Vào một thư mục", @@ -394,6 +447,7 @@ "Language": "Ngôn ngữ", "Last loupe render": "Lần kết xuất kính lúp gần nhất", "Lens": "Ống kính", + "Lens Corrections": "Hiệu chỉnh ống kính", "Library": "Thư viện", "Library Folders": "Thư mục thư viện", "Library Info": "Thông tin thư viện", @@ -420,6 +474,7 @@ "Locate Missing File…": "Định vị tệp bị thiếu…", "Locate Photo": "Định vị ảnh", "Location": "Vị trí", + "Lock Crop Aspect": "Khóa tỷ lệ cắt", "Long Edge": "Cạnh dài", "Looking for photos…": "Đang tìm ảnh…", "Luminance": "Độ sáng", @@ -430,7 +485,10 @@ "Magenta Luminance": "Độ sáng đỏ tím", "Magenta Saturation": "Độ bão hòa đỏ tím", "Make Candidate the Select": "Đặt ảnh ứng viên thành ảnh được chọn", + "Make the denoised picture of the photos I am looking at": "Tạo ảnh đã khử nhiễu cho ảnh tôi đang xem", "Manual": "Thủ công", + "Masking": "Mặt nạ", + "Masking (M)": "Mặt nạ (M)", "Match Total Exposures": "Khớp tổng phơi sáng", "Medium Contrast": "Tương phản trung bình", "Megapixels": "Megapixel", @@ -475,6 +533,7 @@ "New Smart Album": "Album thông minh mới", "New Smart Album from Filter…": "Album thông minh mới từ bộ lọc…", "New Smart Album…": "Album thông minh mới…", + "Next up for AI Denoise…": "Tiếp theo cho AI Khử nhiễu…", "No": "Không", "No Label": "Không nhãn", "No Stars": "Không sao", @@ -490,13 +549,18 @@ "No named people yet": "Chưa có người được đặt tên", "No photo has it; the keywords below it go too.": "Không ảnh nào có nó; các từ khóa bên dưới cũng bị gỡ.", "No photos": "Không có ảnh", + "Noise Reduction": "Giảm nhiễu", "None": "Không có", "OK": "OK", "Off": "Tắt", + "Offset X": "Độ lệch X", + "Offset Y": "Độ lệch Y", "On NixOS, start it from `nix develop`.": "Trên NixOS, hãy khởi chạy từ `nix develop`.", "Open Library…": "Mở thư viện…", "Open Log Folder": "Mở thư mục nhật ký", + "Open in Detail": "Mở chi tiết", "Open…": "Mở…", + "Optics": "Quang học", "Orange Hue": "Sắc cam", "Orange Luminance": "Độ sáng cam", "Orange Saturation": "Độ bão hòa cam", @@ -511,6 +575,7 @@ "Percentage": "Phần trăm", "Performance": "Hiệu năng", "Person": "Người", + "Pet Eye Catchlight": "Điểm sáng mắt thú cưng", "Photo": "Ảnh", "Photo Grid": "Lưới ảnh", "Photos that arrive in this folder (tethering, a scanner, a sync app) are added as soon as they're complete.": "Ảnh đến thư mục này (tethering, máy quét, app đồng bộ) được thêm ngay khi hoàn tất.", @@ -528,7 +593,10 @@ "Portrait (tall)": "Dọc (cao)", "Preferences": "Tùy chọn", "Preferences…": "Tùy chọn…", + "Profile Distortion": "Hồ sơ méo hình", + "Profile Vignetting": "Hồ sơ tối góc", "Public Domain": "Phạm vi công cộng", + "Pupil Size": "Kích thước đồng tử", "Purge Unused Keywords": "Dọn từ khóa không dùng", "Purple": "Tím", "Purple Amount": "Lượng tím", @@ -540,6 +608,7 @@ "Put New Keywords Inside This Keyword": "Đặt từ khóa mới vào trong từ khóa này", "Quit": "Thoát", "Quit LightCraft": "Thoát LightCraft", + "Radius": "Bán kính", "Rating": "Xếp hạng", "Rating cleared": "Đã xóa xếp hạng", "Ratings & flags": "Xếp hạng và cờ", @@ -552,20 +621,25 @@ "Recently Deleted": "Đã xóa gần đây", "Recognise faces (experimental)": "Nhận diện khuôn mặt (thử nghiệm)", "Red": "Đỏ", + "Red Eye": "Mắt đỏ", "Red Hue": "Sắc đỏ", "Red Luminance": "Độ sáng đỏ", "Red Primary": "Màu gốc đỏ", "Red Saturation": "Độ bão hòa đỏ", "Red label": "Nhãn đỏ", + "Red/Cyan Fringe": "Viền đỏ/lam", "Redo": "Làm lại", "Reference View": "Xem tham chiếu", + "Refine AI Mask Detail": "Tinh chỉnh chi tiết mặt nạ AI", "Refine Saturation": "Tinh chỉnh độ bão hòa", + "Refining the mask's detail…": "Đang tinh chỉnh chi tiết mặt nạ…", "Reject": "Đã loại", "Reject below focus": "Loại ảnh dưới ngưỡng lấy nét", "Rejected": "Đã loại", "Rejects": "Ảnh đã loại", "Relink photos whose file was renamed or moved": "Liên kết lại ảnh có tệp đã đổi tên hoặc di chuyển", "Remove": "Gỡ", + "Remove Denoise Model": "Gỡ mô hình khử nhiễu", "Remove Face Box": "Gỡ khung khuôn mặt", "Remove Face Model": "Gỡ mô hình khuôn mặt", "Remove this face box (undo with Edit ▸ Undo)": "Gỡ khung khuôn mặt này (hoàn tác bằng Chỉnh sửa ▸ Hoàn tác)", @@ -587,6 +661,7 @@ "Reset": "Đặt lại", "Reset All Curves": "Đặt lại tất cả đường cong", "Reset Before to Import State": "Đặt lại Before về trạng thái nhập", + "Reset Crop": "Đặt lại cắt", "Reset Panel Layout": "Đặt lại bố cục bảng", "Reset Parametric Curve": "Đặt lại đường cong tham số", "Reset Tone Curve": "Đặt lại đường cong tông màu", @@ -594,6 +669,11 @@ "Restore Library from Backup…": "Khôi phục thư viện từ bản sao lưu…", "Restore keeps their edits; Import as new deletes the old record first.": "Khôi phục giữ chỉnh sửa; Nhập như mới xóa bản ghi cũ trước.", "Review Import": "Xem lại nhập", + "Rotate": "Xoay", + "Rotate Crop": "Xoay vùng cắt", + "Rotate Crop Aspect": "Xoay tỷ lệ cắt", + "Rotate Left": "Xoay trái", + "Rotate Right": "Xoay phải", "Roughness": "Độ thô", "Roundness": "Độ tròn", "Sa": "T7", @@ -611,6 +691,7 @@ "Save Point Curve…": "Lưu đường cong điểm…", "Save as Smart Album…": "Lưu thành album thông minh…", "Saving Lightroom import index…": "Đang lưu chỉ mục nhập Lightroom…", + "Scale": "Tỷ lệ", "Search": "Tìm kiếm", "Search albums": "Tìm album", "Second Window": "Cửa sổ thứ hai", @@ -622,9 +703,11 @@ "Send Feedback…": "Gửi phản hồi…", "Sequence number, counting from the start number": "Số thứ tự, đếm từ số bắt đầu", "Set Color Label": "Đặt nhãn màu", + "Set Crop": "Đặt cắt", "Set Flag": "Đặt cờ", "Set Point Curve": "Đặt đường cong điểm", "Set Rating": "Đặt xếp hạng", + "Set up AI Denoise…": "Thiết lập AI Khử nhiễu…", "Settings": "Cài đặt", "Shadow": "Vùng tối", "Shadows": "Vùng tối", @@ -633,6 +716,8 @@ "Shadows Saturation": "Độ bão hòa vùng tối", "Shadows Tint": "Tông vùng tối", "Shadows split": "Tách vùng tối", + "Sharpen": "Làm nét", + "Sharpening": "Làm nét", "Short Edge": "Cạnh ngắn", "Show": "Hiện", "Show Clipping": "Hiện vùng cắt tông", @@ -650,6 +735,7 @@ "Slideshow": "Trình chiếu", "Smart Album": "Album thông minh", "Smart Album Rule Fields": "Trường quy tắc album thông minh", + "Smoothness": "Độ mịn", "Some rules need fixing (Edit Smart Album…):": "Một số quy tắc cần sửa (Chỉnh sửa album thông minh…):", "Source": "Nguồn", "Square": "Vuông", @@ -663,11 +749,14 @@ "Starting…": "Đang bắt đầu…", "Startup": "Khởi động", "State / Province": "Bang / Tỉnh", + "Straighten": "Chỉnh thẳng", + "Straighten Tool": "Công cụ chỉnh thẳng", "Strong Contrast": "Tương phản mạnh", "Su": "CN", "Suggest Names for Faces": "Gợi ý tên cho khuôn mặt", "Sunday": "Chủ Nhật", "Survey": "Khảo sát", + "Swap Aspect (X)": "Hoán đổi tỷ lệ (X)", "Swap Compare Photos": "Đổi chỗ ảnh so sánh", "Switch light / dark theme": "Chuyển chủ đề sáng / tối", "Synchronize Folder": "Đồng bộ thư mục", @@ -680,11 +769,14 @@ "Temperature": "Nhiệt độ", "Template": "Mẫu", "Temporary session — your library isn't open, and nothing you do here is saved.": "Phiên tạm — thư viện chưa mở và không lưu gì bạn làm ở đây.", + "Test Denoise Model": "Thử mô hình khử nhiễu", "Test Face Model": "Thử mô hình khuôn mặt", "Texture": "Kết cấu", "Th": "T5", + "The denoise model is installed and in use: the AI Denoise Amount slider under Detail now works": "Mô hình khử nhiễu đã cài và đang dùng: thanh AI Denoise Amount trong Chi tiết giờ hoạt động", "The import reads the catalog without changing it and adds its photos, edits, keywords and collections to the library open now.": "Nhập đọc catalog không đổi nó và thêm ảnh, chỉnh sửa, từ khóa và bộ sưu tập vào thư viện đang mở.", "Theme": "Chủ đề", + "This build cannot run denoise models.": "Bản build này không chạy được mô hình khử nhiễu.", "This group is empty: add a rule or remove it.": "Nhóm này trống: thêm quy tắc hoặc xóa nhóm.", "This is a Lightroom catalog, not a LightCraft library. Import it into a LightCraft library instead?": "Đây là catalog Lightroom, không phải thư viện LightCraft. Nhập vào thư viện LightCraft thay vì?", "This is the album you're editing": "Đây là album bạn đang chỉnh sửa", @@ -705,12 +797,17 @@ "Unflagged": "Không gắn cờ", "Unknown": "Không rõ", "Unnamed Faces": "Khuôn mặt chưa đặt tên", + "Upright": "Chỉnh thẳng", "Use Keyword Set": "Dùng bộ từ khóa", + "Vertical": "Dọc", + "Vertical inset (% of short edge)": "Lùi dọc (% cạnh ngắn)", + "Vertical text": "Chữ dọc", "Vibrance": "Độ rực rỡ", "Video": "Video", "Video Duration": "Thời lượng video", "View": "Xem", "Vignette": "Tối góc", + "Vignetting": "Tối góc", "Vintage": "Vintage", "Virtual Copy": "Bản sao ảo", "Wait for the import to finish": "Đợi nhập hoàn tất", @@ -747,6 +844,7 @@ "copy is verified and in the library. Duplicates and files that fail stay where they were.": "bản sao được xác minh và có trong thư viện. Trùng lặp và tệp lỗi giữ nguyên chỗ.", "copyrighted": "có bản quyền", "data is not decoded yet, so they stay preview-only. For CR3s imported earlier, Photo ▸ Reload from Disk (now in": "dữ liệu chưa giải mã, nên vẫn chỉ xem trước. Với CR3 nhập trước đó, Ảnh ▸ Tải lại từ đĩa (giờ trong", + "denoiseModel.accept": "denoiseModel.accept", "doesn't contain": "không chứa", "ends with": "kết thúc bằng", "export. The catalog, XMP sidecars, settings, DNGs, merges, smart previews and the copies an import makes are still": "xuất. Catalog, sidecar XMP, cài đặt, DNG, merge, smart preview và bản sao khi nhập vẫn", @@ -773,6 +871,7 @@ "isn't in the last": "không trong vòng", "isn't one of the choices": "không phải một trong các lựa chọn", "longer just says \"duplicate skipped\": it opens the side panel on Recently Deleted with the photo selected and says": "không chỉ nói \"bỏ qua trùng\": mở bảng bên ở Đã xóa gần đây với ảnh được chọn và nói", + "makes AI Denoise available": "cho phép dùng AI Khử nhiễu", "names an album that no longer exists": "chỉ album không còn tồn tại", "needs a date like 2026, 2026-08 or 2026-08-14": "cần ngày như 2026, 2026-08 hoặc 2026-08-14", "needs a number": "cần một số", @@ -788,6 +887,8 @@ "needs two values": "cần hai giá trị", "never leaves a truncated file; the XMP sidecar of an \"Original\" export follows the \"If file exists\" choice too.": "không bao giờ để tệp cắt cụt; sidecar XMP của xuất \"Original\" cũng theo lựa chọn \"Nếu tệp đã tồn tại\".", "on the card after Review Import is reported instead of being imported with stale details. Checking an export path": "trên thẻ sau Xem lại nhập được báo thay vì nhập với chi tiết cũ. Kiểm tra đường dẫn xuất", + "photo has its denoised picture.": "ảnh đã có ảnh khử nhiễu.", + "photos have their denoised picture.": "ảnh đã có ảnh khử nhiễu.", "pick": "đã chọn", "reject": "đã loại", "smart album value|No": "Không", @@ -799,6 +900,7 @@ "the camera; mapped-out sensor defects are filled in. `.rwl` and `.raw` files are imported too. Photos already": "máy ảnh; điểm lỗi cảm biến được lấp. Tệp `.rwl` và `.raw` cũng được nhập. Ảnh đã", "would make this album include itself through other smart albums": "sẽ khiến album này bao gồm chính nó qua album thông minh khác", "{date} is the capture time; a photo without one uses the time it was imported.": "{date} là thời gian chụp; ảnh không có thì dùng thời gian nhập.", + "⌘-drag to straighten, ⇧G Guided Upright, a grid while transforming.": "⌘-kéo để chỉnh thẳng, ⇧G Chỉnh thẳng có hướng dẫn, lưới khi biến đổi.", "日本語": "日本語", "繁體中文(台灣)": "繁體中文(台灣)" } From 3eec232f694b67d66728f16c84da4980d7da5fcd Mon Sep 17 00:00:00 2001 From: "DUY Tran Nhat (SAE-KIDS)" Date: Tue, 13 Oct 2026 15:54:00 +0700 Subject: [PATCH 014/350] i18n(vi): translate masking and remove workflows --- crates/ui-egui/locales/vi.json | 88 ++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/crates/ui-egui/locales/vi.json b/crates/ui-egui/locales/vi.json index 402f4f6ca..a89a48d41 100644 --- a/crates/ui-egui/locales/vi.json +++ b/crates/ui-egui/locales/vi.json @@ -1,5 +1,6 @@ { " (library default)": " (mặc định thư viện)", + " (inverted)": " (đã đảo)", ", picked": ", đã chọn", ", rejected": ", đã loại", "0: nothing is rejected.": "0: không loại gì.", @@ -8,18 +9,24 @@ "A folder is already being synchronized": "Một thư mục đang được đồng bộ", "A folder is being synchronized": "Một thư mục đang được đồng bộ", "A keyword set needs a name": "Bộ từ khóa cần một tên", + "A sleeping NAS, a dropped network share or a USB drive spinning up no longer freezes the window (issue #104):": "NAS đang ngủ, ổ mạng bị ngắt hoặc ổ USB đang quay lên không còn làm đóng băng cửa sổ (issue #104):", "AI Denoise": "Khử nhiễu AI", "AI Denoise Model": "Mô hình khử nhiễu AI", "AI Denoise is enabled on the requesting photo": "Khử nhiễu AI đã bật trên ảnh yêu cầu", "AI Denoise is off: press Use on a model.": "Khử nhiễu AI đang tắt: nhấn Dùng trên một mô hình.", "AI Denoise needs a model. Install one in Settings.": "Khử nhiễu AI cần một mô hình. Hãy cài trong Cài đặt.", + "AI Mask Model Status": "Trạng thái mô hình mặt nạ AI", + "AI masks with SAM 3 (Object and Describe in the Masking panel): click an object to select it (⌥-click leaves a": "Mặt nạ AI với SAM 3 (Object và Describe trong bảng Mặt nạ): bấm vào đối tượng để chọn (⌥-click để lại", "About": "Giới thiệu", "About LightCraft": "Giới thiệu LightCraft", "Add Catchlight": "Thêm điểm sáng mắt", "Add Face Model…": "Thêm mô hình khuôn mặt…", "Add Folder to Local": "Thêm thư mục vào Cục bộ", + "Add Mask": "Thêm mặt nạ", + "Add Object Click": "Thêm cú nhấp đối tượng", "Add Point Color Sample": "Thêm mẫu Point Color", "Add Red Eye Correction": "Thêm sửa mắt đỏ", + "Add Remove Spot": "Thêm điểm xóa", "Add Selected Photos": "Thêm ảnh đã chọn", "Add in place": "Thêm tại chỗ", "Add in place: the library references the files where they are; nothing is copied or moved.": "Thêm tại chỗ: thư viện tham chiếu tệp ở vị trí hiện tại; không sao chép hay di chuyển gì.", @@ -31,6 +38,8 @@ "Add to My Photos First": "Thêm vào Ảnh của tôi trước", "Add to Selected Photos": "Thêm vào ảnh đã chọn", "Add to Target Album": "Thêm vào album đích", + "Add to this mask": "Thêm vào mặt nạ này", + "Add/Subtract/Intersect Mask": "Thêm/Trừ/Giao mặt nạ", "Added to photos you import that don't already have it.": "Được thêm vào ảnh bạn nhập nếu chưa có.", "Adding Lightroom photos…": "Đang thêm ảnh Lightroom…", "Adding photos…": "Đang thêm ảnh…", @@ -46,6 +55,7 @@ "All Photos": "Tất cả ảnh", "All the photos imported from this disk are included.": "Tất cả ảnh nhập từ đĩa này đều được bao gồm.", "Alt Text": "Văn bản thay thế", + "Analyzing the photo for AI masks…": "Đang phân tích ảnh cho mặt nạ AI…", "Any Searchable Text": "Mọi văn bản tìm được", "Any keyword": "Mọi từ khóa", "Aperture": "Khẩu độ", @@ -56,6 +66,7 @@ "Apply Color Label Set": "Áp dụng bộ nhãn màu", "Apply Metadata Preset": "Áp dụng thiết lập sẵn siêu dữ liệu", "Apply Point Curve Preset": "Áp dụng thiết lập sẵn đường cong điểm", + "Apply the local tone mapping stored in the raw (Apple ProRAW), as the camera renders it": "Áp dụng ánh xạ tông cục bộ lưu trong raw (Apple ProRAW), như máy ảnh hiển thị", "Aqua Hue": "Hue ngọc lam", "Aqua Luminance": "Độ sáng ngọc lam", "Aqua Saturation": "Độ bão hòa ngọc lam", @@ -73,6 +84,7 @@ "Auto Import": "Tự nhập", "Auto Import Now": "Tự nhập ngay", "Auto Import Settings": "Cài đặt tự nhập", + "Auto Mask": "Tự tạo mặt nạ", "Auto Straighten": "Tự chỉnh thẳng", "Auto Sync: edits apply to every selected photo. Auto B&W mix. Automatic versions.": "Auto Sync: chỉnh sửa áp dụng cho mọi ảnh đã chọn. Auto B&W mix. Phiên bản tự động.", "Auto-Stack by Capture Time": "Tự xếp chồng theo thời gian chụp", @@ -86,6 +98,7 @@ "Back Up Library…": "Sao lưu thư viện…", "Back to Grid": "Quay lại lưới", "Back to this person": "Quay lại người này", + "Background": "Nền", "Balance": "Cân bằng", "Best of Similar Shots": "Ảnh đẹp nhất trong nhóm tương tự", "Black & White": "Đen trắng", @@ -103,10 +116,16 @@ "Boundary Warp": "Biến dạng biên", "Browse Folder": "Duyệt thư mục", "Browse Folder…": "Duyệt thư mục…", + "Browser version (experimental), keeping a library safe (issue #107): File ▸ Back Up Library… downloads the catalog": "Phiên bản trình duyệt (thử nghiệm), giữ thư viện an toàn (issue #107): Tệp ▸ Sao lưu thư viện… tải catalog", + "Brush": "Cọ", + "Brush Settings": "Cài đặt cọ", + "Brush Stroke": "Nét cọ", "Camera": "Máy ảnh", "Camera Info": "Thông tin máy ảnh", + "Camera local tone mapping": "Ánh xạ tông cục bộ của máy ảnh", "Cameras and Cards": "Máy ảnh và thẻ nhớ", "Cancel": "Hủy", + "Cancel AI Mask Model Download": "Hủy tải mô hình mặt nạ AI", "Cancel Denoise": "Hủy khử nhiễu", "Cancel Denoise Model Download": "Hủy tải mô hình khử nhiễu", "Cancel Face Model Download": "Hủy tải mô hình khuôn mặt", @@ -132,6 +151,7 @@ "Clear rating": "Xóa xếp hạng", "Clear rating and advance": "Xóa xếp hạng và chuyển tiếp", "Click to restore · double-click to rename": "Nhấp để khôi phục · nhấp đúp để đổi tên", + "Clone": "Nhân bản vùng", "Close": "Đóng", "Cloudy": "Nhiều mây", "Collapse All Stacks": "Thu gọn mọi chồng", @@ -142,7 +162,9 @@ "Color Label Sets": "Bộ nhãn màu", "Color Mixer": "Bộ trộn màu", "Color Noise Reduction": "Giảm nhiễu màu", + "Color Range": "Dải màu", "Color label cleared": "Đã xóa nhãn màu", + "Colour-range masks: click the photo to sample. Luminance ranges: range bar, smoothness, luminance map.": "Mặt nạ vùng màu: bấm ảnh để lấy mẫu. Vùng độ sáng: thanh phạm vi, độ mượt, bản đồ độ sáng.", "Compare": "So sánh", "Compare needs at least two photos": "So sánh cần ít nhất hai ảnh", "Confirm before moving photos to Recently Deleted": "Xác nhận trước khi chuyển ảnh vào Đã xóa gần đây", @@ -168,6 +190,7 @@ "Create Folder": "Tạo thư mục", "Create Folder…": "Tạo thư mục…", "Create Keyword Tag": "Tạo thẻ từ khóa", + "Create New Mask": "Tạo mặt nạ mới", "Create Smart Album": "Tạo album thông minh", "Create Smart Album from Filter…": "Tạo album thông minh từ bộ lọc…", "Create Smart Album…": "Tạo album thông minh…", @@ -187,22 +210,28 @@ "Cycle Crop Overlay": "Chuyển lớp phủ cắt", "Cycle Crop Overlay Orientation": "Chuyển hướng lớp phủ cắt", "Cycle Info Overlay": "Chuyển lớp phủ thông tin", + "Cycle Mask Overlay Color": "Chuyển màu lớp phủ mặt nạ", + "Cycle Mask Overlay Mode": "Chuyển chế độ lớp phủ mặt nạ", "Dark Theme": "Chủ đề tối", "Darks": "Vùng tối vừa", "Date": "Ngày", "Day": "Ngày", "Daylight": "Ánh sáng ban ngày", "Decrease Brush Feather": "Giảm lông cọ", + "Decrease Brush Size": "Giảm kích thước cọ", "Decrease Rating": "Giảm xếp hạng", + "Deep Sky": "Bầu trời sâu", "Defringe": "Khử viền màu", "Dehaze": "Khử sương mù", "Delete": "Xóa", "Delete Album": "Xóa album", + "Delete All Masks": "Xóa mọi mặt nạ", "Delete Color Label Set": "Xóa bộ nhãn màu", "Delete Imported Profile": "Xóa hồ sơ đã nhập", "Delete Keyword": "Xóa từ khóa", "Delete Keyword Set": "Xóa bộ từ khóa", "Delete Keyword…": "Xóa từ khóa…", + "Delete Mask": "Xóa mặt nạ", "Delete Metadata Preset": "Xóa thiết lập sẵn siêu dữ liệu", "Delete Photo": "Xóa ảnh", "Delete Photos": "Xóa ảnh", @@ -211,6 +240,7 @@ "Delete Point Curve Preset": "Xóa thiết lập sẵn đường cong điểm", "Delete Red Eye": "Xóa mắt đỏ", "Delete Red Eye Correction": "Xóa sửa mắt đỏ", + "Delete mask": "Xóa mặt nạ", "Denoise Model Downloads": "Tải mô hình khử nhiễu", "Denoise Models": "Mô hình khử nhiễu", "Denoise Photos": "Khử nhiễu ảnh", @@ -218,6 +248,10 @@ "Denoise Settings": "Cài đặt khử nhiễu", "Denoise Status": "Trạng thái khử nhiễu", "Denoise all photos with an Amount": "Khử nhiễu mọi ảnh có Độ mạnh", + "Density": "Mật độ", + "Describe what to keep": "Mô tả phần giữ lại", + "Describe what to leave out": "Mô tả phần loại trừ", + "Describe what to select": "Mô tả phần cần chọn", "Description": "Mô tả", "Deselect": "Bỏ chọn", "Desktop": "Màn hình chính", @@ -230,8 +264,10 @@ "Display theme": "Chủ đề hiển thị", "Distortion": "Méoc", "Done": "Xong", + "Download AI Mask Model": "Tải mô hình mặt nạ AI", "Download Denoise Model": "Tải mô hình khử nhiễu", "Download Face Model": "Tải mô hình khuôn mặt", + "Download the SAM 3 Model?": "Tải mô hình SAM 3?", "Downloads": "Tải xuống", "Drag Crop Handle": "Kéo tay nắm cắt", "Drag over an eye on the photo; the pupil inside is found automatically.": "Kéo qua mắt trên ảnh; đồng tử bên trong được tìm tự động.", @@ -239,6 +275,7 @@ "Duplicate Component": "Nhân bản thành phần", "Duplicate Mask": "Nhân bản mặt nạ", "Duplicate and Invert Mask": "Nhân bản và đảo mặt nạ", + "Edge setting, and get a sharper zoomed-in pass in the background. The model runs inside LightCraft in pure Rust": "Cài đặt Edge và nhận lượt phóng to sắc nét hơn ở nền. Mô hình chạy trong LightCraft bằng pure Rust", "Edit": "Chỉnh sửa", "Edit Color Label Names": "Sửa tên nhãn màu", "Edit Color Label Names…": "Sửa tên nhãn màu…", @@ -248,6 +285,8 @@ "Edit Keyword Tag…": "Sửa thẻ từ khóa…", "Edit Label Names": "Sửa tên nhãn", "Edit Label Names…": "Sửa tên nhãn…", + "Edit Mask": "Sửa mặt nạ", + "Edit Mask Component": "Sửa thành phần mặt nạ", "Edit Smart Album": "Chỉnh sửa album thông minh", "Edit Smart Album…": "Chỉnh sửa album thông minh…", "Edit settings copied": "Đã sao chép cài đặt chỉnh sửa", @@ -256,6 +295,7 @@ "Enable Lens Corrections": "Bật hiệu chỉnh ống kính", "English": "English", "Enter Full Screen": "Vào toàn màn hình", + "Erase": "Xóa nét", "Evaluate Face Recognition": "Đánh giá nhận diện khuôn mặt", "Every EXIF, GPS and XMP field in the file": "Mọi trường EXIF, GPS và XMP trong tệp", "Exit": "Thoát", @@ -315,6 +355,7 @@ "Flash": "Đèn flash", "Flip Horizontal": "Lật ngang", "Flip Vertical": "Lật dọc", + "Flow": "Dòng cọ", "Fluorescent": "Huỳnh quang", "Focal Length": "Tiêu cự", "Focus (assisted culling)": "Lấy nét (sàng lọc hỗ trợ)", @@ -351,7 +392,10 @@ "Guided Upright Guides": "Đường hướng dẫn chỉnh thẳng", "Has Edits": "Có chỉnh sửa", "Has GPS": "Có GPS", + "Heal": "Sửa vết", + "Heal the small, soft dark spots sensor dust leaves on smooth areas": "Sửa các điểm tối nhỏ, mềm do bụi cảm biến để lại trên vùng mịn", "Help": "Trợ giúp", + "Hide Mask": "Ẩn mặt nạ", "High Contrast B&W": "B&W tương phản cao", "Highlight": "Vùng sáng", "Highlights": "Vùng sáng", @@ -405,6 +449,7 @@ "Include selected photos": "Bao gồm ảnh đã chọn", "Include subfolders": "Bao gồm thư mục con", "Increase Brush Feather": "Tăng độ mềm cọ", + "Increase Brush Size": "Tăng kích thước cọ", "Increase Rating": "Tăng xếp hạng", "Index Faces": "Lập chỉ mục khuôn mặt", "Index Faces in the Background": "Lập chỉ mục khuôn mặt nền", @@ -418,9 +463,15 @@ "Install Denoise Model": "Cài mô hình khử nhiễu", "Install Face Model": "Cài mô hình khuôn mặt", "Install a denoise model to enable AI Denoise on this photo": "Cài mô hình khử nhiễu để bật AI Khử nhiễu cho ảnh này", + "Install the SAM 3 Model": "Cài mô hình SAM 3", "Interface": "Giao diện", "Interface language": "Ngôn ngữ giao diện", + "Intersect": "Giao", + "Intersect with": "Giao với", "Into one folder": "Vào một thư mục", + "Invert": "Đảo", + "Invert Component": "Đảo thành phần", + "Invert Mask": "Đảo mặt nạ", "It tests this album, so testing it back would loop": "Nó kiểm tra album này, nên kiểm tra ngược lại sẽ tạo vòng lặp", "Join the ArtCraft Discord…": "Tham gia Discord ArtCraft…", "Keyboard Shortcuts": "Phím tắt", @@ -466,6 +517,7 @@ "Lightroom import cancelled": "Đã hủy nhập Lightroom", "Lights": "Đèn", "Lights Out": "Tắt đèn", + "Linear Gradient": "Chuyển sắc tuyến tính", "List Albums": "Liệt kê album", "List this folder in Local from now on": "Liệt kê thư mục này trong Cục bộ từ nay", "Local folders": "Thư mục cục bộ", @@ -487,8 +539,10 @@ "Make Candidate the Select": "Đặt ảnh ứng viên thành ảnh được chọn", "Make the denoised picture of the photos I am looking at": "Tạo ảnh đã khử nhiễu cho ảnh tôi đang xem", "Manual": "Thủ công", + "Mask Adjustment": "Điều chỉnh mặt nạ", "Masking": "Mặt nạ", "Masking (M)": "Mặt nạ (M)", + "Masks": "Mặt nạ", "Match Total Exposures": "Khớp tổng phơi sáng", "Medium Contrast": "Tương phản trung bình", "Megapixels": "Megapixel", @@ -515,6 +569,7 @@ "Move Down in Stack": "Di chuyển xuống trong chồng", "Move Folder": "Di chuyển thư mục", "Move Folder To…": "Di chuyển thư mục tới…", + "Move Mask": "Di chuyển mặt nạ", "Move Selected Photos Here": "Di chuyển ảnh đã chọn vào đây", "Move Up in Stack": "Di chuyển lên trong chồng", "Move the files (into the library's Originals/, or a folder you choose), removing them from the source": "Di chuyển tệp (vào Originals/ của thư viện hoặc thư mục bạn chọn), gỡ khỏi nguồn", @@ -544,6 +599,7 @@ "No keywords are exported": "Không xuất từ khóa nào", "No keywords match": "Không có từ khóa khớp", "No keywords yet": "Chưa có từ khóa", + "No masks yet. Choose a mask type above.": "Chưa có mặt nạ. Chọn loại mặt nạ ở trên.", "No metadata found": "Không tìm thấy siêu dữ liệu", "No named people in these photos": "Không có người được đặt tên trong các ảnh này", "No named people yet": "Chưa có người được đặt tên", @@ -552,6 +608,7 @@ "Noise Reduction": "Giảm nhiễu", "None": "Không có", "OK": "OK", + "Object Mask": "Mặt nạ đối tượng", "Off": "Tắt", "Offset X": "Độ lệch X", "Offset Y": "Độ lệch Y", @@ -564,6 +621,7 @@ "Orange Hue": "Sắc cam", "Orange Luminance": "Độ sáng cam", "Orange Saturation": "Độ bão hòa cam", + "Paint only areas like the one under the brush": "Chỉ tô vùng giống vùng dưới cọ", "Panels": "Các bảng", "Parametric curve": "Đường cong tham số", "Paste": "Dán", @@ -593,6 +651,7 @@ "Portrait (tall)": "Dọc (cao)", "Preferences": "Tùy chọn", "Preferences…": "Tùy chọn…", + "Prepare AI Masks": "Chuẩn bị mặt nạ AI", "Profile Distortion": "Hồ sơ méo hình", "Profile Vignetting": "Hồ sơ tối góc", "Public Domain": "Phạm vi công cộng", @@ -608,6 +667,7 @@ "Put New Keywords Inside This Keyword": "Đặt từ khóa mới vào trong từ khóa này", "Quit": "Thoát", "Quit LightCraft": "Thoát LightCraft", + "Radial Gradient": "Chuyển sắc hướng tâm", "Radius": "Bán kính", "Rating": "Xếp hạng", "Rating cleared": "Đã xóa xếp hạng", @@ -615,6 +675,7 @@ "Raw": "Raw", "Read Metadata from File": "Đọc siêu dữ liệu từ tệp", "Read metadata updates from XMP sidecars": "Đọc cập nhật siêu dữ liệu từ sidecar XMP", + "Read the SAM License": "Đọc giấy phép SAM", "Reading photos…": "Đang đọc ảnh…", "Recent Keywords": "Từ khóa gần đây", "Recent Keywords is built in: choose another name": "Từ khóa gần đây là bộ sẵn: hãy chọn tên khác", @@ -631,6 +692,7 @@ "Redo": "Làm lại", "Reference View": "Xem tham chiếu", "Refine AI Mask Detail": "Tinh chỉnh chi tiết mặt nạ AI", + "Refine Mask Edges": "Tinh chỉnh cạnh mặt nạ", "Refine Saturation": "Tinh chỉnh độ bão hòa", "Refining the mask's detail…": "Đang tinh chỉnh chi tiết mặt nạ…", "Reject": "Đã loại", @@ -658,6 +720,7 @@ "Rename Template Tags": "Thẻ mẫu đổi tên", "Rename Version": "Đổi tên phiên bản", "Rename…": "Đổi tên…", + "Reorder Masks": "Sắp xếp lại mặt nạ", "Reset": "Đặt lại", "Reset All Curves": "Đặt lại tất cả đường cong", "Reset Before to Import State": "Đặt lại Before về trạng thái nhập", @@ -676,7 +739,9 @@ "Rotate Right": "Xoay phải", "Roughness": "Độ thô", "Roundness": "Độ tròn", + "SAM 3 download stopped: it resumes where it left off next time.": "Tải SAM 3 đã dừng: lần sau sẽ tiếp tục từ chỗ dừng.", "Sa": "T7", + "Sample Mask Color": "Lấy mẫu màu mặt nạ", "Saturation": "Độ bão hòa", "Saturation Range": "Dải độ bão hòa", "Saturday": "Thứ Bảy", @@ -697,6 +762,7 @@ "Second Window": "Cửa sổ thứ hai", "Select All": "Chọn tất cả", "Select Luminance Range": "Chọn dải độ sáng", + "Select Mask": "Chọn mặt nạ", "Select by Flag, Rating or Label": "Chọn theo cờ, xếp hạng hoặc nhãn", "Select photos to give them keywords.": "Chọn ảnh để gán từ khóa.", "Selected": "Đã chọn", @@ -705,6 +771,7 @@ "Set Color Label": "Đặt nhãn màu", "Set Crop": "Đặt cắt", "Set Flag": "Đặt cờ", + "Set Mask Adjustments": "Đặt điều chỉnh mặt nạ", "Set Point Curve": "Đặt đường cong điểm", "Set Rating": "Đặt xếp hạng", "Set up AI Denoise…": "Thiết lập AI Khử nhiễu…", @@ -720,18 +787,25 @@ "Sharpening": "Làm nét", "Short Edge": "Cạnh ngắn", "Show": "Hiện", + "Show All Mask Overlays": "Hiện mọi lớp phủ mặt nạ", "Show Clipping": "Hiện vùng cắt tông", "Show Luminance Map": "Hiện bản đồ độ sáng", + "Show Mask": "Hiện mặt nạ", + "Show Mask Overlay": "Hiện lớp phủ mặt nạ", + "Show Mask Pins": "Hiện ghim mặt nạ", "Show Original": "Hiện bản gốc", "Show Person": "Hiện người", "Show Photo Counts": "Hiện số lượng ảnh", "Show Photos with Keyword": "Hiện ảnh có từ khóa", + "Show Pins": "Hiện ghim", "Show destination gamut warning": "Hiện cảnh báo gamut đích", "Show in Finder": "Hiện trong trình quản lý tệp", "Show ratings, flags and edit badges": "Hiện xếp hạng, cờ và huy hiệu chỉnh sửa", "Show the template tags; click one to insert it": "Hiện thẻ mẫu; nhấp để chèn", + "Show/Hide Mask": "Hiện/Ẩn mặt nạ", "Shutter Speed": "Tốc độ cửa trập", "Size": "Kích thước", + "Sky": "Bầu trời", "Slideshow": "Trình chiếu", "Smart Album": "Album thông minh", "Smart Album Rule Fields": "Trường quy tắc album thông minh", @@ -749,10 +823,14 @@ "Starting…": "Đang bắt đầu…", "Startup": "Khởi động", "State / Province": "Bang / Tỉnh", + "Stopping…": "Đang dừng…", "Straighten": "Chỉnh thẳng", "Straighten Tool": "Công cụ chỉnh thẳng", "Strong Contrast": "Tương phản mạnh", "Su": "CN", + "Subject": "Chủ thể", + "Subtract": "Trừ", + "Subtract from this mask": "Trừ khỏi mặt nạ này", "Suggest Names for Faces": "Gợi ý tên cho khuôn mặt", "Sunday": "Chủ Nhật", "Survey": "Khảo sát", @@ -773,6 +851,7 @@ "Test Face Model": "Thử mô hình khuôn mặt", "Texture": "Kết cấu", "Th": "T5", + "The SAM 3 model is installed: Object and Describe masks are ready.": "Đã cài mô hình SAM 3: Mặt nạ đối tượng và Mô tả đã sẵn sàng.", "The denoise model is installed and in use: the AI Denoise Amount slider under Detail now works": "Mô hình khử nhiễu đã cài và đang dùng: thanh AI Denoise Amount trong Chi tiết giờ hoạt động", "The import reads the catalog without changing it and adds its photos, edits, keywords and collections to the library open now.": "Nhập đọc catalog không đổi nó và thêm ảnh, chỉnh sửa, từ khóa và bộ sưu tập vào thư viện đang mở.", "Theme": "Chủ đề", @@ -785,6 +864,7 @@ "Title": "Tiêu đề", "Title metadata": "Siêu dữ liệu tiêu đề", "Toggle Keyword from Set": "Bật/tắt từ khóa từ bộ", + "Toggle Mask": "Bật/tắt mặt nạ", "Toggle Zoom": "Bật/tắt thu phóng", "Tone Curve": "Đường cong tông màu", "Tools": "Công cụ", @@ -797,6 +877,7 @@ "Unflagged": "Không gắn cờ", "Unknown": "Không rõ", "Unnamed Faces": "Khuôn mặt chưa đặt tên", + "Update Mask Shape": "Cập nhật hình mặt nạ", "Upright": "Chỉnh thẳng", "Use Keyword Set": "Dùng bộ từ khóa", "Vertical": "Dọc", @@ -833,21 +914,27 @@ "Zoom In": "Phóng to", "Zoom Out": "Thu nhỏ", "Zoom to Fit": "Thu phóng vừa khung", + "and checks the file before using it. Masks keep their selection, so they render and export without the model.": "và kiểm tra tệp trước khi dùng. Mặt nạ giữ vùng chọn, nên kết xuất và xuất không cần mô hình.", "and every imported photo as one zip, and File ▸ Restore Library from Backup… brings it back (the current library": "và mọi ảnh đã nhập thành một zip, và Tệp ▸ Khôi phục thư viện từ bản sao lưu… đưa lại (thư viện hiện tại", + "and never freezes the window. It is optional and not part of LightCraft (Meta's SAM License, about 3.4 GB): the": "và không bao giờ đóng băng cửa sổ. Tùy chọn và không thuộc LightCraft (SAM License của Meta, khoảng 3,4 GB):", "are empty": "trống", "aren't empty": "không trống", + "bundles of any of these — whole folders at once, grouped by pack. Masks inside presets come along.": "gói bất kỳ loại này — cả thư mục một lúc, nhóm theo pack. Mặt nạ trong thiết lập sẵn đi theo.", "camera no longer gets baked in. Photos already imported as \"preview only\" switch over on Reload. (Files that": "máy ảnh không còn bị nướng vào. Ảnh đã nhập \"chỉ xem trước\" chuyển sang khi Tải lại. (Tệp", "can't be tested that way": "không thể kiểm tra theo cách đó", "can't match any rating from 0 to 5": "không khớp xếp hạng nào từ 0 đến 5", "can't test a folder; choose an album in it": "không thể kiểm tra thư mục; hãy chọn album bên trong", + "commercial use subject to GPL conditions": "dùng thương mại theo điều kiện GPL", "contains": "chứa", "copy is verified and in the library. Duplicates and files that fail stay where they were.": "bản sao được xác minh và có trong thư viện. Trùng lặp và tệp lỗi giữ nguyên chỗ.", "copyrighted": "có bản quyền", "data is not decoded yet, so they stay preview-only. For CR3s imported earlier, Photo ▸ Reload from Disk (now in": "dữ liệu chưa giải mã, nên vẫn chỉ xem trước. Với CR3 nhập trước đó, Ảnh ▸ Tải lại từ đĩa (giờ trong", "denoiseModel.accept": "denoiseModel.accept", "doesn't contain": "không chứa", + "e.g. sky · the red car · car, road": "vd. bầu trời · xe đỏ · xe, đường", "ends with": "kết thúc bằng", "export. The catalog, XMP sidecars, settings, DNGs, merges, smart previews and the copies an import makes are still": "xuất. Catalog, sidecar XMP, cài đặt, DNG, merge, smart preview và bản sao khi nhập vẫn", + "first time you use an AI mask, LightCraft asks before downloading it, shows the progress, can cancel and resume,": "lần đầu dùng mặt nạ AI, LightCraft hỏi trước khi tải, hiện tiến trình, có thể hủy và tiếp tục,", "has the first date after the second": "ngày đầu sau ngày thứ hai", "how to restore it or delete it permanently and import it afresh. (For a fresh start on a photo, Reset Edits,": "cách khôi phục hoặc xóa vĩnh viễn và nhập lại. (Để bắt đầu lại trên ảnh, Đặt lại chỉnh sửa,", "import — so \"import complete\" means the copies are good before you format the card — and a name that is taken": "nhập — nên \"nhập xong\" nghĩa là bản sao ổn trước khi format thẻ — và tên đã được dùng", @@ -887,6 +974,7 @@ "needs two values": "cần hai giá trị", "never leaves a truncated file; the XMP sidecar of an \"Original\" export follows the \"If file exists\" choice too.": "không bao giờ để tệp cắt cụt; sidecar XMP của xuất \"Original\" cũng theo lựa chọn \"Nếu tệp đã tồn tại\".", "on the card after Review Import is reported instead of being imported with stale details. Checking an export path": "trên thẻ sau Xem lại nhập được báo thay vì nhập với chi tiết cũ. Kiểm tra đường dẫn xuất", + "part out), or type what to select (\"sky\", \"the red car\", \"car, road\"); both combine with other masks, have an": "một phần), hoặc gõ vùng cần chọn (\"sky\", \"the red car\", \"car, road\"); cả hai kết hợp mặt nạ khác, có", "photo has its denoised picture.": "ảnh đã có ảnh khử nhiễu.", "photos have their denoised picture.": "ảnh đã có ảnh khử nhiễu.", "pick": "đã chọn", From a1c85d4043a2995191d3e94b40be18a0df80da06 Mon Sep 17 00:00:00 2001 From: "DUY Tran Nhat (SAE-KIDS)" Date: Tue, 13 Oct 2026 15:54:00 +0700 Subject: [PATCH 015/350] i18n(vi): translate presets profiles and history --- crates/ui-egui/locales/vi.json | 101 +++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/crates/ui-egui/locales/vi.json b/crates/ui-egui/locales/vi.json index a89a48d41..92848b669 100644 --- a/crates/ui-egui/locales/vi.json +++ b/crates/ui-egui/locales/vi.json @@ -5,6 +5,7 @@ ", rejected": ", đã loại", "0: nothing is rejected.": "0: không loại gì.", "1620 × 1080 preview, and import with their metadata: capture time, camera, lens, exposure, GPS and XMP. Their raw": "xem trước 1620 × 1080 và nhập kèm metadata: thời gian chụp, máy ảnh, ống kính, phơi sáng, GPS và XMP. Raw của chúng", + "23 new built-in presets: Portrait, Landscape, Urban, Food, Seasons, Vintage and B&W toners.": "23 thiết lập sẵn tích hợp mới: Chân dung, Phong cảnh, Đô thị, Ẩm thực, Mùa, Cổ điển và toner Đen trắng.", "A blank template keeps the original names.": "Mẫu trống giữ tên gốc.", "A folder is already being synchronized": "Một thư mục đang được đồng bộ", "A folder is being synchronized": "Một thư mục đang được đồng bộ", @@ -19,6 +20,7 @@ "AI masks with SAM 3 (Object and Describe in the Masking panel): click an object to select it (⌥-click leaves a": "Mặt nạ AI với SAM 3 (Object và Describe trong bảng Mặt nạ): bấm vào đối tượng để chọn (⌥-click để lại", "About": "Giới thiệu", "About LightCraft": "Giới thiệu LightCraft", + "Activity": "Hoạt động", "Add Catchlight": "Thêm điểm sáng mắt", "Add Face Model…": "Thêm mô hình khuôn mặt…", "Add Folder to Local": "Thêm thư mục vào Cục bộ", @@ -64,8 +66,10 @@ "Appearance Settings…": "Cài đặt giao diện…", "Apply": "Áp dụng", "Apply Color Label Set": "Áp dụng bộ nhãn màu", + "Apply Filter Preset": "Áp dụng thiết lập sẵn bộ lọc", "Apply Metadata Preset": "Áp dụng thiết lập sẵn siêu dữ liệu", "Apply Point Curve Preset": "Áp dụng thiết lập sẵn đường cong điểm", + "Apply Preset": "Áp dụng thiết lập sẵn", "Apply the local tone mapping stored in the raw (Apple ProRAW), as the camera renders it": "Áp dụng ánh xạ tông cục bộ lưu trong raw (Apple ProRAW), như máy ảnh hiển thị", "Aqua Hue": "Hue ngọc lam", "Aqua Luminance": "Độ sáng ngọc lam", @@ -92,6 +96,7 @@ "Auto-Tag Photos from Tracklog": "Tự gắn thẻ ảnh từ nhật ký hành trình", "Auto-Tag from Tracklog": "Tự gắn thẻ từ nhật ký hành trình", "Auto-Tag from Tracklog…": "Tự gắn thẻ từ nhật ký hành trình…", + "Autumn Gold": "Vàng mùa thu", "B&W Mix": "Trộn B&W", "B&W Mixer": "Bộ trộn B&W", "Back": "Quay lại", @@ -100,9 +105,15 @@ "Back to this person": "Quay lại người này", "Background": "Nền", "Balance": "Cân bằng", + "Before/After (Y)": "Trước/Sau (Y)", + "Before/After Settings": "Cài đặt Trước/Sau", + "Before/After Split": "Chia Trước/Sau", + "Before/After Split Top/Bottom": "Chia Trước/Sau trên/dưới", + "Before/After Top/Bottom": "Trước/Sau trên/dưới", "Best of Similar Shots": "Ảnh đẹp nhất trong nhóm tương tự", "Black & White": "Đen trắng", "Blacks": "Vùng đen", + "Bleached": "Tẩy", "Blending": "Hòa trộn", "Blue": "Lam", "Blue Hour Boost": "Tăng giờ xanh", @@ -116,6 +127,7 @@ "Boundary Warp": "Biến dạng biên", "Browse Folder": "Duyệt thư mục", "Browse Folder…": "Duyệt thư mục…", + "Browse Profiles": "Duyệt hồ sơ", "Browser version (experimental), keeping a library safe (issue #107): File ▸ Back Up Library… downloads the catalog": "Phiên bản trình duyệt (thử nghiệm), giữ thư viện an toàn (issue #107): Tệp ▸ Sao lưu thư viện… tải catalog", "Brush": "Cọ", "Brush Settings": "Cài đặt cọ", @@ -135,6 +147,7 @@ "Captured": "Đã chụp", "Catalog Statistics": "Thống kê catalog", "Catchlight": "Điểm sáng mắt", + "Charcoal": "Than", "Choose Another Library…": "Chọn thư viện khác…", "Choose Denoise Model": "Chọn mô hình khử nhiễu", "Choose Edit Settings to Copy…": "Chọn cài đặt chỉnh sửa để sao chép…", @@ -143,13 +156,17 @@ "Choose a model below (Use) to start.": "Chọn một mô hình bên dưới (Dùng) để bắt đầu.", "Choose a photo in the grid or filmstrip": "Chọn một ảnh trên lưới hoặc dải phim", "Choose an album…": "Chọn một album…", + "Cinematic": "Điện ảnh", "City": "Thành phố", "Clarity": "Độ rõ", "Clear": "Xóa", "Clear Denoise Cache": "Xóa bộ nhớ đệm khử nhiễu", + "Clear History": "Xóa lịch sử", "Clear Quick Collection": "Xóa Bộ sưu tập nhanh", + "Clear Reference": "Xóa tham chiếu", "Clear rating": "Xóa xếp hạng", "Clear rating and advance": "Xóa xếp hạng và chuyển tiếp", + "Cleared History": "Đã xóa lịch sử", "Click to restore · double-click to rename": "Nhấp để khôi phục · nhấp đúp để đổi tên", "Clone": "Nhân bản vùng", "Close": "Đóng", @@ -174,6 +191,7 @@ "Convert to DNG, Copy as DNG, Photo Merge and smart previews no longer write straight to the final file (issue": "Chuyển sang DNG, Sao chép dạng DNG, Photo Merge và smart preview không còn ghi thẳng vào tệp cuối (issue", "Copy": "Sao chép", "Copy Edit Settings": "Sao chép cài đặt chỉnh sửa", + "Copy History Step Settings to Before": "Sao chép cài đặt bước lịch sử sang Trước", "Copy Metadata": "Sao chép siêu dữ liệu", "Copy Name": "Tên bản sao", "Copy as DNG": "Sao chép thành DNG", @@ -183,6 +201,7 @@ "Copyright": "Bản quyền", "Copyright Info URL": "URL thông tin bản quyền", "Copyright Status": "Trạng thái bản quyền", + "Copyright status, rights usage terms and copyright info URL in Info, metadata presets and exports.": "Trạng thái bản quyền, điều khoản sử dụng quyền và URL thông tin bản quyền trong Info, thiết lập metadata và xuất.", "Copyrighted": "Có bản quyền", "Country": "Quốc gia", "Create Album": "Tạo album", @@ -191,13 +210,19 @@ "Create Folder…": "Tạo thư mục…", "Create Keyword Tag": "Tạo thẻ từ khóa", "Create New Mask": "Tạo mặt nạ mới", + "Create Preset": "Tạo thiết lập sẵn", + "Create Preset…": "Tạo thiết lập sẵn…", "Create Smart Album": "Tạo album thông minh", "Create Smart Album from Filter…": "Tạo album thông minh từ bộ lọc…", "Create Smart Album…": "Tạo album thông minh…", "Create Stack": "Tạo chồng", + "Create Version": "Tạo phiên bản", + "Create Version from Step": "Tạo phiên bản từ bước", "Create Virtual Copy": "Tạo bản sao ảo", "Creator": "Người tạo", "Creator metadata": "Siêu dữ liệu người tạo", + "Crisp Landscape": "Phong cảnh sắc nét", + "Crisp Vista": "Tầm nhìn sắc nét", "Crop": "Cắt", "Crop & Rotate": "Cắt và xoay", "Crop & Rotate (C)": "Cắt và xoay (C)", @@ -227,6 +252,8 @@ "Delete Album": "Xóa album", "Delete All Masks": "Xóa mọi mặt nạ", "Delete Color Label Set": "Xóa bộ nhãn màu", + "Delete Export Preset": "Xóa thiết lập sẵn xuất", + "Delete Filter Preset": "Xóa thiết lập sẵn bộ lọc", "Delete Imported Profile": "Xóa hồ sơ đã nhập", "Delete Keyword": "Xóa từ khóa", "Delete Keyword Set": "Xóa bộ từ khóa", @@ -238,8 +265,10 @@ "Delete Point Color": "Xóa Point Color", "Delete Point Color Sample": "Xóa mẫu Point Color", "Delete Point Curve Preset": "Xóa thiết lập sẵn đường cong điểm", + "Delete Preset": "Xóa thiết lập sẵn", "Delete Red Eye": "Xóa mắt đỏ", "Delete Red Eye Correction": "Xóa sửa mắt đỏ", + "Delete Version": "Xóa phiên bản", "Delete mask": "Xóa mặt nạ", "Denoise Model Downloads": "Tải mô hình khử nhiễu", "Denoise Models": "Mô hình khử nhiễu", @@ -254,6 +283,8 @@ "Describe what to select": "Mô tả phần cần chọn", "Description": "Mô tả", "Deselect": "Bỏ chọn", + "Desert Heat": "Nóng sa mạc", + "Desert Warmth": "Ấm sa mạc", "Desktop": "Màn hình chính", "Detail": "Chi tiết", "Detail (D)": "Chi tiết (D)", @@ -293,6 +324,7 @@ "Edited": "Đã chỉnh sửa", "Empty Recently Deleted": "Dọn Đã xóa gần đây", "Enable Lens Corrections": "Bật hiệu chỉnh ống kính", + "Enable Profile Corrections": "Bật hiệu chỉnh theo hồ sơ", "English": "English", "Enter Full Screen": "Vào toàn màn hình", "Erase": "Xóa nét", @@ -302,13 +334,17 @@ "Expand All Stacks": "Mở rộng mọi chồng", "Expand Stack": "Mở rộng chồng", "Expand/Collapse Stack": "Mở rộng/Thu gọn chồng", + "Export Album with Preset": "Xuất album với thiết lập sẵn", "Export Containing Keywords": "Xuất từ khóa chứa", "Export Keywords": "Xuất từ khóa", "Export Keywords…": "Xuất từ khóa…", "Export Point Curve Presets": "Xuất thiết lập sẵn đường cong điểm", "Export Point Curve Presets…": "Xuất thiết lập sẵn đường cong điểm…", + "Export Presets": "Thiết lập sẵn xuất", "Export Presets…": "Xuất thiết lập sẵn…", "Export Synonyms": "Xuất từ đồng nghĩa", + "Export User Presets…": "Xuất thiết lập sẵn của người dùng…", + "Export with Preset": "Xuất với thiết lập sẵn", "Export with Previous": "Xuất với lần trước", "Export…": "Xuất…", "Exposure": "Phơi sáng", @@ -322,7 +358,12 @@ "Face recognition": "Nhận diện khuôn mặt", "Faces": "Khuôn mặt", "Faces of a Person": "Khuôn mặt của một người", + "Faded Matte": "Mờ matte", + "Faded Slide": "Slide phai", + "Faded Urban": "Đô thị phai", "Faster exports and card imports, with the same protection for what can't be recreated (issue #134): exports,": "Xuất và nhập thẻ nhanh hơn, với cùng mức bảo vệ cho dữ liệu không thể tạo lại (issue #134): xuất,", + "Favorite Preset": "Thiết lập sẵn yêu thích", + "Favorite Profile": "Hồ sơ yêu thích", "Favorites": "Yêu thích", "Feather": "Lông", "File": "Tệp", @@ -339,6 +380,7 @@ "Filter": "Bộ lọc", "Filter Bar": "Thanh bộ lọc", "Filter Keywords": "Lọc từ khóa", + "Filter Presets": "Thiết lập sẵn bộ lọc", "Find Missing Photos": "Tìm ảnh bị thiếu", "Find Missing Photos…": "Tìm ảnh bị thiếu…", "Find Similar Photos": "Tìm ảnh tương tự", @@ -362,6 +404,7 @@ "Folder": "Thư mục", "Folder name (renamed on disk; its photos follow)": "Tên thư mục (đổi tên trên đĩa; ảnh theo thư mục)", "Folders": "Thư mục", + "Food": "Ẩm thực", "Forget Unchanged Local Photos": "Quên ảnh cục bộ không đổi", "Forget unchanged photos": "Quên ảnh không đổi", "Fr": "T6", @@ -373,6 +416,9 @@ "Global Hue": "Sắc độ toàn cục", "Global Luminance": "Độ sáng toàn cục", "Global Saturation": "Độ bão hòa toàn cục", + "Go to History Step": "Đi tới bước Lịch sử", + "Golden Glow": "Ánh vàng", + "Golden Hour": "Giờ vàng", "Grain": "Hạt", "Green": "Lục", "Green Amount": "Lượng xanh lá", @@ -403,6 +449,8 @@ "Highlights Luminance": "Độ sáng vùng sáng", "Highlights Saturation": "Độ bão hòa vùng sáng", "Highlights split": "Tách vùng sáng", + "History": "Lịch sử", + "History & Activity (Y)": "Lịch sử & Hoạt động (Y)", "Home": "Thư mục Nhà", "Horizontal": "Ngang", "Horizontal inset (% of short edge)": "Lùi ngang (% cạnh ngắn)", @@ -464,6 +512,7 @@ "Install Face Model": "Cài mô hình khuôn mặt", "Install a denoise model to enable AI Denoise on this photo": "Cài mô hình khử nhiễu để bật AI Khử nhiễu cho ảnh này", "Install the SAM 3 Model": "Cài mô hình SAM 3", + "Instant ’70s": "Thập niên 70 tức thì", "Interface": "Giao diện", "Interface language": "Ngôn ngữ giao diện", "Intersect": "Giao", @@ -494,6 +543,7 @@ "Keywords you add appear here; ⌥1–⌥9 apply them.": "Từ khóa bạn thêm hiện ở đây; ⌥1–⌥9 áp dụng chúng.", "Label": "Nhãn", "Label Set": "Bộ nhãn", + "Landscape": "Ngang", "Landscape (wide)": "Ngang (rộng)", "Language": "Ngôn ngữ", "Last loupe render": "Lần kết xuất kính lúp gần nhất", @@ -509,6 +559,8 @@ "Library saved": "Đã lưu thư viện", "Light Theme": "Chủ đề sáng", "LightCraft Help": "Trợ giúp LightCraft", + "LightCraft Preset": "Thiết lập sẵn LightCraft", + "LightCraft Presets": "Thiết lập sẵn LightCraft", "LightCraft Website": "Trang web LightCraft", "LightCraft could not start": "LightCraft không thể khởi động", "LightCraft couldn't open the library at": "LightCraft không mở được thư viện tại", @@ -519,6 +571,9 @@ "Lights Out": "Tắt đèn", "Linear Gradient": "Chuyển sắc tuyến tính", "List Albums": "Liệt kê album", + "List History": "Liệt kê Lịch sử", + "List Presets": "Liệt kê thiết lập sẵn", + "List Profiles": "Liệt kê hồ sơ", "List this folder in Local from now on": "Liệt kê thư mục này trong Cục bộ từ nay", "Local folders": "Thư mục cục bộ", "Local library — no cloud account needed": "Thư viện cục bộ — không cần tài khoản đám mây", @@ -564,12 +619,16 @@ "Mo": "T2", "Monday": "Thứ Hai", "Month": "Tháng", + "Moody Portrait": "Chân dung u ám", "More": "Thêm", + "More preset options": "Thêm tùy chọn thiết lập sẵn", "Move Album": "Di chuyển album", "Move Down in Stack": "Di chuyển xuống trong chồng", "Move Folder": "Di chuyển thư mục", "Move Folder To…": "Di chuyển thư mục tới…", "Move Mask": "Di chuyển mặt nạ", + "Move Preset to Group": "Chuyển thiết lập sẵn vào nhóm", + "Move Preset to New Group": "Chuyển thiết lập sẵn vào nhóm mới", "Move Selected Photos Here": "Di chuyển ảnh đã chọn vào đây", "Move Up in Stack": "Di chuyển lên trong chồng", "Move the files (into the library's Originals/, or a folder you choose), removing them from the source": "Di chuyển tệp (vào Originals/ của thư viện hoặc thư mục bạn chọn), gỡ khỏi nguồn", @@ -594,7 +653,9 @@ "No Stars": "Không sao", "No albums match": "Không có album khớp", "No albums yet": "Chưa có album", + "No automatic versions.": "Không có phiên bản tự động.", "No exposure information": "Không có thông tin phơi sáng", + "No filter presets yet": "Chưa có thiết lập sẵn bộ lọc", "No imported folders yet": "Chưa có thư mục đã nhập", "No keywords are exported": "Không xuất từ khóa nào", "No keywords match": "Không có từ khóa khớp", @@ -603,8 +664,11 @@ "No metadata found": "Không tìm thấy siêu dữ liệu", "No named people in these photos": "Không có người được đặt tên trong các ảnh này", "No named people yet": "Chưa có người được đặt tên", + "No new presets": "Không có thiết lập sẵn mới", "No photo has it; the keywords below it go too.": "Không ảnh nào có nó; các từ khóa bên dưới cũng bị gỡ.", "No photos": "Không có ảnh", + "No reference photo": "Không có ảnh tham chiếu", + "No versions yet. Create one to keep this look.": "Chưa có phiên bản. Tạo một phiên bản để giữ diện mạo này.", "Noise Reduction": "Giảm nhiễu", "None": "Không có", "OK": "OK", @@ -648,12 +712,25 @@ "Point Curve": "Đường cong điểm", "Point Curve Presets": "Thiết lập sẵn đường cong điểm", "Point curve": "Đường cong điểm", + "Portrait": "Dọc", "Portrait (tall)": "Dọc (cao)", "Preferences": "Tùy chọn", "Preferences…": "Tùy chọn…", "Prepare AI Masks": "Chuẩn bị mặt nạ AI", + "Preset": "Thiết lập sẵn", + "Preset name": "Tên thiết lập sẵn", + "Presets": "Thiết lập sẵn", + "Presets & Profiles": "Thiết lập sẵn & Hồ sơ", + "Presets (Shift+P)": "Thiết lập sẵn (Shift+P)", + "Presets and profiles": "Thiết lập sẵn và hồ sơ", + "Presets ▾": "Thiết lập sẵn ▾", + "Profile": "Hồ sơ", + "Profile Browser": "Trình duyệt hồ sơ", "Profile Distortion": "Hồ sơ méo hình", + "Profile Menu": "Menu hồ sơ", "Profile Vignetting": "Hồ sơ tối góc", + "Profile:": "Hồ sơ:", + "Profiles": "Hồ sơ", "Public Domain": "Phạm vi công cộng", "Pupil Size": "Kích thước đồng tử", "Purge Unused Keywords": "Dọn từ khóa không dùng", @@ -665,6 +742,7 @@ "Purple Luminance": "Độ sáng tím", "Purple Saturation": "Độ bão hòa tím", "Put New Keywords Inside This Keyword": "Đặt từ khóa mới vào trong từ khóa này", + "Quick Develop": "Chỉnh nhanh", "Quit": "Thoát", "Quit LightCraft": "Thoát LightCraft", "Radial Gradient": "Chuyển sắc hướng tâm", @@ -690,7 +768,9 @@ "Red label": "Nhãn đỏ", "Red/Cyan Fringe": "Viền đỏ/lam", "Redo": "Làm lại", + "Reference": "Tham chiếu", "Reference View": "Xem tham chiếu", + "Reference the files where they are": "Tham chiếu tệp tại chỗ", "Refine AI Mask Detail": "Tinh chỉnh chi tiết mặt nạ AI", "Refine Mask Edges": "Tinh chỉnh cạnh mặt nạ", "Refine Saturation": "Tinh chỉnh độ bão hòa", @@ -730,8 +810,11 @@ "Reset Tone Curve": "Đặt lại đường cong tông màu", "Resize Face Box": "Đổi kích thước khung khuôn mặt", "Restore Library from Backup…": "Khôi phục thư viện từ bản sao lưu…", + "Restore Version": "Khôi phục phiên bản", "Restore keeps their edits; Import as new deletes the old record first.": "Khôi phục giữ chỉnh sửa; Nhập như mới xóa bản ghi cũ trước.", "Review Import": "Xem lại nhập", + "Right-click a photo ▸ Set as Reference Photo, then View → Reference View (Shift+R)": "Nhấp phải ảnh ▸ Đặt làm ảnh tham chiếu, rồi Xem → Chế độ tham chiếu (Shift+R)", + "Right-click a preset to delete it": "Nhấp phải thiết lập sẵn để xóa", "Rotate": "Xoay", "Rotate Crop": "Xoay vùng cắt", "Rotate Crop Aspect": "Xoay tỷ lệ cắt", @@ -747,18 +830,24 @@ "Saturday": "Thứ Bảy", "Save": "Lưu", "Save Color Label Set": "Lưu bộ nhãn màu", + "Save Current Filter as Preset…": "Lưu bộ lọc hiện tại thành thiết lập sẵn…", "Save Current Keywords as Set…": "Lưu từ khóa hiện tại thành bộ…", + "Save Export Preset": "Lưu thiết lập sẵn xuất", + "Save Filter Preset": "Lưu thiết lập sẵn bộ lọc", "Save Keyword Set": "Lưu bộ từ khóa", "Save Metadata Preset": "Lưu thiết lập sẵn siêu dữ liệu", "Save Metadata Preset…": "Lưu thiết lập sẵn siêu dữ liệu…", "Save Metadata to File": "Lưu siêu dữ liệu vào tệp", "Save Point Curve Preset": "Lưu thiết lập sẵn đường cong điểm", "Save Point Curve…": "Lưu đường cong điểm…", + "Save as Preset": "Lưu thành thiết lập sẵn", "Save as Smart Album…": "Lưu thành album thông minh…", + "Save preset": "Lưu thiết lập sẵn", "Saving Lightroom import index…": "Đang lưu chỉ mục nhập Lightroom…", "Scale": "Tỷ lệ", "Search": "Tìm kiếm", "Search albums": "Tìm album", + "Seasons": "Mùa", "Second Window": "Cửa sổ thứ hai", "Select All": "Chọn tất cả", "Select Luminance Range": "Chọn dải độ sáng", @@ -773,7 +862,9 @@ "Set Flag": "Đặt cờ", "Set Mask Adjustments": "Đặt điều chỉnh mặt nạ", "Set Point Curve": "Đặt đường cong điểm", + "Set Profile": "Đặt hồ sơ", "Set Rating": "Đặt xếp hạng", + "Set as Reference Photo": "Đặt làm ảnh tham chiếu", "Set up AI Denoise…": "Thiết lập AI Khử nhiễu…", "Settings": "Cài đặt", "Shadow": "Vùng tối", @@ -878,8 +969,17 @@ "Unknown": "Không rõ", "Unnamed Faces": "Khuôn mặt chưa đặt tên", "Update Mask Shape": "Cập nhật hình mặt nạ", + "Update Preset with Current Settings": "Cập nhật thiết lập sẵn bằng thiết lập hiện tại", + "Update Version": "Cập nhật phiên bản", + "Update Version with Current Settings": "Cập nhật phiên bản bằng thiết lập hiện tại", "Upright": "Chỉnh thẳng", + "Urban": "Đô thị", "Use Keyword Set": "Dùng bộ từ khóa", + "User Presets": "Thiết lập sẵn người dùng", + "Version": "Phiên bản", + "Version name": "Tên phiên bản", + "Versions": "Phiên bản", + "Versions (Shift+V)": "Phiên bản (Shift+V)", "Vertical": "Dọc", "Vertical inset (% of short edge)": "Lùi dọc (% cạnh ngắn)", "Vertical text": "Chữ dọc", @@ -893,6 +993,7 @@ "Virtual Copy": "Bản sao ảo", "Wait for the import to finish": "Đợi nhập hoàn tất", "Waiting to start…": "Đang chờ bắt đầu…", + "Warm Glow": "Ánh ấm", "Watched-folder auto import; Convert to DNG; Duplicate; Build Standard / 1:1 / Smart Previews.": "Tự động nhập thư mục theo dõi; Chuyển sang DNG; Nhân bản; Tạo Standard / 1:1 / Smart Preview.", "We": "T4", "Wednesday": "Thứ Tư", From 33527d26ef8b3f0631829d152e1617c9d1afea4b Mon Sep 17 00:00:00 2001 From: "DUY Tran Nhat (SAE-KIDS)" Date: Tue, 13 Oct 2026 15:54:00 +0700 Subject: [PATCH 016/350] i18n(vi): translate export merge and advanced workflows --- crates/ui-egui/locales/vi.json | 96 ++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/crates/ui-egui/locales/vi.json b/crates/ui-egui/locales/vi.json index 92848b669..18c193979 100644 --- a/crates/ui-egui/locales/vi.json +++ b/crates/ui-egui/locales/vi.json @@ -1,6 +1,7 @@ { " (library default)": " (mặc định thư viện)", " (inverted)": " (đã đảo)", + "(`gpuReason`, `gpuFallback`), Help ▸ System Info and Settings ▸ Performance say why the GPU isn't": "(`gpuReason`, `gpuFallback`), Trợ giúp ▸ Thông tin hệ thống và Cài đặt ▸ Hiệu năng giải thích vì sao GPU không", ", picked": ", đã chọn", ", rejected": ", đã loại", "0: nothing is rejected.": "0: không loại gì.", @@ -90,6 +91,7 @@ "Auto Import Settings": "Cài đặt tự nhập", "Auto Mask": "Tự tạo mặt nạ", "Auto Straighten": "Tự chỉnh thẳng", + "Auto Sync": "Tự đồng bộ", "Auto Sync: edits apply to every selected photo. Auto B&W mix. Automatic versions.": "Auto Sync: chỉnh sửa áp dụng cho mọi ảnh đã chọn. Auto B&W mix. Phiên bản tự động.", "Auto-Stack by Capture Time": "Tự xếp chồng theo thời gian chụp", "Auto-Stack by Capture Time…": "Tự xếp chồng theo thời gian chụp…", @@ -132,6 +134,11 @@ "Brush": "Cọ", "Brush Settings": "Cài đặt cọ", "Brush Stroke": "Nét cọ", + "Build Previews": "Tạo bản xem trước", + "Build Smart Previews": "Tạo smart preview", + "Building smart previews": "Đang tạo smart preview", + "CPU threads": "Luồng CPU", + "Cache": "Bộ nhớ đệm", "Camera": "Máy ảnh", "Camera Info": "Thông tin máy ảnh", "Camera local tone mapping": "Ánh xạ tông cục bộ của máy ảnh", @@ -160,10 +167,13 @@ "City": "Thành phố", "Clarity": "Độ rõ", "Clear": "Xóa", + "Clear Cache": "Xóa bộ nhớ đệm", "Clear Denoise Cache": "Xóa bộ nhớ đệm khử nhiễu", "Clear History": "Xóa lịch sử", + "Clear Preview Cache": "Xóa bộ nhớ đệm xem trước", "Clear Quick Collection": "Xóa Bộ sưu tập nhanh", "Clear Reference": "Xóa tham chiếu", + "Clear cache": "Xóa bộ nhớ đệm", "Clear rating": "Xóa xếp hạng", "Clear rating and advance": "Xóa xếp hạng và chuyển tiếp", "Cleared History": "Đã xóa lịch sử", @@ -212,6 +222,7 @@ "Create New Mask": "Tạo mặt nạ mới", "Create Preset": "Tạo thiết lập sẵn", "Create Preset…": "Tạo thiết lập sẵn…", + "Create Proof Copy": "Tạo bản sao proof", "Create Smart Album": "Tạo album thông minh", "Create Smart Album from Filter…": "Tạo album thông minh từ bộ lọc…", "Create Smart Album…": "Tạo album thông minh…", @@ -291,6 +302,8 @@ "Details": "Chi tiết", "Detect Faces": "Phát hiện khuôn mặt", "Develop": "Phát triển", + "Discard Preview Cache": "Hủy bộ nhớ đệm xem trước", + "Discarding smart previews": "Đang hủy smart preview", "Display": "Màn hình", "Display theme": "Chủ đề hiển thị", "Distortion": "Méoc", @@ -310,6 +323,7 @@ "Edit": "Chỉnh sửa", "Edit Color Label Names": "Sửa tên nhãn màu", "Edit Color Label Names…": "Sửa tên nhãn màu…", + "Edit Copy for External Editor": "Sửa bản sao cho trình chỉnh sửa ngoài", "Edit Date": "Ngày chỉnh sửa", "Edit Keyword Set": "Sửa bộ từ khóa", "Edit Keyword Tag": "Sửa thẻ từ khóa", @@ -320,6 +334,8 @@ "Edit Mask Component": "Sửa thành phần mặt nạ", "Edit Smart Album": "Chỉnh sửa album thông minh", "Edit Smart Album…": "Chỉnh sửa album thông minh…", + "Edit in External Editor": "Chỉnh trong trình ngoài", + "Edit in External Editor (⇧⌘E): a 16-bit TIFF copy, stacked, refreshed when you come back.": "Chỉnh trong trình soạn ngoài (⇧⌘E): bản sao TIFF 16 bit, xếp chồng, làm mới khi bạn quay lại.", "Edit settings copied": "Đã sao chép cài đặt chỉnh sửa", "Edited": "Đã chỉnh sửa", "Empty Recently Deleted": "Dọn Đã xóa gần đây", @@ -334,21 +350,32 @@ "Expand All Stacks": "Mở rộng mọi chồng", "Expand Stack": "Mở rộng chồng", "Expand/Collapse Stack": "Mở rộng/Thu gọn chồng", + "Export": "Xuất", "Export Album with Preset": "Xuất album với thiết lập sẵn", + "Export Album…": "Xuất album…", + "Export As…": "Xuất thành…", "Export Containing Keywords": "Xuất từ khóa chứa", + "Export Group…": "Xuất nhóm…", "Export Keywords": "Xuất từ khóa", "Export Keywords…": "Xuất từ khóa…", + "Export Now": "Xuất ngay", "Export Point Curve Presets": "Xuất thiết lập sẵn đường cong điểm", "Export Point Curve Presets…": "Xuất thiết lập sẵn đường cong điểm…", "Export Presets": "Thiết lập sẵn xuất", "Export Presets…": "Xuất thiết lập sẵn…", "Export Synonyms": "Xuất từ đồng nghĩa", "Export User Presets…": "Xuất thiết lập sẵn của người dùng…", + "Export stopped unexpectedly": "Xuất dừng đột ngột", "Export with Preset": "Xuất với thiết lập sẵn", "Export with Previous": "Xuất với lần trước", + "Exported files are written to a temp file and then renamed into place, so a full disk or an unplugged drive": "Tệp xuất được ghi vào tệp tạm rồi đổi tên vào vị trí, nên đĩa đầy hoặc ổ đã rút", + "Exporting": "Đang xuất", + "Exporting contact sheet": "Đang xuất tờ tiếp xúc", + "Exports are never black because of the GPU (issue #78): a GPU render that runs out of device": "Xuất không bao giờ đen vì GPU (issue #78): kết xuất GPU hết tài nguyên thiết bị", "Export…": "Xuất…", "Exposure": "Phơi sáng", "Exposure (shutter · aperture · ISO)": "Phơi sáng (cửa trập · khẩu độ · ISO)", + "External Editor": "Trình chỉnh sửa ngoài", "Face Boxes": "Khung khuôn mặt", "Face Model Downloads": "Tải mô hình khuôn mặt", "Face Models": "Mô hình khuôn mặt", @@ -410,6 +437,8 @@ "Fr": "T6", "Friday": "Thứ Sáu", "Full Screen Preview": "Xem trước toàn màn hình", + "GPU Rendering": "Kết xuất GPU", + "GPU rendering": "Kết xuất GPU", "General": "Chung", "Generated demo photo": "Ảnh demo được tạo", "Geometry": "Hình học", @@ -436,6 +465,17 @@ "Guided": "Có hướng dẫn", "Guided Upright": "Chỉnh thẳng có hướng dẫn", "Guided Upright Guides": "Đường hướng dẫn chỉnh thẳng", + "HDR Merge": "Ghép HDR", + "HDR Merge Preview": "Xem trước ghép HDR", + "HDR Panorama Merge": "Ghép panorama HDR", + "HDR Panorama Merge Preview": "Xem trước ghép panorama HDR", + "HDR Panorama with Last Settings": "Panorama HDR với thiết lập lần trước", + "HDR Panoramas": "Panorama HDR", + "HDR Panorama…": "Panorama HDR…", + "HDR panorama": "Panorama HDR", + "HDR panoramas": "Panorama HDR", + "HDR with Last Settings": "HDR với thiết lập lần trước", + "HDR…": "HDR…", "Has Edits": "Có chỉnh sửa", "Has GPS": "Có GPS", "Heal": "Sửa vết", @@ -494,6 +534,7 @@ "In a Stack": "Trong chồng", "In library": "Trong thư viện", "In-memory session: these settings last until LightCraft quits.": "Phiên trong bộ nhớ: các cài đặt này chỉ tồn tại đến khi LightCraft thoát.", + "Include on Export": "Bao gồm khi xuất", "Include selected photos": "Bao gồm ảnh đã chọn", "Include subfolders": "Bao gồm thư mục con", "Increase Brush Feather": "Tăng độ mềm cọ", @@ -546,6 +587,7 @@ "Landscape": "Ngang", "Landscape (wide)": "Ngang (rộng)", "Language": "Ngôn ngữ", + "Last GPU fallback": "Dự phòng GPU lần trước", "Last loupe render": "Lần kết xuất kính lúp gần nhất", "Lens": "Ống kính", "Lens Corrections": "Hiệu chỉnh ống kính", @@ -584,6 +626,7 @@ "Lock Crop Aspect": "Khóa tỷ lệ cắt", "Long Edge": "Cạnh dài", "Looking for photos…": "Đang tìm ảnh…", + "Lossy DNG files and Smart Previews open as raw photos.": "Tệp DNG có mất dữ liệu và Smart Preview mở như ảnh RAW.", "Luminance": "Độ sáng", "Luminance Range": "Dải độ sáng", "Luminar looks: `.lmp` files and `.mplumpack` collections import as presets (grouped by collection); the sliders": "Giao diện Luminar: tệp `.lmp` và bộ sưu tập `.mplumpack` nhập thành thiết lập sẵn (nhóm theo bộ sưu tập); các thanh trượt", @@ -601,8 +644,13 @@ "Match Total Exposures": "Khớp tổng phơi sáng", "Medium Contrast": "Tương phản trung bình", "Megapixels": "Megapixel", + "Memory for caches": "Bộ nhớ cho bộ nhớ đệm", "Menu": "Trình đơn", + "Merge": "Ghép", "Merge Keywords": "Gộp từ khóa", + "Merge into…": "Ghép vào…", + "Merged": "Đã ghép", + "Merged PRs": "PR đã gộp", "Metadata": "Siêu dữ liệu", "Metadata Preset": "Thiết lập sẵn siêu dữ liệu", "Metadata Presets": "Thiết lập sẵn siêu dữ liệu", @@ -668,6 +716,7 @@ "No photo has it; the keywords below it go too.": "Không ảnh nào có nó; các từ khóa bên dưới cũng bị gỡ.", "No photos": "Không có ảnh", "No reference photo": "Không có ảnh tham chiếu", + "No usable GPU found: rendering on the CPU": "Không tìm thấy GPU dùng được: kết xuất trên CPU", "No versions yet. Create one to keep this look.": "Chưa có phiên bản. Tạo một phiên bản để giữ diện mạo này.", "Noise Reduction": "Giảm nhiễu", "None": "Không có", @@ -677,6 +726,7 @@ "Offset X": "Độ lệch X", "Offset Y": "Độ lệch Y", "On NixOS, start it from `nix develop`.": "Trên NixOS, hãy khởi chạy từ `nix develop`.", + "Only photos whose AI Denoise amount is above 0 are made. Exports always make theirs if it is missing.": "Chỉ ảnh có lượng AI Denoise trên 0 mới được tạo. Xuất luôn tạo nếu thiếu.", "Open Library…": "Mở thư viện…", "Open Log Folder": "Mở thư mục nhật ký", "Open in Detail": "Mở chi tiết", @@ -685,8 +735,16 @@ "Orange Hue": "Sắc cam", "Orange Luminance": "Độ sáng cam", "Orange Saturation": "Độ bão hòa cam", + "Original offline · editing the smart preview": "Gốc ngoại tuyến · đang chỉnh smart preview", + "Original offline · no smart preview": "Gốc ngoại tuyến · không có smart preview", "Paint only areas like the one under the brush": "Chỉ tô vùng giống vùng dưới cọ", "Panels": "Các bảng", + "Panorama": "Toàn cảnh", + "Panorama Merge": "Ghép panorama", + "Panorama Merge Preview": "Xem trước ghép panorama", + "Panorama with Last Settings": "Panorama với thiết lập lần trước", + "Panoramas": "Panorama", + "Panorama…": "Toàn cảnh…", "Parametric curve": "Đường cong tham số", "Paste": "Dán", "Paste Edit Settings": "Dán cài đặt chỉnh sửa", @@ -700,6 +758,7 @@ "Pet Eye Catchlight": "Điểm sáng mắt thú cưng", "Photo": "Ảnh", "Photo Grid": "Lưới ảnh", + "Photo Merge": "Ghép ảnh", "Photos that arrive in this folder (tethering, a scanner, a sync app) are added as soon as they're complete.": "Ảnh đến thư mục này (tethering, máy quét, app đồng bộ) được thêm ngay khi hoàn tất.", "Photos); importing (also by drag and drop), Find Missing Photos, Build / Discard Smart Previews, the Rename preview,": "Ảnh); nhập (cả kéo thả), Tìm ảnh thiếu, Tạo / Hủy Smart Preview, xem trước Đổi tên,", "Pick": "Đã chọn", @@ -731,6 +790,7 @@ "Profile Vignetting": "Hồ sơ tối góc", "Profile:": "Hồ sơ:", "Profiles": "Hồ sơ", + "Proof copy created": "Đã tạo bản proof", "Public Domain": "Phạm vi công cộng", "Pupil Size": "Kích thước đồng tử", "Purge Unused Keywords": "Dọn từ khóa không dùng", @@ -900,7 +960,13 @@ "Slideshow": "Trình chiếu", "Smart Album": "Album thông minh", "Smart Album Rule Fields": "Trường quy tắc album thông minh", + "Smart Preview Status": "Trạng thái Smart Preview", + "Smart Previews Location": "Vị trí Smart Preview", + "Smart preview available": "Có smart preview", + "Smart previews": "Smart preview", + "Smart previews folder changed": "Đã đổi thư mục smart preview", "Smoothness": "Độ mịn", + "Soft Proofing": "Soft proofing", "Some rules need fixing (Edit Smart Album…):": "Một số quy tắc cần sửa (Chỉnh sửa album thông minh…):", "Source": "Nguồn", "Square": "Vuông", @@ -928,8 +994,13 @@ "Swap Aspect (X)": "Hoán đổi tỷ lệ (X)", "Swap Compare Photos": "Đổi chỗ ảnh so sánh", "Switch light / dark theme": "Chuyển chủ đề sáng / tối", + "Sync Settings": "Đồng bộ thiết lập", + "Sync with System": "Đồng bộ với hệ thống", + "Synchronize": "Đồng bộ hóa", "Synchronize Folder": "Đồng bộ thư mục", "Synchronize Folder…": "Đồng bộ thư mục…", + "Synchronizing folder": "Đang đồng bộ thư mục", + "Synchronizing…": "Đang đồng bộ…", "Synonyms": "Từ đồng nghĩa", "System Info…": "Thông tin hệ thống…", "Tags": "Thẻ", @@ -945,11 +1016,13 @@ "The SAM 3 model is installed: Object and Describe masks are ready.": "Đã cài mô hình SAM 3: Mặt nạ đối tượng và Mô tả đã sẵn sàng.", "The denoise model is installed and in use: the AI Denoise Amount slider under Detail now works": "Mô hình khử nhiễu đã cài và đang dùng: thanh AI Denoise Amount trong Chi tiết giờ hoạt động", "The import reads the catalog without changing it and adds its photos, edits, keywords and collections to the library open now.": "Nhập đọc catalog không đổi nó và thêm ảnh, chỉnh sửa, từ khóa và bộ sưu tập vào thư viện đang mở.", + "The thumbnail cache only ever counts and deletes its own files (issue #98): a library opened on a folder that": "Bộ nhớ đệm thumbnail chỉ đếm và xóa tệp của chính nó (issue #98): thư viện mở trên thư mục", "Theme": "Chủ đề", "This build cannot run denoise models.": "Bản build này không chạy được mô hình khử nhiễu.", "This group is empty: add a rule or remove it.": "Nhóm này trống: thêm quy tắc hoặc xóa nhóm.", "This is a Lightroom catalog, not a LightCraft library. Import it into a LightCraft library instead?": "Đây là catalog Lightroom, không phải thư viện LightCraft. Nhập vào thư viện LightCraft thay vì?", "This is the album you're editing": "Đây là album bạn đang chỉnh sửa", + "Thumbnail cache": "Bộ nhớ đệm hình thu nhỏ", "Thursday": "Thứ Năm", "Tint": "Tông", "Title": "Tiêu đề", @@ -972,9 +1045,11 @@ "Update Preset with Current Settings": "Cập nhật thiết lập sẵn bằng thiết lập hiện tại", "Update Version": "Cập nhật phiên bản", "Update Version with Current Settings": "Cập nhật phiên bản bằng thiết lập hiện tại", + "Updated the edits saved in the external editor": "Đã cập nhật chỉnh sửa lưu trong trình soạn ngoài", "Upright": "Chỉnh thẳng", "Urban": "Đô thị", "Use Keyword Set": "Dùng bộ từ khóa", + "Use the GPU for rendering": "Dùng GPU để kết xuất", "User Presets": "Thiết lập sẵn người dùng", "Version": "Phiên bản", "Version name": "Tên phiên bản", @@ -995,6 +1070,7 @@ "Waiting to start…": "Đang chờ bắt đầu…", "Warm Glow": "Ánh ấm", "Watched-folder auto import; Convert to DNG; Duplicate; Build Standard / 1:1 / Smart Previews.": "Tự động nhập thư mục theo dõi; Chuyển sang DNG; Nhân bản; Tạo Standard / 1:1 / Smart Preview.", + "Watermark": "Hình mờ", "We": "T4", "Wednesday": "Thứ Tư", "What's New": "Có gì mới", @@ -1002,6 +1078,7 @@ "White Balance Selector": "Bộ chọn cân bằng trắng", "White Balance Selector (W)": "Bộ chọn cân bằng trắng (W)", "Whites": "Vùng trắng", + "Will Export": "Sẽ xuất", "Window": "Cửa sổ", "XMP Sidecar Preferences": "Tùy chọn tệp sidecar XMP", "Year": "Năm", @@ -1015,22 +1092,30 @@ "Zoom In": "Phóng to", "Zoom Out": "Thu nhỏ", "Zoom to Fit": "Thu phóng vừa khung", + "a full drive) no longer counts as built and Build Smart Previews replaces it.": "ổ đầy) không còn được coi là đã tạo và Tạo Smart Preview thay thế.", + "again. Change the period (or turn it off) in Settings → Performance.": "lại. Đổi chu kỳ (hoặc tắt) trong Thiết lập → Hiệu năng.", + "already has a `thumbs/` folder of other pictures no longer loses them when the cache is trimmed or cleared.": "đã có thư mục `thumbs/` của ảnh khác không còn mất chúng khi cắt gọn hoặc xóa cache.", "and checks the file before using it. Masks keep their selection, so they render and export without the model.": "và kiểm tra tệp trước khi dùng. Mặt nạ giữ vùng chọn, nên kết xuất và xuất không cần mô hình.", "and every imported photo as one zip, and File ▸ Restore Library from Backup… brings it back (the current library": "và mọi ảnh đã nhập thành một zip, và Tệp ▸ Khôi phục thư viện từ bản sao lưu… đưa lại (thư viện hiện tại", "and never freezes the window. It is optional and not part of LightCraft (Meta's SAM License, about 3.4 GB): the": "và không bao giờ đóng băng cửa sổ. Tùy chọn và không thuộc LightCraft (SAM License của Meta, khoảng 3,4 GB):", "are empty": "trống", "aren't empty": "không trống", + "asked to. `LIGHTCRAFT_GPU_BACKEND=dx12 | vulkan | metal | off` (or wgpu's `WGPU_BACKEND`, which GPU rendering": "khi được hỏi. `LIGHTCRAFT_GPU_BACKEND=dx12 | vulkan | metal | off` (hoặc `WGPU_BACKEND` của wgpu, kết xuất GPU", "bundles of any of these — whole folders at once, grouped by pack. Masks inside presets come along.": "gói bất kỳ loại này — cả thư mục một lúc, nhóm theo pack. Mặt nạ trong thiết lập sẵn đi theo.", + "cached picture": "ảnh trong bộ nhớ đệm", + "cached pictures": "ảnh trong bộ nhớ đệm", "camera no longer gets baked in. Photos already imported as \"preview only\" switch over on Reload. (Files that": "máy ảnh không còn bị nướng vào. Ảnh đã nhập \"chỉ xem trước\" chuyển sang khi Tải lại. (Tệp", "can't be tested that way": "không thể kiểm tra theo cách đó", "can't match any rating from 0 to 5": "không khớp xếp hạng nào từ 0 đến 5", "can't test a folder; choose an album in it": "không thể kiểm tra thư mục; hãy chọn album bên trong", + "channel or MCP, a merge preview path or `lightcraft-cli render IMG.jpg -o IMG.jpg` is refused with a clear": "kênh hoặc MCP, đường dẫn xem trước merge hoặc `lightcraft-cli render IMG.jpg -o IMG.jpg` bị từ chối với thông báo rõ", "commercial use subject to GPL conditions": "dùng thương mại theo điều kiện GPL", "contains": "chứa", "copy is verified and in the library. Duplicates and files that fail stay where they were.": "bản sao được xác minh và có trong thư viện. Trùng lặp và tệp lỗi giữ nguyên chỗ.", "copyrighted": "có bản quyền", "data is not decoded yet, so they stay preview-only. For CR3s imported earlier, Photo ▸ Reload from Disk (now in": "dữ liệu chưa giải mã, nên vẫn chỉ xem trước. Với CR3 nhập trước đó, Ảnh ▸ Tải lại từ đĩa (giờ trong", "denoiseModel.accept": "denoiseModel.accept", + "discarding smart previews": "đang hủy smart preview", "doesn't contain": "không chứa", "e.g. sky · the red car · car, road": "vd. bầu trời · xe đỏ · xe, đường", "ends with": "kết thúc bằng", @@ -1038,9 +1123,12 @@ "first time you use an AI mask, LightCraft asks before downloading it, shows the progress, can cancel and resume,": "lần đầu dùng mặt nạ AI, LightCraft hỏi trước khi tải, hiện tiến trình, có thể hủy và tiếp tục,", "has the first date after the second": "ngày đầu sau ngày thứ hai", "how to restore it or delete it permanently and import it afresh. (For a fresh start on a photo, Reset Edits,": "cách khôi phục hoặc xóa vĩnh viễn và nhập lại. (Để bắt đầu lại trên ảnh, Đặt lại chỉnh sửa,", + "ignored before) chooses the graphics backend; `off` renders on the CPU. The GPU now starts after the window": "bỏ qua trước đó) chọn backend đồ họa; `off` kết xuất trên CPU. GPU giờ khởi động sau cửa sổ", "import — so \"import complete\" means the copies are good before you format the card — and a name that is taken": "nhập — nên \"nhập xong\" nghĩa là bản sao ổn trước khi format thẻ — và tên đã được dùng", "imported as \"preview only\" switch over on Reload.": "đã nhập \"chỉ xem trước\" chuyển sang khi Tải lại.", "imported earlier switch over with Photo ▸ Reload from Disk.": "nhập trước đó chuyển sang với Ảnh ▸ Tải lại từ đĩa.", + "in short pieces so slow integrated GPUs aren't reset by their watchdog. `ui.inspect` → `perf`": "theo đoạn ngắn để GPU tích hợp chậm không bị watchdog reset. `ui.inspect` → `perf`", + "incomplete is redone on the CPU — the file is the same image either way. Work is sent to the GPU": "chưa hoàn thành được làm lại trên CPU — tệp là cùng ảnh dù cách nào. Công việc gửi tới GPU", "is": "là", "is <": "<", "is >": ">", @@ -1050,6 +1138,7 @@ "is empty": "trống", "is in the last": "trong vòng", "is unknown": "không rõ", + "is up, and only when Settings ▸ Performance ▸ Use the GPU for rendering is on; if LightCraft ever dies while": "sẵn sàng, và chỉ khi Cài đặt ▸ Hiệu năng ▸ Dùng GPU để kết xuất bật; nếu LightCraft thoát đột ngột khi", "is yes or no": "là có hoặc không", "is ≤": "≤", "is ≥": "≥", @@ -1060,6 +1149,8 @@ "isn't one of the choices": "không phải một trong các lựa chọn", "longer just says \"duplicate skipped\": it opens the side panel on Recently Deleted with the photo selected and says": "không chỉ nói \"bỏ qua trùng\": mở bảng bên ở Đã xóa gần đây với ảnh được chọn và nói", "makes AI Denoise available": "cho phép dùng AI Khử nhiễu", + "memory, exceeds the GPU's buffer limits, hits a driver error or reset, or comes back": "bộ nhớ, vượt giới hạn buffer GPU, gặp lỗi driver hoặc reset, hoặc trả về", + "message, and the original is left byte for byte. Ordinary earlier exports are still overwritten when asked.": "thông báo, và bản gốc giữ nguyên byte for byte. Các lần xuất trước vẫn bị ghi đè khi được yêu cầu.", "names an album that no longer exists": "chỉ album không còn tồn tại", "needs a date like 2026, 2026-08 or 2026-08-14": "cần ngày như 2026, 2026-08 hoặc 2026-08-14", "needs a number": "cần một số", @@ -1079,14 +1170,19 @@ "photo has its denoised picture.": "ảnh đã có ảnh khử nhiễu.", "photos have their denoised picture.": "ảnh đã có ảnh khử nhiễu.", "pick": "đã chọn", + "preserving RAW editing & full-resolution export instead of using embedded JPEG previews.": "giữ chỉnh RAW và xuất full-resolution thay vì dùng xem trước JPEG nhúng.", "reject": "đã loại", "smart album value|No": "Không", "smart album value|Yes": "Có", + "smart previews": "smart preview", + "starting the GPU, the next launch starts with GPU rendering off and says how to turn it back on.": "khởi động GPU, lần mở sau bắt đầu với kết xuất GPU tắt và hướng dẫn bật lại.", "starts using it for AI Denoise": "bắt đầu dùng nó cho Khử nhiễu AI", "starts with": "bắt đầu bằng", "synced. Import ▸ Copy now checks each copy against the content hash taken while scanning the card instead of": "đồng bộ. Nhập ▸ Sao chép giờ kiểm tra mỗi bản sao với hash nội dung lấy khi quét thẻ thay vì", "the Local folder tree and Auto Import read the disk on worker threads too. The import progress window has Cancel.": "cây thư mục Local và Tự động nhập cũng đọc đĩa trên worker thread. Cửa sổ tiến trình nhập có Hủy.", "the camera; mapped-out sensor defects are filled in. `.rwl` and `.raw` files are imported too. Photos already": "máy ảnh; điểm lỗi cảm biến được lấp. Tệp `.rwl` và `.raw` cũng được nhập. Ảnh đã", + "the same name and \"Overwrite\" (or Export with Previous repeating it), an exact output path from the control": "cùng tên và \"Ghi đè\" (hoặc Xuất với Previous lặp lại), đường dẫn đầu ra chính xác từ kênh điều khiển", + "when the browser may evict the library. Hosting: the sample cache headers no longer mark the (unhashed) files": "khi trình duyệt có thể đuổi thư viện. Hosting: header cache mẫu không còn đánh dấu tệp (chưa hash)", "would make this album include itself through other smart albums": "sẽ khiến album này bao gồm chính nó qua album thông minh khác", "{date} is the capture time; a photo without one uses the time it was imported.": "{date} là thời gian chụp; ảnh không có thì dùng thời gian nhập.", "⌘-drag to straighten, ⇧G Guided Upright, a grid while transforming.": "⌘-kéo để chỉnh thẳng, ⇧G Chỉnh thẳng có hướng dẫn, lưới khi biến đổi.", From 84e9e909ede6b85b31bae66dc471167bc10188d8 Mon Sep 17 00:00:00 2001 From: "DUY Tran Nhat (SAE-KIDS)" Date: Tue, 13 Oct 2026 15:54:00 +0700 Subject: [PATCH 017/350] i18n(vi): complete help and residual catalog strings --- crates/ui-egui/locales/vi.json | 973 +++++++++++++++++++++++++++++++++ 1 file changed, 973 insertions(+) diff --git a/crates/ui-egui/locales/vi.json b/crates/ui-egui/locales/vi.json index 18c193979..8557b4f49 100644 --- a/crates/ui-egui/locales/vi.json +++ b/crates/ui-egui/locales/vi.json @@ -1,16 +1,37 @@ { " (library default)": " (mặc định thư viện)", " (inverted)": " (đã đảo)", + " · best of its burst": " · đẹp nhất trong cụm", + " · in a burst": " · trong một cụm", + "\"saved in memory but not written to disk\", the top bar shows a warning, and LightCraft keeps retrying until the": "\"được lưu trong bộ nhớ nhưng chưa ghi ra đĩa\", thanh trên cùng hiển thị cảnh báo và LightCraft tiếp tục thử lại cho đến khi", + "#106): a DNG is checked against the raw data, written to a temp file, synced and read back before it gets its": "#106): một DNG được đối chiếu với dữ liệu raw, ghi vào tệp tạm, đồng bộ và đọc lại trước khi nhận", + "% of all commits": "% tất cả commit", + "& Containing": "& Chứa", "(`gpuReason`, `gpuFallback`), Help ▸ System Info and Settings ▸ Performance say why the GPU isn't": "(`gpuReason`, `gpuFallback`), Trợ giúp ▸ Thông tin hệ thống và Cài đặt ▸ Hiệu năng giải thích vì sao GPU không", + "(e.g. D750, D780, D850, D7500, Z 50) no longer render nearly black or with crushed shadows: their black level was": "(ví dụ D750, D780, D850, D7500, Z 50) không còn hiển thị gần như đen hoặc vùng tối bị nén: mức đen của chúng đã được", + "(issue #94): an HTTP request from a web page can no longer carry a command in its body. Lines are capped at": "(issue #94): yêu cầu HTTP từ trang web không còn mang lệnh trong phần thân. Số dòng được giới hạn ở", + "+ Group": "+ Nhóm", + "+ Rule": "+ Quy tắc", ", picked": ", đã chọn", ", rejected": ", đã loại", "0: nothing is rejected.": "0: không loại gì.", + "1 day": "1 ngày", + "123 on studio-mac)\") instead of letting both write and silently drop each other's edits. A crash never leaves the": "123 on studio-mac)\") thay vì để cả hai ghi và lặng lẽ bỏ qua chỉnh sửa của nhau. Sự cố không bao giờ để lại", "1620 × 1080 preview, and import with their metadata: capture time, camera, lens, exposure, GPS and XMP. Their raw": "xem trước 1620 × 1080 và nhập kèm metadata: thời gian chụp, máy ảnh, ống kính, phơi sáng, GPS và XMP. Raw của chúng", + "2026-04 or 2026-04-12": "2026-04 hoặc 2026-04-12", "23 new built-in presets: Portrait, Landscape, Urban, Food, Seasons, Vintage and B&W toners.": "23 thiết lập sẵn tích hợp mới: Chân dung, Phong cảnh, Đô thị, Ẩm thực, Mùa, Cổ điển và toner Đen trắng.", + "4 MiB and connections at 16.": "4 MiB và tối đa 16 kết nối.", + "630 drivers): on Windows the window and GPU rendering use DirectX 12 only and never load the Vulkan driver unless": "630 drivers): trên Windows cửa sổ và kết xuất GPU chỉ dùng DirectX 12 và không tải driver Vulkan trừ khi", + "= exactly": "= đúng bằng", "A blank template keeps the original names.": "Mẫu trống giữ tên gốc.", + "A change that can't be saved to disk (full or unplugged drive) is no longer silent: the command reports": "Thay đổi không thể lưu ra đĩa (đĩa đầy hoặc đã rút) không còn im lặng: lệnh báo", + "A filter is hiding this view's photos: change it, or clear it (View → Clear Filters)": "Bộ lọc đang ẩn ảnh trong chế độ xem này: đổi bộ lọc hoặc xóa (Xem → Xóa bộ lọc)", "A folder is already being synchronized": "Một thư mục đang được đồng bộ", "A folder is being synchronized": "Một thư mục đang được đồng bộ", "A keyword set needs a name": "Bộ từ khóa cần một tên", + "A library is open in one program at a time (issue #99): opening a library that LightCraft or `lightcraft-cli` already": "Một thư viện chỉ mở trong một chương trình tại một thời điểm (issue #99): mở thư viện mà LightCraft hoặc `lightcraft-cli` đã", + "A one-time download of about": "Tải một lần khoảng", + "A save that fails part-way (a full disk, a network share that drops) no longer looks like a damaged catalog": "Lưu thất bại giữa chừng (đĩa đầy, ổ mạng bị ngắt) không còn trông như catalog bị hỏng", "A sleeping NAS, a dropped network share or a USB drive spinning up no longer freezes the window (issue #104):": "NAS đang ngủ, ổ mạng bị ngắt hoặc ổ USB đang quay lên không còn làm đóng băng cửa sổ (issue #104):", "AI Denoise": "Khử nhiễu AI", "AI Denoise Model": "Mô hình khử nhiễu AI", @@ -21,7 +42,11 @@ "AI masks with SAM 3 (Object and Describe in the Masking panel): click an object to select it (⌥-click leaves a": "Mặt nạ AI với SAM 3 (Object và Describe trong bảng Mặt nạ): bấm vào đối tượng để chọn (⌥-click để lại", "About": "Giới thiệu", "About LightCraft": "Giới thiệu LightCraft", + "Accept & Download": "Chấp nhận và tải", + "Active": "Đang dùng", "Activity": "Hoạt động", + "Actual size": "Kích thước thực", + "Add": "Thêm", "Add Catchlight": "Thêm điểm sáng mắt", "Add Face Model…": "Thêm mô hình khuôn mặt…", "Add Folder to Local": "Thêm thư mục vào Cục bộ", @@ -31,23 +56,36 @@ "Add Red Eye Correction": "Thêm sửa mắt đỏ", "Add Remove Spot": "Thêm điểm xóa", "Add Selected Photos": "Thêm ảnh đã chọn", + "Add a rule (⌥-click: a group)": "Thêm quy tắc (⌥-nhấp: một nhóm)", "Add in place": "Thêm tại chỗ", "Add in place: the library references the files where they are; nothing is copied or moved.": "Thêm tại chỗ: thư viện tham chiếu tệp ở vị trí hiện tại; không sao chép hay di chuyển gì.", "Add keyword": "Thêm từ khóa", + "Add number": "Thêm số", + "Add to": "Thêm vào", "Add to Album": "Thêm vào album", "Add to All Selected Photos": "Thêm vào mọi ảnh đã chọn", "Add to Apple Photos": "Thêm vào Ảnh Apple", + "Add to Favorites": "Thêm vào Yêu thích", + "Add to Local": "Thêm vào Cục bộ", "Add to My Photos": "Thêm vào Ảnh của tôi", "Add to My Photos First": "Thêm vào Ảnh của tôi trước", "Add to Selected Photos": "Thêm vào ảnh đã chọn", "Add to Target Album": "Thêm vào album đích", + "Add to favorites": "Thêm vào yêu thích", "Add to this mask": "Thêm vào mặt nạ này", "Add/Subtract/Intersect Mask": "Thêm/Trừ/Giao mặt nạ", "Added to photos you import that don't already have it.": "Được thêm vào ảnh bạn nhập nếu chưa có.", + "Adding": "Đang thêm", "Adding Lightroom photos…": "Đang thêm ảnh Lightroom…", "Adding photos…": "Đang thêm ảnh…", "Adding to Apple Photos": "Đang thêm vào Ảnh Apple", "Adding to Apple Photos…": "Đang thêm vào Ảnh Apple…", + "Advanced search…": "Tìm kiếm nâng cao…", + "After": "Sau", + "After 30 days": "Sau 30 ngày", + "After 7 days": "Sau 7 ngày", + "After 90 days": "Sau 90 ngày", + "After a year": "Sau một năm", "After installation, AI Denoise will turn on for the requesting photo.": "Sau khi cài, Khử nhiễu AI sẽ bật cho ảnh yêu cầu.", "Album": "Album", "Albums": "Album", @@ -56,65 +94,104 @@ "All Metadata": "Tất cả siêu dữ liệu", "All Metadata…": "Tất cả siêu dữ liệu…", "All Photos": "Tất cả ảnh", + "All rights reserved": "Đã đăng ký bản quyền", "All the photos imported from this disk are included.": "Tất cả ảnh nhập từ đĩa này đều được bao gồm.", + "All types": "Mọi loại", + "Already installed. Remove it before installing a replacement.": "Đã cài. Hãy gỡ trước khi cài bản thay thế.", "Alt Text": "Văn bản thay thế", + "Always": "Luôn luôn", + "Amount": "Độ mạnh", "Analyzing the photo for AI masks…": "Đang phân tích ảnh cho mặt nạ AI…", + "Angle": "Góc", "Any Searchable Text": "Mọi văn bản tìm được", + "Any camera": "Mọi máy ảnh", "Any keyword": "Mọi từ khóa", + "Any lens": "Mọi ống kính", "Aperture": "Khẩu độ", "Appearance": "Giao diện", "Appearance Mode": "Chế độ giao diện", "Appearance Settings…": "Cài đặt giao diện…", + "Application": "Ứng dụng", "Apply": "Áp dụng", "Apply Color Label Set": "Áp dụng bộ nhãn màu", "Apply Filter Preset": "Áp dụng thiết lập sẵn bộ lọc", "Apply Metadata Preset": "Áp dụng thiết lập sẵn siêu dữ liệu", "Apply Point Curve Preset": "Áp dụng thiết lập sẵn đường cong điểm", "Apply Preset": "Áp dụng thiết lập sẵn", + "Apply Settings JSON": "Áp dụng JSON cài đặt", "Apply the local tone mapping stored in the raw (Apple ProRAW), as the camera renders it": "Áp dụng ánh xạ tông cục bộ lưu trong raw (Apple ProRAW), như máy ảnh hiển thị", + "Approved": "Đã duyệt", + "Aqua": "Ngọc lam", "Aqua Hue": "Hue ngọc lam", "Aqua Luminance": "Độ sáng ngọc lam", "Aqua Saturation": "Độ bão hòa ngọc lam", + "Arrange Panel": "Sắp xếp bảng", "ArtCraft Website": "Trang web ArtCraft", + "ArtCraft — more creative apps": "ArtCraft — thêm ứng dụng sáng tạo", "As Shot": "Như khi chụp", "As shot": "Như khi chụp", + "Ascending": "Tăng dần", "Aspect": "Tỷ lệ", "Aspect Ratio": "Tỷ lệ khung hình", "Assisted Culling": "Sàng lọc hỗ trợ", + "Assisted Culling…": "Sàng lọc hỗ trợ…", "Auto": "Tự động", + "Auto Advance": "Tự chuyển tiếp", + "Auto Advance Off": "Tắt tự chuyển tiếp", + "Auto Advance On": "Bật tự chuyển tiếp", "Auto Advance after rating or flagging": "Tự chuyển tiếp sau khi xếp hạng hoặc gắn cờ", "Auto Advance: move to the next photo after rating or flagging": "Tự chuyển tiếp: sang ảnh tiếp theo sau khi xếp hạng hoặc gắn cờ", + "Auto Align": "Tự căn chỉnh", "Auto B&W Mix": "Tự trộn B&W", "Auto Crop": "Tự cắt", "Auto Import": "Tự nhập", "Auto Import Now": "Tự nhập ngay", "Auto Import Settings": "Cài đặt tự nhập", "Auto Mask": "Tự tạo mặt nạ", + "Auto Select": "Tự chọn", + "Auto Settings": "Cài đặt tự động", "Auto Straighten": "Tự chỉnh thẳng", "Auto Sync": "Tự đồng bộ", "Auto Sync: edits apply to every selected photo. Auto B&W mix. Automatic versions.": "Auto Sync: chỉnh sửa áp dụng cho mọi ảnh đã chọn. Auto B&W mix. Phiên bản tự động.", + "Auto settings applied": "Đã áp dụng cài đặt tự động", "Auto-Stack by Capture Time": "Tự xếp chồng theo thời gian chụp", "Auto-Stack by Capture Time…": "Tự xếp chồng theo thời gian chụp…", "Auto-Tag Photos from Tracklog": "Tự gắn thẻ ảnh từ nhật ký hành trình", "Auto-Tag from Tracklog": "Tự gắn thẻ từ nhật ký hành trình", + "Auto-Tag from Tracklog: GPS locations for your photos from a GPX track log, matched by capture time.": "Auto-Tag from Tracklog: vị trí GPS cho ảnh từ nhật ký track GPX, khớp theo thời gian chụp.", "Auto-Tag from Tracklog…": "Tự gắn thẻ từ nhật ký hành trình…", + "Automatic": "Tự động", + "Automatic renders the Detail view at the size it is shown, up to the photo's own pixels. Choose a size to cap it: smaller is faster.": "Tự động kết xuất chế độ xem Chi tiết đúng kích thước hiển thị, tối đa bằng pixel của ảnh. Chọn kích thước giới hạn: nhỏ hơn thì nhanh hơn.", + "Automatic uses the graphics card where it is faster than the processor: both are timed on this computer the first time a photo is made.": "Tự động dùng card đồ họa khi nhanh hơn bộ xử lý: cả hai được đo thời gian trên máy này lần đầu khi tạo ảnh.", + "Automatically Write Changes into XMP": "Tự ghi thay đổi vào XMP", + "Automatically write changes into XMP sidecars": "Tự ghi thay đổi vào sidecar XMP", "Autumn Gold": "Vàng mùa thu", + "B&W": "B&W", "B&W Mix": "Trộn B&W", "B&W Mixer": "Bộ trộn B&W", "Back": "Quay lại", "Back Up Library…": "Sao lưu thư viện…", + "Back to Edit": "Quay lại chỉnh sửa", + "Back to Edit (E)": "Quay lại chỉnh sửa (E)", "Back to Grid": "Quay lại lưới", "Back to this person": "Quay lại người này", "Background": "Nền", "Balance": "Cân bằng", + "Basic": "Cơ bản", + "Before": "Trước", "Before/After (Y)": "Trước/Sau (Y)", "Before/After Settings": "Cài đặt Trước/Sau", "Before/After Split": "Chia Trước/Sau", "Before/After Split Top/Bottom": "Chia Trước/Sau trên/dưới", "Before/After Top/Bottom": "Trước/Sau trên/dưới", + "Begin Interaction": "Bắt đầu tương tác", "Best of Similar Shots": "Ảnh đẹp nhất trong nhóm tương tự", + "Binary assets added": "Tài nguyên nhị phân đã thêm", + "Binary assets removed": "Tài nguyên nhị phân đã gỡ", + "Bit depth": "Độ sâu bit", "Black & White": "Đen trắng", "Blacks": "Vùng đen", + "Bleach Bypass": "Bleach Bypass", "Bleached": "Tẩy", "Blending": "Hòa trộn", "Blue": "Lam", @@ -126,87 +203,173 @@ "Blue channel": "Kênh xanh lam", "Blue label": "Nhãn lam", "Blue/Yellow Fringe": "Viền xanh lam/vàng", + "Blurry photos below the score are flagged as rejects.": "Ảnh mờ dưới điểm ngưỡng được gắn cờ đã loại.", "Boundary Warp": "Biến dạng biên", + "Bright & Airy": "Sáng và thoáng", + "Bring All to Front": "Đưa tất cả lên trước", + "Bring the library up to date with this folder and the folders inside it:": "Cập nhật thư viện theo thư mục này và các thư mục bên trong:", "Browse Folder": "Duyệt thư mục", "Browse Folder…": "Duyệt thư mục…", "Browse Profiles": "Duyệt hồ sơ", "Browser version (experimental), keeping a library safe (issue #107): File ▸ Back Up Library… downloads the catalog": "Phiên bản trình duyệt (thử nghiệm), giữ thư viện an toàn (issue #107): Tệp ▸ Sao lưu thư viện… tải catalog", + "Browse…": "Duyệt…", "Brush": "Cọ", "Brush Settings": "Cài đặt cọ", "Brush Stroke": "Nét cọ", "Build Previews": "Tạo bản xem trước", "Build Smart Previews": "Tạo smart preview", + "Building previews": "Đang tạo bản xem trước", "Building smart previews": "Đang tạo smart preview", + "By Date": "Theo ngày", + "By day (YYYY/YYYY-MM-DD)": "Theo ngày (YYYY/YYYY-MM-DD)", + "By month (YYYY/YYYY-MM)": "Theo tháng (YYYY/YYYY-MM)", "CPU threads": "Luồng CPU", "Cache": "Bộ nhớ đệm", + "Calibration": "Hiệu chỉnh", "Camera": "Máy ảnh", "Camera Info": "Thông tin máy ảnh", "Camera local tone mapping": "Ánh xạ tông cục bộ của máy ảnh", + "Camera make and model": "Hãng và model máy ảnh", "Cameras and Cards": "Máy ảnh và thẻ nhớ", "Cancel": "Hủy", "Cancel AI Mask Model Download": "Hủy tải mô hình mặt nạ AI", "Cancel Denoise": "Hủy khử nhiễu", "Cancel Denoise Model Download": "Hủy tải mô hình khử nhiễu", + "Cancel Download": "Hủy tải", "Cancel Face Model Download": "Hủy tải mô hình khuôn mặt", + "Cancel Interaction": "Hủy tương tác", "Cancel Pending Photo Action": "Hủy thao tác ảnh đang chờ", + "Cancel Preview Build": "Hủy tạo bản xem trước", + "Cancel pending action": "Hủy thao tác đang chờ", + "Candidate": "Ảnh ứng viên", + "Canon CR2 photos from the EOS 7D, 50D, 60D, 550D, 600D, 1200D, 1300D, 5D Mark II and 1D Mark IV (and other": "Ảnh Canon CR2 từ EOS 7D, 50D, 60D, 550D, 600D, 1200D, 1300D, 5D Mark II và 1D Mark IV (và các", + "Canon CR3 files show their full-size embedded JPEG (e.g. 6960 × 4640 on an EOS R6 Mark III) instead of the": "Tệp Canon CR3 hiển thị JPEG nhúng full-size (ví dụ 6960 × 4640 trên EOS R6 Mark III) thay vì", + "Canon EOS R5 Mark II C-RAW files that opened as \"preview only\" (more than half of them, depending on the": "Tệp Canon EOS R5 Mark II C-RAW từng mở ở chế độ \"chỉ xem trước\" (hơn một nửa, tùy", "Caption": "Chú thích", "Capture Date": "Ngày chụp", + "Capture date and time in your own format (directives below)": "Ngày giờ chụp theo định dạng của bạn (chỉ thị bên dưới)", + "Capture date as YYYYMMDD": "Ngày chụp dạng YYYYMMDD", "Captured": "Đã chụp", + "Captured from": "Chụp từ", + "Captured until": "Chụp đến", "Catalog Statistics": "Thống kê catalog", "Catchlight": "Điểm sáng mắt", + "Change": "Đổi", + "Change Component Mode": "Đổi chế độ thành phần", + "Characters not allowed in file names (/ \\ : * ? \" < > |) become -; an existing name gets -1, -2….": "Ký tự không hợp lệ trong tên tệp (/ \\ : * ? \" < > |) thành -; tên đã tồn tại thêm -1, -2….", "Charcoal": "Than", + "Check All": "Chọn tất cả", + "Check Output Path": "Kiểm tra đường dẫn xuất", + "Check the files of this type": "Chọn tệp loại này", + "Checking and installing the model…": "Đang kiểm tra và cài mô hình…", + "Checking names…": "Đang kiểm tra tên…", + "Checking…": "Đang kiểm tra…", "Choose Another Library…": "Chọn thư viện khác…", "Choose Denoise Model": "Chọn mô hình khử nhiễu", + "Choose Edit Settings to Copy": "Chọn cài đặt chỉnh sửa để sao chép", "Choose Edit Settings to Copy…": "Chọn cài đặt chỉnh sửa để sao chép…", "Choose Face Recognition Model": "Chọn mô hình nhận diện khuôn mặt", "Choose Folder…": "Chọn thư mục…", "Choose a model below (Use) to start.": "Chọn một mô hình bên dưới (Dùng) để bắt đầu.", "Choose a photo in the grid or filmstrip": "Chọn một ảnh trên lưới hoặc dải phim", "Choose an album…": "Chọn một album…", + "Choose…": "Chọn…", "Cinematic": "Điện ảnh", "City": "Thành phố", "Clarity": "Độ rõ", + "Clean Studio": "Studio sạch", "Clear": "Xóa", "Clear Cache": "Xóa bộ nhớ đệm", "Clear Denoise Cache": "Xóa bộ nhớ đệm khử nhiễu", + "Clear Filters": "Xóa bộ lọc", + "Clear Guides": "Xóa đường dẫn", "Clear History": "Xóa lịch sử", "Clear Preview Cache": "Xóa bộ nhớ đệm xem trước", "Clear Quick Collection": "Xóa Bộ sưu tập nhanh", + "Clear Recent Libraries": "Xóa thư viện gần đây", "Clear Reference": "Xóa tham chiếu", + "Clear all": "Xóa tất cả", "Clear cache": "Xóa bộ nhớ đệm", + "Clear form": "Xóa biểu mẫu", "Clear rating": "Xóa xếp hạng", "Clear rating and advance": "Xóa xếp hạng và chuyển tiếp", "Cleared History": "Đã xóa lịch sử", + "Click Zoom Ratio": "Tỷ lệ thu phóng khi nhấp", + "Click a shortcut, then press the new keys (Esc cancels).": "Nhấp một phím tắt, rồi nhấn tổ hợp mới (Esc để hủy).", + "Click a tag to insert it. Examples are for IMG_0042.CR3 taken 14 Jan 2026, 05:58:48.": "Bấm thẻ để chèn. Ví dụ cho IMG_0042.CR3 chụp 14 Jan 2026, 05:58:48.", + "Click photos in the grid to toggle the keyword; Esc stops": "Nhấp ảnh trên lưới để bật/tắt từ khóa; Esc dừng", + "Click the object to select it · ⌥-click leaves a part out": "Nhấp đối tượng để chọn · ⌥-nhấp để loại một phần", + "Click the photo to pick a colour · ⇧-click adds more": "Nhấp ảnh để chọn màu · ⇧-nhấp để thêm", + "Click the photo to pick a colour; ⇧-click adds more (up to 5)": "Nhấp ảnh để chọn màu; ⇧-nhấp để thêm (tối đa 5)", + "Click to clear these filters": "Nhấp để xóa các bộ lọc này", "Click to restore · double-click to rename": "Nhấp để khôi phục · nhấp đúp để đổi tên", + "Click to type a value": "Nhấp để nhập giá trị", "Clone": "Nhân bản vùng", "Close": "Đóng", + "Close Panel": "Đóng bảng", + "Close Window": "Đóng cửa sổ", + "Close all": "Đóng tất cả", + "Close file": "Đóng tệp", + "Close panel": "Đóng bảng", "Cloudy": "Nhiều mây", + "Cmd+Shift+R, keeps the photo and clears its edits.)": "Cmd+Shift+R, giữ ảnh và xóa chỉnh sửa.)", + "Collapse": "Thu gọn", "Collapse All Stacks": "Thu gọn mọi chồng", "Collapse Stack": "Thu gọn chồng", + "Color": "Màu", "Color Grading": "Phân cấp màu", "Color Label": "Nhãn màu", "Color Label Names": "Tên nhãn màu", "Color Label Sets": "Bộ nhãn màu", "Color Mixer": "Bộ trộn màu", "Color Noise Reduction": "Giảm nhiễu màu", + "Color Priority": "Ưu tiên màu", "Color Range": "Dải màu", "Color label cleared": "Đã xóa nhãn màu", + "Color space": "Không gian màu", + "Color space: sRGB (AVIF)": "Không gian màu: sRGB (AVIF)", + "Colors": "Màu sắc", + "Colour-label filter with several labels at once; expandable folder tree in Local.": "Lọc nhãn màu với nhiều nhãn cùng lúc; cây thư mục mở rộng trong Local.", "Colour-range masks: click the photo to sample. Luminance ranges: range bar, smoothness, luminance map.": "Mặt nạ vùng màu: bấm ảnh để lấy mẫu. Vùng độ sáng: thanh phạm vi, độ mượt, bản đồ độ sáng.", + "Combine files…": "Gộp tệp…", + "Command Journal": "Nhật ký lệnh", + "Comments panel": "Bảng bình luận", + "Commits": "Commit", + "Company": "Công ty", "Compare": "So sánh", + "Compare (Shift+C)": "So sánh (Shift+C)", + "Compare Before and After": "So sánh Trước và Sau", "Compare needs at least two photos": "So sánh cần ít nhất hai ảnh", + "Component options": "Tùy chọn thành phần", + "Compressed Nikon NEFs (lossless and lossy compressed, 12- and 14-bit — e.g. D3200, D5100, D7000, D750, D850, Z 50)": "Nikon NEF nén (nén không mất và có mất, 12 và 14 bit — ví dụ D3200, D5100, D7000, D750, D850, Z 50)", + "Compression": "Nén", + "Concrete Cool": "Bê tông lạnh", + "Confirm before deleting": "Xác nhận trước khi xóa", "Confirm before moving photos to Recently Deleted": "Xác nhận trước khi chuyển ảnh vào Đã xóa gần đây", "Constrain Crop": "Giới hạn cắt", + "Content-Aware": "Nhận biết nội dung", + "Continue": "Tiếp tục", + "Continue Without Saving": "Tiếp tục không lưu", "Contrast": "Tương phản", + "Contributors": "Người đóng góp", "Convert to DNG": "Chuyển sang DNG", "Convert to DNG, Copy as DNG, Photo Merge and smart previews no longer write straight to the final file (issue": "Chuyển sang DNG, Sao chép dạng DNG, Photo Merge và smart preview không còn ghi thẳng vào tệp cuối (issue", + "Cool Fade": "Phai lạnh", + "Cool Morning": "Sáng sớm lạnh", "Copy": "Sao chép", + "Copy After's Settings to Before": "Sao chép cài đặt Sau sang Trước", + "Copy Before to After": "Sao chép Trước sang Sau", + "Copy Before's Settings to After": "Sao chép cài đặt Trước sang Sau", "Copy Edit Settings": "Sao chép cài đặt chỉnh sửa", "Copy History Step Settings to Before": "Sao chép cài đặt bước lịch sử sang Trước", "Copy Metadata": "Sao chép siêu dữ liệu", "Copy Name": "Tên bản sao", "Copy as DNG": "Sao chép thành DNG", "Copy into the library (else use the files where they are)": "Sao chép vào thư viện (không thì dùng tệp tại chỗ)", + "Copy pages": "Sao chép trang", "Copy the files (into the library's Originals/, or a folder you choose)": "Sao chép tệp (vào Originals/ của thư viện, hoặc thư mục bạn chọn)", + "Copy to": "Sao chép tới", + "Copy to Clipboard": "Sao chép vào bảng tạm", "Copy: the files are copied to the folder below and the library uses the copies; the originals are left as they are.": "Sao chép: tệp được sao chép vào thư mục bên dưới và thư viện dùng bản sao; bản gốc giữ nguyên.", "Copyright": "Bản quyền", "Copyright Info URL": "URL thông tin bản quyền", @@ -214,12 +377,16 @@ "Copyright status, rights usage terms and copyright info URL in Info, metadata presets and exports.": "Trạng thái bản quyền, điều khoản sử dụng quyền và URL thông tin bản quyền trong Info, thiết lập metadata và xuất.", "Copyrighted": "Có bản quyền", "Country": "Quốc gia", + "Create": "Tạo", "Create Album": "Tạo album", "Create Album…": "Tạo album…", "Create Folder": "Tạo thư mục", "Create Folder…": "Tạo thư mục…", "Create Keyword Tag": "Tạo thẻ từ khóa", "Create New Mask": "Tạo mặt nạ mới", + "Create PDF from clipboard": "Tạo PDF từ bảng tạm", + "Create PDF from file…": "Tạo PDF từ tệp…", + "Create PDF from images…": "Tạo PDF từ ảnh…", "Create Preset": "Tạo thiết lập sẵn", "Create Preset…": "Tạo thiết lập sẵn…", "Create Proof Copy": "Tạo bản sao proof", @@ -240,17 +407,27 @@ "Crop Aspect": "Tỷ lệ cắt", "Crop, Rotate, Geometry": "Cắt, xoay, hình học", "Cropped": "Đã cắt", + "Cross Process": "Cross Process", + "Culling": "Sàng lọc", "Curve": "Đường cong", + "Custom": "Tùy chỉnh", "Custom template…": "Mẫu tùy chỉnh…", + "Custom…": "Tùy chỉnh…", "Cut": "Cắt", + "Cut pages": "Cắt trang", "Cycle Crop Overlay": "Chuyển lớp phủ cắt", "Cycle Crop Overlay Orientation": "Chuyển hướng lớp phủ cắt", "Cycle Info Overlay": "Chuyển lớp phủ thông tin", "Cycle Mask Overlay Color": "Chuyển màu lớp phủ mặt nạ", "Cycle Mask Overlay Mode": "Chuyển chế độ lớp phủ mặt nạ", + "Cylindrical": "Trụ", + "Dark & Moody": "Tối và trầm", + "Dark Mode": "Chế độ tối", "Dark Theme": "Chủ đề tối", + "Darken": "Làm tối", "Darks": "Vùng tối vừa", "Date": "Ngày", + "Date Groups": "Nhóm ngày", "Day": "Ngày", "Daylight": "Ánh sáng ban ngày", "Decrease Brush Feather": "Giảm lông cọ", @@ -258,11 +435,14 @@ "Decrease Rating": "Giảm xếp hạng", "Deep Sky": "Bầu trời sâu", "Defringe": "Khử viền màu", + "Deghost Amount": "Độ khử bóng ma", "Dehaze": "Khử sương mù", "Delete": "Xóa", + "Delete (⌫)": "Xóa (⌫)", "Delete Album": "Xóa album", "Delete All Masks": "Xóa mọi mặt nạ", "Delete Color Label Set": "Xóa bộ nhãn màu", + "Delete Component": "Xóa thành phần", "Delete Export Preset": "Xóa thiết lập sẵn xuất", "Delete Filter Preset": "Xóa thiết lập sẵn bộ lọc", "Delete Imported Profile": "Xóa hồ sơ đã nhập", @@ -271,6 +451,7 @@ "Delete Keyword…": "Xóa từ khóa…", "Delete Mask": "Xóa mặt nạ", "Delete Metadata Preset": "Xóa thiết lập sẵn siêu dữ liệu", + "Delete Permanently": "Xóa vĩnh viễn", "Delete Photo": "Xóa ảnh", "Delete Photos": "Xóa ảnh", "Delete Point Color": "Xóa Point Color", @@ -279,8 +460,12 @@ "Delete Preset": "Xóa thiết lập sẵn", "Delete Red Eye": "Xóa mắt đỏ", "Delete Red Eye Correction": "Xóa sửa mắt đỏ", + "Delete Spot": "Xóa điểm", "Delete Version": "Xóa phiên bản", + "Delete all": "Xóa tất cả", + "Delete all spots": "Xóa mọi điểm", "Delete mask": "Xóa mặt nạ", + "Delete them": "Xóa chúng", "Denoise Model Downloads": "Tải mô hình khử nhiễu", "Denoise Models": "Mô hình khử nhiễu", "Denoise Photos": "Khử nhiễu ảnh", @@ -289,11 +474,16 @@ "Denoise Status": "Trạng thái khử nhiễu", "Denoise all photos with an Amount": "Khử nhiễu mọi ảnh có Độ mạnh", "Density": "Mật độ", + "Depth Range": "Dải độ sâu", + "Descending": "Giảm dần", + "Describe": "Mô tả", "Describe what to keep": "Mô tả phần giữ lại", "Describe what to leave out": "Mô tả phần loại trừ", "Describe what to select": "Mô tả phần cần chọn", + "Describe…": "Mô tả…", "Description": "Mô tả", "Deselect": "Bỏ chọn", + "Deselect All": "Bỏ chọn tất cả", "Desert Heat": "Nóng sa mạc", "Desert Warmth": "Ấm sa mạc", "Desktop": "Màn hình chính", @@ -301,30 +491,50 @@ "Detail (D)": "Chi tiết (D)", "Details": "Chi tiết", "Detect Faces": "Phát hiện khuôn mặt", + "Detect Faces (Photo menu) needs it: a small one-time download.": "Phát hiện khuôn mặt (trình đơn Ảnh) cần nó: tải một lần, dung lượng nhỏ.", "Develop": "Phát triển", + "Diagonal": "Chéo", "Discard Preview Cache": "Hủy bộ nhớ đệm xem trước", "Discarding smart previews": "Đang hủy smart preview", "Display": "Màn hình", + "Display P3": "Display P3", + "Display name": "Tên hiển thị", "Display theme": "Chủ đề hiển thị", "Distortion": "Méoc", + "Document properties…": "Thuộc tính tài liệu…", + "Don't enlarge": "Không phóng to", "Done": "Xong", + "Download": "Tải xuống", "Download AI Mask Model": "Tải mô hình mặt nạ AI", "Download Denoise Model": "Tải mô hình khử nhiễu", "Download Face Model": "Tải mô hình khuôn mặt", + "Download Place Names (GeoNames)": "Tải tên địa điểm (GeoNames)", "Download the SAM 3 Model?": "Tải mô hình SAM 3?", + "Downloaded and checked. Installing…": "Đã tải và kiểm tra. Đang cài…", + "Downloading model": "Đang tải mô hình", + "Downloading place names": "Đang tải tên địa điểm", "Downloads": "Tải xuống", "Drag Crop Handle": "Kéo tay nắm cắt", + "Drag along the horizon; double-click for Auto": "Kéo theo đường chân trời; nhấp đúp để Tự động", "Drag over an eye on the photo; the pupil inside is found automatically.": "Kéo qua mắt trên ảnh; đồng tử bên trong được tìm tự động.", + "Draw Guides": "Vẽ đường dẫn", + "Drop here for the top level": "Thả vào đây cho cấp cao nhất", "Duplicate": "Nhân bản", "Duplicate Component": "Nhân bản thành phần", "Duplicate Mask": "Nhân bản mặt nạ", "Duplicate and Invert Mask": "Nhân bản và đảo mặt nạ", + "Each / starts a folder level; tags are filled in per photo (a level with missing metadata is \"unknown\").": "Mỗi / bắt đầu một cấp thư mục; thẻ được điền theo từng ảnh (cấp thiếu metadata là \"unknown\").", + "Edge": "Cạnh", "Edge setting, and get a sharper zoomed-in pass in the background. The model runs inside LightCraft in pure Rust": "Cài đặt Edge và nhận lượt phóng to sắc nét hơn ở nền. Mô hình chạy trong LightCraft bằng pure Rust", "Edit": "Chỉnh sửa", + "Edit (E)": "Chỉnh sửa (E)", + "Edit Capture Time": "Sửa thời gian chụp", + "Edit Capture Time…": "Sửa thời gian chụp…", "Edit Color Label Names": "Sửa tên nhãn màu", "Edit Color Label Names…": "Sửa tên nhãn màu…", "Edit Copy for External Editor": "Sửa bản sao cho trình chỉnh sửa ngoài", "Edit Date": "Ngày chỉnh sửa", + "Edit Info": "Thông tin chỉnh sửa", "Edit Keyword Set": "Sửa bộ từ khóa", "Edit Keyword Tag": "Sửa thẻ từ khóa", "Edit Keyword Tag…": "Sửa thẻ từ khóa…", @@ -332,21 +542,32 @@ "Edit Label Names…": "Sửa tên nhãn…", "Edit Mask": "Sửa mặt nạ", "Edit Mask Component": "Sửa thành phần mặt nạ", + "Edit Sections": "Các phần chỉnh sửa", + "Edit Set…": "Sửa bộ…", "Edit Smart Album": "Chỉnh sửa album thông minh", "Edit Smart Album…": "Chỉnh sửa album thông minh…", + "Edit Spot": "Sửa điểm", "Edit in External Editor": "Chỉnh trong trình ngoài", "Edit in External Editor (⇧⌘E): a 16-bit TIFF copy, stacked, refreshed when you come back.": "Chỉnh trong trình soạn ngoài (⇧⌘E): bản sao TIFF 16 bit, xếp chồng, làm mới khi bạn quay lại.", "Edit settings copied": "Đã sao chép cài đặt chỉnh sửa", "Edited": "Đã chỉnh sửa", + "Edited or not": "Đã chỉnh hoặc chưa", + "Editing": "Đang chỉnh sửa", + "Effect": "Hiệu ứng", + "Effects": "Hiệu ứng", "Empty Recently Deleted": "Dọn Đã xóa gần đây", "Enable Lens Corrections": "Bật hiệu chỉnh ống kính", "Enable Profile Corrections": "Bật hiệu chỉnh theo hồ sơ", + "End Interaction": "Kết thúc tương tác", "English": "English", "Enter Full Screen": "Vào toàn màn hình", + "Enter a date as YYYY-MM-DD HH:MM:SS": "Nhập ngày dạng YYYY-MM-DD HH:MM:SS", "Erase": "Xóa nét", "Evaluate Face Recognition": "Đánh giá nhận diện khuôn mặt", "Every EXIF, GPS and XMP field in the file": "Mọi trường EXIF, GPS và XMP trong tệp", + "Existing previews": "Bản xem trước hiện có", "Exit": "Thoát", + "Expand": "Mở rộng", "Expand All Stacks": "Mở rộng mọi chồng", "Expand Stack": "Mở rộng chồng", "Expand/Collapse Stack": "Mở rộng/Thu gọn chồng", @@ -365,16 +586,19 @@ "Export Presets…": "Xuất thiết lập sẵn…", "Export Synonyms": "Xuất từ đồng nghĩa", "Export User Presets…": "Xuất thiết lập sẵn của người dùng…", + "Export file names use the Rename Photos tokens ({title}, {seq:2}, {date:%Y-%m-%d}…), plus new {num}, {folder}, {lens}, {iso}, {rating}, {creator}.": "Tên tệp xuất dùng token Đổi tên ảnh ({title}, {seq:2}, {date:%Y-%m-%d}…), cùng {num}, {folder}, {lens}, {iso}, {rating}, {creator} mới.", "Export stopped unexpectedly": "Xuất dừng đột ngột", "Export with Preset": "Xuất với thiết lập sẵn", "Export with Previous": "Xuất với lần trước", "Exported files are written to a temp file and then renamed into place, so a full disk or an unplugged drive": "Tệp xuất được ghi vào tệp tạm rồi đổi tên vào vị trí, nên đĩa đầy hoặc ổ đã rút", "Exporting": "Đang xuất", "Exporting contact sheet": "Đang xuất tờ tiếp xúc", + "Exports and renders never write over a photo's original (issue #93): exporting into the photo's own folder with": "Xuất và kết xuất không bao giờ ghi đè bản gốc của ảnh (issue #93): xuất vào thư mục của ảnh với", "Exports are never black because of the GPU (issue #78): a GPU render that runs out of device": "Xuất không bao giờ đen vì GPU (issue #78): kết xuất GPU hết tài nguyên thiết bị", "Export…": "Xuất…", "Exposure": "Phơi sáng", "Exposure (shutter · aperture · ISO)": "Phơi sáng (cửa trập · khẩu độ · ISO)", + "Extended Description": "Mô tả mở rộng", "External Editor": "Trình chỉnh sửa ngoài", "Face Boxes": "Khung khuôn mặt", "Face Model Downloads": "Tải mô hình khuôn mặt", @@ -382,73 +606,121 @@ "Face Recognition On/Off": "Bật/tắt nhận diện khuôn mặt", "Face boxes": "Khung khuôn mặt", "Face detector": "Bộ phát hiện khuôn mặt", + "Face names written to XMP by Lightroom and other apps show up here.": "Tên khuôn mặt ghi vào XMP bởi Lightroom và ứng dụng khác hiện ở đây.", "Face recognition": "Nhận diện khuôn mặt", "Faces": "Khuôn mặt", "Faces of a Person": "Khuôn mặt của một người", "Faded Matte": "Mờ matte", "Faded Slide": "Slide phai", "Faded Urban": "Đô thị phai", + "Failed": "Thất bại", + "Failed its last test": "Lần thử gần nhất thất bại", "Faster exports and card imports, with the same protection for what can't be recreated (issue #134): exports,": "Xuất và nhập thẻ nhanh hơn, với cùng mức bảo vệ cho dữ liệu không thể tạo lại (issue #134): xuất,", "Favorite Preset": "Thiết lập sẵn yêu thích", "Favorite Profile": "Hồ sơ yêu thích", "Favorites": "Yêu thích", "Feather": "Lông", "File": "Tệp", + "File & date": "Tệp và ngày", "File Extension": "Phần mở rộng tệp", "File Format": "Định dạng tệp", + "File Name": "Tên tệp", "File Path": "Đường dẫn tệp", + "File Size": "Kích thước tệp", "File Type": "Loại tệp", + "File name": "Tên tệp", + "File types:": "Loại tệp:", "Filename": "Tên tệp", "Files with the same content as another file in this import: only the first is imported.": "Tệp trùng nội dung với tệp khác trong lần nhập này: chỉ tệp đầu được nhập.", + "Fill": "Lấp đầy", + "Fill Edges": "Lấp cạnh", "Fill Location": "Điền vị trí", "Fill Location from GPS": "Điền vị trí từ GPS", + "Fill empty City, State and Country from GPS (offline GeoNames place names)": "Điền Thành phố, Bang và Quốc gia trống từ GPS (tên địa danh GeoNames ngoại tuyến)", + "Film": "Phim", "Filmstrip": "Dải phim", "Filmstrip (/)": "Dải phim (/)", "Filter": "Bộ lọc", "Filter Bar": "Thanh bộ lọc", "Filter Keywords": "Lọc từ khóa", "Filter Presets": "Thiết lập sẵn bộ lọc", + "Filter bar": "Thanh bộ lọc", + "Filter fields": "Trường bộ lọc", + "Find Dust Spots": "Tìm điểm bụi", "Find Missing Photos": "Tìm ảnh bị thiếu", "Find Missing Photos…": "Tìm ảnh bị thiếu…", "Find Similar Photos": "Tìm ảnh tương tự", "Find photos added to or missing from this folder on disk, and XMP sidecars changed by other apps": "Tìm ảnh được thêm hoặc thiếu trong thư mục trên đĩa, và sidecar XMP bị ứng dụng khác sửa", + "Find tools and commands…": "Tìm công cụ và lệnh…", "Finding faces": "Đang tìm khuôn mặt", "Find…": "Tìm…", + "First": "Đầu tiên", + "First commit": "Commit đầu tiên", + "Fit": "Vừa khung", + "Fit (F)": "Vừa khung (F)", + "Fit on Screen": "Vừa màn hình", + "Fit to width": "Vừa chiều rộng", + "Fit visible": "Vừa phần hiển thị", "Five stars": "Năm sao", "Fix the marked rules to save this album.": "Sửa các quy tắc đã đánh dấu để lưu album này.", + "Fixed keys": "Phím cố định", "Flag": "Gắn cờ", "Flag as Pick": "Gắn cờ Đã chọn", "Flag as Reject": "Gắn cờ Đã loại", "Flagged as Pick": "Đã gắn cờ Đã chọn", "Flagged as Reject": "Đã gắn cờ Đã loại", "Flash": "Đèn flash", + "Flip H": "Lật ngang", "Flip Horizontal": "Lật ngang", + "Flip Overlay (⇧O)": "Lật lớp phủ (⇧O)", + "Flip V": "Lật dọc", "Flip Vertical": "Lật dọc", + "Float panel": "Bảng nổi", "Flow": "Dòng cọ", "Fluorescent": "Huỳnh quang", "Focal Length": "Tiêu cự", + "Focal length": "Tiêu cự", "Focus (assisted culling)": "Lấy nét (sàng lọc hỗ trợ)", "Folder": "Thư mục", "Folder name (renamed on disk; its photos follow)": "Tên thư mục (đổi tên trên đĩa; ảnh theo thư mục)", "Folders": "Thư mục", + "Folders and {date} use the capture time; a photo without one uses today's date.": "Thư mục và {date} dùng thời gian chụp; ảnh không có thì dùng ngày hôm nay.", "Food": "Ẩm thực", "Forget Unchanged Local Photos": "Quên ảnh cục bộ không đổi", "Forget unchanged photos": "Quên ảnh không đổi", + "Form fields panel": "Bảng trường biểu mẫu", + "Format": "Định dạng", + "Forward": "Tiến", "Fr": "T6", + "Frame time": "Thời gian khung", + "Frame update": "Cập nhật khung", + "Free": "Tự do", + "Fresh & Bright": "Tươi sáng", "Friday": "Thứ Sáu", + "Full": "Đầy đủ", "Full Screen Preview": "Xem trước toàn màn hình", + "Full screen mode": "Chế độ toàn màn hình", + "Full size": "Kích thước đầy đủ", + "GPS Track Log": "Nhật ký theo dõi GPS", "GPU Rendering": "Kết xuất GPU", "GPU rendering": "Kết xuất GPU", "General": "Chung", "Generated demo photo": "Ảnh demo được tạo", "Geometry": "Hình học", + "Get Develop Settings": "Lấy thiết lập chỉnh sửa", "Global Hue": "Sắc độ toàn cục", "Global Luminance": "Độ sáng toàn cục", "Global Saturation": "Độ bão hòa toàn cục", + "Glossy": "Bóng", + "Go back to listing them by name": "Quay lại liệt kê theo tên", "Go to History Step": "Đi tới bước Lịch sử", + "Golden": "Vàng", "Golden Glow": "Ánh vàng", "Golden Hour": "Giờ vàng", + "Grab bag": "Tạp hợp", "Grain": "Hạt", + "Graphic": "Đồ họa", + "Graphics card": "Card đồ họa", "Green": "Lục", "Green Amount": "Lượng xanh lá", "Green Hue": "Sắc xanh lá", @@ -461,7 +733,15 @@ "Green label": "Nhãn lục", "Grid": "Lưới", "Grid Info": "Thông tin lưới", + "Gritty Street": "Phố sần sùi", + "Group": "Nhóm", + "Group by Date: Automatic": "Nhóm theo ngày: Tự động", + "Group by Day": "Nhóm theo ngày", + "Group by Month": "Nhóm theo tháng", + "Group by Year": "Nhóm theo năm", + "Group by date": "Nhóm theo ngày", "Group into Stack": "Gom thành chồng", + "Group name": "Tên nhóm", "Guided": "Có hướng dẫn", "Guided Upright": "Chỉnh thẳng có hướng dẫn", "Guided Upright Guides": "Đường hướng dẫn chỉnh thẳng", @@ -480,8 +760,15 @@ "Has GPS": "Có GPS", "Heal": "Sửa vết", "Heal the small, soft dark spots sensor dust leaves on smooth areas": "Sửa các điểm tối nhỏ, mềm do bụi cảm biến để lại trên vùng mịn", + "Height": "Chiều cao", + "Height (px)": "Chiều cao (px)", "Help": "Trợ giúp", + "Hide LightCraft": "Ẩn LightCraft", "Hide Mask": "Ẩn mặt nạ", + "Hide Others": "Ẩn ứng dụng khác", + "Hide This Section": "Ẩn mục này", + "Hides this shortcut only; the folder and its photos stay as they are": "Chỉ ẩn lối tắt này; thư mục và ảnh trong đó giữ nguyên", + "High": "Cao", "High Contrast B&W": "B&W tương phản cao", "Highlight": "Vùng sáng", "Highlights": "Vùng sáng", @@ -489,16 +776,22 @@ "Highlights Luminance": "Độ sáng vùng sáng", "Highlights Saturation": "Độ bão hòa vùng sáng", "Highlights split": "Tách vùng sáng", + "Histogram": "Biểu đồ histogram", "History": "Lịch sử", "History & Activity (Y)": "Lịch sử & Hoạt động (Y)", "Home": "Thư mục Nhà", "Horizontal": "Ngang", "Horizontal inset (% of short edge)": "Lùi ngang (% cạnh ngắn)", "Horizontal text": "Chữ ngang", + "Hours": "Giờ", + "How to install the model": "Cách cài mô hình", "Hue": "Sắc độ", "Hue Range": "Dải sắc độ", + "I have read these terms and accept them for my own use": "Tôi đã đọc các điều khoản này và chấp nhận cho việc sử dụng của mình", "ISO Speed": "Tốc độ ISO", + "ISO speed": "Tốc độ ISO", "If file exists": "Nếu tệp đã tồn tại", + "If your library can't be opened at launch (open in another program, unreadable, on a drive that isn't connected,": "Nếu thư viện không mở được khi khởi động (đang mở ở chương trình khác, không đọc được, trên ổ chưa kết nối,", "Image": "Ảnh", "Import": "Nhập", "Import Date": "Ngày nhập", @@ -530,9 +823,14 @@ "Importing Lightroom catalog": "Đang nhập catalog Lightroom", "Importing scans the source for photos; it doesn't add the folder to Local (use Local → Browse Folder… to work in a folder without importing).": "Nhập quét nguồn để tìm ảnh; không thêm thư mục vào Local (dùng Local → Duyệt thư mục… để làm việc trong thư mục mà không nhập).", "In Color": "Màu", + "In Photo Grid and Square Grid: Flag as Pick and advance": "Trong Lưới ảnh và Lưới vuông: Gắn cờ Đã chọn và chuyển tiếp", + "In Photo Grid and Square Grid: expand or collapse the stack": "Trong Lưới ảnh và Lưới vuông: mở rộng hoặc thu gọn chồng", "In Recently Deleted": "Trong Đã xóa gần đây", + "In Use": "Đang dùng", "In a Stack": "Trong chồng", "In library": "Trong thư viện", + "In memory — nothing is saved": "Trong bộ nhớ — chưa lưu gì", + "In use": "Đang dùng", "In-memory session: these settings last until LightCraft quits.": "Phiên trong bộ nhớ: các cài đặt này chỉ tồn tại đến khi LightCraft thoát.", "Include on Export": "Bao gồm khi xuất", "Include selected photos": "Bao gồm ảnh đã chọn", @@ -543,7 +841,12 @@ "Index Faces": "Lập chỉ mục khuôn mặt", "Index Faces in the Background": "Lập chỉ mục khuôn mặt nền", "Info": "Thông tin", + "Info (I)": "Thông tin (I)", + "Info Overlay Off": "Tắt lớp phủ thông tin", "Info Overlay: Exposure": "Lớp phủ thông tin: Phơi sáng", + "Info Overlay: File": "Lớp phủ thông tin: Tệp", + "Info overlay": "Lớp phủ thông tin", + "Insert at the cursor": "Chèn tại con trỏ", "Inspect Denoise Model": "Kiểm tra mô hình khử nhiễu", "Inspect Face Model File": "Kiểm tra tệp mô hình khuôn mặt", "Inspect Lightroom Catalog": "Kiểm tra catalog Lightroom", @@ -552,8 +855,11 @@ "Install Denoise Model": "Cài mô hình khử nhiễu", "Install Face Model": "Cài mô hình khuôn mặt", "Install a denoise model to enable AI Denoise on this photo": "Cài mô hình khử nhiễu để bật AI Khử nhiễu cho ảnh này", + "Install from file…": "Cài từ tệp…", "Install the SAM 3 Model": "Cài mô hình SAM 3", + "Install your own ONNX model with denoise-model.json beside it. This build offers no model downloads.": "Cài mô hình ONNX của bạn kèm denoise-model.json bên cạnh. Bản build này không tải mô hình.", "Instant ’70s": "Thập niên 70 tức thì", + "Intent:": "Ý định:", "Interface": "Giao diện", "Interface language": "Ngôn ngữ giao diện", "Intersect": "Giao", @@ -563,7 +869,15 @@ "Invert Component": "Đảo thành phần", "Invert Mask": "Đảo mặt nạ", "It tests this album, so testing it back would loop": "Nó kiểm tra album này, nên kiểm tra ngược lại sẽ tạo vòng lặp", + "Its denoised picture is not made yet, and pictures are not made on their own (Settings, AI Denoise).": "Ảnh đã khử nhiễu chưa được tạo, và ảnh không tự tạo (Cài đặt, AI Denoise).", + "JPEG (Large)": "JPEG (Lớn)", + "JPEG (Small)": "JPEG (Nhỏ)", + "JPEG with the same name (`IMG_0001.CR3` + `IMG_0001.JPG`) no longer share one sidecar: the raw keeps `IMG_0001.xmp`,": "JPEG cùng tên (`IMG_0001.CR3` + `IMG_0001.JPG`) không còn dùng chung một sidecar: raw giữ `IMG_0001.xmp`,", + "Join the ArtCraft Discord": "Tham gia Discord ArtCraft", "Join the ArtCraft Discord…": "Tham gia Discord ArtCraft…", + "Join the ArtCraft community on Discord": "Tham gia cộng đồng ArtCraft trên Discord", + "Keep in Local": "Giữ trong Local", + "Keep it on a drive with room: smart previews are about 1 MB per photo. The thumbnail cache stays in the library.": "Giữ trên ổ còn dung lượng: smart preview khoảng 1 MB mỗi ảnh. Bộ nhớ đệm thumbnail nằm trong thư viện.", "Keyboard Shortcuts": "Phím tắt", "Keyboard shortcuts": "Phím tắt", "Keyword": "Từ khóa", @@ -587,10 +901,19 @@ "Landscape": "Ngang", "Landscape (wide)": "Ngang (rộng)", "Language": "Ngôn ngữ", + "Last": "Cuối", "Last GPU fallback": "Dự phòng GPU lần trước", + "Last commit": "Commit cuối", "Last loupe render": "Lần kết xuất kính lúp gần nhất", + "Last view": "Lần xem trước", + "Lateral Chromatic Aberration": "Quang sai sắc ngang", + "Layer": "Lớp", + "Layers": "Lớp", + "Leave them": "Giữ nguyên", "Lens": "Ống kính", + "Lens Blur": "Làm mờ ống kính", "Lens Corrections": "Hiệu chỉnh ống kính", + "Level": "Mức", "Library": "Thư viện", "Library Folders": "Thư mục thư viện", "Library Info": "Thông tin thư viện", @@ -599,51 +922,88 @@ "Library State": "Trạng thái thư viện", "Library name": "Tên thư viện", "Library saved": "Đã lưu thư viện", + "Licence:": "Giấy phép:", + "Light": "Sáng", + "Light Mode": "Chế độ sáng", "Light Theme": "Chủ đề sáng", + "LightCraft 0.2.0 and older refuse it (\"unsupported format … v2\").": "LightCraft 0.2.0 và cũ hơn từ chối (\"unsupported format … v2\").", + "LightCraft Default": "Mặc định LightCraft", "LightCraft Help": "Trợ giúp LightCraft", "LightCraft Preset": "Thiết lập sẵn LightCraft", "LightCraft Presets": "Thiết lập sẵn LightCraft", "LightCraft Website": "Trang web LightCraft", "LightCraft could not start": "LightCraft không thể khởi động", + "LightCraft couldn't find where to keep your library.": "LightCraft không tìm được nơi lưu thư viện của bạn.", "LightCraft couldn't open the library at": "LightCraft không mở được thư viện tại", + "LightCraft does not know this model, so it assumed:": "LightCraft không biết mô hình này, nên đã giả định:", + "LightCraft no longer crashes at launch on Windows PCs whose Vulkan driver is broken (issue #136, e.g. some Intel UHD": "LightCraft không còn sự cố khi khởi động trên PC Windows có driver Vulkan lỗi (issue #136, ví dụ một số Intel UHD", "LightCraft on GitHub": "LightCraft trên GitHub", + "LightCraft website": "Trang web LightCraft", + "LightCraft — Second Window": "LightCraft — Cửa sổ thứ hai", "Lightroom Classic Catalog": "Catalog Lightroom Classic", "Lightroom import cancelled": "Đã hủy nhập Lightroom", + "Lightroom inspection cancelled": "Đã hủy kiểm tra Lightroom", "Lights": "Đèn", "Lights Out": "Tắt đèn", + "Limit": "Giới hạn", + "Limit file size (KB, 0 = off)": "Giới hạn kích thước tệp (KB, 0 = tắt)", + "Line delta": "Chênh lệch dòng", + "Linear": "Tuyến tính", "Linear Gradient": "Chuyển sắc tuyến tính", + "Lines +/−": "Dòng +/−", + "Lines added": "Dòng đã thêm", + "Lines deleted": "Dòng đã xóa", "List Albums": "Liệt kê album", + "List Develop Controls": "Liệt kê điều khiển chỉnh sửa", "List History": "Liệt kê Lịch sử", "List Presets": "Liệt kê thiết lập sẵn", "List Profiles": "Liệt kê hồ sơ", "List this folder in Local from now on": "Liệt kê thư mục này trong Cục bộ từ nay", + "Loading preview…": "Đang tải xem trước…", + "Local": "Cục bộ", "Local folders": "Thư mục cục bộ", "Local library — no cloud account needed": "Thư viện cục bộ — không cần tài khoản đám mây", "Locate Missing Files…": "Định vị tệp bị thiếu…", "Locate Missing File…": "Định vị tệp bị thiếu…", "Locate Photo": "Định vị ảnh", "Location": "Vị trí", + "Lock": "Khóa", "Lock Crop Aspect": "Khóa tỷ lệ cắt", + "Locked": "Đã khóa", "Long Edge": "Cạnh dài", + "Looking for changes": "Đang tìm thay đổi", "Looking for photos…": "Đang tìm ảnh…", + "Looking up places": "Đang tra địa danh", + "Lossless": "Không mất dữ liệu", "Lossy DNG files and Smart Previews open as raw photos.": "Tệp DNG có mất dữ liệu và Smart Preview mở như ảnh RAW.", + "Low": "Thấp", "Luminance": "Độ sáng", "Luminance Range": "Dải độ sáng", "Luminar looks: `.lmp` files and `.mplumpack` collections import as presets (grouped by collection); the sliders": "Giao diện Luminar: tệp `.lmp` và bộ sưu tập `.mplumpack` nhập thành thiết lập sẵn (nhóm theo bộ sưu tập); các thanh trượt", + "Lush Greens": "Xanh lá tươi", "Magenta": "Đỏ tím", "Magenta Hue": "Sắc đỏ tím", "Magenta Luminance": "Độ sáng đỏ tím", "Magenta Saturation": "Độ bão hòa đỏ tím", "Make Candidate the Select": "Đặt ảnh ứng viên thành ảnh được chọn", + "Make it now": "Tạo ngay", "Make the denoised picture of the photos I am looking at": "Tạo ảnh đã khử nhiễu cho ảnh tôi đang xem", "Manual": "Thủ công", + "Marquee zoom": "Thu phóng vùng chọn", "Mask Adjustment": "Điều chỉnh mặt nạ", "Masking": "Mặt nạ", "Masking (M)": "Mặt nạ (M)", "Masks": "Mặt nạ", + "Match": "Khớp", "Match Total Exposures": "Khớp tổng phơi sáng", + "Matte": "Mờ", + "Matte Soft": "Mờ mềm", + "Med": "TB", "Medium Contrast": "Tương phản trung bình", "Megapixels": "Megapixel", + "Memory Budget": "Ngân sách bộ nhớ", + "Memory Usage": "Dung lượng bộ nhớ", + "Memory budget": "Ngân sách bộ nhớ", "Memory for caches": "Bộ nhớ cho bộ nhớ đệm", "Menu": "Trình đơn", "Merge": "Ghép", @@ -651,11 +1011,15 @@ "Merge into…": "Ghép vào…", "Merged": "Đã ghép", "Merged PRs": "PR đã gộp", + "Merging": "Đang ghép", + "Merging…": "Đang ghép…", + "Meta's terms, not LightCraft's. Downloading it means accepting them.": "Điều khoản của Meta, không phải của LightCraft. Tải xuống nghĩa là chấp nhận chúng.", "Metadata": "Siêu dữ liệu", "Metadata Preset": "Thiết lập sẵn siêu dữ liệu", "Metadata Presets": "Thiết lập sẵn siêu dữ liệu", "Metadata preset": "Thiết lập sẵn siêu dữ liệu", "Metadata read": "Đã đọc siêu dữ liệu", + "Midnight": "Nửa đêm", "Midpoint": "Điểm giữa", "Midtones": "Vùng trung tính", "Midtones Hue": "Sắc vùng trung tính", @@ -664,13 +1028,27 @@ "Midtones split": "Tách vùng trung tính", "Minimize": "Thu nhỏ", "Missing Photos": "Ảnh bị thiếu", + "Missing metadata ({camera}, {title}…) leaves an empty gap; a name that comes out empty keeps the original name.": "Metadata thiếu ({camera}, {title}…) để khoảng trống; tên rỗng giữ tên gốc.", + "Missing photos move to Recently Deleted and can be restored; no file on disk is touched.": "Ảnh thiếu chuyển sang Đã xóa gần đây và có thể khôi phục; không đụng tệp trên đĩa.", + "Misty Morning": "Sáng sương mù", "Mo": "T2", + "Mode": "Chế độ", + "Model": "Mô hình", + "Models": "Mô hình", + "Modified Date": "Ngày sửa đổi", "Monday": "Thứ Hai", + "Mono Red Filter": "Lọc đỏ đơn sắc", + "Mono Rich": "Đơn sắc đậm", + "Mono Soft": "Đơn sắc mềm", + "Monochrome": "Đơn sắc", "Month": "Tháng", + "Moody": "U ám", "Moody Portrait": "Chân dung u ám", "More": "Thêm", "More preset options": "Thêm tùy chọn thiết lập sẵn", + "Move": "Di chuyển", "Move Album": "Di chuyển album", + "Move Down": "Di chuyển xuống", "Move Down in Stack": "Di chuyển xuống trong chồng", "Move Folder": "Di chuyển thư mục", "Move Folder To…": "Di chuyển thư mục tới…", @@ -678,66 +1056,171 @@ "Move Preset to Group": "Chuyển thiết lập sẵn vào nhóm", "Move Preset to New Group": "Chuyển thiết lập sẵn vào nhóm mới", "Move Selected Photos Here": "Di chuyển ảnh đã chọn vào đây", + "Move Sidebar Section": "Di chuyển mục thanh bên", + "Move Up": "Di chuyển lên", "Move Up in Stack": "Di chuyển lên trong chồng", + "Move in Stack": "Di chuyển trong chồng", "Move the files (into the library's Originals/, or a folder you choose), removing them from the source": "Di chuyển tệp (vào Originals/ của thư viện hoặc thư mục bạn chọn), gỡ khỏi nguồn", + "Move them": "Di chuyển chúng", + "Move to": "Chuyển tới", + "Move to Folder": "Chuyển vào thư mục", + "Move to Folder…": "Chuyển vào thư mục…", + "Move to Group": "Chuyển vào nhóm", + "Move to group": "Chuyển vào nhóm", "Move: the files are moved to the folder below; each original (and its XMP sidecar) is removed from the source only after its copy is verified. Duplicates and files that fail stay where they are.": "Di chuyển: tệp chuyển vào thư mục bên dưới; mỗi bản gốc (và sidecar XMP) chỉ bị gỡ khỏi nguồn sau khi bản sao được xác minh. Trùng lặp và tệp lỗi giữ nguyên vị trí.", "Moves every photo imported from this disk to Recently Deleted; no file is touched": "Chuyển mọi ảnh nhập từ đĩa này sang Đã xóa gần đây; không đụng tệp", + "Moves the files and their XMP sidecars into this folder; never overwrites": "Chuyển tệp và sidecar XMP vào thư mục này; không bao giờ ghi đè", "Moves the photos imported from this folder to Recently Deleted; no file is touched": "Chuyển ảnh nhập từ thư mục này sang Đã xóa gần đây; không đụng tệp", + "Muted": "Dịu", + "Muted Film": "Phim dịu", "My Photos": "Ảnh của tôi", "My Photos Panel": "Bảng Ảnh của tôi", + "Name": "Tên", + "Name (A–Z)": "Tên (A–Z)", "Name Face": "Đặt tên khuôn mặt", "Name Faces": "Đặt tên khuôn mặt", + "Name of the folder the original is in": "Tên thư mục chứa bản gốc", "Named": "Đã đặt tên", "Named People": "Người đã đặt tên", + "Names appear in the label menu, the filter bar and the Info panel, and are written to XMP. Empty = the colour's name.": "Tên hiện trong menu nhãn, thanh lọc và bảng Info, và ghi vào XMP. Trống = tên màu mặc định.", + "Navigator": "Điều hướng", + "Needs Work": "Cần chỉnh", + "Neon Dusk": "Hoàng hôn neon", + "Neon Night": "Đêm neon", + "Nested group": "Nhóm lồng nhau", + "Neutral": "Trung tính", + "Never": "Không bao giờ", + "New": "Mới", + "New Album": "Album mới", "New Album…": "Album mới…", + "New Folder on Disk": "Thư mục mới trên đĩa", + "New Folder on Disk…": "Thư mục mới trên đĩa…", "New Folder…": "Thư mục mới…", + "New Group…": "Nhóm mới…", + "New Library": "Thư viện mới", + "New Library: Choose Where to Put It": "Thư viện mới: Chọn nơi đặt", "New Library…": "Thư viện mới…", "New Smart Album": "Album thông minh mới", "New Smart Album from Filter…": "Album thông minh mới từ bộ lọc…", "New Smart Album…": "Album thông minh mới…", + "New album": "Album mới", + "New album…": "Album mới…", + "New blank PDF": "PDF trống mới", + "New name": "Tên mới", + "New time": "Thời gian mới", + "New…": "Mới…", + "Next Appearance Mode": "Chế độ giao diện tiếp theo", + "Next Photo": "Ảnh tiếp theo", "Next up for AI Denoise…": "Tiếp theo cho AI Khử nhiễu…", + "Night Blue": "Xanh đêm", + "Nikon NEFs start from a colour and tone look fitted to the camera's own JPEG, as Sony ARWs do, instead of a muted,": "Nikon NEF bắt đầu từ màu và tông khớp JPEG của máy, như Sony ARW, thay vì tông mờ,", + "Nikon splits into two differently compressed halves still use the preview for now.)": "Nikon chia hai nửa nén khác nhau vẫn dùng xem trước tạm thời.)", "No": "Không", + "No Camera or Card Found": "Không tìm thấy máy ảnh hoặc thẻ", + "No Date Groups": "Không có nhóm ngày", "No Label": "Không nhãn", + "No Recent Libraries": "Không có thư viện gần đây", "No Stars": "Không sao", + "No Tool": "Không có công cụ", "No albums match": "Không có album khớp", "No albums yet": "Chưa có album", "No automatic versions.": "Không có phiên bản tự động.", + "No camera": "Không có máy ảnh", + "No contributor data was built into this copy.": "Bản này không có dữ liệu cộng tác viên.", + "No date": "Không có ngày", + "No dust spots found": "Không tìm thấy điểm bụi", + "No edits yet.": "Chưa có chỉnh sửa.", "No exposure information": "Không có thông tin phơi sáng", "No filter presets yet": "Chưa có thiết lập sẵn bộ lọc", + "No folders to browse": "Không có thư mục để duyệt", + "No graphics processor found: LightCraft renders on the CPU, which is much slower. Details in Help → System Info.": "Không tìm thấy bộ xử lý đồ họa: LightCraft kết xuất trên CPU, chậm hơn nhiều. Chi tiết trong Trợ giúp → Thông tin hệ thống.", "No imported folders yet": "Chưa có thư mục đã nhập", "No keywords are exported": "Không xuất từ khóa nào", "No keywords match": "Không có từ khóa khớp", "No keywords yet": "Chưa có từ khóa", + "No lens data embedded in this file (DNG lens opcodes only).": "Không có dữ liệu ống kính nhúng trong tệp này (chỉ opcode ống kính DNG).", "No masks yet. Choose a mask type above.": "Chưa có mặt nạ. Chọn loại mặt nạ ở trên.", + "No matching commands": "Không có lệnh khớp", + "No matching photos": "Không có ảnh khớp", "No metadata found": "Không tìm thấy siêu dữ liệu", + "No model credits were built into this copy.": "Bản này không có ghi công mô hình.", "No named people in these photos": "Không có người được đặt tên trong các ảnh này", "No named people yet": "Chưa có người được đặt tên", "No new presets": "Không có thiết lập sẵn mới", "No photo has it; the keywords below it go too.": "Không ảnh nào có nó; các từ khóa bên dưới cũng bị gỡ.", + "No photo selected": "Chưa chọn ảnh", "No photos": "Không có ảnh", + "No photos found": "Không tìm thấy ảnh", + "No photos in this folder": "Không có ảnh trong thư mục này", + "No photos match the active filters": "Không có ảnh khớp bộ lọc đang bật", + "No photos match the filters (View → Clear Filters)": "Không có ảnh khớp bộ lọc (Xem → Xóa bộ lọc)", + "No photos yet": "Chưa có ảnh", + "No raw photos yet: cameras appear here once their photos are in the library.": "Chưa có ảnh raw: máy ảnh hiện ở đây khi ảnh của chúng đã có trong thư viện.", "No reference photo": "Không có ảnh tham chiếu", "No usable GPU found: rendering on the CPU": "Không tìm thấy GPU dùng được: kết xuất trên CPU", "No versions yet. Create one to keep this look.": "Chưa có phiên bản. Tạo một phiên bản để giữ diện mạo này.", + "Noise": "Nhiễu", "Noise Reduction": "Giảm nhiễu", + "Non-raw photos": "Ảnh không phải RAW", "None": "Không có", + "Not Now": "Không phải lúc này", + "Not saved": "Chưa lưu", + "Nothing is fetched until you accept. The model is kept on this computer only; LightCraft never uploads or shares it.": "Không tải gì cho đến khi bạn chấp nhận. Mô hình chỉ lưu trên máy này; LightCraft không tải lên hay chia sẻ.", + "Nothing to compare": "Không có gì để so sánh", + "Nothing to survey": "Không có gì để khảo sát", + "Nudge Develop Value": "Điều chỉnh nhẹ giá trị chỉnh sửa", "OK": "OK", + "ONNX model": "Mô hình ONNX", + "Object": "Đối tượng", "Object Mask": "Mặt nạ đối tượng", + "Object and Describe masks use SAM 3, Meta's segmentation model. It isn't part of LightCraft, and everything else works without it.": "Mặt nạ Object và Describe dùng SAM 3, mô hình phân đoạn của Meta. Không thuộc LightCraft, và mọi thứ khác vẫn hoạt động không cần nó.", + "October 2026": "Tháng 10 năm 2026", "Off": "Tắt", "Offset X": "Độ lệch X", "Offset Y": "Độ lệch Y", "On NixOS, start it from `nix develop`.": "Trên NixOS, hãy khởi chạy từ `nix develop`.", + "Only": "Chỉ", "Only photos whose AI Denoise amount is above 0 are made. Exports always make theirs if it is missing.": "Chỉ ảnh có lượng AI Denoise trên 0 mới được tạo. Xuất luôn tạo nếu thiếu.", + "Opacity": "Độ mờ", + "Opacity (%)": "Độ mờ (%)", + "Open Library": "Mở thư viện", "Open Library…": "Mở thư viện…", "Open Log Folder": "Mở thư mục nhật ký", + "Open Recent Library": "Mở thư viện gần đây", + "Open in": "Mở trong", "Open in Detail": "Mở chi tiết", + "Open page": "Mở trang", + "Open the model's page": "Mở trang mô hình", + "Open the place in OpenStreetMap": "Mở địa điểm trên OpenStreetMap", + "Opens the model's own page in your browser, to read about it or get the file yourself.": "Mở trang của mô hình trong trình duyệt, để đọc hoặc tự tải tệp.", "Open…": "Mở…", "Optics": "Quang học", + "Optimize Library": "Tối ưu thư viện", + "Optional name": "Tên tùy chọn", + "Options": "Tùy chọn", + "Orange": "Cam", "Orange Hue": "Sắc cam", "Orange Luminance": "Độ sáng cam", "Orange Saturation": "Độ bão hòa cam", + "Orientation": "Hướng", + "Original": "Gốc", + "Original + Settings": "Gốc + Thiết lập", + "Original extension without the dot": "Phần mở rộng gốc không có dấu chấm", + "Original file name without its extension": "Tên tệp gốc không có phần mở rộng", + "Original files": "Tệp gốc", "Original offline · editing the smart preview": "Gốc ngoại tuyến · đang chỉnh smart preview", "Original offline · no smart preview": "Gốc ngoại tuyến · không có smart preview", + "Originals": "Bản gốc", + "Other images (JPEG, PNG, TIFF, HEIC…)": "Ảnh khác (JPEG, PNG, TIFF, HEIC…)", + "Other…": "Khác…", + "Overlay": "Lớp phủ", + "Overwrite": "Ghi đè", + "Pages": "Trang", + "Paint": "Tô", "Paint only areas like the one under the brush": "Chỉ tô vùng giống vùng dưới cọ", + "Paint over a distraction on the photo to remove it.": "Tô lên vật gây mất tập trung trên ảnh để xóa nó.", + "Paint overlay": "Lớp phủ tô", + "Panasonic and Leica raws (RW2, RWL and the older RAW files, DMC-LX1 to DC-S1R II) develop from the raw data in": "Raw Panasonic và Leica (RW2, RWL và tệp RAW cũ, DMC-LX1 đến DC-S1R II) develop từ dữ liệu raw trong", "Panels": "Các bảng", "Panorama": "Toàn cảnh", "Panorama Merge": "Ghép panorama", @@ -745,34 +1228,61 @@ "Panorama with Last Settings": "Panorama với thiết lập lần trước", "Panoramas": "Panorama", "Panorama…": "Toàn cảnh…", + "Paper": "Giấy", "Parametric curve": "Đường cong tham số", "Paste": "Dán", "Paste Edit Settings": "Dán cài đặt chỉnh sửa", "Paste Metadata": "Dán siêu dữ liệu", + "Paste Selected Settings": "Dán thiết lập đã chọn", "Paste Selected Settings…": "Dán cài đặt đã chọn…", + "Paste Settings": "Dán thiết lập", + "Paste Settings from Previous": "Dán thiết lập từ ảnh trước", + "Paste from Previous": "Dán từ ảnh trước", + "Paste pages": "Dán trang", + "Pastel Haze": "Sương pastel", + "Pending photo action cancelled": "Đã hủy thao tác ảnh đang chờ", + "Pending photo action cancelled because its library or photo changed": "Đã hủy thao tác ảnh đang chờ vì thư viện hoặc ảnh đã thay đổi", "People": "Người", "People Count": "Số người", + "Percent": "Phần trăm", "Percentage": "Phần trăm", + "Perceptual": "Cảm nhận", "Performance": "Hiệu năng", "Person": "Người", + "Perspective": "Phối cảnh", + "Pet Eye": "Mắt thú cưng", "Pet Eye Catchlight": "Điểm sáng mắt thú cưng", "Photo": "Ảnh", "Photo Grid": "Lưới ảnh", + "Photo Grid (G)": "Lưới ảnh (G)", "Photo Merge": "Ghép ảnh", + "Photo menu. The filmstrip has the photo context menu too. Adding a file again that is in Recently Deleted no": "Menu Ảnh. Dải phim cũng có menu ngữ cảnh ảnh. Thêm lại tệp đang ở Đã xóa gần đây không", + "Photo ▸ Edit in External Editor (⇧⌘E) renders a 16-bit TIFF copy, stacks it with the original and opens it here (an app name on macOS, a program path elsewhere).": "Ảnh ▸ Chỉnh trong trình soạn ngoài (⇧⌘E) kết xuất bản sao TIFF 16 bit, xếp chồng với bản gốc và mở tại đây (tên app trên macOS, đường dẫn chương trình ở nơi khác).", + "Photos": "Ảnh", + "Photos in Recently Deleted can be restored from the app: right-click ▸ Restore (or Delete Permanently), also in the": "Ảnh trong Đã xóa gần đây có thể khôi phục trong app: nhấp phải ▸ Khôi phục (hoặc Xóa vĩnh viễn), cũng trong", + "Photos per bracket (0 = auto)": "Ảnh mỗi nhóm bracket (0 = tự động)", + "Photos seen in Local but never added or changed leave the catalog when their folder hasn't been browsed for this long (checked when the library opens). Files stay on disk; browsing the folder shows them again.": "Ảnh chỉ xem trong Local mà chưa thêm hay sửa sẽ rời catalog khi thư mục không được duyệt trong thời gian này (kiểm tra khi mở thư viện). Tệp vẫn trên đĩa; duyệt lại thư mục sẽ thấy chúng.", "Photos that arrive in this folder (tethering, a scanner, a sync app) are added as soon as they're complete.": "Ảnh đến thư mục này (tethering, máy quét, app đồng bộ) được thêm ngay khi hoàn tất.", "Photos); importing (also by drag and drop), Find Missing Photos, Build / Discard Smart Previews, the Rename preview,": "Ảnh); nhập (cả kéo thả), Tìm ảnh thiếu, Tạo / Hủy Smart Preview, xem trước Đổi tên,", "Pick": "Đã chọn", "Pick Flag": "Cờ chọn", "Pick a colour on the photo with the eyedropper.": "Chọn màu trên ảnh bằng ống nhỏ giọt.", "Pick a date": "Chọn ngày", + "Pick the sharpest photo of each burst": "Chọn ảnh nét nhất của mỗi chuỗi", "Picked": "Đã chọn", "Picks": "Ảnh đã chọn", + "Pictures": "Hình ảnh", + "Pixels": "Pixel", + "Place Names Status": "Trạng thái tên địa danh", + "Place names download cancelled": "Đã hủy tải tên địa danh", + "Place names downloaded": "Đã tải tên địa danh", "Point Color": "Màu điểm", "Point Curve": "Đường cong điểm", "Point Curve Presets": "Thiết lập sẵn đường cong điểm", "Point curve": "Đường cong điểm", "Portrait": "Dọc", "Portrait (tall)": "Dọc (cao)", + "Position": "Vị trí", "Preferences": "Tùy chọn", "Preferences…": "Tùy chọn…", "Prepare AI Masks": "Chuẩn bị mặt nạ AI", @@ -783,6 +1293,18 @@ "Presets (Shift+P)": "Thiết lập sẵn (Shift+P)", "Presets and profiles": "Thiết lập sẵn và hồ sơ", "Presets ▾": "Thiết lập sẵn ▾", + "Press keys…": "Nhấn phím…", + "Preview": "Xem trước", + "Preview Build Progress": "Tiến độ tạo xem trước", + "Preview only": "Chỉ xem trước", + "Preview only: editing the camera's embedded JPEG": "Chỉ xem trước: đang chỉnh JPEG nhúng của máy ảnh", + "Preview size": "Kích thước xem trước", + "Preview unavailable": "Không có xem trước", + "Previews": "Xem trước", + "Previous Photo": "Ảnh trước", + "Print": "In", + "Print…": "In…", + "Processor": "Bộ xử lý", "Profile": "Hồ sơ", "Profile Browser": "Trình duyệt hồ sơ", "Profile Distortion": "Hồ sơ méo hình", @@ -790,8 +1312,11 @@ "Profile Vignetting": "Hồ sơ tối góc", "Profile:": "Hồ sơ:", "Profiles": "Hồ sơ", + "Projection": "Chiếu", "Proof copy created": "Đã tạo bản proof", + "Properties": "Thuộc tính", "Public Domain": "Phạm vi công cộng", + "Public domain": "Phạm vi công cộng", "Pupil Size": "Kích thước đồng tử", "Purge Unused Keywords": "Dọn từ khóa không dùng", "Purple": "Tím", @@ -802,79 +1327,181 @@ "Purple Luminance": "Độ sáng tím", "Purple Saturation": "Độ bão hòa tím", "Put New Keywords Inside This Keyword": "Đặt từ khóa mới vào trong từ khóa này", + "Put the locations you removed from Local back (no files change)": "Đưa các vị trí đã gỡ khỏi Local trở lại (không đổi tệp)", + "Quality": "Chất lượng", + "Query Photos": "Truy vấn ảnh", + "Quick Collection": "Bộ sưu tập nhanh", + "Quick Collection and target album (B in the grid), keyword sets (⌥1–⌥9), colour-label sets.": "Quick Collection và album đích (B trên lưới), bộ từ khóa (⌥1–⌥9), bộ nhãn màu.", "Quick Develop": "Chỉnh nhanh", + "Quiet Green": "Xanh êm", "Quit": "Thoát", + "Quit Anyway": "Vẫn thoát", "Quit LightCraft": "Thoát LightCraft", + "Quit while tasks are running?": "Thoát khi tác vụ đang chạy?", + "Quit with unsaved changes?": "Thoát khi còn thay đổi chưa lưu?", + "RAW decoding": "Giải mã RAW", + "Radial": "Hướng tâm", "Radial Gradient": "Chuyển sắc hướng tâm", "Radius": "Bán kính", + "Random": "Ngẫu nhiên", + "Range": "Dải", + "Rate ★": "Xếp hạng ★", + "Rate ★ and advance": "Xếp hạng ★ và chuyển tiếp", + "Rate ★★": "Xếp hạng ★★", + "Rate ★★ and advance": "Xếp hạng ★★ và chuyển tiếp", + "Rate ★★★": "Xếp hạng ★★★", + "Rate ★★★ and advance": "Xếp hạng ★★★ và chuyển tiếp", + "Rate ★★★★": "Xếp hạng ★★★★", + "Rate ★★★★ and advance": "Xếp hạng ★★★★ và chuyển tiếp", + "Rate ★★★★★": "Xếp hạng ★★★★★", + "Rate ★★★★★ and advance": "Xếp hạng ★★★★★ và chuyển tiếp", "Rating": "Xếp hạng", "Rating cleared": "Đã xóa xếp hạng", "Ratings & flags": "Xếp hạng và cờ", "Raw": "Raw", + "Raw default": "Mặc định RAW", + "Raw defaults": "Mặc định RAW", + "Raw files": "Tệp RAW", + "Raw photos": "Ảnh RAW", + "Raw photos as DNG, with the edits embedded. Size, color and output options don't apply.": "Ảnh raw dạng DNG, nhúng chỉnh sửa. Tùy chọn kích thước, màu và đầu ra không áp dụng.", "Read Metadata from File": "Đọc siêu dữ liệu từ tệp", "Read metadata updates from XMP sidecars": "Đọc cập nhật siêu dữ liệu từ sidecar XMP", + "Read mode": "Chế độ đọc", "Read the SAM License": "Đọc giấy phép SAM", + "Reading": "Đang đọc", + "Reading Lightroom catalog": "Đang đọc catalog Lightroom", + "Reading Lightroom catalog…": "Đang đọc catalog Lightroom…", + "Reading a sidecar replaces the photo's rating, labels, metadata and edits with what it says.": "Đọc sidecar thay xếp hạng, nhãn, metadata và chỉnh sửa của ảnh bằng nội dung trong đó.", + "Reading folder": "Đang đọc thư mục", + "Reading folder…": "Đang đọc thư mục…", "Reading photos…": "Đang đọc ảnh…", + "Real name": "Tên thật", + "Recent": "Gần đây", "Recent Keywords": "Từ khóa gần đây", "Recent Keywords is built in: choose another name": "Từ khóa gần đây là bộ sẵn: hãy chọn tên khác", + "Recent Libraries": "Thư viện gần đây", + "Recently Added": "Mới thêm", "Recently Deleted": "Đã xóa gần đây", "Recognise faces (experimental)": "Nhận diện khuôn mặt (thử nghiệm)", + "Recognition models": "Mô hình nhận dạng", "Red": "Đỏ", "Red Eye": "Mắt đỏ", "Red Hue": "Sắc đỏ", "Red Luminance": "Độ sáng đỏ", "Red Primary": "Màu gốc đỏ", "Red Saturation": "Độ bão hòa đỏ", + "Red channel": "Kênh đỏ", "Red label": "Nhãn đỏ", "Red/Cyan Fringe": "Viền đỏ/lam", "Redo": "Làm lại", "Reference": "Tham chiếu", "Reference View": "Xem tham chiếu", "Reference the files where they are": "Tham chiếu tệp tại chỗ", + "Refine": "Tinh chỉnh", "Refine AI Mask Detail": "Tinh chỉnh chi tiết mặt nạ AI", + "Refine Edges": "Tinh chỉnh cạnh", "Refine Mask Edges": "Tinh chỉnh cạnh mặt nạ", "Refine Saturation": "Tinh chỉnh độ bão hòa", "Refining the mask's detail…": "Đang tinh chỉnh chi tiết mặt nạ…", + "Refresh Source": "Làm mới nguồn", + "Refresh Source (/)": "Làm mới nguồn (/)", "Reject": "Đã loại", "Reject below focus": "Loại ảnh dưới ngưỡng lấy nét", "Rejected": "Đã loại", "Rejects": "Ảnh đã loại", + "Relative": "Tương đối", + "Reliability": "Độ tin cậy", + "Relink Photo": "Liên kết lại ảnh", "Relink photos whose file was renamed or moved": "Liên kết lại ảnh có tệp đã đổi tên hoặc di chuyển", + "Relinked": "Đã liên kết lại", + "Reload Changed Files": "Tải lại tệp đã đổi", + "Reload from Disk": "Tải lại từ đĩa", "Remove": "Gỡ", + "Remove (H)": "Xóa (H)", + "Remove CA": "Xóa quang sai sắc", + "Remove Chromatic Aberration": "Xóa quang sai sắc", "Remove Denoise Model": "Gỡ mô hình khử nhiễu", + "Remove Disk from Library": "Gỡ đĩa khỏi thư viện", + "Remove Disk from Library…": "Gỡ đĩa khỏi thư viện…", "Remove Face Box": "Gỡ khung khuôn mặt", "Remove Face Model": "Gỡ mô hình khuôn mặt", + "Remove Folder from Library": "Gỡ thư mục khỏi thư viện", + "Remove a filter above, or choose Clear all": "Gỡ bộ lọc ở trên, hoặc chọn Xóa tất cả", + "Remove from Album": "Gỡ khỏi album", + "Remove from Favorites": "Gỡ khỏi yêu thích", + "Remove from Library…": "Gỡ khỏi thư viện…", + "Remove from Local": "Gỡ khỏi Local", + "Remove from Photo": "Gỡ khỏi ảnh", + "Remove from Selected Photos": "Gỡ khỏi ảnh đã chọn", + "Remove from Stack": "Gỡ khỏi chồng", + "Remove from Target Album": "Gỡ khỏi album đích", + "Remove from favorites": "Gỡ khỏi yêu thích", + "Remove from survey": "Gỡ khỏi khảo sát", + "Remove location info": "Xóa thông tin vị trí", + "Remove missing photos from the library": "Gỡ ảnh mất khỏi thư viện", + "Remove shortcut": "Gỡ lối tắt", "Remove this face box (undo with Edit ▸ Undo)": "Gỡ khung khuôn mặt này (hoàn tác bằng Chỉnh sửa ▸ Hoàn tác)", + "Remove this filter": "Gỡ bộ lọc này", + "Remove this group": "Gỡ nhóm này", + "Remove this rule": "Gỡ quy tắc này", + "Removed": "Đã gỡ", "Rename": "Đổi tên", "Rename Album": "Đổi tên album", "Rename Component": "Đổi tên thành phần", "Rename Folder": "Đổi tên thư mục", "Rename Folder…": "Đổi tên thư mục…", + "Rename Folder… and Move Folder To… (Local) can be undone and redone (issue #97): the folder moves back on disk with": "Đổi tên thư mục… và Di chuyển thư mục tới… (Local) có thể hoàn tác và làm lại (issue #97): thư mục di chuyển lại trên đĩa với", "Rename Keyword": "Đổi tên từ khóa", "Rename Keyword…": "Đổi tên từ khóa…", "Rename Mask": "Đổi tên mặt nạ", "Rename Photos": "Đổi tên ảnh", + "Rename Photos never overwrites another photo when only the letter case changes (issue #95): on case-sensitive": "Đổi tên ảnh không bao giờ ghi đè ảnh khác khi chỉ đổi hoa thường (issue #95): trên hệ thống phân biệt hoa thường", + "Rename Photos reports files it could not move back after a failure (issue #105), e.g. when a network share drops": "Đổi tên ảnh báo tệp không thể chuyển lại sau lỗi (issue #105), ví dụ khi ổ mạng bị ngắt", "Rename Photos…": "Đổi tên ảnh…", "Rename Preset": "Đổi tên thiết lập sẵn", "Rename Preview": "Đổi tên bản xem trước", "Rename Template Tags": "Thẻ mẫu đổi tên", "Rename Version": "Đổi tên phiên bản", "Rename…": "Đổi tên…", + "Rendering": "Đang kết xuất", + "Rendering…": "Đang kết xuất…", + "Reorder Album": "Sắp xếp lại album", "Reorder Masks": "Sắp xếp lại mặt nạ", "Reset": "Đặt lại", + "Reset All": "Đặt lại tất cả", "Reset All Curves": "Đặt lại tất cả đường cong", + "Reset All Keyboard Shortcuts": "Đặt lại tất cả phím tắt", "Reset Before to Import State": "Đặt lại Before về trạng thái nhập", + "Reset Control": "Đặt lại điều khiển", "Reset Crop": "Đặt lại cắt", + "Reset Edits": "Đặt lại chỉnh sửa", "Reset Panel Layout": "Đặt lại bố cục bảng", "Reset Parametric Curve": "Đặt lại đường cong tham số", + "Reset Section": "Đặt lại mục", + "Reset Sidebar Sections": "Đặt lại mục thanh bên", "Reset Tone Curve": "Đặt lại đường cong tông màu", + "Reset all curves: point curves (all channels) and parametric (double-click a channel to reset only that one)": "Đặt lại mọi đường cong: đường cong điểm (mọi kênh) và tham số (nhấp đúp kênh để chỉ đặt lại kênh đó)", + "Reset all edits (Cmd+Shift+R)": "Đặt lại mọi chỉnh sửa (Cmd+Shift+R)", + "Reshuffle": "Xáo trộn lại", "Resize Face Box": "Đổi kích thước khung khuôn mặt", + "Resize panel window": "Thay đổi kích thước cửa sổ bảng", + "Resize panels": "Thay đổi kích thước bảng", + "Resize to": "Thay đổi kích thước thành", + "Resolution (ppi)": "Độ phân giải (ppi)", + "Restore": "Khôi phục", + "Restore (no shortcut)": "Khôi phục (không có phím tắt)", "Restore Library from Backup…": "Khôi phục thư viện từ bản sao lưu…", "Restore Version": "Khôi phục phiên bản", "Restore keeps their edits; Import as new deletes the old record first.": "Khôi phục giữ chỉnh sửa; Nhập như mới xóa bản ghi cũ trước.", + "Restore them": "Khôi phục chúng", + "Retouch": "Chỉnh sửa", + "Reverse the order": "Đảo thứ tự", + "Revert": "Hoàn tác", + "Review": "Xem lại", "Review Import": "Xem lại nhập", "Right-click a photo ▸ Set as Reference Photo, then View → Reference View (Shift+R)": "Nhấp phải ảnh ▸ Đặt làm ảnh tham chiếu, rồi Xem → Chế độ tham chiếu (Shift+R)", "Right-click a preset to delete it": "Nhấp phải thiết lập sẵn để xóa", + "Rights Usage Terms": "Điều khoản sử dụng quyền", "Rotate": "Xoay", "Rotate Crop": "Xoay vùng cắt", "Rotate Crop Aspect": "Xoay tỷ lệ cắt", @@ -882,13 +1509,17 @@ "Rotate Right": "Xoay phải", "Roughness": "Độ thô", "Roundness": "Độ tròn", + "Rules": "Quy tắc", "SAM 3 download stopped: it resumes where it left off next time.": "Tải SAM 3 đã dừng: lần sau sẽ tiếp tục từ chỗ dừng.", "Sa": "T7", + "Same as raw default": "Giống mặc định RAW", "Sample Mask Color": "Lấy mẫu màu mặt nạ", + "Sample a colour on the photo": "Lấy mẫu màu trên ảnh", "Saturation": "Độ bão hòa", "Saturation Range": "Dải độ bão hòa", "Saturday": "Thứ Bảy", "Save": "Lưu", + "Save As…": "Lưu thành…", "Save Color Label Set": "Lưu bộ nhãn màu", "Save Current Filter as Preset…": "Lưu bộ lọc hiện tại thành thiết lập sẵn…", "Save Current Keywords as Set…": "Lưu từ khóa hiện tại thành bộ…", @@ -901,32 +1532,83 @@ "Save Point Curve Preset": "Lưu thiết lập sẵn đường cong điểm", "Save Point Curve…": "Lưu đường cong điểm…", "Save as Preset": "Lưu thành thiết lập sẵn", + "Save as Set…": "Lưu thành bộ…", "Save as Smart Album…": "Lưu thành album thông minh…", + "Save as a new set": "Lưu thành bộ mới", + "Save as set": "Lưu thành bộ", + "Save as…": "Lưu thành…", "Save preset": "Lưu thiết lập sẵn", "Saving Lightroom import index…": "Đang lưu chỉ mục nhập Lightroom…", + "Saving metadata to an XMP sidecar another application wrote no longer replaces it (issue #92): LightCraft merges its": "Lưu metadata vào sidecar XMP do ứng dụng khác ghi không còn thay thế (issue #92): LightCraft gộp", "Scale": "Tỷ lệ", + "Scan failed": "Quét thất bại", + "Scanning": "Đang quét", + "Scanning folder": "Đang quét thư mục", + "Scanning…": "Đang quét…", + "Scores stay on the photos: filter or make smart albums with Focus and Best of Similar Shots.": "Điểm số gắn trên ảnh: lọc hoặc tạo album thông minh với Focus và Best of Similar Shots.", + "Screen": "Màn hình", + "Scroll menu down": "Cuộn menu xuống", + "Scroll menu up": "Cuộn menu lên", "Search": "Tìm kiếm", + "Search Photos": "Tìm ảnh", "Search albums": "Tìm album", + "Search commands or keys": "Tìm lệnh hoặc phím", + "Search…": "Tìm…", "Seasons": "Mùa", "Second Window": "Cửa sổ thứ hai", + "Select": "Chọn", "Select All": "Chọn tất cả", "Select Luminance Range": "Chọn dải độ sáng", "Select Mask": "Chọn mặt nạ", + "Select Photos": "Chọn ảnh", + "Select Spot": "Chọn điểm", + "Select a photo to edit": "Chọn ảnh để chỉnh sửa", + "Select by": "Chọn theo", "Select by Flag, Rating or Label": "Chọn theo cờ, xếp hạng hoặc nhãn", "Select photos to give them keywords.": "Chọn ảnh để gán từ khóa.", + "Select photos, then choose View → Survey (N)": "Chọn ảnh, rồi chọn Xem → Khảo sát (N)", + "Select two photos, then choose View → Compare (Shift+C)": "Chọn hai ảnh, rồi chọn Xem → So sánh (Shift+C)", "Selected": "Đã chọn", + "Selecting…": "Đang chọn…", + "Selenium Tone": "Tông selenium", "Send Feedback…": "Gửi phản hồi…", + "Separated by commas": "Phân tách bằng dấu phẩy", + "Sepia Tone": "Tông sepia", + "Sequence number zero-padded to N digits (1–9)": "Số thứ tự thêm số 0 đến N chữ số (1–9)", "Sequence number, counting from the start number": "Số thứ tự, đếm từ số bắt đầu", + "Services": "Dịch vụ", + "Set": "Bộ", + "Set Album Cover": "Đặt ảnh bìa album", + "Set Before": "Đặt Before", "Set Color Label": "Đặt nhãn màu", "Set Crop": "Đặt cắt", + "Set Develop Values": "Đặt giá trị chỉnh sửa", "Set Flag": "Đặt cờ", + "Set Image Zoom and Pan": "Đặt thu phóng và pan ảnh", + "Set Keyboard Shortcut": "Đặt phím tắt", "Set Mask Adjustments": "Đặt điều chỉnh mặt nạ", "Set Point Curve": "Đặt đường cong điểm", "Set Profile": "Đặt hồ sơ", "Set Rating": "Đặt xếp hạng", + "Set Top of Stack": "Đặt đầu chồng", + "Set as Album Cover": "Đặt làm ảnh bìa album", + "Set as Before": "Đặt làm Before", "Set as Reference Photo": "Đặt làm ảnh tham chiếu", + "Set as Target Album": "Đặt làm album đích", + "Set as Target Album (B adds to it)": "Đặt làm album đích (B thêm vào đó)", + "Set as Top of Stack": "Đặt làm đầu chồng", + "Set date & time": "Đặt ngày & giờ", + "Set name": "Đặt tên", + "Set the mix from the photo's colours": "Đặt hỗn hợp từ màu của ảnh", "Set up AI Denoise…": "Thiết lập AI Khử nhiễu…", "Settings": "Cài đặt", + "Settings file problem": "Lỗi tệp thiết lập", + "Settings files are never quietly reset (issue #103): a damaged `prefs.json`, `presets.json` or `view.json` is kept": "Tệp cài đặt không bao giờ im lặng đặt lại (issue #103): `prefs.json`, `presets.json` hoặc `view.json` hỏng được giữ", + "Settings new raw photos start from. Changing them doesn't touch photos already in the library.": "Cài đặt ảnh raw mới bắt đầu từ. Đổi chúng không ảnh hưởng ảnh đã có trong thư viện.", + "Settings pasted": "Đã dán thiết lập", + "Settings to include": "Thiết lập cần bao gồm", + "Settings…": "Thiết lập…", + "Shade": "Bóng râm", "Shadow": "Vùng tối", "Shadows": "Vùng tối", "Shadows Hue": "Sắc vùng tối", @@ -936,10 +1618,16 @@ "Shadows split": "Tách vùng tối", "Sharpen": "Làm nét", "Sharpening": "Làm nét", + "Sharpness": "Độ nét", + "Shift": "Dịch chuyển", + "Shift by": "Dịch chuyển theo", "Short Edge": "Cạnh ngắn", "Show": "Hiện", + "Show All": "Hiện tất cả", "Show All Mask Overlays": "Hiện mọi lớp phủ mặt nạ", "Show Clipping": "Hiện vùng cắt tông", + "Show Deghost Overlay": "Hiện lớp phủ deghost", + "Show Hidden Local Locations": "Hiện vị trí Local đã ẩn", "Show Luminance Map": "Hiện bản đồ độ sáng", "Show Mask": "Hiện mặt nạ", "Show Mask Overlay": "Hiện lớp phủ mặt nạ", @@ -949,30 +1637,81 @@ "Show Photo Counts": "Hiện số lượng ảnh", "Show Photos with Keyword": "Hiện ảnh có từ khóa", "Show Pins": "Hiện ghim", + "Show Sidebar Section": "Hiện mục thanh bên", + "Show Source": "Hiện nguồn", + "Show Thumbnails": "Hiện hình thu nhỏ", + "Show all overlays": "Hiện mọi lớp phủ", + "Show commands without a shortcut": "Hiện lệnh không có phím tắt", "Show destination gamut warning": "Hiện cảnh báo gamut đích", + "Show display gamut warning": "Hiện cảnh báo gamut màn hình", + "Show file names": "Hiện tên tệp", + "Show in Explorer": "Hiện trong Explorer", + "Show in File Manager": "Hiện trong trình quản lý tệp", "Show in Finder": "Hiện trong trình quản lý tệp", + "Show less": "Hiện ít hơn", + "Show on Map": "Hiện trên bản đồ", + "Show overlay (O)": "Hiện lớp phủ (O)", "Show ratings, flags and edit badges": "Hiện xếp hạng, cờ và huy hiệu chỉnh sửa", + "Show the Navigator while zoomed in": "Hiện Điều hướng khi phóng to", "Show the template tags; click one to insert it": "Hiện thẻ mẫu; nhấp để chèn", "Show/Hide Mask": "Hiện/Ẩn mặt nạ", + "Show/hide My Photos panel": "Hiện/ẩn bảng Ảnh của tôi", "Shutter Speed": "Tốc độ cửa trập", + "Shutter speed": "Tốc độ màn trập", + "Side panels": "Bảng bên", + "Sidebar Sections": "Mục thanh bên", + "Sidecar names": "Tên sidecar", + "Silver": "Bạc", + "Simulate Paper & Ink": "Mô phỏng giấy & mực", "Size": "Kích thước", + "Size (% of short edge)": "Kích thước (% cạnh ngắn)", + "Size limit": "Giới hạn kích thước", + "Skip": "Bỏ qua", + "Skipped: files already in the library elsewhere": "Đã bỏ qua: tệp đã có trong thư viện ở nơi khác", + "Skipped: files that can't be read": "Đã bỏ qua: tệp không đọc được", "Sky": "Bầu trời", "Slideshow": "Trình chiếu", + "Slideshow paused": "Đã tạm dừng trình chiếu", + "Slideshow resumed": "Đã tiếp tục trình chiếu", + "Slideshow · Space pauses · Esc ends": "Trình chiếu · Space tạm dừng · Esc kết thúc", + "Slideshow, second window, All Metadata, System Info.": "Trình chiếu, cửa sổ thứ hai, Toàn bộ siêu dữ liệu, Thông tin hệ thống.", + "Smaller, faster catalogs: photos you only looked at in Local (never added, rated or edited) are forgotten once": "Catalog nhỏ hơn, nhanh hơn: ảnh bạn chỉ xem trong Local (chưa thêm, xếp hạng hay chỉnh) bị quên khi", "Smart Album": "Album thông minh", "Smart Album Rule Fields": "Trường quy tắc album thông minh", "Smart Preview Status": "Trạng thái Smart Preview", "Smart Previews Location": "Vị trí Smart Preview", + "Smart albums with a rule editor: match all / any / none, nested groups, 26 fields.": "Album thông minh với trình soạn quy tắc: khớp tất cả / bất kỳ / không, nhóm lồng nhau, 26 trường.", "Smart preview available": "Có smart preview", "Smart previews": "Smart preview", "Smart previews folder changed": "Đã đổi thư mục smart preview", "Smoothness": "Độ mịn", + "Soft B&W": "B&W mềm", + "Soft Pastel": "Pastel mềm", "Soft Proofing": "Soft proofing", + "Soft Skin": "Da mềm", "Some rules need fixing (Edit Smart Album…):": "Một số quy tắc cần sửa (Chỉnh sửa album thông minh…):", + "Sony ARWs from before about 2017 (RX100, RX100 II–V, RX10, NEX, SLT, ILCE-6000, A7 / A7 II / A7R II and their": "Sony ARW trước khoảng 2017 (RX100, RX100 II–V, RX10, NEX, SLT, ILCE-6000, A7 / A7 II / A7R II và các", + "Sony ILCE-7M4 downsized lossless ARWs now decode subsampled YCbCr tiles into linear RGB,": "Sony ILCE-7M4 ARW lossless thu nhỏ giờ giải mã tile YCbCr subsampled thành RGB tuyến tính,", + "Sort": "Sắp xếp", + "Sort Albums A–Z": "Sắp xếp album A–Z", + "Sort Albums by Name": "Sắp xếp album theo tên", + "Sort Contents A–Z": "Sắp xếp nội dung A–Z", + "Sort by": "Sắp xếp theo", "Source": "Nguồn", + "Source code on GitHub": "Mã nguồn trên GitHub", + "Speed": "Tốc độ", + "Spherical": "Cầu", + "Spiral": "Xoắn ốc", + "Split Stack": "Tách chồng", + "Spring Fresh": "Xuân tươi", "Square": "Vuông", "Square Grid": "Lưới vuông", + "Square Grid (G toggles)": "Lưới vuông (G bật/tắt)", + "Square Grid: show file names and formats": "Lưới vuông: hiện tên tệp và định dạng", "Stack": "Chồng", + "Stack photos taken within this time of each other:": "Chồng ảnh chụp trong khoảng thời gian này của nhau:", "Stacks": "Chồng", + "Standard": "Chuẩn", "Star rating (0–5)": "Xếp hạng sao (0–5)", "Start at": "Bắt đầu tại", "Start number": "Số bắt đầu", @@ -980,18 +1719,33 @@ "Starting…": "Đang bắt đầu…", "Startup": "Khởi động", "State / Province": "Bang / Tỉnh", + "Stop": "Dừng", + "Stop Building Previews": "Dừng tạo xem trước", + "Stop Using as Target Album": "Ngừng dùng làm album đích", + "Stopped": "Đã dừng", + "Stopped by an error (see the log)": "Dừng do lỗi (xem nhật ký)", "Stopping…": "Đang dừng…", "Straighten": "Chỉnh thẳng", "Straighten Tool": "Công cụ chỉnh thẳng", "Strong Contrast": "Tương phản mạnh", + "Style": "Kiểu", "Su": "CN", + "Subfolder": "Thư mục con", + "Subfolder name": "Tên thư mục con", "Subject": "Chủ thể", "Subtract": "Trừ", "Subtract from this mask": "Trừ khỏi mặt nạ này", "Suggest Names for Faces": "Gợi ý tên cho khuôn mặt", + "Suggestions": "Gợi ý", + "Suggests who is in a photo from the faces you have named. Everything stays on your computer.": "Gợi ý ai trong ảnh từ khuôn mặt bạn đã đặt tên. Mọi thứ ở trên máy bạn.", + "Summer Haze": "Sương hè", "Sunday": "Chủ Nhật", "Survey": "Khảo sát", + "Survey (N)": "Khảo sát (N)", + "Swap": "Hoán đổi", "Swap Aspect (X)": "Hoán đổi tỷ lệ (X)", + "Swap Before and After": "Hoán đổi Before và After", + "Swap Before and After Settings": "Hoán đổi thiết lập Before và After", "Swap Compare Photos": "Đổi chỗ ảnh so sánh", "Switch light / dark theme": "Chuyển chủ đề sáng / tối", "Sync Settings": "Đồng bộ thiết lập", @@ -1002,55 +1756,131 @@ "Synchronizing folder": "Đang đồng bộ thư mục", "Synchronizing…": "Đang đồng bộ…", "Synonyms": "Từ đồng nghĩa", + "System": "Hệ thống", + "System Info": "Thông tin hệ thống", "System Info…": "Thông tin hệ thống…", + "System default": "Mặc định hệ thống", + "TZ/ZS series, Leica D-Lux, V-Lux and C-Lux, and the GH6, GH7, G9 II, S5 II and S9 generation. They start from a": "Dòng TZ/ZS, Leica D-Lux, V-Lux và C-Lux, và thế hệ GH6, GH7, G9 II, S5 II và S9. Chúng bắt đầu từ", + "Table": "Bảng", "Tags": "Thẻ", + "Tags: see Tags beside the template. Files are renamed on disk (with their XMP sidecars); existing names get -1, -2…": "Thẻ: xem Thẻ bên cạnh mẫu. Tệp đổi tên trên đĩa (kèm sidecar XMP); tên có sẵn thêm -1, -2…", + "Take a snapshot": "Chụp snapshot", + "Targeted Adjustment": "Điều chỉnh có mục tiêu", + "Targeted adjustment: drag up/down on the photo to adjust the colours there": "Chỉnh có mục tiêu: kéo lên/xuống trên ảnh để chỉnh màu tại đó", "Targeted adjustment: drag up/down on the photo to adjust the curve there": "Chỉnh có mục tiêu: kéo lên/xuống trên ảnh để chỉnh đường cong tại đó", + "Teal & Amber": "Xanh mòng két & hổ phách", + "Teal & Orange": "Xanh mòng két & cam", "Temp": "Nhiệt", "Temperature": "Nhiệt độ", "Template": "Mẫu", "Temporary session — your library isn't open, and nothing you do here is saved.": "Phiên tạm — thư viện chưa mở và không lưu gì bạn làm ở đây.", "Test Denoise Model": "Thử mô hình khử nhiễu", "Test Face Model": "Thử mô hình khuôn mặt", + "Tested and works on this computer": "Đã thử và chạy trên máy này", + "Text": "Văn bản", + "Text direction": "Hướng chữ", "Texture": "Kết cấu", "Th": "T5", + "That includes the photos in the folders inside it.": "Bao gồm cả ảnh trong các thư mục bên trong.", + "That key can't be used as a shortcut": "Phím đó không thể dùng làm phím tắt", "The SAM 3 model is installed: Object and Describe masks are ready.": "Đã cài mô hình SAM 3: Mặt nạ đối tượng và Mô tả đã sẵn sàng.", + "The catalog has a format version (issue #102). Opening a library from an older LightCraft upgrades it; a library": "Catalog có phiên bản định dạng (issue #102). Mở thư viện từ LightCraft cũ hơn sẽ nâng cấp; thư viện", + "The control port (`--control`) closes a connection as soon as it receives anything that isn't a JSON request": "Cổng điều khiển (`--control`) đóng kết nối ngay khi nhận bất kỳ thứ gì không phải yêu cầu JSON", "The denoise model is installed and in use: the AI Denoise Amount slider under Detail now works": "Mô hình khử nhiễu đã cài và đang dùng: thanh AI Denoise Amount trong Chi tiết giờ hoạt động", + "The download didn't work:": "Tải xuống không thành công:", + "The first time, macOS asks whether LightCraft may control Photos.": "Lần đầu, macOS hỏi LightCraft có được phép điều khiển Photos không.", + "The graphics card is set up when the next photo is made.": "Card đồ họa được thiết lập khi ảnh tiếp theo được tạo.", "The import reads the catalog without changing it and adds its photos, edits, keywords and collections to the library open now.": "Nhập đọc catalog không đổi nó và thêm ảnh, chỉnh sửa, từ khóa và bộ sưu tập vào thư viện đang mở.", + "The library is up to date with this folder.": "Thư viện đã đồng bộ với thư mục này.", + "The model is kept on this computer only. LightCraft never uploads or shares it.": "Mô hình chỉ lưu trên máy này. LightCraft không tải lên hay chia sẻ.", + "The number at the end of the original name (IMG_0042 → 0042)": "Số ở cuối tên gốc (IMG_0042 → 0042)", + "The original extension is always added; {ext} only puts it inside the name as well.": "Phần mở rộng gốc luôn được thêm; {ext} chỉ đặt thêm bên trong tên.", + "The original files, unchanged, each with an XMP sidecar holding its edits.": "Tệp gốc không đổi, mỗi tệp kèm sidecar XMP chứa chỉnh sửa.", + "The photo has these settings": "Ảnh có các thiết lập này", + "The processor does the work.": "Bộ xử lý thực hiện công việc.", "The thumbnail cache only ever counts and deletes its own files (issue #98): a library opened on a folder that": "Bộ nhớ đệm thumbnail chỉ đếm và xóa tệp của chính nó (issue #98): thư viện mở trên thư mục", + "Their photos and the keywords below them come together under one keyword.": "Ảnh của chúng và từ khóa bên dưới gộp chung dưới một từ khóa.", "Theme": "Chủ đề", + "There is no model file to install": "Không có tệp mô hình để cài", + "They can be restored from Recently Deleted until it is emptied.": "Có thể khôi phục từ Mới xóa gần đây cho đến khi xóa hết.", + "They move to Recently Deleted and can be restored; no file on disk is touched.": "Chúng chuyển sang Đã xóa gần đây và có thể khôi phục; không đụng tệp trên đĩa.", + "Thirds": "Một phần ba", + "This Computer": "Máy này", + "This build can't download the model yet. To install it by hand, put model.safetensors, vocab.json and merges.txt from Meta's facebook/sam3 in the folder above: Object and Describe work as soon as they are there.": "Bản build này chưa tải mô hình được. Cài tay: đặt model.safetensors, vocab.json và merges.txt từ facebook/sam3 của Meta vào thư mục trên: Object và Describe hoạt động ngay khi có đủ.", "This build cannot run denoise models.": "Bản build này không chạy được mô hình khử nhiễu.", + "This build cannot run recognition models: they can be added and chosen, not used.": "Bản build này không chạy mô hình nhận dạng: có thể thêm và chọn, không dùng được.", + "This build has nowhere to keep denoise models, so AI Denoise is not available. (The desktop app has.)": "Bản build này không có chỗ lưu mô hình khử nhiễu, nên AI Denoise không khả dụng. (App desktop có.)", + "This build has nowhere to keep face models, so the model list is not available. (The desktop app has.)": "Bản build này không có chỗ lưu mô hình khuôn mặt, nên danh sách mô hình không khả dụng. (App desktop có.)", + "This file cannot be used yet": "Tệp này chưa dùng được", + "This folder is not available (drive disconnected?). Smart previews are not built or used until it is back or you choose another folder.": "Thư mục không khả dụng (ổ đã rút?). Smart preview không được tạo hay dùng cho đến khi ổ trở lại hoặc bạn chọn thư mục khác.", + "This folder isn't there: it was moved or renamed, or its disk isn't connected.": "Thư mục không còn: đã di chuyển hoặc đổi tên, hoặc ổ chưa kết nối.", "This group is empty: add a rule or remove it.": "Nhóm này trống: thêm quy tắc hoặc xóa nhóm.", "This is a Lightroom catalog, not a LightCraft library. Import it into a LightCraft library instead?": "Đây là catalog Lightroom, không phải thư viện LightCraft. Nhập vào thư viện LightCraft thay vì?", "This is the album you're editing": "Đây là album bạn đang chỉnh sửa", + "This photo can't be opened": "Không thể mở ảnh này", + "Threshold": "Ngưỡng", "Thumbnail cache": "Bộ nhớ đệm hình thu nhỏ", "Thursday": "Thứ Năm", + "Tick the box to accept the model's terms first": "Đánh dấu hộp để chấp nhận điều khoản mô hình trước", + "Time zone": "Múi giờ", "Tint": "Tông", "Title": "Tiêu đề", "Title metadata": "Siêu dữ liệu tiêu đề", "Toggle Keyword from Set": "Bật/tắt từ khóa từ bộ", "Toggle Mask": "Bật/tắt mặt nạ", + "Toggle Section": "Bật/tắt mục", "Toggle Zoom": "Bật/tắt thu phóng", "Tone Curve": "Đường cong tông màu", "Tools": "Công cụ", + "Top Level": "Cấp cao nhất", + "Transfer": "Chuyển", "Treatment": "Xử lý màu", + "Triangle": "Tam giác", + "Try Again": "Thử lại", + "Try Saving Again": "Thử lưu lại", + "Try again": "Thử lại", + "Try the graphics card again": "Thử lại card đồ họa", "Tu": "T3", "Tuesday": "Thứ Ba", + "Tungsten": "Đèn sợi đốt", + "Turn Off": "Tắt", + "Turn off": "Tắt", + "Turn on Include subfolders, or pick another folder under Local": "Bật Bao gồm thư mục con, hoặc chọn thư mục khác trong Local", + "Type": "Loại", + "Uncheck All": "Bỏ chọn tất cả", + "Uncheck the files of this type": "Bỏ chọn tệp loại này", "Undo": "Hoàn tác", "Unedited": "Chưa chỉnh sửa", + "Unedited raws": "RAW chưa chỉnh", "Unflag": "Bỏ cờ", "Unflagged": "Không gắn cờ", + "Ungroup Stack": "Bỏ nhóm chồng", "Unknown": "Không rõ", + "Unknown Date": "Ngày không xác định", + "Unknown licence": "Giấy phép không xác định", + "Unknown tags stay as typed — check the preview for a {typo}.": "Thẻ không xác định giữ nguyên như đã gõ — kiểm tra xem trước xem có {typo} không.", "Unnamed Faces": "Khuôn mặt chưa đặt tên", + "Unrated": "Chưa xếp hạng", + "Unreadable": "Không đọc được", + "Update": "Cập nhật", "Update Mask Shape": "Cập nhật hình mặt nạ", "Update Preset with Current Settings": "Cập nhật thiết lập sẵn bằng thiết lập hiện tại", + "Update Rules from Current Filter": "Cập nhật quy tắc từ bộ lọc hiện tại", "Update Version": "Cập nhật phiên bản", "Update Version with Current Settings": "Cập nhật phiên bản bằng thiết lập hiện tại", + "Update with Current Settings": "Cập nhật bằng thiết lập hiện tại", "Updated the edits saved in the external editor": "Đã cập nhật chỉnh sửa lưu trong trình soạn ngoài", "Upright": "Chỉnh thẳng", "Urban": "Đô thị", + "Use": "Dùng", "Use Keyword Set": "Dùng bộ từ khóa", + "Use Library Folder": "Dùng thư mục thư viện", + "Use camera-specific defaults": "Dùng mặc định theo máy ảnh", "Use the GPU for rendering": "Dùng GPU để kết xuất", "User Presets": "Thiết lập sẵn người dùng", + "Username": "Tên người dùng", + "Value": "Giá trị", + "Variance": "Phương sai", "Version": "Phiên bản", "Version name": "Tên phiên bản", "Versions": "Phiên bản", @@ -1061,26 +1891,49 @@ "Vibrance": "Độ rực rỡ", "Video": "Video", "Video Duration": "Thời lượng video", + "Videos": "Video", "View": "Xem", + "Viewing and sharing": "Xem và chia sẻ", "Vignette": "Tối góc", "Vignetting": "Tối góc", "Vintage": "Vintage", "Virtual Copy": "Bản sao ảo", + "Visible": "Hiển thị", + "Visualize Spots": "Hiển thị điểm bụi", + "Visualize Spots (A)": "Hiển thị điểm bụi (A)", + "Visualize range": "Hiển thị dải", + "Vivid": "Rực rỡ", + "Vivid Pop": "Bật rực", "Wait for the import to finish": "Đợi nhập hoàn tất", "Waiting to start…": "Đang chờ bắt đầu…", + "Warm Film": "Phim ấm", "Warm Glow": "Ánh ấm", + "Warm Print": "In ấm", + "Warm Table": "Bàn ấm", + "Watched folder": "Thư mục theo dõi", "Watched-folder auto import; Convert to DNG; Duplicate; Build Standard / 1:1 / Smart Previews.": "Tự động nhập thư mục theo dõi; Chuyển sang DNG; Nhân bản; Tạo Standard / 1:1 / Smart Preview.", "Watermark": "Hình mờ", "We": "T4", "Wednesday": "Thứ Tư", "What's New": "Có gì mới", + "When rated or hovered": "Khi đã xếp hạng hoặc rê chuột", "White Balance": "Cân bằng trắng", "White Balance Selector": "Bộ chọn cân bằng trắng", "White Balance Selector (W)": "Bộ chọn cân bằng trắng (W)", "Whites": "Vùng trắng", + "Width": "Chiều rộng", + "Width (% of photo)": "Chiều rộng (% ảnh)", + "Width (px)": "Chiều rộng (px)", + "Width × Height": "Rộng × Cao", "Will Export": "Sẽ xuất", + "Will be replaced": "Sẽ được thay thế", + "Will be restored": "Sẽ được khôi phục", "Window": "Cửa sổ", + "Winter Blue": "Xanh đông", + "Without Saving and Quit (issue #100). It no longer quietly starts a demo session that looked like a reset library and": "Không lưu và Thoát (issue #100). Không còn im lặng bắt đầu phiên demo trông như thư viện bị đặt lại và", + "Works on raw files from cameras with a standard (Bayer) sensor. Other files keep their normal noise reduction.": "Hoạt động trên raw từ máy cảm biến chuẩn (Bayer). Tệp khác giữ khử nhiễu thông thường.", "XMP Sidecar Preferences": "Tùy chọn tệp sidecar XMP", + "XMP sidecars": "Sidecar XMP", "Year": "Năm", "Yellow": "Vàng", "Yellow Hue": "Sắc vàng", @@ -1088,19 +1941,35 @@ "Yellow Saturation": "Độ bão hòa vàng", "Yellow label": "Nhãn vàng", "Yes": "Có", + "You can close this: the download continues, and resumes if interrupted.": "Bạn có thể đóng: tải vẫn tiếp tục và tiếp tục nếu bị gián đoạn.", + "Your Name": "Tên của bạn", + "Your library couldn't be opened": "Không thể mở thư viện của bạn", + "Zoom": "Thu phóng", "Zoom 100%": "Thu phóng 100%", "Zoom In": "Phóng to", "Zoom Out": "Thu nhỏ", "Zoom to Fit": "Thu phóng vừa khung", + "Zoom to page level": "Thu phóng đến cấp trang", + "`Photos/2026/20260114/20260114_001.jpg`) together with their XMP sidecars; each original leaves the card only after its": "`Photos/2026/20260114/20260114_001.jpg`) cùng sidecar XMP; mỗi bản gốc rời thẻ chỉ sau khi", + "`img_1-1.JPG`; on case-insensitive volumes the case change still goes through.": "`img_1-1.JPG`; trên ổ không phân biệt hoa thường đổi hoa thường vẫn thực hiện.", "a full drive) no longer counts as built and Build Smart Previews replaces it.": "ổ đầy) không còn được coi là đã tạo và Tạo Smart Preview thay thế.", + "a literal %": "ký tự % thực", + "a removed photo": "một ảnh đã gỡ", + "afterwards (issue #101): the partial write is cut off before LightCraft retries, so the next launch replays every": "sau đó (issue #101): ghi dở bị cắt trước khi LightCraft thử lại, nên lần khởi động sau phát lại mọi", "again. Change the period (or turn it off) in Settings → Performance.": "lại. Đổi chu kỳ (hoặc tắt) trong Thiết lập → Hiệu năng.", + "against the library's originals no longer scans the whole library when nothing is at that path.": "với bản gốc của thư viện không còn quét cả thư viện khi không có gì ở đường dẫn đó.", + "all": "tất cả", "already has a `thumbs/` folder of other pictures no longer loses them when the cache is trimmed or cleared.": "đã có thư mục `thumbs/` của ảnh khác không còn mất chúng khi cắt gọn hoặc xóa cache.", + "and": "và", "and checks the file before using it. Masks keep their selection, so they render and export without the model.": "và kiểm tra tệp trước khi dùng. Mặt nạ giữ vùng chọn, nên kết xuất và xuất không cần mô hình.", "and every imported photo as one zip, and File ▸ Restore Library from Backup… brings it back (the current library": "và mọi ảnh đã nhập thành một zip, và Tệp ▸ Khôi phục thư viện từ bản sao lưu… đưa lại (thư viện hiện tại", "and never freezes the window. It is optional and not part of LightCraft (Meta's SAM License, about 3.4 GB): the": "và không bao giờ đóng băng cửa sổ. Tùy chọn và không thuộc LightCraft (SAM License của Meta, khoảng 3,4 GB):", + "any": "bất kỳ", "are empty": "trống", "aren't empty": "không trống", + "as `.corrupt-