Unity I2 Localization实现多语言切换
来源:华佗健康网
前言:
在网上找了找I2 Localization的使用,发现教学都收费!!!
一怒之下自己封装了下,朋友们可以拿来直接使用,话不多说,上代码!
目录结构
大致如下,可自由发挥:(用到了一个JSON工具,可自行替换)
EditorTool:
编辑器工具,当更新了多语言文件时,可手动点击更新下配置
MultiLanguageEditor:
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Text;
using MultiLanguage.Entity;
using I2.Loc;
using Newtonsoft.Json;
using UnityEditor;
using UnityEngine;
public class MultiLanguageEditor : Editor
{
[MenuItem("MultiLanguage/更新多语言配置")]
public static async void UpdateAllConfigLanguage()
{
byte[] zipData = await ZipLoader.LoadZipFile("Localize/lang.zip");
using ZipArchive archive = new ZipArchive(new MemoryStream(zipData));
ZipArchiveEntry manifestEntry = archive.GetEntry("manifest.json");
if (manifestEntry == null)
{
return;
}
using StreamReader reader = new StreamReader(manifestEntry.Open(), Encoding.UTF8);
LangManifest manifest = JsonConvert.DeserializeObject<LangManifest>(reader.ReadToEnd());
if (manifest == null)
{
return;
}
// 更新manifest, 如果没有会动态添加, 已有则不做处理 关闭多语种
MultiLanguageManager.ApplyManifestLanguages(manifest);
//更新内置所有语言
foreach (LangData data in manifest.languages)
{
UpdateLangConfig(archive.GetEntry($"{data.code}.csv"));
}
LocalizationManager.DoLocalizeAll(true);
}
private static void UpdateLangConfig(ZipArchiveEntry entry)
{
if (entry == null)
{
return;
}
string code = entry.Name.Replace(".csv", string.Empty);
using StreamReader reader = new StreamReader(entry.Open(), Encoding.UTF8);
string dataStr = reader.ReadToEnd();
List<string[]> csvList = LocalizationReader.ReadCSV(dataStr);
Dictionary<string, string> multilingual = new Dictionary<string, string>();
foreach (string[] arr in csvList)
{
if (arr.Length > 0)
{
string key = arr[0];
string value = "";
if (arr.Length > 1)
{
value = arr[1];
}
multilingual[key] = value;
}
}
if (multilingual.Count > 0)
{
FullRenewalUpdateDicSources(code, multilingual);
}
}
private static void FullRenewalUpdateDicSources(string code, Dictionary<string, string> data)
{
foreach (var source in LocalizationManager.Sources)
{
source.mDictionary.Clear();
UpdateDictionaryData(source, code, data);
}
Debug.Log($"<color=#41d558>语言{code}更新配置成功!</color>");
}
private static void UpdateDictionaryData(LanguageSourceData sources,string code, Dictionary<string, string> dataList)
{
int LangIndex = sources.GetLanguageIndexFromCode(code);
foreach (KeyValuePair<string, string> valuePair in dataList)
{
string key = valuePair.Key;
if (!sources.mDictionary.TryGetValue(key, out TermData termData))
{
termData = sources.AddTerm(key, eTermType.Text, false);
}
termData.Languages[LangIndex] = valuePair.Value;
}
sources.Editor_SetDirty();
AssetDatabase.SaveAssets();
}
}
Entity:
封装了一下用到的对象,也可自由发挥
public class LangData
{
public string code { get; set; }
public string name { get; set; }
}
public class LangManifest
{
public List<LangData> languages { get; set; }
}
public class LanguageUIModel
{
public bool Selected;
public string Language;
}
Extension:
拓展,我这里做了一个string的拓展,去掉换行符及空格
StringExtension:
public static class StringExtension
{
public static string ReplaceLineBreak(this string input)
{
return input.Replace("\r", " ").Replace("\"", "").Trim();
}
}
MultiLanguageManager:
多语言管理类,初始化、切换语言、通过key获取翻译文本
注意:这里需要更改源码中的LocalizationManager.DoLocalizeAll();方法,变为public
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MultiLanguage.Entity;
using MultiLanguage.Extension;
using I2.Loc;
using Newtonsoft.Json;
using UnityEngine;
public static class MultiLanguageManager
{
public static LangManifest Manifest { get; private set; }
private const string PlayerPrefsLanguageKey = "LanguagePlayerPrefs";
public static List<LanguageUIModel> Languages { get; private set; }
public static async Task InitAsync()
{
Languages = new List<LanguageUIModel>();
byte[] zipData = await ZipLoader.LoadZipFile("Localize/lang.zip");
if (HasLanguagePrefs())
{
LocalizationManager.CurrentLanguageCode = GetLanguagePrefs();
}
HandleConfig(zipData);
var languages = LocalizationManager.GetAllLanguagesCode();
foreach (var language in languages)
{
var languageModel = new LanguageUIModel() { Selected = language == LocalizationManager.CurrentLanguageCode, Language = language };
Languages.Add(languageModel);
}
}
public static void SelectLanguage(LanguageUIModel language)
{
foreach (var languageModel in Languages)
{
if(languageModel == language)
{
languageModel.Selected = true;
LocalizationManager.CurrentLanguageCode = languageModel.Language;
SaveLanguagePrefs(LocalizationManager.CurrentLanguageCode);
}
else
{
languageModel.Selected = false;
}
}
}
public static string GetLanguageName(string code)
{
if (Manifest == null)
{
return string.Empty;
}
return Manifest.languages.Find(x => x.code.Equals(code))?.name ?? string.Empty;
}
public static string GetTranslation(string key)
{
return LocalizationManager.GetTranslation(key).ReplaceLineBreak();
}
#region Unzip
public static void HandleConfig(byte[] content)
{
if (content == null)
{
return;
}
using ZipArchive archive = new ZipArchive(new MemoryStream(content));
ZipArchiveEntry manifestEntry = archive.GetEntry("manifest.json");
if (manifestEntry == null)
{
return;
}
using StreamReader reader = new StreamReader(manifestEntry.Open(), Encoding.UTF8);
Manifest = JsonConvert.DeserializeObject<LangManifest>(reader.ReadToEnd());
if (Manifest == null)
{
return;
}
ApplyManifestLanguages(Manifest);
// 更新当前选择的语言
string lang = LocalizationManager.CurrentLanguageCode;
ZipArchiveEntry entry = archive.GetEntry($"{lang}.csv");
//如果想实现运行时切换语言就生效,需要UpdateLangConfig所有语言,否则只能重启应用生效
UpdateLangConfig(entry);
LocalizationManager.DoLocalizeAll(true);
}
/// <summary>
/// 更新manifest, 如果没有会动态添加, 已有则不做处理
/// </summary>
public static void ApplyManifestLanguages(LangManifest manifest)
{
if (manifest == null)
{
return;
}
foreach (LanguageSourceData source in LocalizationManager.Sources)
{
foreach (string code in manifest.languages.Select(x => x.code))
{
string name = GoogleLanguages.GetLanguageName(code).Replace("/", "_");
source.AddLanguage(name, code);
}
}
}
private static void UpdateLangConfig(ZipArchiveEntry entry)
{
if (entry == null)
{
return;
}
string code = entry.Name.Replace(".csv", string.Empty);
using StreamReader reader = new StreamReader(entry.Open(), Encoding.UTF8);
string dataStr = reader.ReadToEnd();
List<string[]> csvList = LocalizationReader.ReadCSV(dataStr);
Dictionary<string, string> multilingual = new Dictionary<string, string>();
foreach (string[] arr in csvList)
{
if (arr.Length > 0)
{
string key = arr[0];
string value = "";
if (arr.Length > 1)
{
value = arr[1];
}
multilingual[key] = value;
}
}
if (multilingual.Count > 0)
{
// refresh
UpdateDicSources(code, multilingual);
}
}
private static void UpdateDicSources(string code, Dictionary<string, string> data)
{
foreach (var source in LocalizationManager.Sources)
{
UpdateDictionaryData(source, code, data);
}
}
private static void UpdateDictionaryData(LanguageSourceData source,string code, Dictionary<string, string> dataList)
{
int LangIndex = source.GetLanguageIndexFromCode(code);
foreach (KeyValuePair<string, string> valuePair in dataList)
{
string key = valuePair.Key;
if (!source.mDictionary.TryGetValue(key, out TermData termData))
{
termData = source.AddTerm(key, eTermType.Text, false);
}
termData.Languages[LangIndex] = valuePair.Value;
}
}
#endregion
#region PlayerPrefs
private static void SaveLanguagePrefs(string languageCode)
{
PlayerPrefs.SetString(PlayerPrefsLanguageKey, languageCode);
}
private static string GetLanguagePrefs()
{
return PlayerPrefs.GetString(PlayerPrefsLanguageKey);
}
private static bool HasLanguagePrefs()
{
return PlayerPrefs.HasKey(PlayerPrefsLanguageKey);
}
#endregion
}
ZipLoader:
加载zip文件工具
using System.IO;
using Cysharp.Threading.Tasks;
using UnityEngine;
using UnityEngine.Networking;
public static class ZipLoader
{
public static async UniTask<byte[]> LoadZipFile(string zipFileName)
{
string zipFilePath = Path.Combine(Application.streamingAssetsPath, zipFileName);
#if UNITY_EDITOR || UNITY_STANDALONE
string fileUrl = "file://" + zipFilePath;
#elif UNITY_IOS || UNITY_ANDROID
string fileUrl = zipFilePath;
#endif
UnityWebRequest www = UnityWebRequest.Get(fileUrl);
await www.SendWebRequest().ToUniTask();
if (www.result != UnityWebRequest.Result.Success)
{
Debug.LogError("Failed to load zip file: " + www.error);
return null;
}
byte[] zipData = www.downloadHandler.data;
return zipData;
}
}
压缩包内文件结构为:
JSON文件内容结构为:
{
"languages": [
{
"code": "en",
"name": "English"
},
{
"code": "zh",
"name": "中文(简体)"
},
{
"code": "ja",
"name": "日本語"
}
]
}
因篇幅问题不能全部显示,请点此查看更多更全内容