我是編程一個菜鳥,英語又不好,有的插件非常牛!我想學(xué)一學(xué),頁面全是英文,完全不知所措,我該怎么辦啊...
嘗試在Unity中漢化一個插件
效果:
思路:
如何在Unity中把一個自己喜歡的插件變成中文?
在Unity中編寫插件一般會用到編輯器擴展
在編輯器擴展中想在Inspector顯示自己想要的屬性名或者別的什么,就需要用到編輯器擴展的API
把這些固定的API存到一個字典里,例如“EditorGUILayout.PropertyField”,“LabelField”...
我可以嘗試先讀取我們想要漢化插件的Editor文件夾下的每一個代碼的每一行
把每一行的每個字符與字典做一個對比
對比成功就說明此行代碼可以被漢化,收集可以被漢化的代碼行,然后把可以被漢化的代碼行替換成我們想要的代碼
替換成功后保存代碼
聽起來好像沒啥問題,試試看
- 創(chuàng)建一個存儲字典的代碼
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu()]
public class SearchCharacterData : ScriptableObject
{
[Header("檢索字符對")]
public List<Item> items;
[Header("添加字符對")]
public bool addItem = false;
private void OnValidate()
{
if (addItem)
{
addItem = false;
items.Add(new Item());
}
}
/// <summary>
/// 物品數(shù)據(jù)
/// </summary>
[System.Serializable]
public class Item
{
public string startStr;
public string endStr;
}
}
-
完成之后我們就可以在項目中創(chuàng)建一個自定義字典了
-
在字典中添加幾對常用AIP用來測試
-
創(chuàng)建一個編輯器窗口代碼文章來源:http://www.zghlxwxcb.cn/news/detail-704061.html
using System;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;
[System.Serializable]
public class Editor_ChinesizationTool : EditorWindow
{
private static Editor_ChinesizationTool _window;
[MenuItem("Tools/漢化編輯器")]
public static void GUIDRefReplaceWin()
{
Rect wr = new Rect(0, 0, 300, 1000);//窗口大小
_window = (Editor_ChinesizationTool)GetWindow(typeof(Editor_ChinesizationTool), true, "漢化編輯");// false 表示不能??康?/span>
_window.Show();
}
}
沒想到要去翻譯一個插件,竟然要自己先寫一個...造孽啊~
- 讀文件
/// <summary>
/// 讀取數(shù)據(jù)
/// </summary>
/// <returns></returns>
public List<string> ReadFileInfo(bool IsUpdateNewData = true)
{
Datas.Clear();
CurrentDatas.Clear();
CurrentSplitDatas.Clear();
if (IsUpdateNewData) NewSplitDatas.Clear();
StreamReader sr = null;//讀取
string assetsName = FileInfo.FullName;
sr = File.OpenText(assetsName.Substring(assetsName.IndexOf("Assets")));//讀取文件
//讀取所有行
int line = 0;
string data = null;
do
{
data = sr.ReadLine();
if (data != null)
{
Datas.Add(data);
CurrentDatas.Add(data);
foreach (var item in searchCharacterData.items)
{
string csData = FindString(data, item.startStr, item.endStr);
if (csData != "")
{
CurrentSplitDatas.Add(new NewCSData(line, csData));
if (IsUpdateNewData) NewSplitDatas.Add(new NewCSData(line, csData));
break;
}
}
}
line++;
} while (data != null);
sr.Close();//關(guān)閉流
sr.Dispose();//銷毀流
return CurrentDatas;
}
- 將改好的數(shù)據(jù)進行寫入
void WriteFileInfo(List<string> datas)
{
StreamWriter sw;//寫入
if (!FileInfo.Exists)
{
Debug.LogError("無法寫入,沒有該文件");
return;
}
ClearData(path);
sw = FileInfo.AppendText();//打開文件
foreach (string linedata in datas)
{
sw.WriteLine(linedata);
}
sw.Flush();//清除緩沖區(qū)
sw.Close();//關(guān)閉流
sw.Dispose();//銷毀流
//ReadFileInfo();
}
- 稍稍修正一下編輯器頁面,隨便導(dǎo)入一個插件試試看
源碼
注意!此文件需要放在Editor文件夾下才可以正常使用
using System;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;
[System.Serializable]
public class Editor_ChinesizationTool : EditorWindow
{
private static Editor_ChinesizationTool _window;
public string modelPath = "Assets";
public List<CSData> cslist = new List<CSData>();
public static Rect modelRect;
int maxLineCount = 5;
Vector2 csDataPos, contentPos;
SearchCharacterData searchCharacterData = null;
CSData CurrentCSData = null;
[MenuItem("Tools/漢化編輯器")]
public static void GUIDRefReplaceWin()
{
Rect wr = new Rect(0, 0, 300, 1000);//窗口大小
_window = (Editor_ChinesizationTool)GetWindow(typeof(Editor_ChinesizationTool), true, "漢化編輯");// false 表示不能??康?/span>
_window.Show();
}
private Material m_material;//1
private void OnEnable()
{
m_material = new Material(Shader.Find("Hidden/Internal-Colored"));//2
m_material.hideFlags = HideFlags.HideAndDontSave;//3
}
void OnGUI()
{
EditorGUILayout.Space();
EditorGUILayout.LabelField("將文件夾拖拽到此處");
EditorGUILayout.Space();
GUI.SetNextControlName("input1");//設(shè)置下一個控件的名字
modelRect = EditorGUILayout.GetControlRect();
modelPath = EditorGUI.TextField(modelRect, modelPath);
EditorGUILayout.Space();
DragFolder();
EditorGUILayout.Space();
searchCharacterData = EditorGUILayout.ObjectField("", searchCharacterData, typeof(SearchCharacterData), true) as SearchCharacterData;
// 導(dǎo)出材質(zhì)
if (searchCharacterData == null)
{
GUILayout.Label("請?zhí)砑幼值?);
return;
}
if (GUILayout.Button("讀取文件"))
{
ReadFile();
CurrentCSData = null;
}
if (CurrentCSData == null)
{
int currentLineCount = 1;
csDataPos = EditorGUILayout.BeginScrollView(csDataPos, GUILayout.Width(1000), GUILayout.Height(500));
bool isLineEnd = true;
maxLineCount = EditorGUILayout.IntField("每行顯示腳本的個數(shù)", maxLineCount);
foreach (CSData csdate in cslist)
{
if (currentLineCount == 1)
{
GUILayout.BeginHorizontal();
isLineEnd = false;
}
if (GUILayout.Button(csdate.name))
{
CurrentCSData = csdate;
}
if (currentLineCount == maxLineCount)
{
GUILayout.EndHorizontal();
currentLineCount = 0;
isLineEnd = true;
}
currentLineCount++;
}
if (isLineEnd == false)
{
GUILayout.EndHorizontal();
}
GUILayout.EndScrollView();
}
if (CurrentCSData != null)
{
EditorGUILayout.BeginVertical("HelpBox");
GUILayout.BeginHorizontal();
csDataPos = EditorGUILayout.BeginScrollView(csDataPos, GUILayout.Width(500), GUILayout.Height(700));
#region 顯示代碼
int line = 1;
lineLocations.Clear();
foreach (var date in CurrentCSData.CurrentDatas)
{
GUILayout.Label(line + " " + date);
foreach (var item in CurrentCSData.CurrentSplitDatas)
{
if (line == item.line)
{
LineLocation lineLocation = new LineLocation();
Rect rect = GUILayoutUtility.GetLastRect();
lineLocation.FirstRect = new Vector2(rect.x, rect.y - csDataPos.y);
lineLocation.FirstRectOffset = csDataPos;
lineLocations.Add(lineLocation);
}
}
line++;
}
GUILayout.EndScrollView();
GUILayout.Space(100);
#endregion
contentPos = EditorGUILayout.BeginScrollView(contentPos, GUILayout.Width(700), GUILayout.Height(700));
for (int i = 0; i < CurrentCSData.CurrentSplitDatas.Count; i++)
{
//GUILayout.BeginHorizontal();
GUILayout.Label(CurrentCSData.CurrentSplitDatas[i].line + 1 + " " + CurrentCSData.CurrentDatas[CurrentCSData.CurrentSplitDatas[i].line]);//找到可更換數(shù)據(jù)
lineLocations[i].FirstRect.y += contentPos.y;
lineLocations[i].LastRectOffset = contentPos;
Rect rect = GUILayoutUtility.GetLastRect();
lineLocations[i].LastRect = new Vector2(rect.x, rect.y);
CurrentCSData.NewSplitDatas[i].data = EditorGUILayout.TextField(CurrentCSData.NewSplitDatas[i].data);
//GUILayout.EndHorizontal();
}
foreach (var item in lineLocations)
{
m_material.SetPass(0);//4
GL.Begin(GL.LINES);
GL.Color(Color.red);
GL.Vertex3(item.FirstRect.x - 100+10, LimitMax(item.FirstRect.y + 30,690+ item.LastRectOffset.y, item.LastRectOffset.y), 0);
GL.Vertex3(item.FirstRect.x - 105+10, LimitMax(item.FirstRect.y + 30, 690+ item.LastRectOffset.y, item.LastRectOffset.y), 0);
GL.End();
GL.Begin(GL.LINES);
GL.Color(Color.black);
GL.Vertex3(item.FirstRect.x - 100+10, LimitMax(item.FirstRect.y + 30,690 + item.LastRectOffset.y, item.LastRectOffset.y), 0);
//================================================================================================
GL.Vertex3(item.LastRect.x-10, LimitMax(item.LastRect.y + 10, 690 + item.LastRectOffset.y, item.LastRectOffset.y), 0);
GL.End();
GL.Begin(GL.LINES);
GL.Color(Color.red);
GL.Vertex3(item.LastRect.x-10, LimitMax(item.LastRect.y + 10, 690 + item.LastRectOffset.y, item.LastRectOffset.y), 0);
GL.Vertex3(item.LastRect.x-5, LimitMax(item.LastRect.y + 10, 690 + item.LastRectOffset.y, item.LastRectOffset.y), 0);
GL.End();
//Debug.Log("FirstRect:" + item.FirstRect+"__"+ "LastRect:"+ item.LastRect);
//break;
}
GUILayout.EndScrollView();
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
if (GUILayout.Button("確認更改"))
{
CurrentCSData.ReadFileInfo(false);
for (int i = 0; i < CurrentCSData.CurrentSplitDatas.Count; i++)
{
CurrentCSData.CurrentDatas[CurrentCSData.CurrentSplitDatas[i].line] =
ReplaceStr(CurrentCSData.CurrentDatas[CurrentCSData.CurrentSplitDatas[i].line],
CurrentCSData.CurrentSplitDatas[i].data,
CurrentCSData.NewSplitDatas[i].data);
}
for (int i = 0; i < CurrentCSData.Datas.Count; i++)
{
CurrentCSData.Datas[i] = CurrentCSData.CurrentDatas[i];
}
CurrentCSData.WriterData();
AssetDatabase.Refresh();
}
if (GUILayout.Button("重新選擇文件"))
{
CurrentCSData = null;
}
GUILayout.EndHorizontal();
GUILayout.EndVertical();
}
EditorGUILayout.Space();
}
List<LineLocation> lineLocations = new List<LineLocation>();
public class LineLocation
{
public Vector2 FirstRectOffset;
public Vector2 FirstRect;
public Vector2 LastRectOffset;
public Vector2 LastRect;
}
public void ReadFile()
{
GetAllFilesAndDertorys(modelPath, searchCharacterData);
}
/// <summary>
/// 獲得拖拽文件
/// </summary>
void DragFolder()
{
//鼠標(biāo)位于當(dāng)前窗口
if (mouseOverWindow == this)
{
//拖入窗口未松開鼠標(biāo)
if (Event.current.type == EventType.DragUpdated)
{
DragAndDrop.visualMode = DragAndDropVisualMode.Generic;//改變鼠標(biāo)外觀
// 判斷區(qū)域
if (modelRect.Contains(Event.current.mousePosition))
GUI.FocusControl("input1");
}
//拖入窗口并松開鼠標(biāo)
else if (Event.current.type == EventType.DragExited)
{
string dragPath = string.Join("", DragAndDrop.paths);
// 判斷區(qū)域
if (modelRect.Contains(Event.current.mousePosition))
modelPath = dragPath;
// 取消焦點(不然GUI不會刷新)
GUI.FocusControl(null);
}
}
}
static string FindString(string str, string StartStr, string EndStr)
{
if (str.Length < 3)
return "";
int index3 = str.IndexOf(StartStr);
if (index3 != -1)
{
int index4 = str.IndexOf(EndStr, index3);
if (index4 != -1)
{
return str.Substring(index3 + StartStr.Length, index4 - index3 - StartStr.Length);
}
}
return "";
}
void GetAllFilesAndDertorys(string _path, SearchCharacterData searchCharacterData)
{
//判斷路徑是否存在
if (Directory.Exists(_path))
{
#region 找到Editor文件夾
DirectoryInfo dir = new DirectoryInfo(_path);
DirectoryInfo[] allDirs = dir.GetDirectories("*", SearchOption.AllDirectories);
string EditorPath = "";
foreach (var item in allDirs)
{
//忽略.meta
if (item.Name.EndsWith(".meta")) continue;
string assetsName = item.FullName;
assetsName = assetsName.Substring(assetsName.IndexOf("Assets"));
if (item.Name == "Editor")
{
EditorPath = assetsName;
break;
}
}
#endregion
if (EditorPath != "")
{
#region 得到Editor文件夾下所有的.cs文件
DirectoryInfo editorDir = new DirectoryInfo(EditorPath);
cslist.Clear();
int ListIndex = 0;
foreach (var item in editorDir.GetFiles("*", SearchOption.AllDirectories))
{
//忽略.meta
string assetsName = item.FullName;
assetsName = assetsName.Substring(assetsName.IndexOf("Assets"));
if (item.Name.EndsWith(".meta")) continue;
if (item.Name.EndsWith(".cs"))
{
cslist.Add(new CSData(ListIndex, item, assetsName, searchCharacterData, this));
}
ListIndex++;
}
#endregion
foreach (var item in cslist)
{
item.ReadFileInfo();
}
}
else
{
Debug.LogError("該目錄沒有Editor文件夾");
}
}
}
string ReplaceStr(string str, string oldStr, string newStr)
{
if (str.Length < 3)
return "";
int strIndex = str.IndexOf(oldStr);
if (strIndex != -1)
{
string startStr = str.Substring(0, strIndex);
string endStr = str.Substring(strIndex + oldStr.Length);
return startStr + newStr + endStr;
}
return "";
}
public float LimitMax(float f, float maxValue = 690, float minValue = 0)
{
//return f;
return Math.Min(maxValue, Math.Max(f, minValue));
}
[System.Serializable]
public class CSData
{
Editor_ChinesizationTool editor_ChinesizationTool = null;
SearchCharacterData searchCharacterData = null;
public string name;
private FileInfo fileInfo;
public int ListIndex = -1;
public string path;
/// <summary>
/// 原始數(shù)據(jù)
/// </summary>
public List<string> Datas = new List<string>();
/// <summary>
/// 當(dāng)前數(shù)據(jù)
/// </summary>
public List<string> CurrentDatas = new List<string>();
/// <summary>
/// 新數(shù)據(jù)
/// </summary>
public List<NewCSData> CurrentSplitDatas = new List<NewCSData>();
public List<NewCSData> NewSplitDatas = new List<NewCSData>();
public FileInfo FileInfo
{
get
{
if (fileInfo == null)
{
editor_ChinesizationTool.ReadFile();
fileInfo = editor_ChinesizationTool.cslist[ListIndex].FileInfo;
}
return fileInfo;
}
set => fileInfo = value;
}
public CSData(int mListIndex, FileInfo mfileInfo, string path, SearchCharacterData searchCharacterData, Editor_ChinesizationTool parent)
{
FileInfo = mfileInfo;
this.path = path;
this.name = FileInfo.Name;
this.searchCharacterData = searchCharacterData;
this.ListIndex = mListIndex;
this.editor_ChinesizationTool = parent;
}
/// <summary>
/// 寫入數(shù)據(jù)
/// </summary>
public void WriterData()
{
WriteFileInfo(Datas);
}
/// <summary>
/// 讀取數(shù)據(jù)
/// </summary>
/// <returns></returns>
public List<string> ReadFileInfo(bool IsUpdateNewData = true)
{
Datas.Clear();
CurrentDatas.Clear();
CurrentSplitDatas.Clear();
if (IsUpdateNewData) NewSplitDatas.Clear();
StreamReader sr = null;//讀取
string assetsName = FileInfo.FullName;
sr = File.OpenText(assetsName.Substring(assetsName.IndexOf("Assets")));//讀取文件
//讀取所有行
int line = 0;
string data = null;
do
{
data = sr.ReadLine();
if (data != null)
{
Datas.Add(data);
CurrentDatas.Add(data);
foreach (var item in searchCharacterData.items)
{
string csData = FindString(data, item.startStr, item.endStr);
if (csData != "")
{
CurrentSplitDatas.Add(new NewCSData(line, csData));
if (IsUpdateNewData) NewSplitDatas.Add(new NewCSData(line, csData));
break;
}
}
}
line++;
} while (data != null);
sr.Close();//關(guān)閉流
sr.Dispose();//銷毀流
return CurrentDatas;
}
void WriteFileInfo(List<string> datas)
{
StreamWriter sw;//寫入
if (!FileInfo.Exists)
{
Debug.LogError("無法寫入,沒有該文件");
return;
}
ClearData(path);
sw = FileInfo.AppendText();//打開文件
foreach (string linedata in datas)
{
sw.WriteLine(linedata);
}
sw.Flush();//清除緩沖區(qū)
sw.Close();//關(guān)閉流
sw.Dispose();//銷毀流
//ReadFileInfo();
}
void ClearData(string path)
{
StreamWriter tmpWrite = new StreamWriter(path);
tmpWrite.Write("");
tmpWrite.Close();
}
}
[System.Serializable]
public class NewCSData
{
public int line = 0;
public string data = "";
public NewCSData(int line, string data)
{
this.line = line;
this.data = data;
}
}
}
最后的最后:
我自己反正沒實踐過,可以先拿這個玩玩看還是挺有意思的~
覺得有意思可以改巴改巴,也可以把建議放在評論區(qū),有空我就更新一下~
Demo源碼文章來源地址http://www.zghlxwxcb.cn/news/detail-704061.html
到了這里,關(guān)于Unity漢化一個插件 制作插件漢化工具的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!