多语言批量修改

This commit is contained in:
kawagiri 2026-05-14 02:41:49 +08:00
parent 1ba545a8e5
commit e2689acf29
13 changed files with 15278 additions and 12439 deletions

File diff suppressed because one or more lines are too long

View File

@ -1410,7 +1410,7 @@ MonoBehaviour:
m_HandleRect: {fileID: 5509163480483728840}
m_Direction: 2
m_Value: 1
m_Size: 0.8158911
m_Size: 0.815011
m_NumberOfSteps: 0
m_OnValueChanged:
m_PersistentCalls:
@ -1481,10 +1481,10 @@ MonoBehaviour:
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_text: "\u786E\u8BA4"
m_text: Confirm
m_isRightToLeft: 0
m_fontAsset: {fileID: 11400000, guid: ce4904f8ddac15944907907115531ad5, type: 2}
m_sharedMaterial: {fileID: 1214840240034325189, guid: ce4904f8ddac15944907907115531ad5, type: 2}
m_fontAsset: {fileID: 11400000, guid: b1d138707f472d747af4792d750f98ea, type: 2}
m_sharedMaterial: {fileID: -8319875257487810009, guid: b1d138707f472d747af4792d750f98ea, type: 2}
m_fontSharedMaterials: []
m_fontMaterial: {fileID: 0}
m_fontMaterials: []
@ -1518,9 +1518,9 @@ MonoBehaviour:
m_HorizontalAlignment: 2
m_VerticalAlignment: 512
m_textAlignment: 65535
m_characterSpacing: 100
m_characterSpacing: 0
m_wordSpacing: 0
m_lineSpacing: 0
m_lineSpacing: -20
m_lineSpacingMax: 0
m_paragraphSpacing: 0
m_charWidthMaxAdj: 0
@ -1580,6 +1580,17 @@ MonoBehaviour:
LineSpacing: 0
ApplyParagraphSpacing: 0
ParagraphSpacing: 0
- Type: 3
ApplyFontSize: 1
FontSize: 24
ApplyCharacterSpacing: 1
CharacterSpacing: 0
ApplyWordSpacing: 1
WordSpacing: 0
ApplyLineSpacing: 1
LineSpacing: -20
ApplyParagraphSpacing: 1
ParagraphSpacing: 0
--- !u!1 &1711532612554376573
GameObject:
m_ObjectHideFlags: 0

View File

@ -755,8 +755,8 @@ RectTransform:
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: -14.600998, y: 0.000036239624}
m_SizeDelta: {x: -88.625, y: -0.0000038147}
m_AnchoredPosition: {x: -19.88, y: 2.4158}
m_SizeDelta: {x: -99.183, y: -4.8316}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &5222751556308516573
CanvasRenderer:
@ -3242,7 +3242,7 @@ RectTransform:
m_Father: {fileID: 658324326176829061}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: -65.503784, y: -960}
m_SizeDelta: {x: 20, y: 20}
m_Pivot: {x: 0.5, y: 0.5}
@ -3796,7 +3796,7 @@ RectTransform:
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 83.23, y: -0.000091552734}
m_SizeDelta: {x: 166.46, y: 59.733}
m_SizeDelta: {x: 166.46, y: 0}
m_Pivot: {x: 0.5, y: 1}
--- !u!114 &2400551985836425900
MonoBehaviour:
@ -4556,7 +4556,7 @@ RectTransform:
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 83.23, y: -0.000091552734}
m_SizeDelta: {x: 166.46, y: 59.733}
m_SizeDelta: {x: 166.46, y: 0}
m_Pivot: {x: 0.5, y: 1}
--- !u!114 &5532509308171059431
MonoBehaviour:
@ -7972,7 +7972,7 @@ RectTransform:
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0.000002861, y: 0.000028818846}
m_SizeDelta: {x: 0.00010681, y: 0}
m_SizeDelta: {x: 0.00010681, y: 10}
m_Pivot: {x: 0, y: 1}
--- !u!114 &852488813056648141
MonoBehaviour:
@ -8585,7 +8585,7 @@ RectTransform:
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0.000002861, y: 0.000028818846}
m_SizeDelta: {x: 0.00010681, y: 10}
m_SizeDelta: {x: 0.00010681, y: 0}
m_Pivot: {x: 0, y: 1}
--- !u!114 &2636698054791453582
MonoBehaviour:
@ -10211,9 +10211,9 @@ RectTransform:
m_Father: {fileID: 4084397047757113258}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_SizeDelta: {x: -8.3629, y: 0}
m_Pivot: {x: 0, y: 1}
--- !u!222 &8501016124821370550
CanvasRenderer:
@ -12590,7 +12590,7 @@ RectTransform:
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 149.3699, y: -65.1}
m_AnchoredPosition: {x: 150, y: -46}
m_SizeDelta: {x: 239.3175, y: 2.2481003}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &7294975872898965817
@ -13522,9 +13522,9 @@ RectTransform:
- {fileID: 656169955482693271}
m_Father: {fileID: 3591097763741017271}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 111.03215, y: -29.8665}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 222.0643, y: 59.733}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &767216046778848098
@ -13896,9 +13896,9 @@ RectTransform:
- {fileID: 4034874040368148762}
m_Father: {fileID: 460822364729243544}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 172.4234, y: -29.8665}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 344.8468, y: 59.733}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &7648120091579805399
@ -14374,7 +14374,7 @@ GameObject:
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 0
m_IsActive: 1
--- !u!224 &8464345181728759303
RectTransform:
m_ObjectHideFlags: 0
@ -15500,8 +15500,8 @@ RectTransform:
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 83.23, y: -0.000091552734}
m_SizeDelta: {x: 166.46, y: 59.733}
m_AnchoredPosition: {x: 169.25162, y: -0.000091552734}
m_SizeDelta: {x: 338.5034, y: 0}
m_Pivot: {x: 0.5, y: 1}
--- !u!114 &2372562429259679674
MonoBehaviour:
@ -16829,9 +16829,9 @@ RectTransform:
- {fileID: 12037518669790445}
m_Father: {fileID: 3457946028282610767}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 111.03215, y: -29.8665}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 222.0643, y: 59.733}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &5734839279286010400
@ -18751,7 +18751,7 @@ GameObject:
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
m_IsActive: 0
--- !u!224 &7279650132883757932
RectTransform:
m_ObjectHideFlags: 0
@ -18811,7 +18811,7 @@ RectTransform:
m_Father: {fileID: 3561218373905709919}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: -65.503784, y: -960}
m_SizeDelta: {x: 20, y: 20}
m_Pivot: {x: 0.5, y: 0.5}
@ -19052,8 +19052,8 @@ RectTransform:
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 3.0912933, y: 3}
m_SizeDelta: {x: -56.1826, y: -6}
m_AnchoredPosition: {x: -18.6314, y: 0}
m_SizeDelta: {x: -99.6279, y: -0.0000038147}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &2082155209361375675
CanvasRenderer:
@ -21125,10 +21125,10 @@ RectTransform:
- {fileID: 8652061982368378950}
m_Father: {fileID: 8823726147371359793}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 111.03215, y: -29.8665}
m_SizeDelta: {x: 222.0643, y: 59.733}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 338.5, y: 53.651}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &1896532852177851316
MonoBehaviour:
@ -21757,9 +21757,9 @@ RectTransform:
- {fileID: 6463223705121097691}
m_Father: {fileID: 2173028587529751265}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 111.03215, y: -29.8665}
m_SizeDelta: {x: 222.0643, y: 59.733}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &4849557949310105883
@ -22373,7 +22373,7 @@ RectTransform:
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 83.23, y: -0.000091552734}
m_SizeDelta: {x: 166.46, y: 0}
m_SizeDelta: {x: 166.46, y: 59.733}
m_Pivot: {x: 0.5, y: 1}
--- !u!114 &4244297049399370593
MonoBehaviour:
@ -23256,9 +23256,9 @@ RectTransform:
m_Father: {fileID: 8770181562458777078}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_SizeDelta: {x: -8.3629, y: 0}
m_Pivot: {x: 0, y: 1}
--- !u!222 &2320321692171427671
CanvasRenderer:
@ -23347,7 +23347,7 @@ RectTransform:
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 83.23, y: -0.000091552734}
m_SizeDelta: {x: 166.46, y: 59.733}
m_SizeDelta: {x: 166.46, y: 0}
m_Pivot: {x: 0.5, y: 1}
--- !u!114 &3493450085961203087
MonoBehaviour:
@ -23422,7 +23422,7 @@ RectTransform:
m_Father: {fileID: 9060693738176851498}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: -65.503784, y: -960}
m_SizeDelta: {x: 20, y: 20}
m_Pivot: {x: 0.5, y: 0.5}
@ -24968,7 +24968,7 @@ RectTransform:
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0.000002861, y: 0.000028818846}
m_SizeDelta: {x: 0.00010681, y: 0}
m_SizeDelta: {x: 0.00010681, y: 10}
m_Pivot: {x: 0, y: 1}
--- !u!114 &6945705488271009981
MonoBehaviour:
@ -26234,9 +26234,9 @@ RectTransform:
m_Father: {fileID: 3911526918901232009}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: -8.3629, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0, y: 1}
--- !u!222 &165601771047519322
CanvasRenderer:

View File

@ -475,6 +475,39 @@ namespace Logic.Multilingual
public string ES;
public string PT;
public string FR;
public string DE; // 德语
public string IDN; // 印尼语 (对应 enum.ID字段名避开与 ID 编号冲突)
public string TH; // 泰语
public string PL; // 波兰语
public string VI; // 越南语
public string MS; // 马来语
public string UK; // 乌克兰语
public string KZ; // 哈萨克语
public string TR; // 土耳其语
public string IT; // 意大利语
public string NL; // 荷兰语
public string FI; // 芬兰语
public string SV; // 瑞典语
public string NO; // 挪威语
public string CS; // 捷克语
public string HU; // 匈牙利语
public string EL; // 希腊语
public string RO; // 罗马尼亚语
public string ET; // 爱沙尼亚语
public string LT; // 立陶宛语
public string HR; // 克罗地亚语
public string SR; // 塞尔维亚语
public string SL; // 斯洛文尼亚语
public string SK; // 斯洛伐克语
public string BE; // 白俄罗斯语
public string HE; // 希伯来语
public string BG; // 保加利亚语
public string UZ; // 乌兹别克语
public string KY; // 吉尔吉斯语
public string MN; // 蒙古语
public string AR; // 阿拉伯语 (RTLTMP 渲染另需配置)
public string DA; // 丹麦语
public string TL; // 菲律宾语
public string Custom; // 自定义语种(仅供 Mod 应用使用)
public bool IsProperNoun;
public bool IsDialogue;
@ -513,6 +546,39 @@ namespace Logic.Multilingual
ES = ES?.Replace("\r\n", "\n") ?? string.Empty;
PT = PT?.Replace("\r\n", "\n") ?? string.Empty;
FR = FR?.Replace("\r\n", "\n") ?? string.Empty;
DE = DE?.Replace("\r\n", "\n") ?? string.Empty;
IDN = IDN?.Replace("\r\n", "\n") ?? string.Empty;
TH = TH?.Replace("\r\n", "\n") ?? string.Empty;
PL = PL?.Replace("\r\n", "\n") ?? string.Empty;
VI = VI?.Replace("\r\n", "\n") ?? string.Empty;
MS = MS?.Replace("\r\n", "\n") ?? string.Empty;
UK = UK?.Replace("\r\n", "\n") ?? string.Empty;
KZ = KZ?.Replace("\r\n", "\n") ?? string.Empty;
TR = TR?.Replace("\r\n", "\n") ?? string.Empty;
IT = IT?.Replace("\r\n", "\n") ?? string.Empty;
NL = NL?.Replace("\r\n", "\n") ?? string.Empty;
FI = FI?.Replace("\r\n", "\n") ?? string.Empty;
SV = SV?.Replace("\r\n", "\n") ?? string.Empty;
NO = NO?.Replace("\r\n", "\n") ?? string.Empty;
CS = CS?.Replace("\r\n", "\n") ?? string.Empty;
HU = HU?.Replace("\r\n", "\n") ?? string.Empty;
EL = EL?.Replace("\r\n", "\n") ?? string.Empty;
RO = RO?.Replace("\r\n", "\n") ?? string.Empty;
ET = ET?.Replace("\r\n", "\n") ?? string.Empty;
LT = LT?.Replace("\r\n", "\n") ?? string.Empty;
HR = HR?.Replace("\r\n", "\n") ?? string.Empty;
SR = SR?.Replace("\r\n", "\n") ?? string.Empty;
SL = SL?.Replace("\r\n", "\n") ?? string.Empty;
SK = SK?.Replace("\r\n", "\n") ?? string.Empty;
BE = BE?.Replace("\r\n", "\n") ?? string.Empty;
HE = HE?.Replace("\r\n", "\n") ?? string.Empty;
BG = BG?.Replace("\r\n", "\n") ?? string.Empty;
UZ = UZ?.Replace("\r\n", "\n") ?? string.Empty;
KY = KY?.Replace("\r\n", "\n") ?? string.Empty;
MN = MN?.Replace("\r\n", "\n") ?? string.Empty;
AR = AR?.Replace("\r\n", "\n") ?? string.Empty;
DA = DA?.Replace("\r\n", "\n") ?? string.Empty;
TL = TL?.Replace("\r\n", "\n") ?? string.Empty;
Custom = Custom?.Replace("\r\n", "\n") ?? string.Empty;
DialogueSpeaker = DialogueSpeaker?.Replace("\r\n", "\n") ?? string.Empty;
Desc = Desc?.Replace("\r\n", "\n") ?? string.Empty;
@ -531,6 +597,39 @@ namespace Logic.Multilingual
MultilingualType.ES => ES,
MultilingualType.PT => PT,
MultilingualType.FR => FR,
MultilingualType.DE => DE,
MultilingualType.ID => IDN, // 印尼语字段名是 IDN避开与 ID 编号字段冲突
MultilingualType.TH => TH,
MultilingualType.PL => PL,
MultilingualType.VI => VI,
MultilingualType.MS => MS,
MultilingualType.UK => UK,
MultilingualType.KZ => KZ,
MultilingualType.TR => TR,
MultilingualType.IT => IT,
MultilingualType.NL => NL,
MultilingualType.FI => FI,
MultilingualType.SV => SV,
MultilingualType.NO => NO,
MultilingualType.CS => CS,
MultilingualType.HU => HU,
MultilingualType.EL => EL,
MultilingualType.RO => RO,
MultilingualType.ET => ET,
MultilingualType.LT => LT,
MultilingualType.HR => HR,
MultilingualType.SR => SR,
MultilingualType.SL => SL,
MultilingualType.SK => SK,
MultilingualType.BE => BE,
MultilingualType.HE => HE,
MultilingualType.BG => BG,
MultilingualType.UZ => UZ,
MultilingualType.KY => KY,
MultilingualType.MN => MN,
MultilingualType.AR => AR,
MultilingualType.DA => DA,
MultilingualType.TL => TL,
MultilingualType.Custom => Custom,
_ => string.Empty,
};
@ -557,6 +656,39 @@ namespace Logic.Multilingual
MultilingualType.ES => !string.IsNullOrEmpty(ES),
MultilingualType.PT => !string.IsNullOrEmpty(PT),
MultilingualType.FR => !string.IsNullOrEmpty(FR),
MultilingualType.DE => !string.IsNullOrEmpty(DE),
MultilingualType.ID => !string.IsNullOrEmpty(IDN),
MultilingualType.TH => !string.IsNullOrEmpty(TH),
MultilingualType.PL => !string.IsNullOrEmpty(PL),
MultilingualType.VI => !string.IsNullOrEmpty(VI),
MultilingualType.MS => !string.IsNullOrEmpty(MS),
MultilingualType.UK => !string.IsNullOrEmpty(UK),
MultilingualType.KZ => !string.IsNullOrEmpty(KZ),
MultilingualType.TR => !string.IsNullOrEmpty(TR),
MultilingualType.IT => !string.IsNullOrEmpty(IT),
MultilingualType.NL => !string.IsNullOrEmpty(NL),
MultilingualType.FI => !string.IsNullOrEmpty(FI),
MultilingualType.SV => !string.IsNullOrEmpty(SV),
MultilingualType.NO => !string.IsNullOrEmpty(NO),
MultilingualType.CS => !string.IsNullOrEmpty(CS),
MultilingualType.HU => !string.IsNullOrEmpty(HU),
MultilingualType.EL => !string.IsNullOrEmpty(EL),
MultilingualType.RO => !string.IsNullOrEmpty(RO),
MultilingualType.ET => !string.IsNullOrEmpty(ET),
MultilingualType.LT => !string.IsNullOrEmpty(LT),
MultilingualType.HR => !string.IsNullOrEmpty(HR),
MultilingualType.SR => !string.IsNullOrEmpty(SR),
MultilingualType.SL => !string.IsNullOrEmpty(SL),
MultilingualType.SK => !string.IsNullOrEmpty(SK),
MultilingualType.BE => !string.IsNullOrEmpty(BE),
MultilingualType.HE => !string.IsNullOrEmpty(HE),
MultilingualType.BG => !string.IsNullOrEmpty(BG),
MultilingualType.UZ => !string.IsNullOrEmpty(UZ),
MultilingualType.KY => !string.IsNullOrEmpty(KY),
MultilingualType.MN => !string.IsNullOrEmpty(MN),
MultilingualType.AR => !string.IsNullOrEmpty(AR),
MultilingualType.DA => !string.IsNullOrEmpty(DA),
MultilingualType.TL => !string.IsNullOrEmpty(TL),
MultilingualType.Custom => !string.IsNullOrEmpty(Custom),
_ => false,
};

View File

@ -387,6 +387,39 @@ namespace Logic.Multilingual
public string ES;
public string PT;
public string FR;
public string DE;
public string IDN; // 印尼语 (对应 enum.ID)
public string TH;
public string PL;
public string VI;
public string MS;
public string UK;
public string KZ;
public string TR;
public string IT;
public string NL;
public string FI;
public string SV;
public string NO;
public string CS;
public string HU;
public string EL;
public string RO;
public string ET;
public string LT;
public string HR;
public string SR;
public string SL;
public string SK;
public string BE;
public string HE;
public string BG;
public string UZ;
public string KY;
public string MN;
public string AR;
public string DA;
public string TL;
public string Custom;
public static OriginalLangFields From(MultilingualItem item)
@ -402,6 +435,39 @@ namespace Logic.Multilingual
ES = item.ES,
PT = item.PT,
FR = item.FR,
DE = item.DE,
IDN = item.IDN,
TH = item.TH,
PL = item.PL,
VI = item.VI,
MS = item.MS,
UK = item.UK,
KZ = item.KZ,
TR = item.TR,
IT = item.IT,
NL = item.NL,
FI = item.FI,
SV = item.SV,
NO = item.NO,
CS = item.CS,
HU = item.HU,
EL = item.EL,
RO = item.RO,
ET = item.ET,
LT = item.LT,
HR = item.HR,
SR = item.SR,
SL = item.SL,
SK = item.SK,
BE = item.BE,
HE = item.HE,
BG = item.BG,
UZ = item.UZ,
KY = item.KY,
MN = item.MN,
AR = item.AR,
DA = item.DA,
TL = item.TL,
Custom = item.Custom,
};
}
@ -417,6 +483,39 @@ namespace Logic.Multilingual
item.ES = ES;
item.PT = PT;
item.FR = FR;
item.DE = DE;
item.IDN = IDN;
item.TH = TH;
item.PL = PL;
item.VI = VI;
item.MS = MS;
item.UK = UK;
item.KZ = KZ;
item.TR = TR;
item.IT = IT;
item.NL = NL;
item.FI = FI;
item.SV = SV;
item.NO = NO;
item.CS = CS;
item.HU = HU;
item.EL = EL;
item.RO = RO;
item.ET = ET;
item.LT = LT;
item.HR = HR;
item.SR = SR;
item.SL = SL;
item.SK = SK;
item.BE = BE;
item.HE = HE;
item.BG = BG;
item.UZ = UZ;
item.KY = KY;
item.MN = MN;
item.AR = AR;
item.DA = DA;
item.TL = TL;
item.Custom = Custom;
}
}

View File

@ -72,19 +72,29 @@ namespace Logic.Multilingual
if (_paramList != null && _paramList.Count != 0)
{
int index = 0;
text.text = Regex.Replace(text.text, "{param}", m =>
text.text = Regex.Replace(text.text, "{param}", m =>
index < _paramList.Count ? _paramList[index++] : m.Value);
}
// TODO 临时换色
text.text = text.text.Replace( "<color=yellow>", "<color=orange>");
// TODO 临时转义换色
text.text = text.text.Replace( "**<", "<color=orange>");
text.text = text.text.Replace( ">**", "</color>");
// RTL 方向切换:阿语/希伯来语开 RTL其他语言关掉。
// 注意:仅控制字符排列方向,不做 shaping(字母连写);连写需第三方库 ArabicFixer 预处理字符串。
ApplyRTLDirection(text, MultilingualManager.Instance.CurrentType);
}
}
// 仅阿拉伯语 / 希伯来语开启 TMP 内置 RTL其他语言显式关掉
// 避免切语言时阿语切走后 isRightToLeftText 残留导致下一种语言反向显示
private static void ApplyRTLDirection(TextMeshProUGUI text, MultilingualType type)
{
text.isRightToLeftText = (type == MultilingualType.AR || type == MultilingualType.HE);
}
public void BindFontID()
{
if (FontBan) return;
@ -155,9 +165,10 @@ namespace Logic.Multilingual
// TODO 临时转义换色
text.text = text.text.Replace( "**<", "<color=orange>");
text.text = text.text.Replace( ">**", "</color>");
if (font != null) text.font = font;
MatchTextCfg(text, type);
ApplyRTLDirection(text, type);
}
}
}

View File

@ -167,11 +167,22 @@ namespace Logic.Multilingual
/// </summary>
public static List<string> GetSubscribedModPaths()
{
var paths = new List<string>();
var entries = GetSubscribedModEntries();
var paths = new List<string>(entries.Count);
foreach (var e in entries) paths.Add(e.Folder);
return paths;
}
/// <summary>
/// 同 GetSubscribedModPaths但同时返回 Steam PublishedFileId_t用于 UI 去重)
/// </summary>
public static List<SubscribedModEntry> GetSubscribedModEntries()
{
var entries = new List<SubscribedModEntry>();
try
{
uint numSubscribed = SteamUGC.GetNumSubscribedItems();
if (numSubscribed == 0) return paths;
if (numSubscribed == 0) return entries;
var subscribedIds = new PublishedFileId_t[numSubscribed];
SteamUGC.GetSubscribedItems(subscribedIds, numSubscribed);
@ -187,7 +198,7 @@ namespace Logic.Multilingual
if (string.IsNullOrEmpty(folder) || !Directory.Exists(folder)) continue;
// 仅收集包含 mod_info.json 的文件夹(确认为多语言 Mod
if (File.Exists(Path.Combine(folder, WorkshopModExporter.ModInfoFileName)))
paths.Add(folder);
entries.Add(new SubscribedModEntry { Folder = folder, FileId = fileId });
}
}
}
@ -196,7 +207,16 @@ namespace Logic.Multilingual
LogSystem.LogWarning($"WorkshopModLoader: 获取 Workshop 订阅列表失败 - {e.Message}");
}
return paths;
return entries;
}
/// <summary>
/// 已订阅 mod 的本地路径 + Steam PublishedFileId 配对
/// </summary>
public struct SubscribedModEntry
{
public string Folder;
public PublishedFileId_t FileId;
}
/// <summary>
@ -261,6 +281,39 @@ namespace Logic.Multilingual
case MultilingualType.ES: item.ES = value; break;
case MultilingualType.PT: item.PT = value; break;
case MultilingualType.FR: item.FR = value; break;
case MultilingualType.DE: item.DE = value; break;
case MultilingualType.ID: item.IDN = value; break; // 印尼语字段名是 IDN
case MultilingualType.TH: item.TH = value; break;
case MultilingualType.PL: item.PL = value; break;
case MultilingualType.VI: item.VI = value; break;
case MultilingualType.MS: item.MS = value; break;
case MultilingualType.UK: item.UK = value; break;
case MultilingualType.KZ: item.KZ = value; break;
case MultilingualType.TR: item.TR = value; break;
case MultilingualType.IT: item.IT = value; break;
case MultilingualType.NL: item.NL = value; break;
case MultilingualType.FI: item.FI = value; break;
case MultilingualType.SV: item.SV = value; break;
case MultilingualType.NO: item.NO = value; break;
case MultilingualType.CS: item.CS = value; break;
case MultilingualType.HU: item.HU = value; break;
case MultilingualType.EL: item.EL = value; break;
case MultilingualType.RO: item.RO = value; break;
case MultilingualType.ET: item.ET = value; break;
case MultilingualType.LT: item.LT = value; break;
case MultilingualType.HR: item.HR = value; break;
case MultilingualType.SR: item.SR = value; break;
case MultilingualType.SL: item.SL = value; break;
case MultilingualType.SK: item.SK = value; break;
case MultilingualType.BE: item.BE = value; break;
case MultilingualType.HE: item.HE = value; break;
case MultilingualType.BG: item.BG = value; break;
case MultilingualType.UZ: item.UZ = value; break;
case MultilingualType.KY: item.KY = value; break;
case MultilingualType.MN: item.MN = value; break;
case MultilingualType.AR: item.AR = value; break;
case MultilingualType.DA: item.DA = value; break;
case MultilingualType.TL: item.TL = value; break;
case MultilingualType.Custom: item.Custom = value; break;
}
}

View File

@ -169,6 +169,9 @@ namespace TH1_UI.View.Outside
MultilingualType.UZ => "Oʻzbekcha",//没字体
MultilingualType.KY => "Кыргызча",
MultilingualType.MN => "Монгол",
MultilingualType.AR => "العربية",
MultilingualType.DA => "Dansk",
MultilingualType.TL => "Filipino",
MultilingualType.Custom => "Custom",
_ => type.ToString()
};

View File

@ -450,19 +450,69 @@ namespace TH1_UI.View.Outside
_allMods.Clear();
// 1. 本地 Mod包括已安装的订阅 Mod因为 GetSubscribedModPaths 也读 mod_info.json
int beforeLocal = _allMods.Count;
AppendLocalMods(_allMods, WorkshopModLoader.GetLocalModPaths(), ModListItemSource.Local);
AppendLocalMods(_allMods, WorkshopModLoader.GetSubscribedModPaths(), ModListItemSource.Subscribed);
int localCount = _allMods.Count - beforeLocal;
int beforeSubscribed = _allMods.Count;
AppendSubscribedMods(_allMods, WorkshopModLoader.GetSubscribedModEntries());
int subscribedCount = _allMods.Count - beforeSubscribed;
// 诊断日志:本地 + 订阅集合明细fileId / title / folder
var diagSb = new System.Text.StringBuilder();
diagSb.Append($"[UIOutsideMod] RebuildAllModsCache: Local={localCount} Subscribed={subscribedCount} ");
diagSb.Append($"hasQueriedWorkshop={_hasQueriedWorkshop} BrowserResultsCount={WorkshopModBrowser.Instance.Results.Count}\n");
diagSb.Append(" --- 本地/订阅集合 ---\n");
for (int i = 0; i < _allMods.Count; i++)
{
var m = _allMods[i];
diagSb.Append($" [{i}] Source={m.Source} fileId={m.SteamFileId.m_PublishedFileId} title=\"{m.Title}\" folder=\"{m.LocalFolder}\"\n");
}
// 2. Steam 工坊查询结果(仅在用户点过查询按钮后才有)
// 注意:已订阅的 mod 已经在第 1 步用 Subscribed 来源出现过,这里按 FileId 去重 —— 命中则把工坊元数据合并到那条本地记录上,不再单独 add。
if (_hasQueriedWorkshop)
{
diagSb.Append(" --- Workshop 查询结果遍历 ---\n");
int idxInResults = 0;
foreach (var item in WorkshopModBrowser.Instance.Results)
{
// 先按 FileId 去重(订阅版本场景命中),失败再 fallback 用 title 去重(本地导出版本 fileId=0
// 但与 Steam 上传版本 title 完全相同 —— 应当视为同一 mod 合并)
var existing = FindByFileId(_allMods, item.FileId);
string matchReason = "FileId";
if (existing == null && !string.IsNullOrEmpty(item.Title))
{
existing = FindByTitle(_allMods, item.Title);
if (existing != null) matchReason = "Title";
}
if (existing != null)
{
diagSb.Append($" [Workshop#{idxInResults}] fileId={item.FileId.m_PublishedFileId} title=\"{item.Title}\" → 命中本地({matchReason}),合并元数据,跳过 Add\n");
// 把 Workshop 元数据合并到已存在的 Subscribed 记录上(保留 Source=Subscribed让 UI 仍按本地视角处理)
existing.SteamFileId = item.FileId;
existing.SteamIsSubscribed = item.IsSubscribed;
existing.SteamIsInstalled = item.IsInstalled;
existing.SteamVotesUp = item.VotesUp;
existing.SteamVotesDown = item.VotesDown;
existing.SteamFileSize = (ulong)item.FileSize;
existing.SteamCreatedTime = item.CreatedTime;
existing.SteamUpdatedTime = item.UpdatedTime;
// 本地 mod_info 里 author 可能空,工坊回来的 OwnerSteamId 能解析出 PersonaName 时回填
if (string.IsNullOrEmpty(existing.Author))
existing.Author = ResolveSteamPersonaName(item.OwnerSteamId);
// Title/Description 不覆盖:本地 mod_info 的可能是玩家最新编辑过的,工坊页可能滞后
idxInResults++;
continue;
}
diagSb.Append($" [Workshop#{idxInResults}] fileId={item.FileId.m_PublishedFileId} title=\"{item.Title}\" → 未命中本地,作为 Workshop 来源 Add\n");
_allMods.Add(new UIOutsideModListData
{
Source = ModListItemSource.Workshop,
Title = item.Title,
Author = "", // Steam 查询拿的是 OwnerSteamId作者名要后续 RequestUserInformation 才能拿
Author = ResolveSteamPersonaName(item.OwnerSteamId),
Description = item.Description,
TargetLanguage = MultilingualType.None, // 在线 Mod 在订阅安装前拿不到 mod_infoTargetLanguage 留空
SteamFileId = item.FileId,
@ -475,8 +525,56 @@ namespace TH1_UI.View.Outside
SteamUpdatedTime = item.UpdatedTime,
LocalFolder = item.InstallFolder,
});
idxInResults++;
}
}
diagSb.Append($" --- 最终 _allMods.Count={_allMods.Count} ---");
Logic.CrashSight.LogSystem.LogInfo(diagSb.ToString());
}
// 用 FileId 在已收集列表里找一条(默认值 0 当作"无 FileId",跳过匹配)
private static UIOutsideModListData FindByFileId(List<UIOutsideModListData> list, PublishedFileId_t fileId)
{
if (fileId.m_PublishedFileId == 0) return null;
foreach (var m in list)
{
if (m.SteamFileId.m_PublishedFileId == fileId.m_PublishedFileId) return m;
}
return null;
}
// 用 Title 二次去重(本地导出 mod fileId=0无法和 Steam 上传版本按 FileId 关联;
// 而它们的 mod_info.title 完全一致,是同一个 mod 的两个副本,应合并)
private static UIOutsideModListData FindByTitle(List<UIOutsideModListData> list, string title)
{
if (string.IsNullOrEmpty(title)) return null;
foreach (var m in list)
{
if (m.Title == title) return m;
}
return null;
}
// 把 Workshop mod 的 OwnerSteamId 解析为 PersonaName。
// 首次访问该用户时 Steam 客户端可能还没缓存名字,会返回空 / "[unknown]"
// RequestUserInformation 是异步后台拉取,下次 Query/重开界面就有了 —— 发售前不补回调刷新,足够用。
private static string ResolveSteamPersonaName(ulong ownerSteamId)
{
if (ownerSteamId == 0) return "";
try
{
var cSteamId = new CSteamID(ownerSteamId);
// 第二参数 true = 只要昵称,不要 avatar返回 false 说明本地没缓存,已经在后台拉
SteamFriends.RequestUserInformation(cSteamId, true);
var name = SteamFriends.GetFriendPersonaName(cSteamId);
if (string.IsNullOrEmpty(name) || name == "[unknown]") return "";
return name;
}
catch
{
return "";
}
}
private static void AppendLocalMods(List<UIOutsideModListData> dst, List<string> folders, ModListItemSource source)
@ -503,6 +601,42 @@ namespace TH1_UI.View.Outside
}
}
// Subscribed 来源额外把 PublishedFileId 一并存入,方便和 Workshop 在线结果按 FileId 去重
private static void AppendSubscribedMods(List<UIOutsideModListData> dst, List<WorkshopModLoader.SubscribedModEntry> entries)
{
foreach (var entry in entries)
{
var info = WorkshopModExporter.ReadModInfo(entry.Folder);
if (info == null)
{
Logic.CrashSight.LogSystem.LogWarning($"[UIOutsideMod] 订阅 mod 的 mod_info.json 读取失败fileId={entry.FileId} folder={entry.Folder}");
continue;
}
MultilingualType target = MultilingualType.None;
if (Enum.TryParse<MultilingualType>(info.targetLanguage, true, out var parsed))
target = parsed;
// title 为空的"空选项"诊断:日志里能定位到具体哪个 fileId/folder
if (string.IsNullOrEmpty(info.title))
{
Logic.CrashSight.LogSystem.LogWarning($"[UIOutsideMod] 订阅 mod title 为空回退显示文件夹名。fileId={entry.FileId} folder={entry.Folder}");
}
dst.Add(new UIOutsideModListData
{
Source = ModListItemSource.Subscribed,
Title = string.IsNullOrEmpty(info.title) ? System.IO.Path.GetFileName(entry.Folder) : info.title,
Author = info.author ?? "",
Description = info.description ?? "",
TargetLanguage = target,
Version = info.version ?? "",
LocalFolder = entry.Folder,
SteamFileId = entry.FileId,
});
}
}
private static List<UIOutsideModListData> FilterMods(List<UIOutsideModListData> src, MultilingualType filter)
{
if (filter == MultilingualType.None) return new List<UIOutsideModListData>(src);
@ -588,6 +722,26 @@ namespace TH1_UI.View.Outside
}
RefreshSubscribeUI();
// 切换条目时 TMP 文本长度不一ContentSizeFitter / VerticalLayoutGroup 异步刷新会导致旧文本残影叠字。
// 这里同帧强制重建一遍 DetailRoot 下所有 layout确保新文案立刻按新尺寸落位。
ForceRebuildDetailLayout();
}
private void ForceRebuildDetailLayout()
{
if (DetailRoot == null) return;
var root = DetailRoot.transform as RectTransform;
if (root == null) return;
// 先把所有子 LayoutGroup 重建一遍(从最深层往外,避免父级先重建子级尺寸还没定)
var groups = DetailRoot.GetComponentsInChildren<UnityEngine.UI.LayoutGroup>(true);
for (int i = groups.Length - 1; i >= 0; i--)
{
var rt = groups[i].transform as RectTransform;
if (rt != null) UnityEngine.UI.LayoutRebuilder.ForceRebuildLayoutImmediate(rt);
}
// 最后重建一次根,覆盖根上的 ContentSizeFitter
UnityEngine.UI.LayoutRebuilder.ForceRebuildLayoutImmediate(root);
}
// 订阅状态 UI3 个 hint 互斥 + 2 个按钮按状态显示
@ -772,7 +926,7 @@ namespace TH1_UI.View.Outside
{
_availableMods.Clear();
AppendLocalMods(_availableMods, WorkshopModLoader.GetLocalModPaths(), ModListItemSource.Local);
AppendLocalMods(_availableMods, WorkshopModLoader.GetSubscribedModPaths(), ModListItemSource.Subscribed);
AppendSubscribedMods(_availableMods, WorkshopModLoader.GetSubscribedModEntries());
}
// 把 Config 里当前编辑语言的 ModPaths 拷贝到 _editingModPaths编辑副本

View File

@ -185,6 +185,9 @@ namespace TH1_UI.View.Top
MultilingualType.UZ => "Oʻzbekcha",
MultilingualType.KY => "Кыргызча",
MultilingualType.MN => "Монгол",
MultilingualType.AR => "العربية",
MultilingualType.DA => "Dansk",
MultilingualType.TL => "Filipino",
MultilingualType.Custom => "Custom",
_ => type.ToString()
};

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff