Unity項目中文字的統一管理

一款遊戲在研發初期就需要考慮多語言的問題,否則後期在進行多國語言版本時就面臨着巨大的成本。鑑於之前頁遊的經驗,其它同事設計出讀取Excel的方式來管理所有的文字。但是我在使用中發現很致使的一個問題,當多人編輯一個Excel時,衝突了就很麻煩,解決起來的成本還蠻高的。

之後我想了一些辦法,例如搭建一個web站點,將所有的字符串 Key、Value保存到數據庫中,避免衝突,方便去查詢。但感覺還是太過麻煩,成本略高。然後就想到一個辦法,既然讀取一個Excel容易衝突,那我就弄多個文件,一個人編輯一個Excel,這樣總不會衝突了吧。然後添加 Key 的時候,先查找 Key是否存在,如果存在就提醒添加者。

這樣問題就變成從讀取單個文件變成遍歷一個文件夾下的文件。因爲Excel在打開時,會生成一個臨時文件並被佔用,所以不可以對它進行操作(如複製)。

using System;
using UnityEditor;
using UnityEditor.UI;
using UnityEngine;
using UnityEngine.UI;
using System.IO;
using OfficeOpenXml;
using System.Collections.Generic;
using System.Text.RegularExpressions;

namespace xxxx
{
    [InitializeOnLoad]
    public class StringsWatcher
    {
        static string stringsPath;
        static DateTime lastModifyTime;
        static string stringsFolderPath;

        static StringsWatcher()
        {
            stringsFolderPath = Path.GetDirectoryName(Application.dataPath);
            stringsFolderPath = Path.Combine(stringsFolderPath, "strings");

            // 創建Strings文件夾
            if (!Directory.Exists(stringsFolderPath))
            {
                Directory.CreateDirectory(stringsFolderPath);
            }

            // stringsPath = Path.GetFullPath(Path.Combine(rootPath, "Strings.xlsx"));

            EditorApplication.update += Update;
        }

        static void Update()
        {
            if (EditorApplication.isPlaying || EditorApplication.isCompiling) return;

            //if (!File.Exists(stringsPath)) return;
            if (!Directory.Exists(stringsFolderPath)) return;

            DateTime time = Directory.GetLastWriteTime(stringsFolderPath);

            if (lastModifyTime == time) return;

            lastModifyTime = time;

            Debug.Log("Reloading " + stringsFolderPath + ", Time : " + time.ToString());

            DateTime startTime = DateTime.Now;

            // ExcelPackage package = new ExcelPackage(new FileInfo(tempFile));

            List<string> keys = new List<string>();
            List<string> values = new List<string>();

            // 遍歷 strings 目錄下的excel文件
            DirectoryInfo folder = new DirectoryInfo(stringsFolderPath);
            foreach (FileInfo fileItem in folder.GetFiles())
            {
                string strFileType = fileItem.Extension;

                // 如果是 excel 文件且不是臨時文件, 臨時文件以~$開關,讀取臨時文件會報錯誤:Invaliddataexception the file is not an valid package file
                if (new Regex(@"^[^~]+\.xlsx$").IsMatch(fileItem.Name.ToLower()))
                {
                    string tempFile = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
                    File.Copy(fileItem.FullName, tempFile);

                    //Debug.Log(fileItem.Name + ", " + tempFile);

                    ExcelPackage package = new ExcelPackage(new FileInfo(tempFile));
                    ExcelWorksheet sheet = package.Workbook.Worksheets[1];

                    int rows = sheet.Dimension.Rows;
                    for (int row = 2; row <= rows; row++)
                    {
                        object keyObj = sheet.Cells[row, 1].Value;
                        object valueObj = sheet.Cells[row, 2].Value;

                        // Valid key and value is null or not.
                        if (keyObj == null)
                        {
                            Debug.LogError("Find Key is null. fileName : " + fileItem.Name + ", rowIndex : " + row);
                            return;
                        }

                        if (valueObj == null)
                        {
                            Debug.LogError("Find Key is null. fileName : " + fileItem.Name + ", rowIndex : " + row);
                            return;
                        }

                        // Find key is Exist or not                        
                        if (keys.Find(x => x == keyObj.ToString()) != null)
                        {
                            Debug.LogError("Find Report Key. fileName : " + fileItem.Name + ", rowIndex : " + row);
                            return;
                        }
                        
                        string key = keyObj.ToString();
                        string value = valueObj.ToString();

                        keys.Add(key);
                        values.Add(value);
                    }

                    // 每刪除一個文件大約多0.1秒
                    File.Delete(tempFile);
                }
                
                // 更新內存的數據,重新保存assets
                AssetDatabase.SaveAssets();
            }

            DateTime endTime = DateTime.Now;
            Debug.Log("Rebuild string.assets time : " + (endTime - startTime).TotalSeconds + "s");
        }
    }
}

如果你讀取Excel時遇到了 Invaliddataexception the file is not an valid package file ,上面的代碼或許對你有所幫助。

除了文字外,遊戲項目中還需要管理的就是帶有文字的UI圖片,這個也需要提前進行約定,制定相關的規範。

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