rustum 发表于 2022-1-8 10:08

Unity中简易的语言本地化思路

思路

做一个单例:LanguageSys.
它持有2个字典
语言类型 - id - 文字内容语言类型 - id - 图片资源(Sprite)

它向外界提供3个方法 + 1个属性
根据Id获取文字内容根据Id获取图片资源获取当前的语言类型
[*]属性:当前的语言类型。允许外界修改。
若当前语言类型修改成功(修改前后不是同一语言类型),发出事件:语言类型发生了变化,传出参数:当前的语言类型。

外界实际根据语言类型设置文字内容时,有几种方式

[*]为各目标text和img配置languageId,在初始时设置内容。
监听“语言类型变化”事件,在事件触发时设置内容。
[*]为各类语言类型配置此时要显示的GameObject,在初始时显示当前语言类型对应的GO,隐藏其他语言类型对应的GO。
监听“语言类型变化”事件,在事件触发时再次进行前述隐藏和显示GO的操作。在代码中直接调用LanguageSys提供的相关方法。
参考代码

LanguageSys
public class LanguageSys{    public static LanguageSys Instance{ get; private set; }    private Dictionary<int, Dictionary<int, string>> _strDict;    private Dictionary<int, Dictionary<int, Sprite>> _spriteDict;    private const string CurLanguageTypeStorageKey = "CurLanguageType";    public LanguageType CurLanguageType    {      get { return IntToLanguageType(CurIntLanguageType); }      set         {            if (CurLanguageType != value)            {                PlayerPrefs.SetInt(CurLanguageTypeStorageKey, LanguageTypeToInt(value));                ChangeCurLanguageTypeEvent?.Invoke(CurLanguageType);                Debug.Log("修改语言类型:" + CurLanguageType);            }      }    }    private int CurIntLanguageType    {      get { return PlayerPrefs.GetInt(CurLanguageTypeStorageKey, 0); }    }    public Action<LanguageType> ChangeCurLanguageTypeEvent;    public bool IsDefaultLanguageType    {      get { return CurLanguageType == LanguageType.None; }    }    public static void Init()    {      if (Instance == null)      {            Instance = new LanguageSys();      }    }    private LanguageSys()    {      // TODO: 初始化2个字典    }    public void Destroy()    {    }    public static int LanguageTypeToInt(LanguageType type)    {      return (int)type;    }    public static LanguageType IntToLanguageType(int value)    {      return (LanguageType)value;    }    public static string GetLanguageName(LanguageType type)    {      string name = string.Empty;      switch (type)      {            case LanguageType.Chinese : name = "简体中文";break;            case LanguageType.English : name = "English";break;            default:break;      }      return name;    }    // 如果是英文类型,则需要用序数词的形式显示数字    public string IntToStrByLanguageType(int value)    {      string str = value.ToString();      if (CurLanguageType == LanguageType.English)      {            str = value.Ordinal();      }      return str;    }    public string GetStr(int id)    {      string value = string.Empty;      if (_strDict.ContainsKey(CurIntLanguageType) || _strDict.ContainsKey(id))      {            value = _strDict;      }      else      {            Debug.LogError("LanguageSys获取目标字符串失败,id:" + id);      }      return value;    }    public Sprite GetSprite(int id)    {      Sprite value = null;      if (_spriteDict.ContainsKey(CurIntLanguageType) || _spriteDict.ContainsKey(id))      {            value = _spriteDict;      }      else      {            Debug.LogError("LanguageSys获取目标图片失败,id:" + id);      }      return value;    }}public enum LanguageType{   None,    Chinese,    English,}
外界直接为目标text和img设置内容,需为各目标配置Id
public class UILanguageLocalize : MonoBehaviour{        private TextAndId[] _texts;        private ImgAndId[] _imgs;    private void Start()    {      SetData(LanguageSys.Instance.CurLanguageType);      LanguageSys.Instance.ChangeCurLanguageTypeEvent += OnChangeLanguage;    }    private void OnDestroy()    {      if (LanguageSys.Instance != null)      {            LanguageSys.Instance.ChangeCurLanguageTypeEvent -= OnChangeLanguage;      }    }    private void OnChangeLanguage(LanguageType curType)    {      SetData(curType);    }    private void SetData(LanguageType type)    {      Debug.Log("SetData " + type);      if (_texts != null)      {            foreach (var text in _texts)            {                text.Text.text = LanguageSys.Instance.GetStr(text.Id);            }      }      if (_imgs != null)      {            foreach (var img in _imgs)            {                img.Image.sprite = LanguageSys.Instance.GetSprite(img.Id);            }      }    }        private struct TextAndId    {      public Text Text;      public int Id;    }        private struct ImgAndId    {      public Image Image;      public int Id;    }}
外界根据当前语言类型,设置相应GO的显示和隐藏
public class UILanguageGoLocalize : MonoBehaviour{        private LanguageTypeAndGos[] _gos;    private void Start()    {      SetActive(LanguageSys.Instance.CurLanguageType);      LanguageSys.Instance.ChangeCurLanguageTypeEvent += OnChangeLanguage;    }    private void OnDestroy()    {      if (LanguageSys.Instance != null)      {            LanguageSys.Instance.ChangeCurLanguageTypeEvent -= OnChangeLanguage;      }    }    private void OnChangeLanguage(LanguageType curType)    {      SetActive(curType);    }    private void SetActive(LanguageType type)    {      if (_gos != null)      {            foreach (var go in _gos)            {                bool isActive = go.LanguageType == type;                foreach (var o in go.Gos)                {                  if (o.activeSelf != isActive)                  {                        o.SetActive(isActive);                  }                }            }      }    }        private struct LanguageTypeAndGos    {      public LanguageType LanguageType;      public GameObject[] Gos;    }}其他

需注意,Unity中直接读表(如excel)获取到的string,若其中有换行符"\n",会被变为"\n"。
因此在读取到str后,需将其中的"\n"替换为"\n"。
str = str.Replace("\\n", "\n");
在本地化语言时,需要用到的一些方法。
将数字(int)以序数词的形式显示。
public static class MyExtension{    // 基数词(int)转为序数词(str)    public static string Ordinal(this int number)    {      const string TH = "th";      string s = number.ToString();      if (number < 1)      {            return s;      }      number %= 100;      if ((number >= 11) && (number <= 13))      {            return s + TH;      }      switch (number % 10)      {            case 1: return s + "st";            case 2: return s + "nd";            case 3: return s + "rd";            default: return s + TH;      }    }}
页: [1]
查看完整版本: Unity中简易的语言本地化思路