Files
Unlucky-Launcher/crates/app-iced/src/pages/instances/text.rs
T
AskaEth 1a4e1fee12 feat(app-iced): M120 实例页与启动阶段标签跟着界面语言走
来源:M106 r1 复审点名——中文机器上首屏(实例页)仍是英中混排(页头 / New instance /
Import / ALL INSTANCES / VERSION / Present on disk / Running · pid / Launch failed)。
用户的原话是「我系统语言是中文 为什么打开软件是英文」。

改了什么
- i18n:catalog/instances.rs 从 6 条死 key 补到 34 条(页头 / 列表列头 / 详情动作 /
  窄窗说明 / 元信息标签与值 / 隔离档位 / 运行状态 / 四个启动阶段)。族在装配链第 2 位,
  新 key 追加在本族末尾,golden 对应位置插入(不是文件末尾追加)。
- 页面:新增 pages/instances/text.rs(Texts)——页面唯一的取词入口,实例页里不再有
  任何可见英文字面量;detail / demo 也改从它取。
- 阶段标签:view/instances.rs 的 Running / Launch failed / 四阶段全部走目录;
  **数字与分隔符不随语言变形**(运行中 · pid 1234 与 Running · pid 1234 只换前半句)。
- 顺手修掉两处「语言反向泄漏」:原版徽标此前直接画 presenter 的中文「原版」(英文界面
  会漏中文),现在走 LoaderVanilla;隔离档位 isolated/shared 也从 core 的稳定 id 换成人话。
- 删掉 InstancesLastPlayed:M117 加的整句 key,从未接线,形状与「标签 + 值」的元信息卡
  不符,由 InstancesMetaLastPlayed + InstancesNeverPlayed 取代。

守门(pages/instances/tests/i18n.rs + app/view/tests.rs)
- 中文态无 ASCII 英文单词(品牌 Java / 技术标识 pid 白名单);
- 每一条 Instances* 的两套译文必须不同(切语言时真的变);
- Running 的数字与 · pid 分隔符在两套语言里逐字保留;
- 页面源码里 29 条旧英文基线不许回来;每条 key 都必须被页面引用(死 key)。

出图:DevDocs/artifacts/m120/01~12(有实例 / 空态 / 运行中 × 浅深 × 中英)。
2026-11-05 13:36:44 +08:00

103 lines
4.4 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! 实例页的**文案入口**:页面上一处可见英文字面量都不留,全部从目录取。
//!
//! ## 为什么要有这一层(而不是在控件树里直接 `catalog.text(..)`)
//!
//! 页面要的文案有 20 多条,直接写的话每个调用点都是「key 名 + 这一处画什么」的重复劳动,
//! 而且**守门测试没法取样**:iced 0.14 的 `Element` 没有内省接口(`instances/tests.rs` 里
//! 「读源码」那条注释解释过同一件事),所以「上屏文本」只能从**页面取词的那一个入口**拿。
//! 于是所有取词收进 [`Texts`],页面用 `texts.xxx()` 画,测试用同一个 `Texts` 断言——
//! 一处定义、两处消费,不存在「测试抄了一份平行实现」。
//!
//! ## 它抓得住什么 / 抓不住什么
//!
//! - **抓得住**:目录里某条中文忘了翻(`pages/instances/tests/i18n.rs` 的「无 ASCII 英文单词」)、
//! 某条中英写成一样(「切换语言文本真的变」)、`Running · pid {pid}` 的数字与分隔符被翻译走样;
//! - **抓不住**:页面上又冒出一条**新**硬编码字面量——那由同文件里「旧串不许回来」的源码扫描
//! 兜已知的那批,加上出图人工看(`DevDocs/artifacts/m120/`);
//! - **抓不住**:译文本身翻得顺不顺(那只能人工审图)。
//!
//! ## 口径
//!
//! 品牌名不翻译(`Java` / `Fabric` / `Forge` 原样);`pid` 是进程号的技术标识,两套语言都写
//! `pid`(改成「进程」会丢掉「拿它去任务管理器里搜」这条可操作性)。
//!
//! **启动阶段(下载中 / 校验中 / …)不在这张表里**:它在 `app/view/instances.rs` 拼进
//! `Row.status`(「阶段 · 百分比」是一整句),与元信息卡同一层——页面只画模型给的字符串。
use unlucky_i18n::{Catalog, Key};
/// 实例页 + 详情列的文案(一个 `Catalog` 的薄包装,`Copy`)。
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct Texts(Catalog);
impl Texts {
/// 从目录取一套(调用方给 `model.lang.catalog()`)。
pub(super) fn of(catalog: Catalog) -> Self {
Self(catalog)
}
// ------------------------------------------------------------- 页头
pub(super) fn title(self) -> &'static str {
self.text(Key::InstancesTitle)
}
pub(super) fn subtitle(self) -> &'static str {
self.text(Key::InstancesSubtitle)
}
pub(super) fn new_instance(self) -> &'static str {
self.text(Key::InstancesNew)
}
pub(super) fn import(self) -> &'static str {
self.text(Key::InstancesImport)
}
// --------------------------------------------------------------- 列表列
pub(super) fn all_title(self) -> &'static str {
self.text(Key::InstancesAllTitle)
}
// --------------------------------------------------------------- 详情列
pub(super) fn back(self) -> &'static str {
self.text(Key::InstancesBack)
}
pub(super) fn play(self) -> &'static str {
self.text(Key::InstancesPlay)
}
pub(super) fn stop(self) -> &'static str {
self.text(Key::InstancesStop)
}
pub(super) fn duplicate(self) -> &'static str {
self.text(Key::InstancesDuplicate)
}
pub(super) fn open_folder(self) -> &'static str {
self.text(Key::InstancesOpenFolder)
}
pub(super) fn delete(self) -> &'static str {
self.text(Key::InstancesDelete)
}
pub(super) fn empty_title(self) -> &'static str {
self.text(Key::InstancesEmptyTitle)
}
pub(super) fn empty_body(self) -> &'static str {
self.text(Key::InstancesEmptyBody)
}
pub(super) fn narrow_note(self) -> &'static str {
self.text(Key::InstancesNarrowNote)
}
fn text(self, key: Key) -> &'static str {
self.0.text(key)
}
/// 这一页的全部 key(守门测试的取样口:**从 `Key::ALL` 过滤出来**,不是手抄一份清单)。
///
/// 域判据是前缀 `Instances`——本族的 key 名是契约(`catalog/instances.rs` 里一条一条写着),
/// 新加的 key 只要还在这个族里就自动进守门范围,不需要有人记得来登记。
#[cfg(test)]
pub(super) fn keys() -> impl Iterator<Item = Key> {
Key::ALL
.iter()
.copied()
.filter(|key| key.name().starts_with("Instances"))
}
}