美文网首页
Unity中简易的语言本地化思路

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

作者: 全新的饭 | 来源:发表于2022-01-07 17:37 被阅读0次

思路

做一个单例:LanguageSys.
它持有2个字典

  1. 语言类型 - id - 文字内容
  2. 语言类型 - id - 图片资源(Sprite)

它向外界提供3个方法 + 1个属性

  1. 根据Id获取文字内容
  2. 根据Id获取图片资源
  3. 获取当前的语言类型
  4. 属性:当前的语言类型。允许外界修改。
    若当前语言类型修改成功(修改前后不是同一语言类型),发出事件:语言类型发生了变化,传出参数:当前的语言类型。

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

  1. 为各目标text和img配置languageId,在初始时设置内容。
    监听“语言类型变化”事件,在事件触发时设置内容。
  2. 为各类语言类型配置此时要显示的GameObject,在初始时显示当前语言类型对应的GO,隐藏其他语言类型对应的GO。
    监听“语言类型变化”事件,在事件触发时再次进行前述隐藏和显示GO的操作。
  3. 在代码中直接调用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[CurIntLanguageType].ContainsKey(id))
        {
            value = _strDict[CurIntLanguageType][id];
        }
        else
        {
            Debug.LogError("LanguageSys获取目标字符串失败,id:" + id);
        }

        return value;
    }

    public Sprite GetSprite(int id)
    {
        Sprite value = null;
        if (_spriteDict.ContainsKey(CurIntLanguageType) || _spriteDict[CurIntLanguageType].ContainsKey(id))
        {
            value = _spriteDict[CurIntLanguageType][id];
        }
        else
        {
            Debug.LogError("LanguageSys获取目标图片失败,id:" + id);
        }

        return value;
    }
}
public enum LanguageType
{ 
    None,
    Chinese,
    English,
}

外界直接为目标text和img设置内容,需为各目标配置Id

public class UILanguageLocalize : MonoBehaviour
{
    [SerializeField]
    private TextAndId[] _texts;
    [SerializeField]
    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);
            }
        }
    }

    [Serializable]
    private struct TextAndId
    {
        public Text Text;
        public int Id;
    }

    [Serializable]
    private struct ImgAndId
    {
        public Image Image;
        public int Id;
    }
}

外界根据当前语言类型,设置相应GO的显示和隐藏

public class UILanguageGoLocalize : MonoBehaviour
{
    [SerializeField]
    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);
                    }
                }
            }
        }
    }

    [Serializable]
    private struct LanguageTypeAndGos
    {
        public LanguageType LanguageType;
        public GameObject[] Gos;
    }
}

其他

需注意,Unity中直接读表(如excel)获取到的string,若其中有换行符"\n",会被变为"\n"。
因此在读取到str后,需将其中的"\n"替换为"\n"。

str = str.Replace("\\n", "\n");

在本地化语言时,需要用到的一些方法。

  1. 将数字(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;
        }
    }
}

相关文章

网友评论

      本文标题:Unity中简易的语言本地化思路

      本文链接:https://www.haomeiwen.com/subject/osojcrtx.html