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(有实例 / 空态 / 运行中 × 浅深 × 中英)。
This commit is contained in:
1 parent
2f491c31f9
commit
1a4e1fee12
17 files changed
+924
-119
No files matched your search
@@ -8,6 +8,7 @@
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
use unlucky_i18n::Key;
|
||||
use unlucky_presenter::dto::{AppCommand, AppEvent, Backend, CoreEvent};
|
||||
use unlucky_presenter::mock_data::mock_instances;
|
||||
|
||||
@@ -159,9 +160,11 @@ fn launching_goes_through_the_backend_and_comes_back_as_events() {
|
||||
!detail.can_launch && detail.can_stop,
|
||||
"派发 LaunchInstance 后后端发回了 Busy 事件:按钮组合必须已经翻转"
|
||||
);
|
||||
// 阶段名跟界面语言走(M120):断言对着**当前生效语言**的目录算,别在中文机器上钉死英文
|
||||
let stage = app.lang().catalog().text(Key::InstancesStageDownload);
|
||||
assert_eq!(
|
||||
detail.status.as_deref(),
|
||||
Some("Downloading · 0%"),
|
||||
Some(format!("{stage} · 0%").as_str()),
|
||||
"状态行来自事件里的进度,不是本地假造"
|
||||
);
|
||||
}
|
||||
@@ -185,8 +188,13 @@ fn ticks_advance_the_backend_script() {
|
||||
|
||||
let detail = app.view.instances.detail.as_ref().expect("有选中项");
|
||||
let status = detail.status.as_deref().unwrap_or_default();
|
||||
let catalog = app.lang().catalog();
|
||||
let (verify, launch) = (
|
||||
catalog.text(Key::InstancesStageVerify),
|
||||
catalog.text(Key::InstancesStageLaunch),
|
||||
);
|
||||
assert!(
|
||||
status.starts_with("Verifying") || status.starts_with("Starting"),
|
||||
status.starts_with(verify) || status.starts_with(launch),
|
||||
"50 拍之后应已过下载阶段,实际 {status:?}"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -144,14 +144,17 @@ pub(super) fn model(
|
||||
) -> pages::Model {
|
||||
let route = state.route().clone();
|
||||
let screen = pages::Screen::of(&route).unwrap_or(pages::Screen::Instances);
|
||||
// 实例页的文案真源:`App::lang` 的目录(M120)。列表 overline / 元信息标签 / 空态都从它取。
|
||||
let catalog = lang.catalog();
|
||||
|
||||
let rows: Vec<Row> = state
|
||||
.tiles()
|
||||
.into_iter()
|
||||
.map(|cell| Row {
|
||||
id: cell.instance.id.clone(),
|
||||
name: cell.instance.name.clone(),
|
||||
supporting: supporting_line(cell.instance),
|
||||
status: runtime_status(&cell.instance.runtime),
|
||||
supporting: supporting_line(cell.instance, catalog),
|
||||
status: runtime_status(&cell.instance.runtime, catalog),
|
||||
})
|
||||
.collect();
|
||||
|
||||
@@ -160,7 +163,7 @@ pub(super) fn model(
|
||||
.instances
|
||||
.iter()
|
||||
.find(|instance| &instance.id == id)
|
||||
.map(detail_of),
|
||||
.map(|instance| detail_of(instance, catalog)),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
|
||||
@@ -7,74 +7,125 @@
|
||||
//! | [`detail_of`] | 详情列的全部字段 | [`crate::pages::Detail`] |
|
||||
//! | [`last_played`] | `2026-10-29 19:22 UTC` / `Never` | 元信息卡 `LAST PLAYED` |
|
||||
//!
|
||||
//! 这里只做「快照字段 → 要画什么」,不碰控件树。文案的语言由调用方传给 `view::model` 的
|
||||
//! `Lang` 决定(页面与这一段都从同一个 `Lang` 取目录,见 `pages::Model.lang`)。
|
||||
//! 这里只做「快照字段 → 要画什么」,不碰控件树。**文案的语言由调用方的 [`Catalog`] 决定**
|
||||
//! (`view::model` 把 `App::lang` 的目录传进来),不再是 M90 时期的英文基线字面量。
|
||||
//!
|
||||
//! ## 两条接法上的取舍
|
||||
//!
|
||||
//! 1. **原版徽标走词表**:`LoaderInfo::badge()` 对原版返回**中文**「原版」(那是 presenter 的
|
||||
//! 面向中文日志的 `label()`),英文界面里直接画它就是「中文漏进英文界面」。所以原版这一支
|
||||
//! 改走 [`Key::LoaderVanilla`],装加载器时仍是 `Fabric 0.16.5`(品牌 + 版本号,不翻译);
|
||||
//! 2. **运行状态只翻标签本体**:`Running · pid 1234` → `运行中 · pid 1234`,`pid` 与数字、
|
||||
//! `·` 分隔符一个字都不动([`Key::InstancesRunning`] 的占位符只有 `{pid}`)。
|
||||
|
||||
use unlucky_presenter::dto::{InstanceRuntime, InstanceSummary, LaunchStage};
|
||||
use unlucky_i18n::{Catalog, Key};
|
||||
use unlucky_presenter::dto::{InstanceRuntime, InstanceSummary, LaunchStage, LoaderKind};
|
||||
|
||||
use crate::pages::{Detail, Meta};
|
||||
|
||||
/// 列表行的副文案:`1.20.4 · Fabric 0.16.5`(原版只写「原版」,见 `LoaderInfo::badge`)。
|
||||
pub(super) fn supporting_line(instance: &InstanceSummary) -> String {
|
||||
format!("{} · {}", instance.mc_version, instance.loader.badge())
|
||||
/// 列表行的副文案:`1.20.4 · Fabric 0.16.5`(原版只写「原版 / Vanilla」,见 [`loader_badge`])。
|
||||
pub(super) fn supporting_line(instance: &InstanceSummary, catalog: Catalog) -> String {
|
||||
format!(
|
||||
"{} · {}",
|
||||
instance.mc_version,
|
||||
loader_badge(instance, catalog)
|
||||
)
|
||||
}
|
||||
|
||||
/// 加载器徽标:原版走词表,其余是品牌 + 版本号(原样)。
|
||||
fn loader_badge(instance: &InstanceSummary, catalog: Catalog) -> String {
|
||||
// `badge()` 在「原版 / 版本号为空」两种情况都给 `kind.label()`(中文「原版」),只有这一支要过词表。
|
||||
if instance.loader.kind == LoaderKind::Vanilla || instance.loader.version.is_empty() {
|
||||
catalog.text(Key::LoaderVanilla).to_string()
|
||||
} else {
|
||||
format!(
|
||||
"{} {}",
|
||||
instance.loader.kind.label(),
|
||||
instance.loader.version
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// 隔离档位:`isolated` / `shared` 是两个稳定 id(`core::game::IsolationMode::as_str`),
|
||||
/// 直接上屏就是英文界面漏中文、中文界面漏英文。只认这两档,**其余原样**(`inherit` / `custom` /
|
||||
/// 未来新增的值不许在这里被猜成一个意思)。
|
||||
fn isolation(raw: &str, catalog: Catalog) -> String {
|
||||
match raw {
|
||||
"isolated" => catalog.text(Key::InstancesIsolationIsolated).to_string(),
|
||||
"shared" => catalog.text(Key::InstancesIsolationShared).to_string(),
|
||||
other => other.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
/// 运行状态(列表行的 overline 与详情页的状态行共用一份文案)。
|
||||
pub(super) fn runtime_status(runtime: &InstanceRuntime) -> Option<String> {
|
||||
pub(super) fn runtime_status(runtime: &InstanceRuntime, catalog: Catalog) -> Option<String> {
|
||||
match runtime {
|
||||
InstanceRuntime::Idle => None,
|
||||
// 「阶段 · 百分比」:百分比是数字,不过词表;只有阶段名换语言
|
||||
InstanceRuntime::Busy { stage, progress } => Some(format!(
|
||||
"{} · {:.0}%",
|
||||
stage_label(*stage),
|
||||
stage_label(*stage, catalog),
|
||||
progress.ratio() * 100.0
|
||||
)),
|
||||
InstanceRuntime::Running { pid } => Some(format!("Running · pid {pid}")),
|
||||
InstanceRuntime::Failed { reason } => Some(format!("Launch failed · {reason}")),
|
||||
InstanceRuntime::Running { pid } => {
|
||||
Some(catalog.render(Key::InstancesRunning, &[("pid", &pid.to_string())]))
|
||||
}
|
||||
// `reason` 是 core 给的诊断原文(**数据**,不翻译);只有前半句是界面文案
|
||||
InstanceRuntime::Failed { reason } => {
|
||||
Some(catalog.render(Key::InstancesFailed, &[("reason", reason)]))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 阶段文案(英文基线;i18n mission 接手后统一走词表)。
|
||||
///
|
||||
/// 不复用 `LaunchStage::label()`:那是中文,而本 crate 的界面文案在 i18n 之前是英文基线
|
||||
/// (见 `pages/instances/data.rs` 的同一条理由:干净 CI 上没有中文字体)。
|
||||
fn stage_label(stage: LaunchStage) -> &'static str {
|
||||
match stage {
|
||||
LaunchStage::Download => "Downloading",
|
||||
LaunchStage::Verify => "Verifying",
|
||||
LaunchStage::Launch => "Starting",
|
||||
LaunchStage::Window => "Waiting for window",
|
||||
}
|
||||
/// 阶段文案:**不**复用 `LaunchStage::label()`(那是核心层的中文诊断串,英文界面会漏中文)。
|
||||
fn stage_label(stage: LaunchStage, catalog: Catalog) -> &'static str {
|
||||
catalog.text(match stage {
|
||||
LaunchStage::Download => Key::InstancesStageDownload,
|
||||
LaunchStage::Verify => Key::InstancesStageVerify,
|
||||
LaunchStage::Launch => Key::InstancesStageLaunch,
|
||||
LaunchStage::Window => Key::InstancesStageWindow,
|
||||
})
|
||||
}
|
||||
|
||||
/// 详情列的内容(字段全部来自 [`InstanceSummary`])。
|
||||
pub(super) fn detail_of(instance: &InstanceSummary) -> Detail {
|
||||
// 视觉 P2-2(M90 r2):列表行与详情曾经「同物两名」(列表 `badge()` 出「原版」、详情硬编码
|
||||
// 「Vanilla」)。现在两边都走 `LoaderInfo::badge()` 这一个入口;等 i18n 落地后由词表统一,
|
||||
// 届时两处会同时变——这正是要的。
|
||||
let loader = instance.loader.badge();
|
||||
|
||||
pub(super) fn detail_of(instance: &InstanceSummary, catalog: Catalog) -> Detail {
|
||||
Detail {
|
||||
id: instance.id.clone(),
|
||||
name: instance.name.clone(),
|
||||
subtitle: supporting_line(instance),
|
||||
subtitle: supporting_line(instance, catalog),
|
||||
meta: vec![
|
||||
meta("VERSION", &instance.mc_version),
|
||||
meta("LOADER", &loader),
|
||||
meta("ISOLATION", &instance.isolation),
|
||||
meta("VERSION ID", &instance.version_id),
|
||||
meta(
|
||||
"FILES",
|
||||
if instance.version_present {
|
||||
"Present on disk"
|
||||
catalog.text(Key::InstancesMetaVersion),
|
||||
&instance.mc_version,
|
||||
),
|
||||
meta(
|
||||
catalog.text(Key::InstancesMetaLoader),
|
||||
&loader_badge(instance, catalog),
|
||||
),
|
||||
meta(
|
||||
catalog.text(Key::InstancesMetaIsolation),
|
||||
&isolation(&instance.isolation, catalog),
|
||||
),
|
||||
meta(
|
||||
catalog.text(Key::InstancesMetaVersionId),
|
||||
&instance.version_id,
|
||||
),
|
||||
meta(
|
||||
catalog.text(Key::InstancesMetaFiles),
|
||||
catalog.text(if instance.version_present {
|
||||
Key::InstancesPresentOnDisk
|
||||
} else {
|
||||
"Missing"
|
||||
},
|
||||
Key::InstancesMissing
|
||||
}),
|
||||
),
|
||||
meta(
|
||||
catalog.text(Key::InstancesMetaLastPlayed),
|
||||
&last_played(instance.last_played.as_deref(), catalog),
|
||||
),
|
||||
meta("LAST PLAYED", &last_played(instance.last_played.as_deref())),
|
||||
],
|
||||
// 真快照没有「正文描述」这种字段(偏离 #9):演示数据才有正文段
|
||||
note: None,
|
||||
status: runtime_status(&instance.runtime),
|
||||
status: runtime_status(&instance.runtime, catalog),
|
||||
can_launch: matches!(
|
||||
instance.runtime,
|
||||
InstanceRuntime::Idle | InstanceRuntime::Failed { .. }
|
||||
@@ -95,11 +146,11 @@ fn meta(label: &str, value: &str) -> Meta {
|
||||
|
||||
/// ISO-8601(`2026-10-29T19:22:00Z`)→ `2026-10-29 19:22 UTC`;`None` = 从未启动。
|
||||
///
|
||||
/// 只做切片不做时区换算:core 给的是 UTC,`Z` 就是它的时区;本地时区换算等 i18n/时间格式 mission。
|
||||
/// 只做切片不做时区换算:core 给的是 UTC,`Z` 就是它的时区;本地时区换算等时间格式 mission。
|
||||
/// 非 ASCII 或长度不足时原样返回(不 panic、不猜)。
|
||||
pub(super) fn last_played(raw: Option<&str>) -> String {
|
||||
pub(super) fn last_played(raw: Option<&str>, catalog: Catalog) -> String {
|
||||
let Some(text) = raw else {
|
||||
return "Never".to_string();
|
||||
return catalog.text(Key::InstancesNeverPlayed).to_string();
|
||||
};
|
||||
match (text.get(0..10), text.get(11..16)) {
|
||||
(Some(date), Some(time)) if date.starts_with(|c: char| c.is_ascii_digit()) => {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
//! `app/view.rs` 的守门测试(rebase 到 5adac23 之后 view.rs 贴 400 行上限,按「测试独立成文件」拆出)。
|
||||
|
||||
use super::*;
|
||||
// 拆分后 `view.rs` 不再 import 这三个(它们只被搬走的实例页转换用),用到的地方自己引
|
||||
use unlucky_presenter::dto::{
|
||||
InstanceRuntime, InstanceSummary, LaunchStage, LoaderInfo, LoaderKind, Progress,
|
||||
};
|
||||
@@ -31,9 +30,9 @@ fn instance(runtime: InstanceRuntime) -> InstanceSummary {
|
||||
/// 与「取证密闭」正好相反,而且图看起来完全正常);② 加了变体却映射到别的态这种复制粘贴错。
|
||||
/// 抓不住:`shell::overridden`(标题栏 / 导航轨按钮走的**另一处** match,断言在 `shell/tests.rs`),
|
||||
/// 也抓不住不消费 `model.forced` 的裸 `iced::button`(设置页「外观」区就是)。
|
||||
/// 测试用的薄包装:默认宽度 / 默认分类 / 空草稿。
|
||||
fn at(state: &AppState, forced: Option<crate::cli::ForcedState>) -> pages::Model {
|
||||
let (draft, lang) = (pages::InstallDraft::default(), Lang::En);
|
||||
/// 测试用的薄包装:默认宽度 / 默认分类 / 空草稿 / **给定语言**。
|
||||
fn at_lang(state: &AppState, forced: Option<crate::cli::ForcedState>, lang: Lang) -> pages::Model {
|
||||
let draft = pages::InstallDraft::default();
|
||||
let page = pages::content::PageState::default();
|
||||
model(
|
||||
state,
|
||||
@@ -46,6 +45,11 @@ fn at(state: &AppState, forced: Option<crate::cli::ForcedState>) -> pages::Model
|
||||
)
|
||||
}
|
||||
|
||||
/// 同 [`at_lang`],语言取英文(绝大多数断言只关心「快照 → 模型」的映射,不关心译文)。
|
||||
fn at(state: &AppState, forced: Option<crate::cli::ForcedState>) -> pages::Model {
|
||||
at_lang(state, forced, Lang::En)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_forced_state_maps_to_the_expected_interaction() {
|
||||
let state = AppState::new();
|
||||
@@ -122,22 +126,131 @@ fn failed_instances_can_be_retried() {
|
||||
reason: "exit 1".to_string(),
|
||||
});
|
||||
assert_eq!(
|
||||
runtime_status(&failed.runtime).as_deref(),
|
||||
runtime_status(&failed.runtime, Lang::En.catalog()).as_deref(),
|
||||
Some("Launch failed · exit 1")
|
||||
);
|
||||
assert!(detail_of(&failed).can_launch, "失败后要能重试");
|
||||
assert!(
|
||||
detail_of(&failed, Lang::En.catalog()).can_launch,
|
||||
"失败后要能重试"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn timestamps_are_sliced_not_guessed() {
|
||||
let en = Lang::En.catalog();
|
||||
assert_eq!(
|
||||
last_played(Some("2026-10-29T19:22:00Z")),
|
||||
last_played(Some("2026-10-29T19:22:00Z"), en),
|
||||
"2026-10-29 19:22 UTC"
|
||||
);
|
||||
assert_eq!(last_played(None), "Never");
|
||||
assert_eq!(last_played(None, en), "Never");
|
||||
// 短串 / 非 ASCII 原样返回(不 panic)
|
||||
assert_eq!(last_played(Some("2026-10")), "2026-10");
|
||||
assert_eq!(last_played(Some("昨天")), "昨天");
|
||||
assert_eq!(last_played(Some("2026-10"), en), "2026-10");
|
||||
assert_eq!(last_played(Some("昨天"), en), "昨天");
|
||||
// 「从未游玩」是唯一走词表的那一支
|
||||
assert_eq!(last_played(None, Lang::ZhCn.catalog()), "从未游玩");
|
||||
}
|
||||
|
||||
/// **快照 → 页面文案跟着 `App::lang` 走**(M120 的核心接线断言,模型这一层)。
|
||||
///
|
||||
/// 抓得住:`view::model` 又把语言写死成 `Lang::En`(M106 之前的原样)、阶段/元信息标签还留着
|
||||
/// 英文基线字面量、原版徽标直接画 presenter 的中文「原版」。这三种都不会让任何别的测试红。
|
||||
/// 抓不住:页面把 key 画没画上屏(那是 `pages/instances/tests/i18n.rs` 的取样口 + 出图)。
|
||||
#[test]
|
||||
fn the_runtime_lines_and_meta_labels_follow_the_language() {
|
||||
let mut state = AppState::new();
|
||||
state.apply(unlucky_presenter::dto::AppEvent::Core(
|
||||
unlucky_presenter::dto::CoreEvent::InstancesChanged(vec![
|
||||
instance(InstanceRuntime::Running { pid: 1234 }),
|
||||
instance(InstanceRuntime::Busy {
|
||||
stage: LaunchStage::Verify,
|
||||
progress: Progress {
|
||||
done: 750,
|
||||
total: 1_500,
|
||||
},
|
||||
}),
|
||||
]),
|
||||
));
|
||||
state.navigate(Route::Detail("survival".to_string()));
|
||||
|
||||
let en = at_lang(&state, None, Lang::En);
|
||||
let zh = at_lang(&state, None, Lang::ZhCn);
|
||||
|
||||
// 列表 overline:中英各一份,数字与分隔符不动
|
||||
assert_eq!(
|
||||
en.instances.rows[0].status.as_deref(),
|
||||
Some("Running · pid 1234")
|
||||
);
|
||||
assert_eq!(
|
||||
zh.instances.rows[0].status.as_deref(),
|
||||
Some("运行中 · pid 1234")
|
||||
);
|
||||
assert_eq!(
|
||||
en.instances.rows[1].status.as_deref(),
|
||||
Some("Verifying · 50%")
|
||||
);
|
||||
assert_eq!(zh.instances.rows[1].status.as_deref(), Some("校验中 · 50%"));
|
||||
|
||||
// 元信息卡的标签与值
|
||||
let (en_detail, zh_detail) = (
|
||||
en.instances.detail.expect("有详情"),
|
||||
zh.instances.detail.expect("有详情"),
|
||||
);
|
||||
let labels = |detail: &pages::Detail| -> Vec<String> {
|
||||
detail.meta.iter().map(|cell| cell.label.clone()).collect()
|
||||
};
|
||||
assert_eq!(
|
||||
labels(&en_detail),
|
||||
vec![
|
||||
"VERSION",
|
||||
"LOADER",
|
||||
"ISOLATION",
|
||||
"VERSION ID",
|
||||
"FILES",
|
||||
"LAST PLAYED"
|
||||
]
|
||||
);
|
||||
assert_eq!(
|
||||
labels(&zh_detail),
|
||||
vec!["版本", "加载器", "隔离方式", "版本标识", "文件", "上次游玩"]
|
||||
);
|
||||
|
||||
// 值里只有「是否在磁盘上」与「上次游玩」是可翻译的;版本号 / 隔离方式 / 版本标识是数据
|
||||
// 隔离档位是 core 的稳定 id(`isolated` / `shared`),也要换成人话;认不出来的原样上屏
|
||||
assert_eq!(en_detail.meta[2].value, "Isolated");
|
||||
assert_eq!(zh_detail.meta[2].value, "独立目录");
|
||||
assert_eq!(en_detail.meta[4].value, "Present on disk");
|
||||
assert_eq!(zh_detail.meta[4].value, "已在磁盘上");
|
||||
assert_eq!(
|
||||
en_detail.meta[5].value, "2026-10-29 19:22 UTC",
|
||||
"时间戳是数据:只切片,不随语言变形"
|
||||
);
|
||||
assert_eq!(zh_detail.meta[5].value, "2026-10-29 19:22 UTC");
|
||||
|
||||
// 详情状态行与列表 overline 同源
|
||||
assert_eq!(zh_detail.status.as_deref(), Some("运行中 · pid 1234"));
|
||||
}
|
||||
|
||||
/// 原版徽标:`LoaderInfo::badge()` 对原版返回**中文**「原版」,英文界面里必须换回 `Vanilla`。
|
||||
///
|
||||
/// 抓得住:`loader_badge` 退回直接调 `badge()`(M90 ~ M119 的形状)——那样英文界面会漏中文,
|
||||
/// 而中文界面又是对的,所以只有这条双语断言抓得住它。
|
||||
#[test]
|
||||
fn the_vanilla_badge_follows_the_language() {
|
||||
let mut bare = instance(InstanceRuntime::Idle);
|
||||
bare.loader = LoaderInfo {
|
||||
kind: LoaderKind::Vanilla,
|
||||
version: String::new(),
|
||||
};
|
||||
let mut state = AppState::new();
|
||||
state.apply(unlucky_presenter::dto::AppEvent::Core(
|
||||
unlucky_presenter::dto::CoreEvent::InstancesChanged(vec![bare]),
|
||||
));
|
||||
state.navigate(Route::Detail("survival".to_string()));
|
||||
|
||||
let en = at_lang(&state, None, Lang::En);
|
||||
let zh = at_lang(&state, None, Lang::ZhCn);
|
||||
assert_eq!(en.instances.rows[0].supporting, "1.20.4 · Vanilla");
|
||||
assert_eq!(zh.instances.rows[0].supporting, "1.20.4 · 原版");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in new issue
Block a user