Unity UGUI 本地化方案 - Localiztion Tool

問題及難點

相信做海外遊戲代理的同學一定會遇到需要做本地化的問題,其中資源可以通過替換合圖來處理。而文本是其中一個比較難處理的問題。其中主要難點在於UGUI本身沒有提供相應的插件,而對於一開始沒規劃的項目來說,你需要去找出其中所有的外語文本,找到後再將對應Text控件替換成你自定義的控件,替換後再需要填入對應的Key值。這對於策劃來說簡直是惡夢~

工具的基本原理

LocalizationText控件

UGUI中的Text控件只提供了text屬性接口供你進行對文本的設置,那麼要實現本地化有下面兩種做法:

  • 1.在Text控件初始化後使用代碼將其text屬性修改,這樣的話,我們需要在所有的有Text控件的地方添加相應的修改代碼,這顯然是不符合可持續發展的。
  • 2.自定義新的Text控件,在編輯器階段完成對Key值的設置。這種方案需要我們繼承Text控件,並修改其輸入接口,從修改text改爲修改Key,通過Key來得到相應語言的文本。

綜上,我們採取第二種方案來實現我們的LocalizationText控件,通過對Key的設置得到文本,如圖:
這裏寫圖片描述
有了LocaliztionText我們只需要輸入Key**Help**而不需要直接填寫幫助二字,通過爲不同語言建立映射表我們就可得到對應語言的Help的文本。這裏寫圖片描述

相關代碼實現

這裏我主要是先去看了UGUI源碼,根據其中Text的實現做了修改。

using System;
using UnityEngine.UI;
using UnityEngine;

namespace Localization
{
    public class LocalizationText : Text
    {
        #region Param


        [Header("Localization")]
        [SerializeField]
        protected string m_KeyString;

        public string keyString {
            get {return this.m_KeyString; }
            set { this.m_KeyString =  value; }
        }
        #endregion

        #region Override Part
        public override string text
        {
            get
            {
                if (!ClientString.LocalizationDict.ContainsKey(keyString))
                {
                    m_Text = string.Format("[{0}]",m_KeyString);
                }
                else
                {
                    m_Text = ClientString.LocalizationDict[keyString];
                }
                return m_Text;
            }
            set
            {
                if (String.IsNullOrEmpty(value))
                {
                    if (String.IsNullOrEmpty(m_Text))
                        return;
                    m_Text = "";
                    SetVerticesDirty();
                }
                else if (m_Text != value)
                {
                    m_Text = value;
                    SetVerticesDirty();
                    SetLayoutDirty();
                }
            }
        }
        #endregion
    }
}

這部分的代碼其實比較簡單,主要是進行了一個Key/Value的映射,然後設置對應的Text。其中的KeyString則是多語言文本映射用的Key值。
總的來說,此控件的原理是比較簡單的,Key->Value->Set Text。但對於一個完整的方案來說這是遠遠不夠的,我們還需要有自動化修改的工具。

控件替換工具

這個工具簡直是那些用UGUI的Text控件開發了很久後,突然想做多語言的項目的救星。因爲如果你通過將項目中的Text控件刪除後再AddComponent< LocalizationText >的話會出現一個很災難性的問題,那就是MonoBehaviour中對相應Text控件的引用都會丟失,因爲Unity是通過GUID和FileID來找到對應類型控件的,而這樣的處理方式會讓GUID和FileID改變從而導致嚴重的後果。所以這個控件替換工具就非常重要了~

原理

上面說到Unity中用GUID和FileID來找對應類型控件的,那麼只需要找到初始Text控件的GUID和FileID,然後更改爲LocaliztionText控件的GUID和FileID則可以達到我們的目的。下面是一個場景文件(.unity)文件的內容,我們在場景文件中添加了一個物體名叫Normal Text上面掛着Text控件。
這裏寫圖片描述
中間的圖片表示的是Normal Text這個物體的結構,他有三個m_Component其中有一個是Text,Text控件的結構如圖,所以在右邊Text Component部分的m_Script處,只要把FileID和GUID修改爲Localization Text對應的FileID和GUID即可,這樣就避免了上面提到的引用丟失問題。那麼怎麼得到Localiztion Text的GUID和FileID呢。最簡單的方法是添加一個Localization Text物體(也就是現在場景中的Localization Text),然後去場景文件內容中查看。
這裏寫圖片描述

所以此工具的基本原理就是將Text控件的FileID和GUID換成LocaliztionText控件的FileID和GUID。
具體代碼如下(基本就是一個文本級別的操作):

public static void UpgradeToLocalizationText(string assetPath, string textCompGUID, string textCompFileID, string localizeCompGUID, string localizeCompFileID, List<string> jpTextList)
{
    ClearConsole();
    string formatedGUID = string.Format("guid: {0},", localizeCompGUID);
    string fullPath = Path.Combine(Application.dataPath.Substring(0, Application.dataPath.LastIndexOf('/')), assetPath);
    string[] lines = System.IO.File.ReadAllLines(fullPath);
    string fullText = System.IO.File.ReadAllText(fullPath);

    for (int i = 0; i < lines.Length; i++)
    {
        if(lines[i].Contains(textCompFileID)) {
            int scriptLineIdx = i;  //往下遍歷直到找到m_Text
            while(i < lines.Length) {

                if(lines[i].Contains("--- !u!"))    //發現下一個控件時跳出
                    break;  

                if (JpUtil.PlainText_IsContainsJapanese(lines[i]))
                {
                    string jpText = Regex.Unescape(lines[i].Split('\"')[1]).Replace("\n", "\\n");
                    jpTextList.Add(jpText);

                    //發現了FileID相同 但GUID不同的情況,所以直接把FileID後面的GUID替換
                    lines[scriptLineIdx] = Regex.Replace(lines[scriptLineIdx], guidReplacePattern, formatedGUID);
                    lines[scriptLineIdx] = lines[scriptLineIdx].Replace(textCompFileID, localizeCompFileID);
                    break;
                }
                i++;
            }
        }
    }
    string text = string.Join("\n", lines);
    System.IO.File.WriteAllText(fullPath, text);
    AssetDatabase.Refresh();
}

優化方案

上面的控件及工具解決了這一方案中的兩個難點,但是我們還可以進行優化,就是對有需要變化(例如內容爲日文或者英文)的控件才進行轉化,這其中的處理就是

JpUtil.PlainText_IsContainsJapanese(lines[i])

這一處理會判斷文本中是否有日文,有的話纔對Text控件進行升級,所以你需要爲不同的語言做不同的文本判斷,我們項目爲日文所以我做了日文的判斷。

除此之外在策劃將對應的翻譯都處理好後需要來設置LocaliztionText的Key值,我新增了一個自動設置Key值的功能,原理是將其中的內容進行比對,用Value找到Key值,然後填入。

這個工具已經上傳到GitHub:Localization Text Tool (麻煩Star一哈)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章