737 lines
30 KiB
C#
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.

/*
* @Author: 白哉
* @Description:
* @Date: 2025年05月26日 星期一 11:05:13
* @Modify:
*/
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using Logic.CrashSight;
using TMPro;
using Unity.VisualScripting;
using UnityEngine;
namespace Logic.Multilingual
{
public enum MultilingualType
{
None = 0,
ZH = 1, // 简体中文 / Simplified Chinese
TDZH = 2, // 繁体中文 / Traditional Chinese
EN = 3, // 英文 / English
JP = 4, // 日语 / Japanese
KR = 5, // 韩语 / Korean
RU = 10, // 俄语 / Russian
ES = 11, // 西班牙语 / Spanish
PT = 12, // 葡萄牙语 / Portuguese
FR = 13, // 法语 / French
DE = 14, // 德语 / German
ID = 15, // 印尼语 / Indonesian
TH = 16, // 泰语 / Thai
PL = 17, // 波兰语 / Polish
VI = 18, // 越南语 / Vietnamese
MS = 19, // 马来语 / Malay
UK = 20, // 乌克兰语 / Ukrainian
KZ = 21, // 哈萨克语 / Kazakh
TR = 22, // 土耳其语 / Turkish
IT = 23, // 意大利语 / Italian
NL = 24, // 荷兰语 / Dutch
FI = 25, // 芬兰语 / Finnish
SV = 26, // 瑞典语 / Swedish
NO = 27, // 挪威语 / Norwegian
CS = 28, // 捷克语 / Czech
HU = 29, // 匈牙利语 / Hungarian
EL = 30, // 希腊语 / Greek
RO = 31, // 罗马尼亚语 / Romanian
ET = 32, // 爱沙尼亚语 / Estonian
LT = 33, // 立陶宛语 / Lithuanian
HR = 34, // 克罗地亚语 / Croatian
SR = 35, // 塞尔维亚语 / Serbian
SL = 36, // 斯洛文尼亚语 / Slovenian
SK = 37, // 斯洛伐克语 / Slovak
BE = 38, // 白俄罗斯语 / Belarusian
HE = 39, // 希伯来语 / Hebrew
BG = 40, // 保加利亚语 / Bulgarian
UZ = 41, // 乌兹别克语 / Uzbek
KY = 42, // 吉尔吉斯语 / Kyrgyz
MN = 43, // 蒙古语 / Mongolian
AR = 44, // 阿拉伯语 / Arabic
DA = 45, // 丹麦语 / Danish
TL = 46, // 菲律宾语 / Tagalog (Filipino)
Custom = 999, // 自定义语种 / Custom Language
Max = 1000, // 最大值 / Max value
}
internal static class MultilingualRichTextColors
{
public const string DefaultEmbeddedHex = "#D98200";
}
public class MultilingualData : ScriptableObject
{
public List<MultilingualFontGroup> FontGroups = new List<MultilingualFontGroup>();
public List<MultilingualItem> Items = new List<MultilingualItem>();
public List<MultilingualType> TargetTypes = new List<MultilingualType>();
private Dictionary<uint, MultilingualItem> _itemDict;
public Dictionary<uint, MultilingualItem> ItemDict => _itemDict;
public string GetMultilingualStr(uint id, MultilingualType type)
{
if (_itemDict == null) RefreshDict();
if (_itemDict == null) return string.Empty;
if (!_itemDict.TryGetValue(id, out var item))
{
RefreshDict(true);
if (!_itemDict.TryGetValue(id, out item)) return string.Empty;
}
var ret = item.GetStrByType(type);
// Fallback 链:
// 1. 5 种主语言(除 EN自己有就用自己没有就直接返回空不 fallback
// 2. EN自己没有 → 兜底到 ZH
// 3. 其他语言(含 Custom自己没有 → 兜底到 ENEN 还没有 → 兜底到 ZH
// ZH 是终极兜底,自己不 fallback
if (string.IsNullOrEmpty(ret) && NeedsEnglishFallback(type))
{
ret = item.GetStrByType(MultilingualType.EN);
}
if (string.IsNullOrEmpty(ret) && NeedsChineseFallback(type))
{
ret = item.GetStrByType(MultilingualType.ZH);
}
if (string.IsNullOrEmpty(ret)) return ret;
ret = ResolveEmbeddedStringsRunning(ret, type);
return ret;
}
// 是否需要回落英文:仅 5 种主语言(中英日韩繁)和 None/Max 不回落
private static bool NeedsEnglishFallback(MultilingualType type)
{
return type != MultilingualType.None
&& type != MultilingualType.Max
&& type != MultilingualType.ZH
&& type != MultilingualType.TDZH
&& type != MultilingualType.EN
&& type != MultilingualType.JP
&& type != MultilingualType.KR;
}
// 是否需要回落中文:除 ZH 自身外都需要(包括 EN 自己 — EN 没翻译时也兜底中文)
// ZH/None/Max 不 fallback避免无意义查询
private static bool NeedsChineseFallback(MultilingualType type)
{
return type != MultilingualType.None
&& type != MultilingualType.Max
&& type != MultilingualType.ZH;
}
public TMP_FontAsset GetMultilingualFont(uint fontId, MultilingualType type)
{
if (fontId == 0) return null;
foreach (var group in FontGroups)
{
if (group.FontID != fontId) continue;
return type switch
{
MultilingualType.ZH => group.ZHFont,
MultilingualType.TDZH => group.TDZHFont,
MultilingualType.EN => group.ENFont,
MultilingualType.JP => group.JPFont,
MultilingualType.KR => group.KRFont,
MultilingualType.RU => group.RUFont,
MultilingualType.ES => group.ESFont,
MultilingualType.PT => group.PTFont,
MultilingualType.FR => group.FRFont,
MultilingualType.Custom => group.ENFont, // Custom 语种回退到 EN 字体
_ => null,
};
}
return null;
}
public uint GetFontGroupID(TMP_FontAsset font)
{
foreach (var group in FontGroups)
{
if (group.ZHFont == font) return group.FontID;
}
return 0;
}
public void RefreshDict(bool force = false)
{
if (_itemDict == null) _itemDict = new Dictionary<uint, MultilingualItem>();
if (!force && _itemDict.Count == Items.Count) return;
_itemDict.Clear();
foreach (var item in Items) _itemDict[item.ID] = item;
}
public MultilingualType GetSystemLanguageTargetMultilingual(MultilingualType type)
{
var index = (int)type - 1;
if (index >= TargetTypes.Count) return type;
return TargetTypes[index];
}
public string GetMultilingualStrEditor(uint id, MultilingualType type)
{
if (_itemDict == null) RefreshDict();
if (_itemDict == null) return string.Empty;
if (!_itemDict.TryGetValue(id, out var item))
{
RefreshDict(true);
if (!_itemDict.TryGetValue(id, out item)) return string.Empty;
}
var ret = item.GetStrByType(type);
if (string.IsNullOrEmpty(ret)) return ret;
ret = ResolveEmbeddedStrings(ret, type);
return ret;
}
// 获取字符串中嵌套的 ID 列表 (按对应语种的顺序)
public List<uint> GetSubStringIdRunning(uint id, MultilingualType type)
{
var result = new List<uint>();
if (_itemDict == null) RefreshDict();
if (_itemDict == null) return result;
if (!_itemDict.TryGetValue(id, out var item)) return result;
var origin = item.GetStrByType(type);
if (string.IsNullOrEmpty(origin)) return result;
var regex = new Regex(@"\*\*<(?:!\[(\d+)\])?(\d+)>\*\*");
var matches = regex.Matches(origin);
foreach (Match m in matches)
{
if (uint.TryParse(m.Groups[2].Value, out var subId))
{
result.Add(subId);
}
}
return result;
}
// ID 转 String (运行时)
public string ResolveEmbeddedStringsRunning(string origin, MultilingualType type)
{
if (string.IsNullOrEmpty(origin)) return string.Empty;
var regex = new Regex(@"\*\*<(?:!\[(\d+)\])?(\d+)>\*\*");
var result = regex.Replace(origin, m =>
{
var prefixGroup = m.Groups[1]; // [n] 中的 n
var idStr = m.Groups[2].Value; // id
RefreshDict();
if (!uint.TryParse(idStr, out var subId)) return m.Value;
if (_itemDict == null || !_itemDict.TryGetValue(subId, out var subItem)) return m.Value;
var str = subItem.GetStrByType(type);
// 检测嵌套:展开后的字符串不应再包含 **<...>**
if (Regex.IsMatch(str, @"\*\*<.+?>\*\*"))
{
LogSystem.LogError($"ResolveEmbeddedStrings: 检测到嵌套引用ID: {subId},内容: {str}");
return m.Value;
}
var hex = subItem.Color;
if (string.IsNullOrEmpty(hex))
{
hex = MultilingualRichTextColors.DefaultEmbeddedHex;
}
if (!hex.StartsWith("#")) hex = "#" + hex;
if (!string.IsNullOrEmpty(subItem.Icon))
return $"<sprite name=\"{subItem.Icon}\"><color={hex}>{str}</color>";
return $"<color={hex}>{str}</color>";
});
return result;
}
// ID 转 String
public string ResolveEmbeddedStrings(string origin, MultilingualType type)
{
if (string.IsNullOrEmpty(origin)) return string.Empty;
var regex = new Regex(@"\*\*<(?:!\[(\d+)\])?(\d+)>\*\*");
var result = regex.Replace(origin, m =>
{
var prefixGroup = m.Groups[1]; // [n] 中的 n
var idStr = m.Groups[2].Value; // id
RefreshDict();
if (!uint.TryParse(idStr, out var subId)) return m.Value;
if (_itemDict == null || !_itemDict.TryGetValue(subId, out var subItem)) return m.Value;
var str = subItem.GetStrByType(type);
// 检测嵌套:展开后的字符串不应再包含 **<...>**
if (Regex.IsMatch(str, @"\*\*<.+?>\*\*"))
{
LogSystem.LogError($"ResolveEmbeddedStrings: 检测到嵌套引用ID: {subId},内容: {str}");
return m.Value;
}
if (prefixGroup.Success)
{
return $"**<![{prefixGroup.Value}]{str}>**";
}
else
{
return $"**<{str}>**";
}
});
return result;
}
// String 转 ID
public string UnResolveEmbeddedStrings(string origin, MultilingualType type)
{
if (string.IsNullOrEmpty(origin)) return string.Empty;
var regex = new Regex(@"\*\*<(?:!\[(\d+)\])?(.+?)>\*\*");
var result = regex.Replace(origin, m =>
{
var prefixGroup = m.Groups[1]; // [n] 中的 n
var str = m.Groups[2].Value; // 内部字符串
// 已经是 id 则跳过
if (uint.TryParse(str, out _))
{
if (prefixGroup.Success)
{
return $"**<![{prefixGroup.Value}]{str}>**";
}
return m.Value;
}
// 检测嵌套:内部字符串不应再包含 **<...>**
if (Regex.IsMatch(str, @"\*\*<.+?>\*\*"))
{
LogSystem.LogError($"UnResolveEmbeddedStrings: 检测到嵌套引用,内容: {str}");
return m.Value;
}
RefreshDict();
// 在 _itemDict 中反查 id
uint id = 0;
bool found = false;
foreach (var kv in _itemDict)
{
if (kv.Value.GetStrByType(type) == str)
{
id = kv.Key;
found = true;
break;
}
}
if (!found)
{
LogSystem.LogError($"UnResolveEmbeddedStrings: 找不到字符串对应的ID字符串: origin:{origin} str:{str}");
return m.Value;
}
if (prefixGroup.Success)
{
return $"**<![{prefixGroup.Value}]{id}>**";
}
else
{
return $"**<{id}>**";
}
});
return result;
}
/// <summary>
/// 将其他语言的嵌入字符串对齐到中文已转换好的ID格式
/// zhResolved: 中文已经通过 UnResolveEmbeddedStrings 转换后的字符串(包含 **<id>** 和 **<![n]id>**
/// otherOrigin: 其他语言的原始字符串(包含 **<str>** 和 **<![n]str>**
/// type: 当前语言类型(用于日志)
/// itemId: 当前item的ID用于日志
/// </summary>
public string AlignEmbeddedStringsToZH(string zhResolved, string otherOrigin, MultilingualType type,
uint itemId)
{
if (string.IsNullOrEmpty(otherOrigin)) return otherOrigin;
if (string.IsNullOrEmpty(zhResolved)) return otherOrigin;
// 解析中文已转换的嵌入引用
var zhRegex = new Regex(@"\*\*<(?:!\[(\d+)\])?(\d+)>\*\*");
var zhMatches = zhRegex.Matches(zhResolved);
// 构建中文的 n->完整匹配 字典带前缀n的和 无前缀的有序列表
var zhPrefixDict = new Dictionary<string, string>(); // n -> **<![n]id>**
var zhNoPrefixList = new List<string>(); // **<id>** 有序列表
foreach (Match m in zhMatches)
{
var prefixGroup = m.Groups[1];
var idStr = m.Groups[2].Value;
if (prefixGroup.Success)
{
zhPrefixDict[prefixGroup.Value] = $"**<![{prefixGroup.Value}]{idStr}>**"; // n -> **<![n]id>**
}
else
{
zhNoPrefixList.Add(m.Value); // **<id>**
}
}
// 解析其他语言的嵌入引用
// 允许匹配 **<>**(空内容),导回时也按中文顺序对齐为 **<id>**
var otherRegex = new Regex(@"\*\*<(?:!\[(\d+)\])?(.*?)>\*\*");
var otherMatches = otherRegex.Matches(otherOrigin);
// 分类其他语言的匹配带前缀n的 和 不带前缀的
var otherPrefixMatches = new List<Match>();
var otherNoPrefixMatches = new List<Match>();
foreach (Match m in otherMatches)
{
var prefixGroup = m.Groups[1];
var content = m.Groups[2].Value;
if (prefixGroup.Success)
{
otherPrefixMatches.Add(m);
}
else
{
// 不带顺序前缀且内容已经是纯数字id时无需按顺序再次对齐
if (uint.TryParse(content, out _)) continue;
otherNoPrefixMatches.Add(m);
}
}
// 从后往前替换,避免索引偏移
// 收集所有需要替换的操作
var replacements = new List<(int index, int length, string replacement)>();
// 1. 处理带前缀 **<![n]str>** 的情况使用中文对应n的 **<![n]id>**
foreach (var m in otherPrefixMatches)
{
var n = m.Groups[1].Value;
if (zhPrefixDict.TryGetValue(n, out var zhReplacement))
{
replacements.Add((m.Index, m.Length, zhReplacement));
}
else
{
LogSystem.LogError(
$"AlignEmbeddedStringsToZH: 语言{type} ID:{itemId} 中文找不到前缀[{n}]对应的引用,删除此项: {m.Value}");
replacements.Add((m.Index, m.Length, string.Empty));
}
}
// 2. 处理不带前缀 **<str>** 的情况:按顺序对齐中文的 **<id>**
int zhCount = zhNoPrefixList.Count;
int otherCount = otherNoPrefixMatches.Count;
if (zhCount != otherCount)
{
LogSystem.LogError(
$"AlignEmbeddedStringsToZH: 语言{type} ID:{itemId} **<str>**数量不匹配,中文:{zhCount} 当前语言:{otherCount}");
}
for (int i = 0; i < otherNoPrefixMatches.Count; i++)
{
var m = otherNoPrefixMatches[i];
if (i < zhCount)
{
// 对齐中文的 **<id>**
replacements.Add((m.Index, m.Length, zhNoPrefixList[i]));
}
else
{
// 中文少,删除其他语言多余的 **<str>**
replacements.Add((m.Index, m.Length, string.Empty));
}
}
// 按索引从后往前排序并替换
replacements.Sort((a, b) => b.index.CompareTo(a.index));
var result = otherOrigin;
foreach (var (index, length, replacement) in replacements)
{
result = result.Substring(0, index) + replacement + result.Substring(index + length);
}
return result;
}
}
[Serializable]
public class MultilingualItem
{
public uint ID;
public string ZH;
public string TDZH;
public string EN;
public string JP;
public string KR;
public string RU;
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;
public string DialogueSpeaker;
public bool IsDeprecated;
public bool IsCustom;
public bool IsSpecialTerm;
// 次要文案:版本说明 / 地理科普等不重要文本,导出时可整体排除以减少送翻量
public bool IsSecondary;
// 活跃文本:编辑器扫场景/prefab/DataAssets 时实际被引用的条目
// 旧数据没有这个字段反序列化默认 false,但语义上"未标"应当 = true(避免老数据全部被当成 inactive)
// 由 ExcelExportToAssetInternal 从 Excel 第二列回写
// 默认值 true:Unity反序列化没有这个字段时,会用类型默认(false),所以对老 asset 必须跑一次"导回"刷新
public bool IsActive = true;
// 默认橘色
public string Color;
public string Icon;
[NonSerialized]
public string Desc;
public MultilingualItem()
{
IsCustom = false;
}
public void Refresh()
{
ZH = ZH?.Replace("\r\n", "\n") ?? string.Empty;
TDZH = TDZH?.Replace("\r\n", "\n") ?? string.Empty;
EN = EN?.Replace("\r\n", "\n") ?? string.Empty;
JP = JP?.Replace("\r\n", "\n") ?? string.Empty;
KR = KR?.Replace("\r\n", "\n") ?? string.Empty;
RU = RU?.Replace("\r\n", "\n") ?? string.Empty;
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;
}
public string GetStrByType(MultilingualType type)
{
return type switch
{
MultilingualType.ZH => ZH,
MultilingualType.TDZH => TDZH,
MultilingualType.EN => EN,
MultilingualType.JP => JP,
MultilingualType.KR => KR,
MultilingualType.RU => RU,
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,
};
}
public bool IsTranslate(MultilingualType type)
{
if (type == MultilingualType.ZH) return true;
if (type == MultilingualType.None)
{
return !string.IsNullOrEmpty(TDZH) && !string.IsNullOrEmpty(EN) &&
!string.IsNullOrEmpty(JP) && !string.IsNullOrEmpty(KR) &&
!string.IsNullOrEmpty(RU) && !string.IsNullOrEmpty(ES) &&
!string.IsNullOrEmpty(PT) && !string.IsNullOrEmpty(FR);
}
return type switch
{
MultilingualType.TDZH => !string.IsNullOrEmpty(TDZH),
MultilingualType.EN => !string.IsNullOrEmpty(EN),
MultilingualType.JP => !string.IsNullOrEmpty(JP),
MultilingualType.KR => !string.IsNullOrEmpty(KR),
MultilingualType.RU => !string.IsNullOrEmpty(RU),
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,
};
}
// 不分大小写将 True 或者 False 字符串转换为布尔值
public static bool ParseBoolStr(string str)
{
return string.Equals(str, "True", StringComparison.OrdinalIgnoreCase);
}
}
[Serializable]
public class MultilingualFontGroup
{
public uint FontID;
public TMP_FontAsset ZHFont;
public TMP_FontAsset TDZHFont;
public TMP_FontAsset ENFont;
public TMP_FontAsset JPFont;
public TMP_FontAsset KRFont;
public TMP_FontAsset RUFont;
public TMP_FontAsset ESFont;
public TMP_FontAsset PTFont;
public TMP_FontAsset FRFont;
}
}