diff --git a/crates/ui-egui/locales/cs-formats.json b/crates/ui-egui/locales/cs-formats.json index 1eb882f09..3a3f92697 100644 --- a/crates/ui-egui/locales/cs-formats.json +++ b/crates/ui-egui/locales/cs-formats.json @@ -137,6 +137,7 @@ "Rendering on the CPU: {why}": "Vykreslování na CPU: {why}", "Replace {} with:": "Nahradit {} za:", "Reset {name}": "Obnovit {name}", + "{name} value": "{name} – hodnota", "Reset {} Channel": "Obnovit kanál {}", "Restore {}": "Obnovit {}", "Restore {} Photo{}": "Obnovit fotografie: {}{:.0}", diff --git a/crates/ui-egui/locales/de-formats.json b/crates/ui-egui/locales/de-formats.json index 79390f136..15abae213 100644 --- a/crates/ui-egui/locales/de-formats.json +++ b/crates/ui-egui/locales/de-formats.json @@ -115,6 +115,7 @@ "Rendering on the CPU: {why}": "Rendering auf der CPU: {why}", "Replace {} with:": "{} ersetzen durch:", "Reset {name}": "{name} zurücksetzen", + "{name} value": "{name}: Wert", "Reset {} Channel": "Kanal {} zurücksetzen", "Restore {}": "{} wiederherstellen", "Restore {} Photo{}": "{} Foto{} wiederherstellen", diff --git a/crates/ui-egui/locales/es-formats.json b/crates/ui-egui/locales/es-formats.json index 33e5f52fc..74e98d815 100644 --- a/crates/ui-egui/locales/es-formats.json +++ b/crates/ui-egui/locales/es-formats.json @@ -115,6 +115,7 @@ "Rendering on the CPU: {why}": "Renderizado en la CPU: {why}", "Replace {} with:": "Reemplazar {} por:", "Reset {name}": "Restablecer {name}", + "{name} value": "Valor de {name}", "Reset {} Channel": "Restablecer canal {}", "Restore {}": "Restaurar {}", "Restore {} Photo{}": "Restaurar {} foto{}", diff --git a/crates/ui-egui/locales/fi-formats.json b/crates/ui-egui/locales/fi-formats.json index 1daab3dab..f17d9ceb6 100644 --- a/crates/ui-egui/locales/fi-formats.json +++ b/crates/ui-egui/locales/fi-formats.json @@ -165,6 +165,7 @@ "Rendering on the CPU: {why}": "Renderöidään suorittimella: {why}", "Replace {} with:": "Korvaa {} seuraavalla:", "Reset {name}": "Nollaa {name}", + "{name} value": "{name}: arvo", "Reset {} Channel": "Nollaa kanava {}", "Restore {}": "Palauta {}", "Restore {} Photo{}": "Palauta kuvia: {}{:.0}", diff --git a/crates/ui-egui/locales/fr-formats.json b/crates/ui-egui/locales/fr-formats.json index 294273781..90785ed0b 100644 --- a/crates/ui-egui/locales/fr-formats.json +++ b/crates/ui-egui/locales/fr-formats.json @@ -115,6 +115,7 @@ "Rendering on the CPU: {why}": "Rendu sur le processeur : {why}", "Replace {} with:": "Remplacer {} par :", "Reset {name}": "Réinitialiser {name}", + "{name} value": "{name} : valeur", "Reset {} Channel": "Réinitialiser le canal {}", "Restore {}": "Restaurer {}", "Restore {} Photo{}": "Restaurer {} photo{}", diff --git a/crates/ui-egui/locales/id-formats.json b/crates/ui-egui/locales/id-formats.json index 7fc325522..abba40434 100644 --- a/crates/ui-egui/locales/id-formats.json +++ b/crates/ui-egui/locales/id-formats.json @@ -135,6 +135,7 @@ "Label Set: {name}": "Set label: {name}", "Quick Develop: {name}": "Olah cepat: {name}", "Reset {name}": "Atur ulang {name}", + "{name} value": "Nilai {name}", "Updated “{name}”": "“{name}” diperbarui", "{month}": "{month:02}", "{month} {year}": "{month:02}/{year}", diff --git a/crates/ui-egui/locales/it-formats.json b/crates/ui-egui/locales/it-formats.json index 7efae90e9..f15f75150 100644 --- a/crates/ui-egui/locales/it-formats.json +++ b/crates/ui-egui/locales/it-formats.json @@ -113,6 +113,7 @@ "Rendering on the CPU: {why}": "Rendering sulla CPU: {why}", "Replace {} with:": "Sostituisci {} con:", "Reset {name}": "Reimposta {name}", + "{name} value": "Valore di {name}", "Reset {} Channel": "Reimposta canale {}", "Restore {}": "Ripristina {}", "Restore {} Photo{}": "Ripristina {} foto{:.0}", diff --git a/crates/ui-egui/locales/ja-formats.json b/crates/ui-egui/locales/ja-formats.json index 99c14bf16..4e17e4c57 100644 --- a/crates/ui-egui/locales/ja-formats.json +++ b/crates/ui-egui/locales/ja-formats.json @@ -135,6 +135,7 @@ "Label Set: {name}": "ラベルセット:{name}", "Quick Develop: {name}": "クイック現像: {name}", "Reset {name}": "{name}をリセット", + "{name} value": "{name}の値", "Updated “{name}”": "「{name}」を更新しました", "{month}": "{month}月", "{month} {year}": "{year}年{month}月", diff --git a/crates/ui-egui/locales/ka-formats.json b/crates/ui-egui/locales/ka-formats.json index 460368261..c19104860 100644 --- a/crates/ui-egui/locales/ka-formats.json +++ b/crates/ui-egui/locales/ka-formats.json @@ -137,6 +137,7 @@ "Rendering on the CPU: {why}": "რენდერი CPU-ზე: {why}", "Replace {} with:": "{}-ის ჩანაცვლება:", "Reset {name}": "ჩამოყრა: {name}", + "{name} value": "{name}: მნიშვნელობა", "Reset {} Channel": "არხის ჩამოყრა: {}", "Restore {}": "აღდგენა: {}", "Restore {} Photo{}": "ფოტოს აღდგენა: {}{:.0}", diff --git a/crates/ui-egui/locales/pl-formats.json b/crates/ui-egui/locales/pl-formats.json index 20c7f840d..dfa9901c8 100644 --- a/crates/ui-egui/locales/pl-formats.json +++ b/crates/ui-egui/locales/pl-formats.json @@ -106,6 +106,7 @@ "Rendering on the CPU: {why}": "Renderowanie na procesorze: {why}", "Replace {} with:": "Zamień {} na:", "Reset {name}": "Wyzeruj {name}", + "{name} value": "{name}: wartość", "Reset {} Channel": "Wyzeruj kanał {}", "Restore {}": "Przywróć {}", "Restore {} Photo{}": "Przywróć zdjęcia: {}{:.0}", diff --git a/crates/ui-egui/locales/pt-br-formats.json b/crates/ui-egui/locales/pt-br-formats.json index f17f2c0fd..cf4ab1221 100644 --- a/crates/ui-egui/locales/pt-br-formats.json +++ b/crates/ui-egui/locales/pt-br-formats.json @@ -84,6 +84,7 @@ "Rename “{name}”": "Renomear “{name}”", "Rendering on the CPU: {why}": "Renderizando na CPU: {why}", "Reset {name}": "Redefinir {name}", + "{name} value": "Valor de {name}", "Reset {} Channel": "Redefinir canal {}", "Restore {}": "Restaurar {}", "Restore {} Photo{}": "Restaurar {} foto{}", diff --git a/crates/ui-egui/locales/ru-formats.json b/crates/ui-egui/locales/ru-formats.json index 76b7af427..ba0a38bb3 100644 --- a/crates/ui-egui/locales/ru-formats.json +++ b/crates/ui-egui/locales/ru-formats.json @@ -120,6 +120,7 @@ "Rendering on the CPU: {why}": "Рендеринг на CPU: {why}", "Replace {} with:": "Заменить {} на:", "Reset {name}": "Сбросить: {name}", + "{name} value": "{name}: значение", "Reset {} Channel": "Сбросить канал: {}", "Restore {}": "Восстановить {}", "Restore {} Photo{}": "Восстановить фото: {}{:.0}", diff --git a/crates/ui-egui/locales/sv-formats.json b/crates/ui-egui/locales/sv-formats.json index 9a71a0288..76112013c 100644 --- a/crates/ui-egui/locales/sv-formats.json +++ b/crates/ui-egui/locales/sv-formats.json @@ -161,6 +161,7 @@ "Rendering on the CPU: {why}": "Renderar på processorn: {why}", "Replace {} with:": "Ersätt {} med:", "Reset {name}": "Återställ {name}", + "{name} value": "{name}: värde", "Reset {} Channel": "Återställ kanalen {}", "Restore {}": "Återställ {}", "Restore {} Photo{}": "Återställ {} foto{}", diff --git a/crates/ui-egui/locales/uk-formats.json b/crates/ui-egui/locales/uk-formats.json index 36022ac1a..b653126e9 100644 --- a/crates/ui-egui/locales/uk-formats.json +++ b/crates/ui-egui/locales/uk-formats.json @@ -115,6 +115,7 @@ "Rendering on the CPU: {why}": "Рендеринг на ЦП: {why}", "Replace {} with:": "Замінити {} на:", "Reset {name}": "Скинути: {name}", + "{name} value": "{name}: значення", "Reset {} Channel": "Скинути канал: {}", "Restore {}": "Відновити {}", "Restore {} Photo{}": "Відновити фото: {}{:.0}", diff --git a/crates/ui-egui/locales/vi-formats.json b/crates/ui-egui/locales/vi-formats.json index d5e28bff0..5dc695884 100644 --- a/crates/ui-egui/locales/vi-formats.json +++ b/crates/ui-egui/locales/vi-formats.json @@ -165,6 +165,7 @@ "Rendering on the CPU: {why}": "Đang kết xuất trên CPU: {why}", "Replace {} with:": "Thay {} bằng:", "Reset {name}": "Đặt lại {name}", + "{name} value": "Giá trị {name}", "Reset {} Channel": "Đặt lại kênh {}", "Restore {}": "Khôi phục {}", "Restore {} Photo{}": "Khôi phục {} ảnh{:.0}", diff --git a/crates/ui-egui/locales/zh-hans-formats.json b/crates/ui-egui/locales/zh-hans-formats.json index 7406c39b8..3146c84ba 100644 --- a/crates/ui-egui/locales/zh-hans-formats.json +++ b/crates/ui-egui/locales/zh-hans-formats.json @@ -135,6 +135,7 @@ "Label Set: {name}": "标签集:{name}", "Quick Develop: {name}": "快速编辑:{name}", "Reset {name}": "重置{name}", + "{name} value": "{name}的值", "Updated “{name}”": "已更新“{name}”", "{verb} {n} Photo{}": "{verb} {n} 张照片{:.0}", "{year}": "{year}年", diff --git a/crates/ui-egui/locales/zh-hant-formats.json b/crates/ui-egui/locales/zh-hant-formats.json index d5c4eb279..bc175e6d5 100644 --- a/crates/ui-egui/locales/zh-hant-formats.json +++ b/crates/ui-egui/locales/zh-hant-formats.json @@ -80,6 +80,7 @@ "Rename “{name}”": "重新命名「{name}」", "Rendering on the CPU: {why}": "使用 CPU 算繪:{why}", "Reset {name}": "重設{name}", + "{name} value": "{name}的數值", "Reset {} Channel": "重設 {} 通道", "Restore {}": "還原為 {}", "Restore {} Photo{}": "還原 {} 張照片{:.0}", diff --git a/crates/ui-egui/src/widgets.rs b/crates/ui-egui/src/widgets.rs index 558edfe8d..1e0bd851b 100644 --- a/crates/ui-egui/src/widgets.rs +++ b/crates/ui-egui/src/widgets.rs @@ -421,7 +421,8 @@ pub fn slider(ui: &mut Ui, spec: &ControlSpec, value: f64, enabled: bool, label_ // takes the click) let value_rect = Rect::from_min_max(pos2(label_rect.right() - 64.0, label_rect.top()), label_rect.max); let value_resp = ui.interact(value_rect, id.with("value"), if enabled { Sense::click_and_drag() } else { Sense::hover() }); - crate::widgets::announce(&value_resp, format!("{label_text}: {}", crate::i18n::tr("Click to type a value, drag to change it"))); + // the name is short ("Exposure value"); how to use it is the description the hover text below gives + crate::widgets::announce(&value_resp, crate::i18n::tr_format!("{name} value", name = label_text.clone())); register(ui, format!("sliderValue:{}", spec.id), value_rect); // say that an exact value can be typed here (issue #534: an exact crop angle was hard to find) let value_resp = if enabled { value_resp.on_hover_text(crate::i18n::tr("Click to type a value, drag to change it")) } else { value_resp }; diff --git a/crates/ui-egui/tests/it/accessibility.rs b/crates/ui-egui/tests/it/accessibility.rs index 04d64f3e5..1ce6f9a0d 100644 --- a/crates/ui-egui/tests/it/accessibility.rs +++ b/crates/ui-egui/tests/it/accessibility.rs @@ -249,3 +249,19 @@ fn tab_walks_the_right_panels_top_to_bottom() { } } } + +/// A slider's value field is " value" (the instruction to click, type or drag is its +/// description, not part of the name VoiceOver reads on every visit). +#[test] +fn a_slider_value_field_is_named_value_and_describes_how_to_use_it() { + const INSTRUCTION: &str = "Click to type a value, drag to change it"; + let h = harness(ViewMode::Detail, RightPanel::Edit); + let buttons: Vec<_> = h.root().children_recursive().filter(|n| n.accesskit_node().role() == Role::Button).collect(); + let names: Vec = buttons.iter().filter_map(|n| n.accesskit_node().label()).collect(); + let field = buttons + .iter() + .find(|n| n.accesskit_node().label().as_deref() == Some("Exposure value")) + .unwrap_or_else(|| panic!("a value field named \"Exposure value\": {names:?}")); + assert_eq!(field.accesskit_node().description().as_deref(), Some(INSTRUCTION), "the instruction is its description"); + assert!(!names.iter().any(|n| n.contains(INSTRUCTION)), "no name carries the instruction: {names:?}"); +} diff --git a/docs/parity-checklist.md b/docs/parity-checklist.md index 90cfc248f..8d3c72a79 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-25 · **Change:** minor (LR-BEHAV-TITLEBAR: a double-click follows the system setting, and a panel over the bar keeps the window still; KEYC-METADATA, LRC-LIB-KEYWORDS: ⌥0 / ⌥⇧0 go to the next / previous keyword set; LRC-DEV-HISTOGRAM-DRAG: the histogram's five tonal zones — hover for the value, drag to adjust the Basic control the press locked, double-click to reset; LR-VIEW-HISTOGRAM note updated; MENU-BAR: on macOS a menu item that yields its key to a focused text field or to shortcut recording really lets it go; LR-MERGE-HDR / LR-MERGE-PANO: Lanczos-3 warps; LR-IMP-LOCAL: browsing from the sidebar records the folder; LR-VIEW-ZOOM: only a full-size drag within 20 ms clears a slow-drag verdict; LR-IMP-ADD-DIALOG: hierarchical import album destination reconciled with main, #2362; KEY-SLIDER-NUDGE: vertical wheel nudges need a click or drag in the row; leaving it disarms them; LR-EDIT-OPTICS-PROFILE: Fujifilm nine-knot lens tables read at the plain radius; LR-VIEW-ZOOM: only a full-size drag within 20 ms clears a slow-drag verdict; LRC-LIB-LIBFOLDERS, LR-BEHAV-BG-TASKS: Synchronize Folder's scan shows its folder listing and stops it on ✕; LRC-LIB-LIBFOLDERS: Synchronize Folder says a folder is up to date; LR-LIB-STACK: filmstrip stack badge click; LRC-LIB-REFVIEW / CATALOG-SWITCH: Escape preserves edits; catalog-local pins; deleted and malformed references refused; LRC-LIB-COMPARE: the Info panel labels the active photo while culling, #2398; KEYC-RATING: `\` shows / hides the Filter Bar in the grids; LR-VIEW-PHOTOGRID: the grid reads only the photos an import batch or an edit touched, not the whole list; earlier: LRC-PRINT-PAGE: Print Page Options; LR-META-XMP: fewer false unimported-XMP warnings; KEYC-METADATA: ⌘K / Ctrl+K Add Keywords; LRC-DEV-HISTOGRAM-DRAG: the histogram's five tonal zones — hover for the value, drag to adjust the Basic control the press locked, double-click to reset; LR-VIEW-HISTOGRAM note updated; MENU-BAR: on macOS a menu item that yields its key to a focused text field or to shortcut recording really lets it go; LR-MERGE-HDR / LR-MERGE-PANO: Lanczos-3 warps; LR-IMP-LOCAL: browsing from the sidebar records the folder; LR-VIEW-ZOOM: only a full-size drag within 20 ms clears a slow-drag verdict; LR-IMP-ADD-DIALOG: hierarchical import album destination reconciled with main, #2362; KEY-SLIDER-NUDGE: vertical wheel nudges need a click or drag in the row; leaving it disarms them; LR-EDIT-OPTICS-PROFILE: Fujifilm nine-knot lens tables read at the plain radius; LR-VIEW-ZOOM: only a full-size drag within 20 ms clears a slow-drag verdict; LRC-LIB-LIBFOLDERS, LR-BEHAV-BG-TASKS: Synchronize Folder's scan shows its folder listing and stops it on ✕; LRC-LIB-LIBFOLDERS: Synchronize Folder says a folder is up to date; LR-LIB-STACK: filmstrip stack badge click; LRC-LIB-REFVIEW / CATALOG-SWITCH: Escape preserves edits; catalog-local pins; deleted and malformed references refused; LRC-LIB-COMPARE: the Info panel labels the active photo while culling, #2398; KEYC-RATING: `\` shows / hides the Filter Bar in the grids; LR-VIEW-PHOTOGRID: the grid reads only the photos an import batch or an edit touched, not the whole list; earlier: LRC-PRINT-PAGE: Print Page Options; LR-META-XMP: fewer false unimported-XMP warnings) · **Target:** Adobe Lightroom Classic 15.5 / Lightroom 9.6 +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-27 · **Change:** minor (LR-BEHAV-ACCESS: a slider's value field is named ` value`, with how to use it as its description; LR-BEHAV-TITLEBAR: a double-click follows the system setting, and a panel over the bar keeps the window still; KEYC-METADATA, LRC-LIB-KEYWORDS: ⌥0 / ⌥⇧0 go to the next / previous keyword set; LRC-DEV-HISTOGRAM-DRAG: the histogram's five tonal zones — hover for the value, drag to adjust the Basic control the press locked, double-click to reset; LR-VIEW-HISTOGRAM note updated; MENU-BAR: on macOS a menu item that yields its key to a focused text field or to shortcut recording really lets it go; LR-MERGE-HDR / LR-MERGE-PANO: Lanczos-3 warps; LR-IMP-LOCAL: browsing from the sidebar records the folder; LR-VIEW-ZOOM: only a full-size drag within 20 ms clears a slow-drag verdict; LR-IMP-ADD-DIALOG: hierarchical import album destination reconciled with main, #2362; KEY-SLIDER-NUDGE: vertical wheel nudges need a click or drag in the row; leaving it disarms them; LR-EDIT-OPTICS-PROFILE: Fujifilm nine-knot lens tables read at the plain radius; LR-VIEW-ZOOM: only a full-size drag within 20 ms clears a slow-drag verdict; LRC-LIB-LIBFOLDERS, LR-BEHAV-BG-TASKS: Synchronize Folder's scan shows its folder listing and stops it on ✕; LRC-LIB-LIBFOLDERS: Synchronize Folder says a folder is up to date; LR-LIB-STACK: filmstrip stack badge click; LRC-LIB-REFVIEW / CATALOG-SWITCH: Escape preserves edits; catalog-local pins; deleted and malformed references refused; LRC-LIB-COMPARE: the Info panel labels the active photo while culling, #2398; KEYC-RATING: `\` shows / hides the Filter Bar in the grids; LR-VIEW-PHOTOGRID: the grid reads only the photos an import batch or an edit touched, not the whole list; earlier: LRC-PRINT-PAGE: Print Page Options; LR-META-XMP: fewer false unimported-XMP warnings; KEYC-METADATA: ⌘K / Ctrl+K Add Keywords; LRC-DEV-HISTOGRAM-DRAG: the histogram's five tonal zones — hover for the value, drag to adjust the Basic control the press locked, double-click to reset; LR-VIEW-HISTOGRAM note updated; MENU-BAR: on macOS a menu item that yields its key to a focused text field or to shortcut recording really lets it go; LR-MERGE-HDR / LR-MERGE-PANO: Lanczos-3 warps; LR-IMP-LOCAL: browsing from the sidebar records the folder; LR-VIEW-ZOOM: only a full-size drag within 20 ms clears a slow-drag verdict; LR-IMP-ADD-DIALOG: hierarchical import album destination reconciled with main, #2362; KEY-SLIDER-NUDGE: vertical wheel nudges need a click or drag in the row; leaving it disarms them; LR-EDIT-OPTICS-PROFILE: Fujifilm nine-knot lens tables read at the plain radius; LR-VIEW-ZOOM: only a full-size drag within 20 ms clears a slow-drag verdict; LRC-LIB-LIBFOLDERS, LR-BEHAV-BG-TASKS: Synchronize Folder's scan shows its folder listing and stops it on ✕; LRC-LIB-LIBFOLDERS: Synchronize Folder says a folder is up to date; LR-LIB-STACK: filmstrip stack badge click; LRC-LIB-REFVIEW / CATALOG-SWITCH: Escape preserves edits; catalog-local pins; deleted and malformed references refused; LRC-LIB-COMPARE: the Info panel labels the active photo while culling, #2398; KEYC-RATING: `\` shows / hides the Filter Bar in the grids; LR-VIEW-PHOTOGRID: the grid reads only the photos an import batch or an edit touched, not the whole list; earlier: LRC-PRINT-PAGE: Print Page Options; LR-META-XMP: fewer false unimported-XMP warnings) · **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 @@ -479,7 +479,7 @@ differences and missing bindings are in [ui-parity.md](ui-parity.md#shortcuts). | LR-BEHAV-TOOLTIPS | Tooltips with shortcuts | P0 | ✅ | `crates/ui-egui/src/panels/bottombar.rs` | | | LR-BEHAV-TEXTFIELD | Text fields behave alike | P1 | 🟡 | `crates/ui-egui/src/widgets/text_field.rs`, `crates/ui-egui/src/panels/topbar.rs`, `crates/ui-egui/src/widgets.rs`, `crates/ui-egui/src/panels/right.rs` (`meta_field`), `crates/ui-egui/src/dialogs.rs`, `crates/ui-egui/src/panels/unnamed.rs` | one shared field: right-click Cut / Copy / Paste / Select All (no Paste in the browser), Esc gives back the text from before the edit, Return / leaving / Esc reported to the caller, optional select-on-focus; agents use `ui.clipboard` (MCP `clipboard`) and `ui.inspect` → `copied`. Used by Search Photos, slider values, the Info panel's metadata fields (multi-line captions), the one-field dialogs (New / Rename Album, New Smart Album, Rename / Merge Keywords, text prompts) and the unnamed faces' name field so far; the other text fields (most dialogs, import, settings, masking, keywords …) still use egui's own and have no menu | | LR-BEHAV-HEADLESS | Headless UI snapshots | P2 | ✅ | `apps/lightcraft-cli/src/main.rs`, `crates/ui-egui/src/headless.rs`, `docs/control-protocol.md` | `snapshot` rasterizes the UI and defaults photo development to the CPU before the first frame, without adapter discovery; scaled dimensions are validated before allocation, and UI zoom preserves the requested physical viewport; JSON-lines control scripts are supported | -| LR-BEHAV-ACCESS | Accessibility | P2 | 🟡 | `crates/ui-egui/src/widgets.rs`, `crates/ui-egui/src/widgets/text_field.rs`, `crates/ui-egui/src/panels/grid.rs`, `crates/ui-egui/tests/it/accessibility.rs` | AccessKit (VoiceOver / Narrator / AT-SPI): sliders announce control, value, range and step and take Increment / Decrement, buttons / icon buttons / dropdowns / section headers / sources their labels and state, text fields their caption, grid thumbnails file name, rating, flag and label. `tests/it/accessibility.rs` fails on an unnamed control, a slider without range or an untitled dialog in every view, Develop tool and 13 dialogs, and checks that Crop and Remove sliders are reached with Tab and that Tab walks the right panels top to bottom. Canvas tools by keyboard (`crates/ui-egui/src/canvas_keys.rs`, `crates/ui-egui/src/tests/canvas_keys.rs`): crop corners, edges and box, spot targets and sources, a New spot point (Return adds), radial / linear gradient handles and mask pins take the focus, are announced with their position and move with the arrows (Shift: further). Dialogs with one name field (New Album, New Smart Album, Save Metadata Preset, the renames) take the focus once when they open, so Tab and Shift+Tab reach their check box, Cancel and OK, and Return and Esc still confirm and cancel (`crates/ui-egui/src/tests/dialog_tab.rs`). Brush strokes and red-eye ellipses are pointer-only; not tried with a real screen reader ([audit](ui-parity.md#accessibility-audit)) | +| LR-BEHAV-ACCESS | Accessibility | P2 | 🟡 | `crates/ui-egui/src/widgets.rs`, `crates/ui-egui/src/widgets/text_field.rs`, `crates/ui-egui/src/panels/grid.rs`, `crates/ui-egui/tests/it/accessibility.rs` | AccessKit (VoiceOver / Narrator / AT-SPI): sliders announce control, value, range and step and take Increment / Decrement (the value field beside each is named ` value` and describes how to type or drag), buttons / icon buttons / dropdowns / section headers / sources their labels and state, text fields their caption, grid thumbnails file name, rating, flag and label. `tests/it/accessibility.rs` fails on an unnamed control, a slider without range or an untitled dialog in every view, Develop tool and 13 dialogs, and checks that Crop and Remove sliders are reached with Tab and that Tab walks the right panels top to bottom. Canvas tools by keyboard (`crates/ui-egui/src/canvas_keys.rs`, `crates/ui-egui/src/tests/canvas_keys.rs`): crop corners, edges and box, spot targets and sources, a New spot point (Return adds), radial / linear gradient handles and mask pins take the focus, are announced with their position and move with the arrows (Shift: further). Dialogs with one name field (New Album, New Smart Album, Save Metadata Preset, the renames) take the focus once when they open, so Tab and Shift+Tab reach their check box, Cancel and OK, and Return and Esc still confirm and cancel (`crates/ui-egui/src/tests/dialog_tab.rs`). Brush strokes and red-eye ellipses are pointer-only; not tried with a real screen reader ([audit](ui-parity.md#accessibility-audit)) | | LR-BEHAV-LOCALE | Language options | P2 | ✅ | `cmd:app.language.english`, `cmd:app.language.simplifiedChinese`, `cmd:app.language.traditionalChinese`, `cmd:app.language.japanese`, `cmd:app.language.portuguese`, `cmd:app.language.french`, `cmd:app.language.spanish`, `cmd:app.language.german`, `cmd:app.language.russian`, `cmd:app.language.ukrainian`, `cmd:app.language.georgian`, `cmd:app.language.polish`, `cmd:app.language.czech`, `cmd:app.language.italian`, `cmd:app.language.swedish`, `cmd:app.language.finnish`, `cmd:app.language.indonesian`, `cmd:app.language.vietnamese` | Edit > Language lists every language in the table and the active one is checked; shared with Settings > General (docs/localization.md) | | LR-BEHAV-LOCALIZE | Localisation | P2 | 🟡 | `crates/ui-egui/src/i18n.rs`, `crates/ui-egui/locales/`, `docs/localization.md`, `docs/localization-zh-hans.md`, `docs/localization-zh-hant.md`, `docs/localization-ja.md`, `docs/localization-pt-br.md`, `docs/localization-es.md`, `docs/localization-de.md`, `docs/localization-ru.md`, `docs/localization-ka.md`, `docs/localization-pl.md` | One table entry per language (code, endonym, ISO 15924 script, catalog): English, Simplified Chinese, Traditional Chinese (Taiwan), Japanese, Brazilian Portuguese, Spanish, German, Russian, French, Ukrainian, Polish, Czech, Italian, Georgian, Swedish, Finnish, Indonesian and Vietnamese UI with a persisted language preference and craft-fonts regular/bold faces per script (a variable face, as for Arabic, is drawn heavier for bold from its one file); menus, edit, crop/masks, settings, import/export and primary progress messages. Adding a language registers the locale and its language command, plus two catalogs. Stock presets/profiles, history steps, library headings, date headings and capture times are localised (user-named items stay verbatim); the Ukrainian catalog covers every existing catalog key, command/control label and rule-editor label; the German catalog reports newly added gaps; the other catalogs fall back to English for messages they lack. Technical errors remain English; release notes are translated in German and Ukrainian; craft-fonts faces for other scripts (Thai, Arabic, …) are UI fallbacks in every language, for file, folder and album names (#736); Traditional Chinese borrows the Simplified Chinese face (no TC face in craft-fonts yet), and the web build embeds the Japanese, Thai and Georgian faces in WASM while loading the Simplified Chinese face from a separate font file. | | LR-BEHAV-LEARN | Tutorials | OOS | 🚫 | | | @@ -959,3 +959,4 @@ Latin stays upright. Advanced Japanese composition remains open. Regression cove | 2026-10-23 | patch | LR-BEHAV-ACCESS: the name field of New Album, New Smart Album, Rename and the other one-field dialogs takes the keyboard focus once when the dialog opens instead of every frame, so Tab and Shift+Tab reach the check box, Cancel and OK; status unchanged (🟡) | | 2026-10-22 | minor | LR-CROP-AUTO: Auto straighten turns by at most 10° and only on at least 3 agreeing lines, and says when it finds nothing to level by; measured on 68 photos straightened by hand and 300 left as shot, unwanted turns of more than 1° fell from 79 to 19 of the 300. Downgraded ✅ → 🟡: it still leaves most tilted photos alone | | 2026-10-23 | patch | LRC-LIB-FILTERBAR: showing an album (`library.source`) while the filter holds an album drops the filter's album, as showing a library folder already dropped its folder filter; before, the old album stayed in the filter unseen (the filter bar has no album chip) and narrowed the next source such as All Photos; the row's note says so; status unchanged (✅) | +| 2026-10-27 | patch | LR-BEHAV-ACCESS: a slider's value field is named "Exposure value" (the slider's name and "value"), and "Click to type a value, drag to change it" is its description, where the whole sentence was part of the name, read on every visit; status stays 🟡 | diff --git a/docs/whats-new.md b/docs/whats-new.md index c6c259200..9134e029e 100644 --- a/docs/whats-new.md +++ b/docs/whats-new.md @@ -1,5 +1,12 @@ # What's new in LightCraft +## 2026-10-27 + +### Screen readers name a slider's value field "value" +- The number beside a slider is now named "Exposure value" (the slider's name and "value"), and "Click to type a value, + drag to change it" is its description. It was named "Exposure: Click to type a value, drag to change it", so + VoiceOver read the whole sentence each time it reached the field, once for every slider in the Edit panel. + ## 2026-10-24 ### Relative-date filters and smart albums follow the clock