From 1d240ff1f2a212f0cacf62c08076676947b15dda Mon Sep 17 00:00:00 2001 From: AskaEth Date: Sun, 8 Nov 2026 21:29:37 +0800 Subject: [PATCH] =?UTF-8?q?fix(i18n):=20=E5=A4=8D=E5=AE=A1=20r1=20?= =?UTF-8?q?=E2=80=94=E2=80=94=20=E4=B8=A4=E5=8F=A5=E8=BF=91=E4=B9=89?= =?UTF-8?q?=E8=BD=AF=E4=BB=B6=E6=B8=B2=E6=9F=93=E8=AF=B4=E6=98=8E=E5=90=88?= =?UTF-8?q?=E4=B8=80=EF=BC=8C=E7=94=9F=E6=95=88=E5=B1=82=E7=BA=A7=E7=A0=81?= =?UTF-8?q?=E7=BF=BB=E6=88=90=E8=AF=91=E6=96=87=EF=BC=88M180=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit P2-1(一屏两句重复): - 留面板那一句(就在被禁用的滑块旁边,正好回答「为什么拖不动」),措辞同时点名面板与玻璃 - 删 `SettingsAppearanceSoftwareRendererNote`(catalog 一条 + 金表一行,两边同时删) - 删 `bg_image.rs` 的 `backend_note` 渲染块与 `State::backend_note()`;state.rs 391 → 382 行 P2-2(配色:preset 的机器码): - `palette::level_key(code)` 把 `preset`/`wallpaper`/其余 映射到已有的三条档位 key,不新增平行词表 - `bg_image.rs` 用 `tr(PaletteLevel, {level})` 传译文,中文界面显示「配色:内置色卡」 - 补 `every_level_code_maps_to_its_own_sentence`:三个码值一一对应 + 三条译文互不相同 顺手(复审 L-1/L-2/L-4,全在本 scope 内): - `appearance_texts` 加「渲染后不许残留 `{`」断言(参数名写错当场红) - `section/mod.rs` 文档:取词口 t/tr、填充措辞、清掉孤立 `//!`、把「没有一句英文」改成 写明两处例外(`{reason}` 原文串、专名) --- .../app-iced/src/pages/appearance/palette.rs | 54 +++++++++++++++++++ .../src/pages/appearance/section/bg_image.rs | 17 +++--- .../src/pages/appearance/section/mod.rs | 12 +++-- crates/app-iced/src/pages/appearance/state.rs | 9 ---- crates/app-iced/src/pages/appearance/tests.rs | 12 ++++- crates/i18n/src/catalog/golden/tail.rs | 3 +- .../i18n/src/catalog/settings/appearance.rs | 13 +++-- 7 files changed, 88 insertions(+), 32 deletions(-) diff --git a/crates/app-iced/src/pages/appearance/palette.rs b/crates/app-iced/src/pages/appearance/palette.rs index 0543de4..c20ecb9 100644 --- a/crates/app-iced/src/pages/appearance/palette.rs +++ b/crates/app-iced/src/pages/appearance/palette.rs @@ -130,6 +130,24 @@ pub fn note(provenance: &Provenance) -> Option { }) } +/// 生效层级**码值** → 已有的那三条档位 key(M180 复审 P2-2:中文界面里不许留机器码)。 +/// +/// 码值的全部来源只有两处,取值集合相同:`Level::code()`(`background-image` / `wallpaper` / +/// `preset`)与 `PaletteSource::as_str()`(同三个词)。所以三条 key 就够,**不新增平行词表**—— +/// 卡片底部「配色来源」用它们表示**用户选的**档,这一行用它们表示**回落之后真正生效**的档。 +/// +/// 未识别的码值落到 `background-image` 那条(宁可显示一个偏保守的档名,也不许把机器码漏进 +/// 中文界面——这条兜底本身由 `tests` 里的 `every_level_code_maps_to_its_own_sentence` 钉住)。 +/// `state.rs` 已贴 400 行线,所以这个映射住在本文件。 +#[must_use] +pub fn level_key(code: &str) -> Key { + match code { + "preset" => Key::SettingsAppearancePalettePreset, + "wallpaper" => Key::SettingsAppearancePaletteWallpaper, + _ => Key::SettingsAppearancePaletteBackground, + } +} + #[cfg(test)] mod tests { use super::{note, resolve, Source}; @@ -273,4 +291,40 @@ mod tests { None ); } + + /// **M180 复审 P2-2 的守门**:生效层级的**每一个码值**都必须映射到它自己那条中文句子。 + /// + /// 抓得住:① 三个码值被映射到同一条 key(界面上分不出到底生效的是哪一级); + /// ② 某条映射被删掉 / 写错(`preset` 落到 background 那条 ⇒ 中文界面说「取自背景图」); + /// ③ 有人再加一级却忘了扩映射。 + /// 抓不住:译文本身的措辞(那是 `catalog/settings/appearance.rs` 的译文守卫的事)。 + /// + /// 变异证明:把 `"preset"` 那行删掉(落进兜底)⇒ 本条红,且 `assert_ne!` 直接点名码值。 + /// + /// 为什么这条必须有:`the_appearance_card_speaks_chinese` 断的是**整句**非 ASCII, + /// 而「配色:preset」里有汉字 ⇒ 整句非 ASCII ⇒ 那个守卫放过它。这个口子只能在这里堵。 + #[test] + fn every_level_code_maps_to_its_own_sentence() { + use super::level_key; + + let codes = ["background-image", "wallpaper", "preset"]; + let keys: Vec = codes.iter().copied().map(level_key).collect(); + assert_eq!( + keys, + vec![ + Key::SettingsAppearancePaletteBackground, + Key::SettingsAppearancePaletteWallpaper, + Key::SettingsAppearancePalettePreset, + ], + "码值与档位 key 必须一一对应" + ); + + // 三条中文句子互不相同(否则「映射对了」但界面上仍分不出层级)。 + let zh = unlucky_i18n::Lang::ZhCn.catalog(); + let mut texts: Vec<&str> = keys.iter().map(|key| zh.text(*key)).collect(); + let total = texts.len(); + texts.sort_unstable(); + texts.dedup(); + assert_eq!(texts.len(), total, "三条档位译文有重复:{texts:?}"); + } } diff --git a/crates/app-iced/src/pages/appearance/section/bg_image.rs b/crates/app-iced/src/pages/appearance/section/bg_image.rs index 4ea9e68..6c71e6b 100644 --- a/crates/app-iced/src/pages/appearance/section/bg_image.rs +++ b/crates/app-iced/src/pages/appearance/section/bg_image.rs @@ -17,6 +17,7 @@ use crate::pages::Message; use crate::theme::Ui; use super::super::background::{self, BG_DIM_MAX}; +use super::super::palette; use super::super::state::State; use super::super::Change; use super::{choice, choice_row, fixed2, label, note_line, slider_row, t, tr, tr_note}; @@ -66,19 +67,15 @@ pub(super) fn push<'a>( .into(), ); - // ⑥ 诊断(读盘失败 / CPU 降级 / 配色回落)——**不许静默**,且必须在**首屏可见处** + // ⑥ 诊断(读盘失败 / 配色回落)——**不许静默**,且必须在**首屏可见处** // (复审 r1 P2-3:文案落在折叠线以下等于没提示)。位置就在背景图那两行的紧下方。 + // + // CPU 档的「面板/玻璃被强制」那句**不在这里**:它是张卡级状态,挂在被禁用的面板滑块旁边 + // (`panel.rs` 的 `PanelOpacityForcedHint`),一屏只出现一次(M180 复审 P2-1)。 for note in state.diagnostics() { let text = tr_note(lang, note); rows.push(note_line(ui, &text, ui.color(Role::Error))); } - if let Some(key) = state.backend_note() { - rows.push(note_line( - ui, - t(key, lang), - ui.color(Role::OnSurfaceVariant), - )); - } if let Some(note) = state .image() .and_then(|image| background::small_tile_note(image, state.bg_fill)) @@ -93,10 +90,12 @@ pub(super) fn push<'a>( ui.color(Role::OnSurfaceVariant), )); } + // 生效的配色层级:显示的是**回落之后真正生效**的那一级(与底部「配色来源」里用户选的那一档 + // 不一定相同)。码值 → 已有的三条档位 key(不新增平行词表),所以中文界面也读得懂。 let level = tr( lang, Key::SettingsAppearancePaletteLevel, - &[("level", state.palette_level())], + &[("level", t(palette::level_key(state.palette_level()), lang))], ); rows.push(note_line(ui, &level, ui.color(Role::OnSurfaceVariant))); diff --git a/crates/app-iced/src/pages/appearance/section/mod.rs b/crates/app-iced/src/pages/appearance/section/mod.rs index e6b7367..a769e6c 100644 --- a/crates/app-iced/src/pages/appearance/section/mod.rs +++ b/crates/app-iced/src/pages/appearance/section/mod.rs @@ -9,7 +9,7 @@ //! | 面板透明度滑块(下限 0.4,CPU 档禁用) | `appearance.panel_alpha` | [`Change::PanelAlpha`] | //! | 背景图开关 | `appearance.bg_image_enabled` | [`Change::BgEnabled`] | //! | 背景图路径(文本框) | `appearance.bg_image` | [`Change::BgImage`] | -//! | 填充(封面 / 拉伸 / 平铺) | `appearance.bg_fill` | [`Change::BgFill`] | +//! | 填充(铺满 / 完整显示 / 平铺) | `appearance.bg_fill` | [`Change::BgFill`] | //! | 暗化强度(0~0.95) | `appearance.bg_dim` | [`Change::BgDim`] | //! | 配色来源(三档) | `appearance.palette_source` | [`Change::PaletteSource`] | //! @@ -20,7 +20,7 @@ //! //! | 文件 | 是什么 | //! |---|---| -//! | 本文件(`section/mod.rs`) | **壳**:[`section`] 按顺序拼各段 + [`card`] 卡片 + 行控件([`label`] / [`slider_row`] / [`choice_row`] / [`choice`] / [`note_line`])+ 取词口 [`t`] | +//! | 本文件(`section/mod.rs`) | **壳**:[`section`] 按顺序拼各段 + [`card`] 卡片 + 行控件([`label`] / [`slider_row`] / [`choice_row`] / [`choice`] / [`note_line`])+ 两个取词口 [`t`] / [`tr`] | //! | [`window`] | ① 整窗透明度 + ② 窗口圆角(含「因整窗 α 不生效」的 notice 与说明段) | //! | [`panel`] | ③ 面板透明度(CPU 档强制 1.0,值 / 生效值分开显示) | //! | [`bg_image`] | ④ 背景图开关 + ⑤ 路径 + ⑥ 诊断 + ⑦ 填充 + ⑧ 暗化 | @@ -41,8 +41,12 @@ //! `lang` 从 `settings::view` 的 `Language.effective` → `Group.body` → [`section`] 一路递进来。 //! M179 只把管子接通(当时本组 27 条文案里真正本地化的只有圆角那 5 条);M180 `I18NAPPEAR` 把 //! 剩下 22 条字面量与 `state.rs` / `background.rs` / `palette.rs` 的运行时诊断全部搬进 -//! `catalog/settings/appearance.rs`,于是中文界面上这一页**没有一句是英文**。 - +//! `catalog/settings/appearance.rs`,于是中文界面上这一页的**卡片文案**没有一句是英文。 +//! +//! 两处例外(M180 复审 L-1 记下的口径):① 写进 `{reason}` 的**原因串**里,来自本仓库自写的 +//! 两条(`"no path configured"`、`"unknown image format …"`)与 OS / 解码库给出的文本仍是英文—— +//! 它们是不可翻译的第三方或诊断原文;② `Windows 11` / `macOS` / `Linux` / `PNG` / `JPEG` / `BMP` +//! 这些专名。除此之外这一页不出现英文。 //! //! ## 为什么「值」与「生效值」分开显示 //! diff --git a/crates/app-iced/src/pages/appearance/state.rs b/crates/app-iced/src/pages/appearance/state.rs index 354b3b9..753da40 100644 --- a/crates/app-iced/src/pages/appearance/state.rs +++ b/crates/app-iced/src/pages/appearance/state.rs @@ -203,15 +203,6 @@ impl State { &self.diagnostics } - /// CPU 档降级的说明 key(`None` = 没有降级)。 - /// - /// M180:返回 key 而不是英文句子——本文件已 390 行、贴着 400 行硬线,**不放文案表**。 - #[must_use] - pub fn backend_note(&self) -> Option { - self.panel_is_forced() - .then_some(Key::SettingsAppearanceSoftwareRendererNote) - } - /// 配色来源的提示 key(`None` = 一级成功)。 #[must_use] pub fn palette_note(&self) -> Option { diff --git a/crates/app-iced/src/pages/appearance/tests.rs b/crates/app-iced/src/pages/appearance/tests.rs index b57dceb..0f8208f 100644 --- a/crates/app-iced/src/pages/appearance/tests.rs +++ b/crates/app-iced/src/pages/appearance/tests.rs @@ -119,6 +119,17 @@ fn appearance_texts(lang: Lang, case: Case) -> Vec<(Key, String)> { .map(|(key, text)| (key, text.to_owned())) .collect(); texts.extend(probe::take_rendered()); + + // 复审 L-2:`{name}` 换完还留着花括号 ⇒ 某处参数名与模板不一致(`("floor", …)` 写成 + // `("flor", …)` 时句子会原样显示「下限 {floor}」,而「整句非 ASCII」的守卫看不出来)。 + // 三档状态合起来覆盖本页全部 `tr()` 调用,所以这条断言是全覆盖的。 + for (key, text) in &texts { + assert!( + !text.contains('{'), + "{case:?}:{} 渲染后还留着占位符「{text}」——`tr()` 的参数名与模板对不上", + key.name() + ); + } texts } @@ -150,7 +161,6 @@ const CARD_KEYS: &[Key] = &[ Key::SettingsAppearancePanelOpacityHint, Key::SettingsAppearancePanelOpacityForcedValue, Key::SettingsAppearancePanelOpacityForcedHint, - Key::SettingsAppearanceSoftwareRendererNote, Key::SettingsAppearanceBackgroundImage, Key::SettingsAppearanceOff, Key::SettingsAppearanceOn, diff --git a/crates/i18n/src/catalog/golden/tail.rs b/crates/i18n/src/catalog/golden/tail.rs index 78f95db..ab1155a 100644 --- a/crates/i18n/src/catalog/golden/tail.rs +++ b/crates/i18n/src/catalog/golden/tail.rs @@ -38,7 +38,7 @@ pub(super) const ROWS: &[(&str, &str, &str)] = &[ ("SettingsAppearancePanelOpacity", "Panel transparency", "面板透明度"), ("SettingsAppearancePanelOpacityHint", "Only the panel/card layer. Floor {floor}; independent of window transparency.", "只作用于面板 / 卡片这一层。下限 {floor};与整窗透明度互不影响。"), ("SettingsAppearancePanelOpacityForcedValue", "100% (forced from {requested})", "100%(强制,原请求值 {requested})"), - ("SettingsAppearancePanelOpacityForcedHint", "Software renderer: panels stay fully opaque (window transparency still works).", "软件渲染:面板恒为不透明(整窗透明度仍然有效)。"), + ("SettingsAppearancePanelOpacityForcedHint", "Software renderer: panels and glass stay fully opaque (window transparency still works).", "软件渲染:面板与玻璃效果恒为不透明(整窗透明度仍然有效)。"), ("SettingsAppearanceBackgroundImage", "Background image", "背景图"), ("SettingsAppearanceOff", "Off", "关"), ("SettingsAppearanceOn", "On", "开"), @@ -54,7 +54,6 @@ pub(super) const ROWS: &[(&str, &str, &str)] = &[ ("SettingsAppearancePaletteBackground", "Background", "取自背景图"), ("SettingsAppearancePaletteWallpaper", "Wallpaper", "取自壁纸"), ("SettingsAppearancePalettePreset", "Preset", "内置色卡"), - ("SettingsAppearanceSoftwareRendererNote", "Software renderer: panel transparency and glass stay fully opaque (window transparency still works).", "软件渲染:面板透明度与玻璃效果恒为不透明(整窗透明度仍然有效)。"), ("SettingsAppearanceBgReadFailed", "Background image could not be read: {reason}", "背景图读不出来:{reason}"), ("SettingsAppearanceBgDecodeFailed", "Background image could not be decoded ({reason}; this build decodes PNG, JPEG and BMP)", "背景图解不开({reason};这个构建只支持 PNG、JPEG 与 BMP)"), ("SettingsAppearanceBgTooLarge", "Background image is too large to decode: {width}×{height} (limit {limit} px per edge)", "背景图太大,解不开:{width}×{height}(每边上限 {limit} 像素)"), diff --git a/crates/i18n/src/catalog/settings/appearance.rs b/crates/i18n/src/catalog/settings/appearance.rs index 52cdddd..3d3dce5 100644 --- a/crates/i18n/src/catalog/settings/appearance.rs +++ b/crates/i18n/src/catalog/settings/appearance.rs @@ -70,8 +70,8 @@ macro_rules! settings_appearance_entries { "100%(强制,原请求值 {requested})" ), SettingsAppearancePanelOpacityForcedHint => ( - "Software renderer: panels stay fully opaque (window transparency still works).", - "软件渲染:面板恒为不透明(整窗透明度仍然有效)。" + "Software renderer: panels and glass stay fully opaque (window transparency still works).", + "软件渲染:面板与玻璃效果恒为不透明(整窗透明度仍然有效)。" ), SettingsAppearanceBackgroundImage => ("Background image", "背景图"), SettingsAppearanceOff => ("Off", "关"), @@ -91,11 +91,10 @@ macro_rules! settings_appearance_entries { SettingsAppearancePaletteBackground => ("Background", "取自背景图"), SettingsAppearancePaletteWallpaper => ("Wallpaper", "取自壁纸"), SettingsAppearancePalettePreset => ("Preset", "内置色卡"), - // ---- M180:运行时诊断(`state.rs` 的 backend_note + `background.rs` 的三种读盘失败 + 小图平铺) - SettingsAppearanceSoftwareRendererNote => ( - "Software renderer: panel transparency and glass stay fully opaque (window transparency still works).", - "软件渲染:面板透明度与玻璃效果恒为不透明(整窗透明度仍然有效)。" - ), + // ---- M180:运行时诊断(`background.rs` 的三种读盘失败 + 小图平铺)。 + // + // M180 r1 复审 P2-1:软件渲染那句**只有一条**,就挂在面板那一行(`PanelOpacityForcedHint`) + // 上——它挨着被禁用的滑块,正好回答「为什么拖不动」;这里不再有第二句。 SettingsAppearanceBgReadFailed => ( "Background image could not be read: {reason}", "背景图读不出来:{reason}"