737 lines
30 KiB
C#
737 lines
30 KiB
C#
/*
|
||
* @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):自己没有 → 兜底到 EN,EN 还没有 → 兜底到 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; // 阿拉伯语 (RTL,TMP 渲染另需配置)
|
||
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;
|
||
}
|
||
}
|