Unity 国际化 多语言设置

很多游戏中都有语言设置选项,NGUI插件中自带了国际化脚本,但是灵活性较低,而且目前项目是UGUI,以下是修改后,以便记录。

Localization和NGUI中用法一样,挂在在一个不销毁的游戏物体上,并设置当前语言,及所有语言的陪标

//----------------------------------------------

//----------------------------------------------

using UnityEngine;
using System.Collections.Generic;
using UnityEngine.UI;


public class Localization : MonoBehaviour
{
    static Localization mInst;

    static public Localization instance
    {
        get
        {
            if (mInst == null)
            {
                mInst = Object.FindObjectOfType(typeof(Localization)) as Localization;

                if (mInst == null)
                {
                    GameObject go = new GameObject("_Localization");
                    DontDestroyOnLoad(go);
                    mInst = go.AddComponent<Localization>();
                }
            }
            return mInst;
        }
    }

    public string startingLanguage;
    

    public TextAsset[] languages;

    Dictionary<int, string> mDictionary = new Dictionary<int, string>();
    string mLanguage;
    
    public string currentLanguage
    {
        get
        {
            //if (string.IsNullOrEmpty(mLanguage))
            {
                currentLanguage = PlayerPrefs.GetString("Language");

                if (string.IsNullOrEmpty(mLanguage))
                {
                    currentLanguage = startingLanguage;

                    if (string.IsNullOrEmpty(mLanguage) && (languages != null && languages.Length > 0))
                    {
                        currentLanguage = languages[0].name;
                    }
                }
            }
            return mLanguage;
        }
        set
        {
            if (mLanguage != value)
            {
                startingLanguage = value;

                if (!string.IsNullOrEmpty(value))
                {
                    if (languages != null)
                    {
                        for (int i = 0, imax = languages.Length; i < imax; ++i)
                        {
                            TextAsset asset = languages[i];

                            if (asset != null && asset.name == value)
                            {
                                Load(asset);
                                return;
                            }
                        }
                    }
                    
                    TextAsset txt = Resources.Load(value, typeof(TextAsset)) as TextAsset;

                    if (txt != null)
                    {
                        Load(txt);
                        return;
                    }
                }
                
                mDictionary.Clear();
                PlayerPrefs.DeleteKey("Language");
            }
        }
    }

    /// <summary>
    /// Determine the starting language.
    /// </summary>

    void Awake() { if (mInst == null) { mInst = this; DontDestroyOnLoad(gameObject); } else Destroy(gameObject); }

    /// <summary>
    /// Start with the specified starting language.
    /// </summary>

    void Start() { if (!string.IsNullOrEmpty(startingLanguage)) currentLanguage = startingLanguage; }

    /// <summary>
    /// Oddly enough... sometimes if there is no OnEnable function in Localization, it can get the Awake call after UILocalize's OnEnable.
    /// </summary>

    void OnEnable() { if (mInst == null) mInst = this; }

    /// <summary>
    /// Remove the instance reference.
    /// </summary>

    void OnDestroy() { if (mInst == this) mInst = null; }

    /// <summary>
    /// Load the specified asset and activate the localization.
    /// </summary>

    void Load(TextAsset asset)
    {
        mLanguage = asset.name;
        PlayerPrefs.SetString("Language", mLanguage);
        ByteReader reader = new ByteReader(asset);
        mDictionary = reader.ReadDictionary();
        // Broadcast("OnLocalize");
    }
   

    public string Get(int key)
    {
        string val;
        return (mDictionary.TryGetValue(key, out val)) ? val : null;
    }

}



ByteReader数据解析类,不多余解释


//----------------------------------------------
//            NGUI: Next-Gen UI kit
// Copyright © 2011-2012 Tasharen Entertainment
//----------------------------------------------

using UnityEngine;
using System.Text;
using System.Collections.Generic;

/// <summary>
/// MemoryStream.ReadLine has an interesting oddity: it doesn't always advance the stream's position by the correct amount:
/// http://social.msdn.microsoft.com/Forums/en-AU/Vsexpressvcs/thread/b8f7837b-e396-494e-88e1-30547fcf385f
/// Solution? Custom line reader with the added benefit of not having to use streams at all.
/// </summary>

public class ByteReader
{
    byte[] mBuffer;
    int mOffset = 0;

    public ByteReader(byte[] bytes) { mBuffer = bytes; }
    public ByteReader(TextAsset asset) { mBuffer = asset.bytes; }

    /// <summary>
    /// Whether the buffer is readable.
    /// </summary>

    public bool canRead { get { return (mBuffer != null && mOffset < mBuffer.Length); } }

    /// <summary>
    /// Read a single line from the buffer.
    /// </summary>

    static string ReadLine(byte[] buffer, int start, int count)
    {
#if UNITY_FLASH
		// Encoding.UTF8 is not supported in Flash :(
		StringBuilder sb = new StringBuilder();

		int max = start + count;

		for (int i = start; i < max; ++i)
		{
			byte byte0 = buffer[i];

			if ((byte0 & 128) == 0)
			{
				// If an UCS fits 7 bits, its coded as 0xxxxxxx. This makes ASCII character represented by themselves
				sb.Append((char)byte0);
			}
			else if ((byte0 & 224) == 192)
			{
				// If an UCS fits 11 bits, it is coded as 110xxxxx 10xxxxxx
				if (++i == count) break;
				byte byte1 = buffer[i];
				int ch = (byte0 & 31) << 6;
				ch |= (byte1 & 63);
				sb.Append((char)ch);
			}
			else if ((byte0 & 240) == 224)
			{
				// If an UCS fits 16 bits, it is coded as 1110xxxx 10xxxxxx 10xxxxxx
				if (++i == count) break;
				byte byte1 = buffer[i];
				if (++i == count) break;
				byte byte2 = buffer[i];

				if (byte0 == 0xEF && byte1 == 0xBB && byte2 == 0xBF)
				{
					// Byte Order Mark -- generally the first 3 bytes in a Windows-saved UTF-8 file. Skip it.
				}
				else
				{
					int ch = (byte0 & 15) << 12;
					ch |= (byte1 & 63) << 6;
					ch |= (byte2 & 63);
					sb.Append((char)ch);
				}
			}
			else if ((byte0 & 248) == 240)
			{
				// If an UCS fits 21 bits, it is coded as 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 
				if (++i == count) break;
				byte byte1 = buffer[i];
				if (++i == count) break;
				byte byte2 = buffer[i];
				if (++i == count) break;
				byte byte3 = buffer[i];

				int ch = (byte0 & 7) << 18;
				ch |= (byte1 & 63) << 12;
				ch |= (byte2 & 63) << 6;
				ch |= (byte3 & 63);
				sb.Append((char)ch);
			}
		}
		return sb.ToString();
#else
        return Encoding.UTF8.GetString(buffer, start, count);
#endif
    }

    /// <summary>
    /// Read a single line from the buffer.
    /// </summary>

    public string ReadLine()
    {
        int max = mBuffer.Length;

        // Skip empty characters
        while (mOffset < max && mBuffer[mOffset] < 32) ++mOffset;

        int end = mOffset;

        if (end < max)
        {
            for (;;)
            {
                if (end < max)
                {
                    int ch = mBuffer[end++];
                    if (ch != '\n' && ch != '\r') continue;
                }
                else ++end;

                string line = ReadLine(mBuffer, mOffset, end - mOffset - 1);
                mOffset = end;
                return line;
            }
        }
        mOffset = max;
        return null;
    }

    /// <summary>
    /// Assume that the entire file is a collection of key/value pairs.
    /// </summary>

    public Dictionary<int, string> ReadDictionary()
    {
        Dictionary<int, string> dict = new Dictionary<int, string>();
        char[] separator = new char[] { '=' };

        while (canRead)
        {
            string line = ReadLine();
            if (line == null) break;

#if UNITY_FLASH
			string[] split = line.Split(separator, System.StringSplitOptions.RemoveEmptyEntries);
#else
            string[] split = line.Split(separator, 2, System.StringSplitOptions.RemoveEmptyEntries);
#endif

            if (split.Length == 2)
            {
                int key = int.Parse(split[0].Trim());
                string val = split[1].Trim();
                dict[key] = val;
            }
        }
        return dict;
    }
}


将UILocalize脚本挂在在Text上或者Image上,就是需要多语言切换的UI上


//----------------------------------------------

//----------------------------------------------

using UnityEngine;
using UnityEngine.UI;

public class UILocalize : MonoBehaviour
{
    /// <summary>
    /// Localization key.
    /// </summary>
    public string Atlas;
    public string key;

    string mLanguage;
    bool mStarted = false;

    /// <summary>
    /// This function is called by the Localization manager via a broadcast SendMessage.
    /// </summary>

    void OnLocalize(Localization loc) { if (mLanguage != loc.currentLanguage) Localize(); }

    /// <summary>
    /// Localize the widget on enable, but only if it has been started already.
    /// </summary>

    void OnEnable() { if (mStarted && Localization.instance != null) Localize(); }

    /// <summary>
    /// Localize the widget on start.
    /// </summary>

    void Start()
    {
        mStarted = true;
        if (Localization.instance != null) Localize();
    }

    /// <summary>
    /// Force-localize the widget.
    /// </summary>

    public void Localize(string key = null)
    {
        if (key == null)
            key = this.key;
        Localization loc = Localization.instance;
        MaskableGraphic w = GetComponent<MaskableGraphic>();
        Text lbl = w as Text;
        Image sp = w as Image;

        // If no localization key has been specified, use the label's text as the key
        if (string.IsNullOrEmpty(mLanguage) && string.IsNullOrEmpty(key) && lbl != null)
            key = lbl.text;

        // If we still don't have a key, use the widget's name
        string val = string.IsNullOrEmpty(key) ? w.name : loc.Get(int.Parse(key));

        if (val != null)
        {
            if (lbl != null)
            {
                lbl.text = val;
            }
            else if (sp != null)
            {
                if (Atlas == null)
                    return;
                sp.sprite = DoRo.Manager.LoadManager.Instance.LoadSprite(Atlas, val);
            }
        }
        mLanguage = loc.currentLanguage;
    }
}

还有一个Dropdown切换,设置的 还没改好,后面不上

徐超 2016.05.13

©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页