feat(packui): M113 第一批 —— 内容库页的导入/导出区(界面 + DTO + i18n + 拖拽落点)
导入入口(拖拽 + 路径输入 + 目标实例)与导出(格式选择 + 预检)的**界面层**,
数据面镜像 M111/M112 的管线报告(presenter DTO),进度整块复用下载页的安装面板。
## 落了什么
- pages/content/packui*:入口 / 进度块 / 结果块 / 导出预检块(每文件 ≤400)
- 拖拽区(hover 变主色描边)+ 路径输入框 + 目标实例 chips
- 进度:一行「步骤 n/5 · 解包覆盖内容」+ **下载页那块安装面板**(不另画进度条)
- 结果:三态(Success/Partial/Failed)+ 缺文件逐条(Warn/Tertiary)+ 冲突逐条
(成因 + 本次处置 + 可展开三方 SHA-1)+ 致命块(Error/ErrorContainer)
- 导出:mrpack / CF 二选一 + 包名/版本/路径 + 预检「将内联 N 个文件 · 无法导出 M 项」
+ 逐条无法导出项 + 已知损失 + 确认写盘
- presenter/src/dto/pack{,/format,/import,/conflict,/export}.rs:镜像 core 报告的 DTO
(三态、五阶段、三分类、十一条原因,全部 from_slug 与 core 稳定码逐字对齐)
- i18n:81 条 Pack* 键(content_entries! 尾部追加;golden.rs 同序同文)
- app/update.rs:FileDropped / FileHovered / FilesHoveredLeft → 内容库页(本版唯一的选文件通道)
- M109 的四个文件各一处插入:mod 声明 + Pack(..) 变体 + pack 字段 + 正列插入点
## 边界(如实)
- 没有系统文件选择框:依赖树里无对话框依赖,加它要动根 Cargo.toml + 许可门禁 +
Linux 后端选型(影响单文件产物)。入口是拖拽 + 路径输入,原因写在界面上。
- 冲突没有逐文件决策:core 的 ConflictPolicy 是整次导入一个全局档,ConflictFile 是事后账。
本批给「逐文件看 + 整体翻档(以包为准重新导入)」,文案明写「两者都留(改名)暂不支持」。
默认一律 KeepUser——绝不默认覆盖用户改过的文件。
- 本批按钮半通:拖拽/路径/格式/实例/展开都真生效;「点导入真的开跑」「预检/确认写盘」
要等第二批的 AppCommand 与事件通道(M109 rebase 到新 main 后按新形状写一次)。
This commit is contained in:
1 parent
0367073d32
commit
fbeff94e55
31 files changed
+3646
-9
No files matched your search
@@ -83,6 +83,160 @@ macro_rules! content_entries {
|
||||
"Installing from CurseForge is not available yet",
|
||||
"CurseForge 来源的安装尚未开放"
|
||||
),
|
||||
// --- M113: pack import / export(PACKUI)---
|
||||
PackTitle => ("Modpack import & export", "整合包导入 / 导出"),
|
||||
PackImportTitle => ("Import a modpack", "导入整合包"),
|
||||
PackDropHint => (
|
||||
"Drop a .mrpack, .zip or a MultiMC/Prism instance folder here",
|
||||
"把 .mrpack / .zip 或 MultiMC·Prism 实例目录拖到这里"
|
||||
),
|
||||
PackDropActive => ("Release to probe the pack", "松手开始探测"),
|
||||
PackNoDialog => (
|
||||
"This build has no system file picker: drag the file in, or paste its path below (a picker needs a dialog dependency that is not in the tree).",
|
||||
"本版没有系统文件选择框:请把文件拖进来,或在下面粘贴路径(文件框需要引入对话框依赖,当前依赖树里没有)。"
|
||||
),
|
||||
PackPathLabel => ("Pack path", "整合包路径"),
|
||||
PackPathPlaceholder => ("D:\\packs\\Better MC.mrpack", "D:\\packs\\Better MC.mrpack"),
|
||||
PackImportAction => ("Import", "导入"),
|
||||
PackCancel => ("Cancel import", "取消导入"),
|
||||
PackDismiss => ("Dismiss", "关闭"),
|
||||
PackTargetLabel => ("Install into", "装到实例"),
|
||||
PackTargetNew => ("New instance", "新建实例"),
|
||||
PackInstanceName => ("Instance name", "实例名"),
|
||||
PackStageLine => ("Step {index}/{total} · {stage}", "步骤 {index}/{total} · {stage}"),
|
||||
PackStageProbe => ("Reading the manifest", "读取清单"),
|
||||
PackStageExtract => ("Unpacking overrides", "解包覆盖内容"),
|
||||
PackStageFetch => ("Fetching missing files", "补下载文件"),
|
||||
PackStageCommit => ("Writing files", "落地写盘"),
|
||||
PackStageRegister => ("Registering the instance", "登记实例"),
|
||||
PackProbeTitle => (
|
||||
"This pack is almost a known format",
|
||||
"这个包差一点就是已知格式"
|
||||
),
|
||||
PackProbeLooksLike => (
|
||||
"Looks like {format}, but missing: {missing}",
|
||||
"看起来像 {format},但缺:{missing}"
|
||||
),
|
||||
PackProbeUnknown => (
|
||||
"No known format claims this pack",
|
||||
"没有任何已知格式认领这个包"
|
||||
),
|
||||
PackProbeSaw => ("Found in the pack: {saw}", "包里看到:{saw}"),
|
||||
PackProbeNothing => ("nothing recognisable", "没有可识别的东西"),
|
||||
PackStatusSuccess => ("Imported", "已导入"),
|
||||
PackStatusPartial => ("Imported with gaps", "导入完成,但有缺口"),
|
||||
PackStatusFailed => ("Import failed — rolled back", "导入失败 —— 已整包回滚"),
|
||||
PackReportWritten => ("{count} files written · {bytes}", "{count} 个文件已写盘 · {bytes}"),
|
||||
PackReportMissing => (
|
||||
"{count} files could not be fetched (tolerated)",
|
||||
"有 {count} 个文件没搞到(可容忍)"
|
||||
),
|
||||
PackReportConflicts => (
|
||||
"{count} files you had changed (yours kept by default)",
|
||||
"{count} 个文件你改过(默认保留你的)"
|
||||
),
|
||||
PackReportRejectedNote => ("not supported by the client", "客户端不支持"),
|
||||
PackOverwriteAction => ("Re-import, the pack wins", "以包为准重新导入"),
|
||||
PackOverwriteNote => (
|
||||
"Keeping both (renamed) is not supported yet: the import pipeline has one global conflict policy and no per-file decision channel.",
|
||||
"「两者都留(改名)」暂不支持:导入管线只有一套全局冲突策略,没有逐文件决策通道。"
|
||||
),
|
||||
PackMissingOffline => ("offline import", "离线导入"),
|
||||
PackMissingNoSource => (
|
||||
"no download source (CurseForge file API not wired)",
|
||||
"拿不到下载地址(CF 文件端点未接通)"
|
||||
),
|
||||
PackMissingFetchFailed => ("download failed: {detail}", "下载失败:{detail}"),
|
||||
PackFatalTitle => (
|
||||
"Rolled back — nothing was left behind",
|
||||
"已回滚 —— 目标目录零残留"
|
||||
),
|
||||
PackFatalHint => ("What to try next", "下一步可以试"),
|
||||
PackConflictUserModified => ("you changed it", "你改过"),
|
||||
PackConflictUserDeleted => ("you deleted it", "你删过"),
|
||||
PackConflictPreExisting => ("was already there", "本来就在"),
|
||||
PackChoiceKeepUser => ("kept yours", "保留我的"),
|
||||
PackChoiceOverwrite => ("pack version used", "用包里的"),
|
||||
PackConflictHashes => (
|
||||
"pack {pack} · base {base} · disk {disk}",
|
||||
"包内 {pack} · 基线 {base} · 磁盘 {disk}"
|
||||
),
|
||||
PackConflictDetail => ("Hashes", "三方哈希"),
|
||||
PackFormatModrinth => ("Modrinth .mrpack", "Modrinth .mrpack"),
|
||||
PackFormatCurseforge => ("CurseForge manifest", "CurseForge 清单"),
|
||||
PackFormatMultimc => ("MultiMC / Prism instance", "MultiMC·Prism 实例"),
|
||||
PackExportTitle => ("Export this instance", "导出这个实例"),
|
||||
PackExportOpen => ("Export…", "导出…"),
|
||||
PackExportFormat => ("Format", "格式"),
|
||||
PackExportName => ("Pack name", "包名"),
|
||||
PackExportVersion => ("Version", "版本"),
|
||||
PackExportOutput => ("Save to (empty = suggested)", "保存到(留空 = 自动)"),
|
||||
PackExportPrecheck => ("Dry run", "预检"),
|
||||
PackExportConfirm => ("Write the pack", "确认写盘"),
|
||||
PackExportAbort => ("Back", "返回"),
|
||||
PackExportMultimcNote => (
|
||||
"MultiMC/Prism can only be imported, not exported (by design).",
|
||||
"MultiMC·Prism 只能导入、不能导出(有意省略)。"
|
||||
),
|
||||
PackExportDone => ("Wrote {path} · {bytes}", "已写出 {path} · {bytes}"),
|
||||
PackExportFailed => ("Export failed: {reason}", "导出失败:{reason}"),
|
||||
PackExportPending => ("Scanning the instance…", "正在扫描实例…"),
|
||||
PackPreviewHead => (
|
||||
"Will inline {inline} files · {skipped} items cannot be exported",
|
||||
"将内联 {inline} 个文件 · 无法导出 {skipped} 项"
|
||||
),
|
||||
PackPreviewRemote => (
|
||||
"{count} files can be referenced remotely",
|
||||
"{count} 个文件可走远程引用"
|
||||
),
|
||||
PackPreviewInlineBytes => (
|
||||
"{bytes} copied into overrides/",
|
||||
"{bytes} 会原样拷进 overrides/"
|
||||
),
|
||||
PackPreviewSkippedTitle => (
|
||||
"Not in the pack (listed one by one)",
|
||||
"没进包(逐条列出)"
|
||||
),
|
||||
PackPreviewNotes => ("Known losses", "已知损失"),
|
||||
PackPreviewTarget => ("Will be written to {path}", "将写到 {path}"),
|
||||
PackPreviewMore => ("…and {count} more files", "…还有 {count} 个文件"),
|
||||
PackPreviewComplete => ("Nothing is left out", "没有遗漏任何文件"),
|
||||
PackPreviewIncomplete => (
|
||||
"Some files will not be in the pack",
|
||||
"有文件不会进包"
|
||||
),
|
||||
PackReasonModrinthSha1 => ("Modrinth match (SHA-1)", "Modrinth 命中(SHA-1)"),
|
||||
PackReasonCurseFingerprint => (
|
||||
"CurseForge match (fingerprint)",
|
||||
"CurseForge 命中(文件指纹)"
|
||||
),
|
||||
PackReasonNoRemoteMatch => (
|
||||
"unknown to both catalogs, inlined",
|
||||
"两个目录都不认识,已内联"
|
||||
),
|
||||
PackReasonCurseOnly => (
|
||||
"only CurseForge knows it, this format cannot use it, inlined",
|
||||
"只有 CF 认识,目标格式用不上,已内联"
|
||||
),
|
||||
PackReasonModrinthOnly => (
|
||||
"only Modrinth knows it, the CF manifest cannot use it, inlined",
|
||||
"只有 Modrinth 认识,CF 清单用不上,已内联"
|
||||
),
|
||||
PackReasonMissingSha512 => ("match has no sha512, inlined", "命中缺 sha512,已内联"),
|
||||
PackReasonMissingCurseIds => (
|
||||
"match has no projectID/fileID, inlined",
|
||||
"命中缺 projectID/fileID,已内联"
|
||||
),
|
||||
PackReasonDisabled => (
|
||||
"disabled file, this format cannot express it (.disabled kept)",
|
||||
"禁用文件,目标格式表达不了(保留 .disabled)"
|
||||
),
|
||||
PackReasonSymlink => ("symbolic link, skipped", "符号链接,已跳过"),
|
||||
PackReasonUnsafePath => (
|
||||
"path fails the pack path rules, skipped",
|
||||
"路径过不了包内规整,已跳过"
|
||||
),
|
||||
PackReasonUnreadable => ("cannot read it, skipped", "读不出来,已跳过"),
|
||||
} }
|
||||
};
|
||||
}
|
||||
|
||||
@@ -219,4 +219,85 @@ pub(super) const GOLDEN: &[(&str, &str, &str)] = &[
|
||||
("ContentModpackNotReady", "Installing modpacks is not available yet", "整合包安装尚未开放"),
|
||||
("ContentSourceUnavailable", "CurseForge needs an API key: add one in Settings", "CurseForge 需要在设置里配置密钥才能搜索"),
|
||||
("ContentSourceNotWired", "Installing from CurseForge is not available yet", "CurseForge 来源的安装尚未开放"),
|
||||
("PackTitle", "Modpack import & export", "整合包导入 / 导出"),
|
||||
("PackImportTitle", "Import a modpack", "导入整合包"),
|
||||
("PackDropHint", "Drop a .mrpack, .zip or a MultiMC/Prism instance folder here", "把 .mrpack / .zip 或 MultiMC·Prism 实例目录拖到这里"),
|
||||
("PackDropActive", "Release to probe the pack", "松手开始探测"),
|
||||
("PackNoDialog", "This build has no system file picker: drag the file in, or paste its path below (a picker needs a dialog dependency that is not in the tree).", "本版没有系统文件选择框:请把文件拖进来,或在下面粘贴路径(文件框需要引入对话框依赖,当前依赖树里没有)。"),
|
||||
("PackPathLabel", "Pack path", "整合包路径"),
|
||||
("PackPathPlaceholder", "D:\\packs\\Better MC.mrpack", "D:\\packs\\Better MC.mrpack"),
|
||||
("PackImportAction", "Import", "导入"),
|
||||
("PackCancel", "Cancel import", "取消导入"),
|
||||
("PackDismiss", "Dismiss", "关闭"),
|
||||
("PackTargetLabel", "Install into", "装到实例"),
|
||||
("PackTargetNew", "New instance", "新建实例"),
|
||||
("PackInstanceName", "Instance name", "实例名"),
|
||||
("PackStageLine", "Step {index}/{total} · {stage}", "步骤 {index}/{total} · {stage}"),
|
||||
("PackStageProbe", "Reading the manifest", "读取清单"),
|
||||
("PackStageExtract", "Unpacking overrides", "解包覆盖内容"),
|
||||
("PackStageFetch", "Fetching missing files", "补下载文件"),
|
||||
("PackStageCommit", "Writing files", "落地写盘"),
|
||||
("PackStageRegister", "Registering the instance", "登记实例"),
|
||||
("PackProbeTitle", "This pack is almost a known format", "这个包差一点就是已知格式"),
|
||||
("PackProbeLooksLike", "Looks like {format}, but missing: {missing}", "看起来像 {format},但缺:{missing}"),
|
||||
("PackProbeUnknown", "No known format claims this pack", "没有任何已知格式认领这个包"),
|
||||
("PackProbeSaw", "Found in the pack: {saw}", "包里看到:{saw}"),
|
||||
("PackProbeNothing", "nothing recognisable", "没有可识别的东西"),
|
||||
("PackStatusSuccess", "Imported", "已导入"),
|
||||
("PackStatusPartial", "Imported with gaps", "导入完成,但有缺口"),
|
||||
("PackStatusFailed", "Import failed — rolled back", "导入失败 —— 已整包回滚"),
|
||||
("PackReportWritten", "{count} files written · {bytes}", "{count} 个文件已写盘 · {bytes}"),
|
||||
("PackReportMissing", "{count} files could not be fetched (tolerated)", "有 {count} 个文件没搞到(可容忍)"),
|
||||
("PackReportConflicts", "{count} files you had changed (yours kept by default)", "{count} 个文件你改过(默认保留你的)"),
|
||||
("PackReportRejectedNote", "not supported by the client", "客户端不支持"),
|
||||
("PackOverwriteAction", "Re-import, the pack wins", "以包为准重新导入"),
|
||||
("PackOverwriteNote", "Keeping both (renamed) is not supported yet: the import pipeline has one global conflict policy and no per-file decision channel.", "「两者都留(改名)」暂不支持:导入管线只有一套全局冲突策略,没有逐文件决策通道。"),
|
||||
("PackMissingOffline", "offline import", "离线导入"),
|
||||
("PackMissingNoSource", "no download source (CurseForge file API not wired)", "拿不到下载地址(CF 文件端点未接通)"),
|
||||
("PackMissingFetchFailed", "download failed: {detail}", "下载失败:{detail}"),
|
||||
("PackFatalTitle", "Rolled back — nothing was left behind", "已回滚 —— 目标目录零残留"),
|
||||
("PackFatalHint", "What to try next", "下一步可以试"),
|
||||
("PackConflictUserModified", "you changed it", "你改过"),
|
||||
("PackConflictUserDeleted", "you deleted it", "你删过"),
|
||||
("PackConflictPreExisting", "was already there", "本来就在"),
|
||||
("PackChoiceKeepUser", "kept yours", "保留我的"),
|
||||
("PackChoiceOverwrite", "pack version used", "用包里的"),
|
||||
("PackConflictHashes", "pack {pack} · base {base} · disk {disk}", "包内 {pack} · 基线 {base} · 磁盘 {disk}"),
|
||||
("PackConflictDetail", "Hashes", "三方哈希"),
|
||||
("PackFormatModrinth", "Modrinth .mrpack", "Modrinth .mrpack"),
|
||||
("PackFormatCurseforge", "CurseForge manifest", "CurseForge 清单"),
|
||||
("PackFormatMultimc", "MultiMC / Prism instance", "MultiMC·Prism 实例"),
|
||||
("PackExportTitle", "Export this instance", "导出这个实例"),
|
||||
("PackExportOpen", "Export…", "导出…"),
|
||||
("PackExportFormat", "Format", "格式"),
|
||||
("PackExportName", "Pack name", "包名"),
|
||||
("PackExportVersion", "Version", "版本"),
|
||||
("PackExportOutput", "Save to (empty = suggested)", "保存到(留空 = 自动)"),
|
||||
("PackExportPrecheck", "Dry run", "预检"),
|
||||
("PackExportConfirm", "Write the pack", "确认写盘"),
|
||||
("PackExportAbort", "Back", "返回"),
|
||||
("PackExportMultimcNote", "MultiMC/Prism can only be imported, not exported (by design).", "MultiMC·Prism 只能导入、不能导出(有意省略)。"),
|
||||
("PackExportDone", "Wrote {path} · {bytes}", "已写出 {path} · {bytes}"),
|
||||
("PackExportFailed", "Export failed: {reason}", "导出失败:{reason}"),
|
||||
("PackExportPending", "Scanning the instance…", "正在扫描实例…"),
|
||||
("PackPreviewHead", "Will inline {inline} files · {skipped} items cannot be exported", "将内联 {inline} 个文件 · 无法导出 {skipped} 项"),
|
||||
("PackPreviewRemote", "{count} files can be referenced remotely", "{count} 个文件可走远程引用"),
|
||||
("PackPreviewInlineBytes", "{bytes} copied into overrides/", "{bytes} 会原样拷进 overrides/"),
|
||||
("PackPreviewSkippedTitle", "Not in the pack (listed one by one)", "没进包(逐条列出)"),
|
||||
("PackPreviewNotes", "Known losses", "已知损失"),
|
||||
("PackPreviewTarget", "Will be written to {path}", "将写到 {path}"),
|
||||
("PackPreviewMore", "…and {count} more files", "…还有 {count} 个文件"),
|
||||
("PackPreviewComplete", "Nothing is left out", "没有遗漏任何文件"),
|
||||
("PackPreviewIncomplete", "Some files will not be in the pack", "有文件不会进包"),
|
||||
("PackReasonModrinthSha1", "Modrinth match (SHA-1)", "Modrinth 命中(SHA-1)"),
|
||||
("PackReasonCurseFingerprint", "CurseForge match (fingerprint)", "CurseForge 命中(文件指纹)"),
|
||||
("PackReasonNoRemoteMatch", "unknown to both catalogs, inlined", "两个目录都不认识,已内联"),
|
||||
("PackReasonCurseOnly", "only CurseForge knows it, this format cannot use it, inlined", "只有 CF 认识,目标格式用不上,已内联"),
|
||||
("PackReasonModrinthOnly", "only Modrinth knows it, the CF manifest cannot use it, inlined", "只有 Modrinth 认识,CF 清单用不上,已内联"),
|
||||
("PackReasonMissingSha512", "match has no sha512, inlined", "命中缺 sha512,已内联"),
|
||||
("PackReasonMissingCurseIds", "match has no projectID/fileID, inlined", "命中缺 projectID/fileID,已内联"),
|
||||
("PackReasonDisabled", "disabled file, this format cannot express it (.disabled kept)", "禁用文件,目标格式表达不了(保留 .disabled)"),
|
||||
("PackReasonSymlink", "symbolic link, skipped", "符号链接,已跳过"),
|
||||
("PackReasonUnsafePath", "path fails the pack path rules, skipped", "路径过不了包内规整,已跳过"),
|
||||
("PackReasonUnreadable", "cannot read it, skipped", "读不出来,已跳过"),
|
||||
];
|
||||
Reference in new issue
Block a user