fix(app-iced): M106 r2 —— 两处「改了行为、旧口径还在树里」(复审 p2-1 / p2-2)

p2-1(它在撒谎):`renderer/acceptance/locale.rs::Chain::line()` 还打 `ui_text=pinned-en`,
注释写着「pages/mod.rs::render 里下载页固定传 Lang::En」、`setting` 回退 `<未接线>`——M106 之后
两句同时为假,于是 `ULL_ACCEPTANCE=1` 时启动日志两行互相矛盾(旧行说「文案钉在英文」,新行说
「生效中文」)。修法:`Chain` 增 `machine`(只看平台源 + 环境变量,供 `[env] language=` 用)与
`detection`(含 `ui.language` 手选,与 App 的 `[i18n] choice=…` 同源);`host()` 真读
`SettingsBridge::load_ui_language()`,`line()` 删掉 `ui_text`、`setting` 打真实值。
实测三行现在一致:
  [i18n] setting=<未设置=跟随系统> platform=registry:zh-CN env=env:<未设置> -> lang=zh-CN locale=zh-CN source=registry
  [i18n] choice=system lang=zh-CN locale=zh-CN source=registry effective=zh-CN
`locale_tests.rs` 把钉假串的那条改成「不许出现 pinned-en」的回归绊线,并新增
`i18n_line_honours_the_explicit_setting_without_rewriting_the_machine_language`。

p2-2(doc-only):`pages/model.rs` 的「只是留口,产品路径先给 Lang::En」与 `pages/download.rs`
的「产品路径现传 Lang::En,接上探测结果时只改调用点」都已被实际代码推翻(`app/state.rs` +
`refresh_view` 在填、调用点已是 `model.lang`),按事实重写。顺带修掉 `fonts/cjk.rs` 里同样的
「设置层的读取点尚未接线」。

门禁:`cargo fmt --all -- --check` 退出码 0;`cargo test -p unlucky-app-iced --lib` 退出码 0
(409 passed, 0 failed)。全改动文件 ≤400 行(最大 269)。
This commit is contained in:
AskaEth committed 2026-11-05 01:17:36 +08:00
1 parent 89dcb6bdf3
commit 954a129e01
14 files changed
+286 -107

No files matched your search

+7 -49
View File
@@ -20,7 +20,6 @@ use std::time::Instant;
use iced::window;
use unlucky_design::color::SchemeFlavor;
use unlucky_i18n::Lang;
use unlucky_presenter::backend::{build_backend, config_path, AppOptions};
use unlucky_presenter::dto::Backend;
use unlucky_presenter::prefs::ThemeMode;
@@ -60,11 +59,6 @@ pub(super) const IDLE_TICK: std::time::Duration = std::time::Duration::from_secs
/// 3 秒够真 host 把「命令已受理」的第一条事件交回来;之后由「有 Busy/Running 实例」这个条件续订。
pub(super) const WATCH_WINDOW: std::time::Duration = std::time::Duration::from_secs(3);
/// 设置页左侧分组的取证开关:`ULL_SETTINGS_GROUP=0` 直达 General(语言行在那里)。
///
/// 只影响 `--screenshot` 那一次进程(见 [`App::with_presenter`]);交互模式按用户点的那一组。
pub(super) const SETTINGS_GROUP_ENV: &str = "ULL_SETTINGS_GROUP";
/// 进程内「run() 开始」的时刻(首帧耗时基线)。
pub(super) static STARTED: OnceLock<Instant> = OnceLock::new();
/// 首帧日志只打一次。
@@ -206,17 +200,11 @@ impl App {
backend_tier,
flavor,
);
// 取证开关(D30,与 `ULL_START_ROUTE` 同一条思路):`ULL_SETTINGS_GROUP=<下标>` 选设置页的
// 左侧分组。设置页出厂停在「外观」(`APPEARANCE_GROUP`),而「语言」那一行在 General 组——
// 出图必须能直达,否则验收图里根本没有用户抱怨的那一行。**只在截图通道生效**:交互模式
// 一律按用户点的那一组。
if options.screenshot.is_some() {
if let Some(index) = std::env::var(SETTINGS_GROUP_ENV)
.ok()
.and_then(|raw| raw.trim().parse::<usize>().ok())
{
appearance.selected_group = index;
}
// 取证开关(D30):`ULL_SETTINGS_GROUP=<下标>` 直达设置页的某一组(出图要看见语言行)。
if let Some(index) =
crate::ui::lang::screenshot_settings_group(options.screenshot.is_some())
{
appearance.selected_group = index;
}
// 界面语言(M106):**M92 已经探测对了,问题是一直没人用**——`pages::Model.lang` 此前在
// `view::model` 里被写死成 `Lang::En`,于是中文系统上开出来的是全英文界面。
@@ -328,7 +316,8 @@ impl App {
// 否则会出现「选项区英文、取消弹窗中文」的同屏两语(复审 P2-2)。
if self.state.install_cancelled != self.install_cancelled_seen {
self.install_cancelled_seen = self.state.install_cancelled;
// M106:提示语跟着**生效语言**走(M105 留的 `view::ui_lang()` 占位到此收口)。
// M106:提示语跟着**生效语言**走(M105 留的 `view::ui_lang()` 占位已删——它恒英文,
// 中文界面会弹出英文提示,那正是 M105 r1 复审 P2-2 要堵的同屏两语)。
let text = pages::cancelled_toast(self.lang());
self.state.toasts.push(ToastKind::Info, text);
}
@@ -378,37 +367,6 @@ impl App {
pub(super) fn ui(&self) -> &Ui {
&self.ui
}
/// 当前生效的界面语言(= 目录选择;页面文案一律由它派生)。
pub(super) fn lang(&self) -> Lang {
self.lang.lang()
}
/// 设置页语言行要的两件:档位(画选中态)+ 生效语言(画回显)。
pub(super) fn language(&self) -> pages::Language {
self.lang.for_settings()
}
/// 换界面语言(设置页语言行 → `pages::Message::Language`)。
///
/// 三件事缺一不可:①档位与结论换掉 ②视图模型重建(`view_dirty` + `refresh_view`,目录是
/// 视图模型的一部分)③落盘(重启后保持所选语言)。字体不在这里重扫:中文档缺字体时的
/// 判据/信号归 `i18n::font::decide` + `fonts/cjk.rs`(见报告「没验的部分」)。
pub(super) fn set_language(&mut self, choice: unlucky_i18n::LangChoice) {
if choice == self.lang.choice() {
return;
}
self.lang = LangState::of(choice);
self.lang.log();
if !self.bridge.persist_ui_language(choice.setting_value()) {
eprintln!(
"[i18n] 语言偏好没落盘(配置只读或数据根解析不出来):本次生效,重启会回到旧值"
);
}
self.lang.log_cjk();
self.view_dirty = true;
self.refresh_view();
}
}
/// 启动参数 → presenter 的后端选项。