Skip to content

Instantly share code, notes, and snippets.

@kalineh
Created September 29, 2020 01:02
Show Gist options
  • Save kalineh/0ca4f639315cad42faef117901b2d149 to your computer and use it in GitHub Desktop.
Save kalineh/0ca4f639315cad42faef117901b2d149 to your computer and use it in GitHub Desktop.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
public static class LocalizationEditorMenu
{
[MenuItem("Custom/Localization Quick Import")]
public static void LocalizationQuickImport()
{
var locPath = string.Format("Assets/Prefabs/Localization.prefab", Application.dataPath);
var locObj = AssetDatabase.LoadAssetAtPath<GameObject>(locPath);
if (locObj == null)
return;
var loc = locObj.GetComponent<Localization>();
if (loc == null)
return;
var textPath = string.Format("{0}/Localization.csv", Application.dataPath);
var text = System.IO.File.ReadAllText(textPath);
var errors = loc.Validate(text);
if (errors > 0)
return;
loc.Reimport(text);
EditorUtility.SetDirty(loc);
AssetDatabase.SaveAssets();
}
}
[CustomEditor(typeof(Localization))]
class LocalizationEditor
: Editor
{
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
var self = target as Localization;
if (GUILayout.Button("Clear"))
self.Clear();
if (GUILayout.Button("Validate"))
{
var filename = EditorUtility.OpenFilePanel("LocalizationData.csv", Application.dataPath, "csv");
if (string.IsNullOrEmpty(filename))
return;
var data = System.IO.File.ReadAllText(filename);
self.Clear();
self.Validate(data);
}
if (GUILayout.Button("Import"))
{
var filename = EditorUtility.OpenFilePanel("LocalizationData.csv", Application.dataPath, "csv");
if (string.IsNullOrEmpty(filename))
return;
var data = System.IO.File.ReadAllText(filename);
var errors = self.Validate(data);
if (errors <= 0)
{
Undo.RecordObject(self, "Reimport");
self.Clear();
self.Reimport(data);
EditorUtility.SetDirty(self);
}
}
GUILayout.Label(string.Format("Language: {0}", self.languages[self.languageIndex].code));
if (Application.isPlaying)
{
var currLanguageIndex = EditorGUILayout.IntSlider(self.languageIndex, 0, self.languages.Count - 1);
if (currLanguageIndex != self.languageIndex)
self.ChangeLanguage(currLanguageIndex);
}
}
}
#endif
//LANGUAGE|Language|日本語|한국어|中文|Francais|Italian|Deutsch|Spanish|Dog
// 0: keys
// 1: en
// 2: ja
// 3: kr
// 4: zh
// 5: fr
// 6: it
// 7: de
// 8: es
// 9: pl
// 10: dog
public class Localization
: MonoBehaviour
{
private static Localization _Instance;
public static Localization Instance
{
get
{
if (_Instance == null)
_Instance = GameObject.Find("Localization").GetComponent<Localization>();
return _Instance;
}
}
public void Awake()
{
if (Localization._Instance != null && Localization._Instance != this)
{
GameObject.Destroy(this.gameObject);
return;
}
Localization._Instance = this;
transform.SetParent(null);
GameObject.DontDestroyOnLoad(gameObject);
}
private Dictionary<string, string> key;
private static char delimiter = ',';
private static char quote = '"';
[System.Serializable]
public class Language
{
public string code;
public List<string> data;
}
[System.NonSerialized]
public int languageIndex;
public List<Language> languages;
private Dictionary<string, int> lookup;
public void OnEnable()
{
var language = Options.Instance.Language;
ChangeLanguage(language);
RebuildLookup();
}
public void Clear()
{
languages = new List<Language>();
languages.Add(new Language() { code = "keys", data = new List<string>(), });
languages.Add(new Language() { code = "en", data = new List<string>(), });
languages.Add(new Language() { code = "ja", data = new List<string>(), });
languages.Add(new Language() { code = "kr", data = new List<string>(), });
languages.Add(new Language() { code = "zh", data = new List<string>(), });
languages.Add(new Language() { code = "fr", data = new List<string>(), });
languages.Add(new Language() { code = "it", data = new List<string>(), });
languages.Add(new Language() { code = "de", data = new List<string>(), });
languages.Add(new Language() { code = "es", data = new List<string>(), });
languages.Add(new Language() { code = "pl", data = new List<string>(), });
languages.Add(new Language() { code = "dog", data = new List<string>(), });
}
public int Validate(string text)
{
#if UNITY_EDITOR
var timeStart = EditorApplication.timeSinceStartup;
#else
var timeStart = Time.realtimeSinceStartup;
#endif
var errors = 0;
for (int i = 0; i < languages.Count; ++i)
Debug.LogFormat("Localization.Validate: language {0} = {1}", i, languages[i].code);
var clean = text;
var seperators = new char[] { delimiter, };
var newlines = new char[] { '\n', };
clean = text.Replace("\r\n", "\n");
clean = text.Replace("\n", "\n");
var lines = text.Split(newlines);
Debug.LogFormat("Localization.Validate: validating {0} entries...", lines.Length);
for (int i = 0; i < lines.Length; ++i)
{
var line = lines[i];
var data = line.SplitE(delimiter, quote);
var last = errors;
if (string.IsNullOrWhiteSpace(line))
{
Debug.LogFormat("{0}: empty line", i + 1);
errors++;
continue;
}
if (line.Contains("||"))
{
Debug.LogFormat("{0}: double || found, likely error", i + 1);
errors++;
continue;
}
if (data.Length <= 0)
{
Debug.LogFormat("{0}: empty row", i + 1);
errors++;
continue;
}
if (data.Length < languages.Count)
{
Debug.LogFormat("{0}: missing language entry for {1} (found {2} of {3})", i + 1, data[0], data.Length, languages.Count);
errors++;
continue;
}
if (data.Length > languages.Count)
{
Debug.LogFormat("{0}: too many language entries for {1} (found {2} of {3})", i + 1, data[0], data.Length, languages.Count);
errors++;
continue;
}
for (int j = 0; j < data.Length; ++j)
{
if (string.IsNullOrWhiteSpace(data[j]))
{
Debug.LogFormat("{0}: missing data in key {1} for language {2}", i + 1, data[0], j);
errors++;
}
}
for (int j = 0; j < lines.Length; ++j)
{
if (j == i)
continue;
var lineCheck = lines[j];
var lineCheckSplit = lineCheck.Split(seperators);
if (lineCheckSplit.Length <= 0)
continue;
var lineCheckKey = lineCheckSplit[0];
if (lineCheckKey == data[0])
{
Debug.LogFormat("{0}: duplicate key {1}", i + 1, data[0]);
errors++;
}
}
if (last != errors)
continue;
//Debug.LogFormat("{0}: OK {1}", i + 1, data[0]);
}
#if UNITY_EDITOR
var timeEnd = EditorApplication.timeSinceStartup;
var timeTaken = (float)(timeEnd - timeStart);
#else
var timeTaken = Time.realtimeSinceStartup;
#endif
Debug.LogFormat("Localization.Validate: complete with {0} errors (took {1}ms)", errors, timeTaken * 1000.0f);
return errors;
}
public void Reimport(string text)
{
#if UNITY_EDITOR
var timeStart = EditorApplication.timeSinceStartup;
#else
var timeStart = Time.realtimeSinceStartup;
#endif
var clean = text;
var seperators = new char[] { delimiter, };
var newlines = new char[] { '\n', };
clean = text.Replace("\r\n", "\n");
clean = text.Replace("\n", "\n");
var lines = text.Split(newlines, System.StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < lines.Length; ++i)
{
var line = lines[i];
var data = line.SplitE(delimiter, quote);
var key = data[0];
languages[0].data.Add(key);
for (int j = 1; j < data.Length; ++j)
languages[j].data.Add(data[j]);
}
#if UNITY_EDITOR
var timeEnd = EditorApplication.timeSinceStartup;
var timeTaken = (float)(timeEnd - timeStart);
#else
var timeTaken = Time.realtimeSinceStartup;
#endif
Debug.LogFormat("Localization.Reimport: complete (took {0}ms)", timeTaken * 1000.0f);
}
public void RebuildLookup()
{
lookup = new Dictionary<string, int>();
var keys = languages[0].data;
for (int i = 0; i < keys.Count; ++i)
lookup.Add(keys[i], i);
}
#if UNITY_EDITOR
public string EditorGet(string key)
{
var keys = languages[0];
var language = languages[1];
for (int i = 0; i < keys.data.Count; ++i)
{
var k = keys.data[i];
if (k == key)
return languages[1].data[i];
}
return string.Format("!{0}!", key);
}
#endif
public string Get(string key)
{
#if UNITY_EDITOR
if (lookup.ContainsKey(key) == false)
{
Debug.LogErrorFormat("Localization: missing key request: {0}", key);
return string.Format("!{0}!", key);
}
#endif
var index = lookup[key];
var value = languages[languageIndex].data[index];
return value;
}
public string Get1(string key, object arg0)
{
#if UNITY_EDITOR
if (lookup.ContainsKey(key) == false)
{
Debug.LogErrorFormat("Localization: missing key request: {0}", key);
return string.Format("!{0}!", key);
}
#endif
var format = Get(key);
var value = string.Format(format, arg0);
return value;
}
public string Get2(string key, object arg0, object arg1)
{
#if UNITY_EDITOR
if (lookup.ContainsKey(key) == false)
{
Debug.LogErrorFormat("Localization: missing key request: {0}", key);
return string.Format("!{0}!", key);
}
#endif
var format = Get(key);
var value = string.Format(format, arg0, arg1);
return value;
}
public string Get3(string key, object arg0, object arg1, object arg2)
{
#if UNITY_EDITOR
if (lookup.ContainsKey(key) == false)
{
Debug.LogErrorFormat("Localization: missing key request: {0}", key);
return string.Format("!{0}!", key);
}
#endif
var format = Get(key);
var value = string.Format(format, arg0, arg1, arg2);
return value;
}
public void CycleLanguage()
{
ChangeLanguage((languageIndex + 1) % languages.Count);
}
public void ChangeLanguage(int index)
{
languageIndex = index;
foreach (var dynamic in Tracked<LocalizationDynamic>.Instances)
dynamic.Translate();
foreach (var character in Tracked<Character>.Instances)
character.SetupNametag();
}
public List<string> CollectKeysByPrefix(string prefix)
{
var results = new List<string>();
var keys = languages[0].data;
for (int i = 0; i < keys.Count; ++i)
{
var key = keys[i];
if (key.StartsWith(prefix))
results.Add(key);
}
return results;
}
#if UNITY_EDITOR
public static string EditorLocalizeGet(string key)
{
var obj = GameObject.FindObjectOfType<Localization>();
var value = obj.EditorGet(key);
return value;
}
#endif
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment