chore(i18n): initial integration with NDMF localization system

This commit is contained in:
bd_ 2023-12-19 14:25:04 +09:00
parent b3d5102ae5
commit fd44d244ec
10 changed files with 43 additions and 49 deletions

View File

@ -4,7 +4,7 @@
"version": "3.5.0" "version": "3.5.0"
}, },
"nadena.dev.ndmf": { "nadena.dev.ndmf": {
"version": "0.3.0" "version": "1.3.0-alpha.0"
} }
}, },
"locked": { "locked": {

View File

@ -4,7 +4,7 @@
"version": "3.4.2" "version": "3.4.2"
}, },
"nadena.dev.ndmf": { "nadena.dev.ndmf": {
"version": "0.3.0" "version": "1.3.0-alpha.0"
} }
}, },
"locked": { "locked": {

View File

@ -3,6 +3,8 @@ using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using nadena.dev.ndmf.localization;
using nadena.dev.ndmf.ui;
using Newtonsoft.Json; using Newtonsoft.Json;
using UnityEditor; using UnityEditor;
using UnityEngine; using UnityEngine;
@ -19,13 +21,13 @@ namespace nadena.dev.modular_avatar.core.editor
private static ImmutableDictionary<string, string> SupportedLanguageDisplayNames private static ImmutableDictionary<string, string> SupportedLanguageDisplayNames
= ImmutableDictionary<string, string>.Empty = ImmutableDictionary<string, string>.Empty
.Add("en", "English") .Add("en-us", "English")
.Add("ja", "日本語") .Add("ja-jp", "日本語")
.Add("zh-hans", "简体中文") .Add("zh-hans", "简体中文")
.Add("ko", "한국어"); .Add("ko-kr", "한국어");
private static ImmutableList<string> private static ImmutableList<string>
SupportedLanguages = new string[] {"en", "ja", "zh-hans", "ko"}.ToImmutableList(); SupportedLanguages = new string[] {"en-us", "ja-jp", "zh-hans", "ko-kr"}.ToImmutableList();
private static string[] DisplayNames = SupportedLanguages.Select(l => private static string[] DisplayNames = SupportedLanguages.Select(l =>
{ {
@ -37,51 +39,53 @@ namespace nadena.dev.modular_avatar.core.editor
internal static string OverrideLanguage { get; set; } = null; internal static string OverrideLanguage { get; set; } = null;
[MenuItem("Tools/Modular Avatar/Reload localizations")] public static Localizer L { get; private set; }
public static void Reload()
static Localization()
{ {
Cache.Clear(); Localizer localizer = new Localizer(SupportedLanguages[0], () =>
OnLangChange?.Invoke(); {
List<(string, Func<string, string>)> languages = new List<(string, Func<string, string>)>();
foreach (var lang in SupportedLanguages)
{
languages.Add((lang, LanguageLookup(lang)));
}
return languages;
});
L = localizer;
LanguagePrefs.RegisterLanguageChangeCallback(typeof(Localization), _ => OnLangChange?.Invoke());
} }
private static ImmutableDictionary<string, string> GetLocalization(string lang) private static Func<string,string> LanguageLookup(string lang)
{ {
if (Cache.TryGetValue(lang, out var info))
{
return info;
}
var fallback = lang == FallbackLanguage
? ImmutableDictionary<string, string>.Empty
: GetLocalization(FallbackLanguage);
var filename = localizationPathRoot + "/" + lang + ".json"; var filename = localizationPathRoot + "/" + lang + ".json";
try try
{ {
var langData = File.ReadAllText(filename); var langData = File.ReadAllText(filename);
var tmp = JsonConvert.DeserializeObject<Dictionary<string, string>>(langData); var langMap = JsonConvert.DeserializeObject<Dictionary<string, string>>(langData);
foreach (var kvp in fallback) return langMap.GetValueOrDefault;
{
if (!tmp.ContainsKey(kvp.Key))
{
tmp[kvp.Key] = kvp.Value;
}
}
info = tmp.ToImmutableDictionary();
Cache[lang] = info;
return info;
} }
catch (Exception e) catch (Exception e)
{ {
Debug.LogError("Failed to load language file " + filename); Debug.LogError("Failed to load language file " + filename);
Debug.LogException(e); Debug.LogException(e);
return ImmutableDictionary<string, string>.Empty; return (k) => null;
} }
} }
[MenuItem("Tools/Modular Avatar/Reload localizations")]
public static void Reload()
{
Localizer.ReloadLocalizations();
Cache.Clear();
}
public static GUIContent G(string key) public static GUIContent G(string key)
{ {
var tooltip = S(key + ".tooltip", null); var tooltip = S(key + ".tooltip", null);
@ -107,11 +111,9 @@ namespace nadena.dev.modular_avatar.core.editor
public static string S(string key, string defValue) public static string S(string key, string defValue)
{ {
var info = GetLocalization(GetSelectedLocalization()); if (L.TryGetLocalizedString(key, out var val))
if (info.TryGetValue(key, out var value))
{ {
return value; return val;
} }
else else
{ {
@ -121,22 +123,14 @@ namespace nadena.dev.modular_avatar.core.editor
public static string GetSelectedLocalization() public static string GetSelectedLocalization()
{ {
return OverrideLanguage ?? EditorPrefs.GetString("nadena.dev.modularavatar.lang", "en"); return LanguagePrefs.Language;
} }
public static void ShowLanguageUI() public static void ShowLanguageUI()
{ {
EditorGUILayout.Separator(); EditorGUILayout.Separator();
var curLang = GetSelectedLocalization(); LanguageSwitcher.DrawImmediate();
var curIndex = SupportedLanguages.IndexOf(curLang);
var newIndex = EditorGUILayout.Popup("Editor Language", curIndex, DisplayNames);
if (newIndex != curIndex)
{
EditorPrefs.SetString("nadena.dev.modularavatar.lang", SupportedLanguages[newIndex]);
Reload();
}
} }
} }
} }

View File

@ -16,6 +16,6 @@
}, },
"vpmDependencies": { "vpmDependencies": {
"com.vrchat.avatars": ">=3.2.0", "com.vrchat.avatars": ">=3.2.0",
"nadena.dev.ndmf": ">=1.2.5 <2.0.0-a" "nadena.dev.ndmf": ">=1.3.0-alpha.0 <2.0.0-a"
} }
} }