Unity 本地化(多语言)插件Localization
Posted 北海6516
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity 本地化(多语言)插件Localization相关的知识,希望对你有一定的参考价值。
游戏本地化主要是文字和资源(图片等)随语言变化,比如游戏内一些艺术字使用的是图片,就要根据语言加载不同的图片
安装,配置
Localization是unity官方推出的本地化插件,通过PackageManager安装
使用前需要先创建本地化配置,Edit > Project Settings > Localization,生成总的配置文件
Locale Generator用于添加或移出语言,每添加一种语言也会生成对应的配置文件,然后选择默认语言的配置文件,如上图
创建表格
Window > Asset Management > Localization Tables 创建表格,用于建立不同资源之间的对应关系,就是一个key对应多个语言的资源,可以选择创建文本表或者资源表,写好表名后就可以创建了
文本表(String Table)
这里先以文本表演示,创建一个表名为MyStringTable的String Table
UI上添加一个TextMeshPro,右键选择Localize
会自动添加一个脚本,指定表名和Entry Name(也就是表中的key),然后在场景中挂脚本进行测试
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Localization;
using UnityEngine.Localization.Settings;
using UnityEngine.ResourceManagement.AsyncOperations;
public class TestLocalization : MonoBehaviour
AsyncOperationHandle m_InitializeOperation;
private Locale _chineseLocale;
private Locale _englishLocale;
void Start()
// SelectedLocaleAsync will ensure that the locales have been initialized and a locale has been selected.
m_InitializeOperation = LocalizationSettings.SelectedLocaleAsync;
if (m_InitializeOperation.IsDone)
InitializeCompleted(m_InitializeOperation);
else
m_InitializeOperation.Completed += InitializeCompleted;
void InitializeCompleted(AsyncOperationHandle obj)
var locales = LocalizationSettings.AvailableLocales.Locales;
for (int i = 0; i < locales.Count; ++i)
var locale = locales[i];
if (locale.LocaleName == "Chinese (Simplified) (zh-Hans)")
_chineseLocale = locale;
else if (locale.LocaleName == "English (en)")
_englishLocale = locale;
private void OnGUI()
if (GUI.Button(new Rect(0, 0, 100, 50),"中文"))
LocalizationSettings.Instance.SetSelectedLocale(_chineseLocale);
if (GUI.Button(new Rect(0, 60, 100, 50),"英文"))
LocalizationSettings.Instance.SetSelectedLocale(_englishLocale);
运行时修改Locale就可以改变语言,这种方法适用于界面上的静态文本,也可以在代码中获取对应的文本,需要指定表名和key,如下
using System;
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.Localization.Settings;
using UnityEngine.ResourceManagement.AsyncOperations;
public class TestLocalization2 : MonoBehaviour
public TextMeshProUGUI text;
void Start()
StartCoroutine(LoadStrings());
IEnumerator LoadStrings()
// A string table may not be immediately available such as during initialization of the localization system or when a table has not been loaded yet.
var loadingOperation = LocalizationSettings.StringDatabase.GetTableAsync("MyStringTable");
yield return loadingOperation;
if (loadingOperation.Status == AsyncOperationStatus.Succeeded)
var stringTable = loadingOperation.Result;
text.text = stringTable.GetEntry("id_hello").GetLocalizedString();
else
Debug.LogError("Could not load String Table\\n" + loadingOperation.OperationException.ToString());
或者在初始化时通过表名获得该文本表,然后由文本表获取字符串
using UnityEngine;
using UnityEngine.Localization;
using UnityEngine.Localization.Settings;
using UnityEngine.Localization.Tables;
public class TestLocalization3 : MonoBehaviour
public LocalizedStringTable stringTable = new LocalizedStringTable TableReference = "MyStringTable" ;
string m_TranslatedStringHello;
void OnEnable()
stringTable.TableChanged += LoadStrings;
void OnDisable()
stringTable.TableChanged -= LoadStrings;
void LoadStrings(StringTable stringTable)
m_TranslatedStringHello = GetLocalizedString(stringTable, "id_hello");
static string GetLocalizedString(StringTable table, string entryName)
var entry = table.GetEntry(entryName);
return entry.GetLocalizedString();
void OnGUI()
// We can check if the localization system is ready using the InitializationOperation.
// Initialization involves loading locales and optionally preloading localized data for the current locale.
if (!LocalizationSettings.InitializationOperation.IsDone)
GUILayout.Label("Initializing Localization");
return;
GUILayout.Label(m_TranslatedStringHello);
Window > Asset Management > Localization Scene Controls
编辑器下,我们可以通过Localization Scene Controls来修改当前Locale,便于debug
如果游戏中的文本量不是很大,可以通过Localization的文本表管理,文本量很大的话还是建议通过Excel来管理,自己写一个管理器来加载文本
资源表(Asset Table)
资源表的逻辑类似,先创建一个MyAssetTable,添加测试数据,因为资源项是Object类型,所以支持任何资源,这里添加两个sprite
在UI上添加一个Image,右键选择Localize,自动添加脚本,指定表名和key,就可以测试了
这个适用于界面上的静态图片,Raw Image和Audio Source组件同样支持右键选择Localize
拓展
我想让TextMeshPro的字体也随着语言改变,Localization也提供了接口支持拓展,首先创建三个脚本
using System;
namespace UnityEngine.Localization
[Serializable]
public class LocalizedTmpFont : LocalizedAsset<TMPro.TMP_FontAsset>
using System;
using UnityEngine.Events;
namespace UnityEngine.Localization.Events
[Serializable]
public class UnityEventTmpFont : UnityEvent<TMPro.TMP_FontAsset>
using TMPro;
using UnityEngine.Localization.Events;
namespace UnityEngine.Localization.Components
[AddComponentMenu("Localization/Asset/Localize TmpFont Event")]
public class LocalizeTmpFontEvent : LocalizedAssetEvent<TMPro.TMP_FontAsset, LocalizedTmpFont, UnityEventTmpFont>
private TextMeshProUGUI text;
private void Awake()
text = GetComponent<TextMeshProUGUI>();
protected override void UpdateAsset(TMP_FontAsset localizedAsset)
base.UpdateAsset(localizedAsset);
text.font = localizedAsset;
资源表中也添加想要的字体
最后就可以在TextMeshPro上挂LocalizeTmpFontEvent脚本,指定表名和id
Unity3D研究之多语言用中文做KEY
做多语言的时候用中文做KEY绝对是有100%的优点,假设用英文表示那么代码里面给文字赋值的地方全都是英文。写的代码多了以后维护起来就没有人能看懂了,或者看起来非常费劲。
对PoolManager不了解的能够看下初探PoolManager插件非常适合新手学习。
说说用中文做KEY的原理:Unity中给文字赋值的地方就两处, 一个是提前预制在UI Prefab上的文字。另一个是写在代码里面的文字。那么在开发阶段我们在Prefab和代码里面直接就写中文,等项目后期通过工具把所有中文的地方所有提取出来。然后把提取出来的中文交给策划。让策划他们去翻译去,这样我们之前写的中文就是多语言的KEY。终于显示的界面上的文字是用这个中文KEY读表读出来的。
NGUI里全部的文字都是在UILabel中,但是我们要做图文混排,一般都是在UILabel上在拓展一个自己的脚本,用这个脚本在生成相应的UILabel和UISprite。这篇文章我就先以UILabel来说明原理。
1.遍历全部UIPrefab把包括UILabe(或者是你自己写的)组件找出来,而且把文字提取出来。
2.遍历全部的CS代码。把全部 StrUtil.GetText(“成功智慧网\n我要换行“); 双引號中间的中文以及字符全部提取出来。
直接上思路代码。
using UnityEngine;
using System.Collections;
using UnityEditor;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
public class TestStart :Editor
{
//UIPrefab文件夹文件夹
private static string UIPrefabPath = Application.dataPath + "/UI";
//脚本的文件夹文件夹
private static string ScriptPath = Application.dataPath + "/Scripts";
//导出的中文KEY路径
private static string OutPath = Application.dataPath +"/out.txt";
private static List<string>Localization = null;
private static string staticWriteText = "";
[MenuItem("Tools/导出多语言")]
static void ExportChinese()
{
Localization = new List<string>();
staticWriteText ="";
//提取Prefab上的中文
staticWriteText +="----------------Prefab----------------------\n";
LoadDiectoryPrefab(new DirectoryInfo(UIPrefabPath));
//提取CS中的中文
staticWriteText +="----------------Script----------------------\n";
LoadDiectoryCS(new DirectoryInfo(ScriptPath));
//终于把提取的中文生成出来
string textPath = OutPath;
if (System.IO.File.Exists (textPath))
{
File.Delete (textPath);
}
using(StreamWriter writer = new StreamWriter(textPath, false, Encoding.UTF8))
{
writer.Write(staticWriteText);
}
AssetDatabase.Refresh();
}
//递归全部UI Prefab
static public void LoadDiectoryPrefab(DirectoryInfo dictoryInfo)
{
if(!dictoryInfo.Exists) return;
DirectoryInfo []chindDictoryInfos = dictoryInfo.GetDirectories();
foreach(DirectoryInfo chindDictoryInfo in chindDictoryInfos)
{
LoadDiectoryPrefab(chindDictoryInfo);
}
FileInfo[] fileInfos = dictoryInfo.GetFiles("*.prefab", SearchOption.AllDirectories);
foreach (FileInfo files in fileInfos)
{
string path = files.FullName;
string assetPath = path.Substring(path.IndexOf("Assets/"));
GameObject prefab = AssetDatabase.LoadAssetAtPath(assetPath, typeof(GameObject)) as GameObject;
GameObject instance = GameObject.Instantiate(prefab) as GameObject;
SearchPrefabString(instance.transform);
GameObject.DestroyImmediate(instance);
}
}
//递归全部C#代码
static public void LoadDiectoryCS(DirectoryInfo dictoryInfo)
{
if(!dictoryInfo.Exists) return;
DirectoryInfo []chindDictoryInfos = dictoryInfo.GetDirectories();
foreach(DirectoryInfo chindDictoryInfo in chindDictoryInfos)
{
LoadDiectoryPrefab(chindDictoryInfo);
}
FileInfo[] fileInfos = dictoryInfo.GetFiles("*.cs", SearchOption.AllDirectories);
foreach (FileInfo files in fileInfos)
{
string path = files.FullName;
string assetPath = path.Substring(path.IndexOf("Assets/"));
TextAsset textAsset = AssetDatabase.LoadAssetAtPath(assetPath, typeof(TextAsset)) as TextAsset;
string text = textAsset.text;
//用正則表達式把代码里面两种字符串中间的字符串提取出来。
Regex reg = new Regex("StrUtil.GetText\\(\".*?\"");
MatchCollection mc = reg.Matches(text);
foreach(Match m in mc)
{
string format = m.Value;
format = format.Replace("StrUtil.GetText(\"","");
format = format.Replace("\"","");
if(!Localization.Contains(format) && !string.IsNullOrEmpty(format)){
Localization.Add(format);
staticWriteText+=format+"\n";
}
}
}
}
//提取Prefab上的中文
static public void SearchPrefabString(Transform root)
{
foreach(Transform chind in root)
{
//由于这里是写样例,所以我用的是UILabel
//这里应该是写你用于图文混排的脚本。
UILabel label = chind.GetComponent<UILabel>();
if(label != null)
{
string text = label.text;
if(!Localization.Contains(text) && !string.IsNullOrEmpty(text)){
Localization.Add(text);
text = text.Replace("\n",@"\n");
staticWriteText+=text+"\n";
}
}
if(chind.childCount >0)
SearchPrefabString(chind);
}
}
}
比方这个是个简单界面上赋值的代码。用StrUtil.GetText()去取中文。StrUtiL类是我们自己写的。
using UnityEngine;
using System.Collections;
public class UIMain : MonoBehaviour
{
private UILabel mName = null;
void Awake ()
{
mName = transform.Find("name").GetComponent<UILabel>();
mName.text = StrUtil.GetText("雨松MOMO\n我要换行");
mName.text = StrUtil.GetText("我是{0}我的网名{1}","宣雨松","雨松MOMO");
}
}
StrUtiL类里面去处理Key从本地数据表里中替换相应多语言显示的文字。
using UnityEngine;
using System.Collections;
public class StrUtil
{
static public string GetText( string text)
{
//通过传进来的中文KEY 去数据表里面读相应替换的多语言文字
return text;
}
static public string GetText(string text,params object[] args)
{
//通过传进来的中文KEY 去数据表里面读相应替换的多语言文字
return string.Format(text,args);
}
}
使用工具代码提取,终于将全部多语言中文的地方提取在txt里面。
最后就是让策划拿着生成出来的中文KEY在Excel表里。给出相应的翻译文字。
另一个重要的知识点就是换行问题,可能你在Prefab上进行的换行的操作,可是\n并非字符串。所以我们要把\n转成”\n”字符串写进去。
text.Replace(“\n”,@”\n”);
反过来在读取表的时候还是须要再把”\n”字符串转成\n换行符
text.Replace(@”\n”,”\n”);
这样就没问题了。策划也能够直接在数据表里填写\n来进行换行了。
最后的思考
1.开发的过程中可能要改动代码或者要加新功能删功能,所以我们要把差异性的中文Key提取出来,也就是把新添加的KEY 或者 新删除的KEY列举出来。
由于没有变化的就不须要策划又一次翻译了。
2.最好能直接帮策划生成Excel文件。Windows上非常easy。可是MAC就不行。我知道怎么在Mac上读取excel文件。可是我不知道在mac上怎么生成Excel有哪位大神知道还请告知一下我。
要能生成.xlsx的那种。谢谢啦。
3.由于要做图文混排,所以UILabel我已经不直接使用了,而是又写了一个类去管理UILable和UISprite, 事实上就是依据XML或者JSON 一类的描写叙述符去动态生成UILable和UISprite在帮它的动态的算坐标,算间距 一类的。
由于你的中文KEY须要传參数 比方 “我叫{0}我今年{1}大了” 一类的字符串。所以还是在写一个方法。
最后是本文的下载地址,事实上本文主要还是提供一个思路。 假设你有对多语言更好的建议,或者是办法。欢迎在以下给我留言,谢谢。
以上是关于Unity 本地化(多语言)插件Localization的主要内容,如果未能解决你的问题,请参考以下文章