diff --git a/CHANGELOG.md b/CHANGELOG.md index ed59360..782987a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### 第九阶段:剧情与收尾 - 多语言:新增 de fr es pl ru ja 六种语言表(连同 zh en 共 8 种,对应游戏主菜单的语言)。英文表是源文,其他语言由 Gemini 分块译出(术语表 `docs/i18n-glossary.md` 在运营仓库,游戏已有的词用官方译名),未经人工校对,文件头有说明。键集合、占位符、`§ ¶ \\n` 标记由单元测试逐语言核对,非中日语言里不得出现汉字或假名。 +- 多语言布局:表格单元、按钮文字放不下时自动缩小字号(最小 68%)再省略,商品名限定两行内缩放;de fr es pl ru 的钱包表、手册章节列表、硬件钱包粘贴键按语言放宽;ru de 等少数过长标签改短(永续“加保证金”键、收益池列头)。 - 中文“匿名币”改称“隐私币”(英文 privacy coin),手册、黑市标签同步。 - 英文手册里写死的“六天”“7 天”改为占位符 `{BmBulkDays}`、`{AmlWindowDays}`,和中文一致。 - 手册里剩下的写死数字也进了 `Tuning`:出金审查污点系数 `AmlTaintMult` 与超额权重 `AmlExcessWeight`、出售速度界线 `BmSellFastMult` / `BmSellDay1Mult`;剧情联动的期限和涨幅改用已有的 `Story*` / `Tumbler*` 常量占位。占位符新增 `{Name:+%}`(倍数显示成涨幅)。 diff --git a/src/Decentralized/Core.cs b/src/Decentralized/Core.cs index 77cc00d..683c150 100644 --- a/src/Decentralized/Core.cs +++ b/src/Decentralized/Core.cs @@ -14,6 +14,12 @@ namespace Decentralized public static class L { public static string T(string key, params object[] args) => ModHelper.GetLocalized(ModInfo.Id, key, args); + + /// 当前游戏语言代码(en zh de fr es pl ru ja)。 + public static string Code => LocHelper.GetCurrentLocaleCode() ?? "en"; + + /// 译文普遍比中英文长的语言:表格列宽、操作键区按此放宽。 + public static bool Wide { get { var c = Code; return c == "de" || c == "fr" || c == "es" || c == "pl" || c == "ru"; } } } public static class Log diff --git a/src/Decentralized/HandbookWindow.cs b/src/Decentralized/HandbookWindow.cs index d376621..1b81f3d 100644 --- a/src/Decentralized/HandbookWindow.cs +++ b/src/Decentralized/HandbookWindow.cs @@ -11,7 +11,9 @@ namespace Decentralized { public const string Id = "pd_handbook"; private const float WinW = 828f, WinH = 680f, ScreenW = 768f, ScreenH = 578f, Bezel = 6f; - private const float ListW = 190f, TextW = 540f; + private static float ListW => L.Wide ? 276f : 190f; + private static float RowW => L.Wide ? ListW - 52f : ListW - 12f; + private static float TextW => L.Wide ? 456f : 540f; private static int _chapter; private static readonly List _picked = new List(); @@ -61,7 +63,7 @@ namespace Decentralized for (int i = 0; i < chapters.Length; i++) { int k = i; - PledgerSkin.TableRow(b, ListW - 12f, 30f, new[] { ListW - 12f }, new[] { TextAnchor.MiddleLeft }, + PledgerSkin.TableRow(b, RowW, 30f, new[] { RowW }, new[] { TextAnchor.MiddleLeft }, new[] { Title(chapters[i]) }, i == _chapter, () => { _chapter = k; Open(); }, _rows, _clear); } b.End(); diff --git a/src/Decentralized/ModFiles/Localization/de.csv b/src/Decentralized/ModFiles/Localization/de.csv index c21b997..0c94d79 100644 --- a/src/Decentralized/ModFiles/Localization/de.csv +++ b/src/Decentralized/ModFiles/Localization/de.csv @@ -498,7 +498,7 @@ perp.open,Eröffnen perp.margin,Margin (CRC) perp.preview,Nominal {0} Ausführung {1} perp.do.open,Eröffnen -perp.do.add,Margin hinzufügen +perp.do.add,+ Margin perp.do.close,Schließen perp.opened,"{0} {1} eröffnet: Margin {2} CRC, {3}×." perp.added,{0} CRC Margin hinzugefügt. @@ -683,11 +683,11 @@ air.err.wallet,Mit der freigebenden Wallet signieren. pool.h,Drittanbieter-Renditepools (CRC) pool.none,Derzeit keine vorhanden. pool.col.name,Pool -pool.col.rate,Tageszins +pool.col.rate,Zins pool.col.reserve,Reserve -pool.col.lock,Timelock +pool.col.lock,Sperre pool.col.audit,Audit -pool.col.mine,Eigene +pool.col.mine,Mein pool.yes,ja pool.no,nein pool.pending,in Auszahlung diff --git a/src/Decentralized/ModFiles/Localization/es.csv b/src/Decentralized/ModFiles/Localization/es.csv index 4824417..2f10b9c 100644 --- a/src/Decentralized/ModFiles/Localization/es.csv +++ b/src/Decentralized/ModFiles/Localization/es.csv @@ -498,7 +498,7 @@ perp.open,Abrir perp.margin,Margen (CRC) perp.preview,Nocional {0} ejecución {1} perp.do.open,Abrir -perp.do.add,Agregar margen +perp.do.add,+ Margen perp.do.close,Cerrar perp.opened,"Se abrió {0} {1}: margen {2} CRC, {3}×." perp.added,Se agregaron {0} CRC de margen. @@ -683,11 +683,11 @@ air.err.wallet,Firmar con la billetera que aprobó. pool.h,Fondos de rendimiento de terceros (CRC) pool.none,Ninguno por ahora. pool.col.name,Fondo -pool.col.rate,Tasa diaria +pool.col.rate,Tasa/día pool.col.reserve,Reserva pool.col.lock,Bloqueo pool.col.audit,Auditoría -pool.col.mine,Mi depósito +pool.col.mine,Mío pool.yes,sí pool.no,no pool.pending,retirando diff --git a/src/Decentralized/ModFiles/Localization/fr.csv b/src/Decentralized/ModFiles/Localization/fr.csv index 06ae01c..d4d1000 100644 --- a/src/Decentralized/ModFiles/Localization/fr.csv +++ b/src/Decentralized/ModFiles/Localization/fr.csv @@ -498,7 +498,7 @@ perp.open,Ouvrir perp.margin,Marge (CRC) perp.preview,Notionnel {0} exécution {1} perp.do.open,Ouvrir -perp.do.add,Ajouter de la marge +perp.do.add,+ Marge perp.do.close,Fermer perp.opened,"Position {0} {1} ouverte : marge {2} CRC, {3}×." perp.added,{0} CRC de marge ajoutés. @@ -687,7 +687,7 @@ pool.col.rate,Taux/j pool.col.reserve,Réserve pool.col.lock,Blocage pool.col.audit,Audit -pool.col.mine,Dépôt +pool.col.mine,Mon dépôt pool.yes,oui pool.no,non pool.pending,retrait en cours diff --git a/src/Decentralized/ModFiles/Localization/pl.csv b/src/Decentralized/ModFiles/Localization/pl.csv index d747e00..929e2df 100644 --- a/src/Decentralized/ModFiles/Localization/pl.csv +++ b/src/Decentralized/ModFiles/Localization/pl.csv @@ -406,7 +406,7 @@ poin.out.done,Wypłacono {0} {1} na {2}. wallets.count,Portfele {0}/{1} wallets.col.name,Nazwa wallets.col.addr,Adres -wallets.col.taint,Skażenie +wallets.col.taint,Skażone wallets.open,Otwórz wallets.use,Połącz wallets.current,Połączono @@ -498,7 +498,7 @@ perp.open,Otwórz perp.margin,Depozyt zabezpieczający (CRC) perp.preview,Nominał {0} realizacja {1} perp.do.open,Otwórz -perp.do.add,Dodaj depozyt +perp.do.add,+ Depozyt perp.do.close,Zamknij perp.opened,"Otwarto {0} {1}: depozyt {2} CRC, {3}×." perp.added,Dodano {0} CRC depozytu. diff --git a/src/Decentralized/ModFiles/Localization/ru.csv b/src/Decentralized/ModFiles/Localization/ru.csv index 02e44b3..36efc50 100644 --- a/src/Decentralized/ModFiles/Localization/ru.csv +++ b/src/Decentralized/ModFiles/Localization/ru.csv @@ -154,7 +154,7 @@ avg.short,ср. покупка {0} avg.none,— col.asset,Актив col.amount,Сумма -col.value,Стоимость +col.value,Оценка col.avg,Ср. покупка bank.cash.k,Кредиты bank.rent.k,Аренда @@ -406,7 +406,7 @@ poin.out.done,{0} {1} выведено на {2}. wallets.count,Кошельки {0}/{1} wallets.col.name,Название wallets.col.addr,Адрес -wallets.col.taint,Загрязнение +wallets.col.taint,Грязные wallets.open,Открыть wallets.use,Подключить wallets.current,Подключено @@ -425,7 +425,7 @@ wallets.destroy.sure,Подтвердить wallets.destroy.notempty,В {0} ещё есть монеты. Сначала выведите их. wallets.destroyed,Уничтожен {0}: {1} hw.balance.value,≈ {0} -wallets.rename,Переименовать +wallets.rename,Назвать wallets.rename.h,Новое имя для {0} wallets.rename.ok,ОК hw.fee.slow,Медленно @@ -498,7 +498,7 @@ perp.open,Открыть perp.margin,Маржа (CRC) perp.preview,Номинал {0} цена исполнения {1} perp.do.open,Открыть -perp.do.add,Добавить маржу +perp.do.add,+ Маржа perp.do.close,Закрыть perp.opened,"Открыто {0} {1}: маржа {2} CRC, {3}×." perp.added,Добавлено {0} CRC маржи. @@ -685,7 +685,7 @@ pool.none,Сейчас пулов нет. pool.col.name,Пул pool.col.rate,Ставка pool.col.reserve,Резерв -pool.col.lock,Таймлок +pool.col.lock,Лок pool.col.audit,Аудит pool.col.mine,Вклад pool.yes,да diff --git a/src/Decentralized/PledgerSkin.cs b/src/Decentralized/PledgerSkin.cs index 27e4894..93a7f8e 100644 --- a/src/Decentralized/PledgerSkin.cs +++ b/src/Decentralized/PledgerSkin.cs @@ -123,6 +123,7 @@ namespace Decentralized b.BeginPanel(w, height - 6f, align, 0f, 0f); if (clear != null) clear.Add(b.Last.image); b.AddLabel(i < texts.Length ? texts[i] : ""); + FitCurrent(b); b.End(); } b.End(); @@ -142,12 +143,46 @@ namespace Decentralized b.BeginPanel(w, height - 6f, align, 0f, 0f); if (clear != null) clear.Add(b.Last.image); b.AddLabel(i < headers.Length ? "" + headers[i] + "" : ""); + FitCurrent(b); b.End(); } b.End(); b.End(); } + /// 单行固定宽度的文字放不下时先缩小字号(最小 68%),再省略:各语言译文长度不同,不靠逐语言调列宽。 + public static void Fit(TMP_Text t) + { + if (t == null) return; + t.enableWordWrapping = false; + t.enableAutoSizing = true; + t.fontSizeMax = t.fontSize; + t.fontSizeMin = Mathf.Round(t.fontSize * 0.68f); + t.overflowMode = TextOverflowModes.Ellipsis; + } + + /// 刚加的标签限定在固定高度内(可折行),放不下时缩小字号:商品名等多语言下长度差很大的标题用。 + public static void FitBox(CustomUIBuilder b, float height) + { + var c = b.CurrentContainer; + if (c == null || c.childCount == 0) return; + var t = c.GetChild(c.childCount - 1).GetComponentInChildren(true); + if (t == null) return; + var le = t.gameObject.GetComponent() ?? t.gameObject.AddComponent(); + le.minHeight = height; le.preferredHeight = height; le.flexibleHeight = 0f; + t.enableAutoSizing = true; + t.fontSizeMax = t.fontSize; + t.fontSizeMin = Mathf.Round(t.fontSize * 0.7f); + t.overflowMode = TextOverflowModes.Ellipsis; + } + + /// 对当前容器(刚加完标签的单元面板)里的文字做 Fit。 + public static void FitCurrent(CustomUIBuilder b) + { + if (b.CurrentContainer == null) return; + foreach (var t in b.CurrentContainer.GetComponentsInChildren(true)) Fit(t); + } + /// 应用整套 PLEDGER 皮肤:机身、边框、墨水屏、刻字、文字颜色、触控键、滚动条与数据表行。 public static void Apply(CustomUIWindow win, RectTransform screen, Image bezel, Image paper, ICollection picked, ICollection clear, IEnumerable rows = null) { @@ -230,6 +265,7 @@ namespace Decentralized } foreach (var t in btn.GetComponentsInChildren(true)) { + Fit(t); t.color = on ? Ink : KeyText; if (on) t.fontStyle |= FontStyles.Bold; } diff --git a/src/Decentralized/TerminalWindow.cs b/src/Decentralized/TerminalWindow.cs index 4f36e80..3a6bce9 100644 --- a/src/Decentralized/TerminalWindow.cs +++ b/src/Decentralized/TerminalWindow.cs @@ -119,6 +119,7 @@ namespace Decentralized b.BeginPanel(w, 26f, align, 0f, 0f); _clear.Add(b.Last.image); b.AddLabel(header ? "" + text + "" : text); + PledgerSkin.FitCurrent(b); b.End(); } @@ -984,7 +985,7 @@ namespace Decentralized { var d = Session.Data; b.AddLabel(L.T("wallets.count", d.Wallets.Count, Tuning.WalletMax), "wallets_count_dim"); - var cols = new[] { 100f, 110f, 85f, 70f, 375f }; + var cols = L.Wide ? new[] { 100f, 92f, 62f, 62f, 372f } : new[] { 100f, 110f, 85f, 70f, 375f }; var aligns = new[] { TextAnchor.MiddleLeft, TextAnchor.MiddleLeft, TextAnchor.MiddleRight, TextAnchor.MiddleRight, TextAnchor.MiddleLeft }; TableHeader(b, 740f, cols, aligns, L.T("wallets.col.name"), L.T("wallets.col.addr"), L.T("col.value"), L.T("wallets.col.taint"), ""); for (int i = 0; i < d.Wallets.Count; i++) @@ -1009,7 +1010,7 @@ namespace Decentralized Cell(b, cols[3], Fmt.Credits(w.Taint), false, TextAnchor.MiddleRight); b.End(); b.End(); - b.BeginPanel(cols[4] - 150f, 32f, TextAnchor.MiddleLeft, 0f, 0f); + b.BeginPanel(cols[4] - (L.Wide ? 112f : 150f), 32f, TextAnchor.MiddleLeft, 0f, 0f); _clear.Add(b.Last.image); b.BeginRow(4f, TextAnchor.MiddleLeft); RowKey(b, L.T("wallets.open"), () => WalletWindow.Open(w)); @@ -1018,11 +1019,11 @@ namespace Decentralized if (idx > 0) RowKey(b, _destroyPick == w.Address ? L.T("wallets.destroy.sure") : L.T("wallets.destroy"), () => DestroyWallet(w)); b.End(); b.End(); - b.BeginPanel(84f, 32f, TextAnchor.MiddleRight, 0f, 0f); + b.BeginPanel(L.Wide ? 92f : 84f, 32f, TextAnchor.MiddleRight, 0f, 0f); _clear.Add(b.Last.image); b.BeginRow(0f, TextAnchor.MiddleRight); if (idx != d.Current) RowKey(b, L.T("wallets.use"), () => { d.Current = idx; Session.Save(); Open(); }); - else b.AddLabel(L.T("wallets.current"), "wallets_cur_dim"); + else { b.AddLabel(L.T("wallets.current"), "wallets_cur_dim"); PledgerSkin.FitCurrent(b); } b.End(); b.End(); b.End(); @@ -1754,6 +1755,7 @@ namespace Decentralized var sprite = Icon(g.Item); if (sprite != null) c.AddImage(sprite, 64f, 64f); else c.AddSpace(64f); c.AddLabel("" + ItemName(g.Item) + ""); + PledgerSkin.FitBox(c, 52f); bool asic = g.Kind == GoodKind.Gpu && g.Model != null && Hardware.Specs.TryGetValue(g.Model, out var gs) && gs.Asic; c.AddLabel(asic ? (g.Health >= 100 ? L.T("black.kind.asicnew") : L.T("black.kind.asic", (int)Math.Round(g.Health))) : g.Kind == GoodKind.Gpu ? (g.Health >= 100 ? L.T("black.kind.gpunew") : L.T("black.kind.gpu", (int)Math.Round(g.Health))) : L.T("black.kind." + g.Kind + (g.Kind == GoodKind.Contraband ? "." + g.Level : "")), "good_kind_dim"); if (!string.IsNullOrEmpty(line2)) c.AddLabel(line2, "good_line2_dim"); diff --git a/src/Decentralized/WalletWindow.cs b/src/Decentralized/WalletWindow.cs index 727dcef..6fc024e 100644 --- a/src/Decentralized/WalletWindow.cs +++ b/src/Decentralized/WalletWindow.cs @@ -265,7 +265,7 @@ namespace Decentralized b.AddHeader(L.T("hw.send")); b.AddLabel(L.T("hw.to")); b.BeginRow(6f, TextAnchor.MiddleLeft); - b.BeginPanel(RowW - 70f, -1f, TextAnchor.MiddleLeft, 0f, 0f); + b.BeginPanel(RowW - (L.Wide ? 100f : 70f), -1f, TextAnchor.MiddleLeft, 0f, 0f); _clear.Add(b.Last.image); b.AddInput("0x", dev.To, s => dev.To = s, "to", s => dev.To = s); b.End();