- 需要一个校验程序,能找到整个项目所有text,并且对每种语言json都有它的键。
文本控件绑定key:继承还是组合
整个项目每个Text控件都有一个id。可以把Text所在的game Object名字当id,或者继承Text实现一个有id的。
using UnityEngine; using UnityEngine.UI; namespace MyFarm { public class LocalText:Text { [SerializeField] public string key; } }然后发现继承Text,加一个key,检查器也显示不出来,必须自定义检查器编辑器:
using UnityEditor; namespace MyFarm { [CustomEditor(typeof(LocalText), true)] public class LocalTextEditor: UnityEditor.UI.TextEditor { LocalText m_Text; protected override void OnEnable() { base.OnEnable(); m_Text = (LocalText)target; } public override void OnInspectorGUI() { base.OnInspectorGUI(); m_Text.key = EditorGUILayout.TextField("key", m_Text.key); } } }或许这也不是最好的方案,应该弄一个类,require Text控件。就不用重写检查器了。
考虑到继承Text需要把项目资源的Text控件一个个替换,重新设置对齐、字大小、字颜色,还是组合比较好!
using System.Reflection; using UnityEngine; using UnityEngine.UI; namespace MyFarm { [RequireComponent(typeof(Text))] public class LocalTextKey:MonoBehaviour { [SerializeField] string key; public string Key => key; Text _text; Text text { get { if(_text == null) { _text = GetComponent<Text>(); } return _text; } } private void Start() { UpdateText(MySettingsManager.Instance.settings.gameLanguage); MySettingsManager.Instance.onLanguageChanged += UpdateText; } private void OnDestroy() { MySettingsManager.Instance.onLanguageChanged -= UpdateText; } public void UpdateText(string langName) { var dic = LanguageManager.Instance.LangDic; if (dic.ContainsKey(langName)) { var langSO = dic[langName]; FieldInfo field = langSO.GetType().GetField(key); if (field != null) { text.text = field.GetValue(langSO).ToString(); } } } } }一种语言的配置文件:json还是SO
每种语言一个json,里面是id-文本的字典。可以用SO编辑,生成json。或者直接用SO也行;
每个文本是作字段还是字典键值对
如果作键值对,每种语言还要一个个加键,作为字段,写好配置脚本所有语言都有这些字段。
作键值对,手动加键可能漏键,应该使用Excel写配置,文本Id作表头,就不会漏键。
如果作字段,语言组件持有Id,按字段名去查,需要用反射,频繁查性能不好,需要把FieldInfo缓存下来。
那么我们形成2种工作流,作为字段,SO配置;作为键值对,Excel配置。
然后我想到第3种工作流,配置时文本作为字段,用SO配置,但是读取时读取成字典。因为json对象字段和字典键值对看起来是一样的。这样不用反射,没有性能问题。
语言配置文件放哪?
如果想支持热更新,放AB包,那么一定要从配置树的某个节点记录语言配置总表的包名和资源名。
语言管理器
负责读取语言配置总表和单语言配置文件,给其他系统取用。这里语言单独做了管理器,由设置管理器调用。
using System.Collections; using System.Collections.Generic; using UnityEngine; namespace MyFarm { /// <summary> /// 多语言管理器。负责加载每种语言的配置文件,让各处的LocalTextKey脚本根据语言设置来取用文本 /// </summary> public class LanguageManager:MySingleton<LanguageManager> { LanguageListSO languageListSO; Dictionary<string, LanguageSO> langDic=new(); public Dictionary<string, LanguageSO> LangDic => langDic; List<string> langList; public List<string> LangList { get { if (langList == null) { langList = new List<string>(langDic.Keys); } return langList; } } public LanguageManager() { languageListSO = MyABManager.LoadRes<LanguageListSO>(MyConfigManager.Instance.mainConfig.languageAB, MyConfigManager.Instance.mainConfig.languageConfigPath); foreach(var lang in languageListSO.languageSOs) { langDic[lang.name] = lang; } } } }通过得到字段,得到对象的字段值得到文本,结果是空字符串。而且其他文本控件没问题,只有一个有问题
if (field == null) { field = langSO.GetType().GetField(key); } if (field != null) { text.text = field.GetValue(langSO).ToString();//是空字符串 }配表里的物品名称、描述如何做多语言?
那么配表里的名字、描述也都要写键了,然后一种语言是一个字典,