// Unity C# reference source // Copyright (c) Unity Technologies. For terms of use, see // https://unity3d.com/legal/licenses/Unity_Reference_Only_License using UnityEngine; using UnityEngine.Internal; using UnityEngine.Assertions; using System; using System.Collections.Generic; using System.Reflection; using JetBrains.Annotations; namespace UnityEditor { /// /// This provides Localization function. /// public static class L10n { static object lockObject = new object(); static Dictionary s_GroupNames = new Dictionary(128); private readonly struct LocKey : IEquatable { [NotNull] public readonly string defaultString; [NotNull] public readonly string groupName; public LocKey(string _defaultString, string _groupName) { defaultString = _defaultString ?? string.Empty; groupName = _groupName ?? string.Empty; } public bool Equals(LocKey other) { return defaultString == other.defaultString && groupName == other.groupName; } public override bool Equals(object obj) { return obj is LocKey other && Equals(other); } public override int GetHashCode() { unchecked { return (defaultString.GetHashCode() * 397) ^ groupName.GetHashCode(); } } } static Dictionary s_LocalizedStringCache = new Dictionary(10 << 10); internal static void ClearCache() { lock (lockObject) s_LocalizedStringCache.Clear(); } internal static string GetGroupName(System.Reflection.Assembly assembly) { if (assembly == null) return null; lock (lockObject) { if (!s_GroupNames.TryGetValue(assembly, out var name)) { var attrobjs = assembly.GetCustomAttributes(typeof(LocalizationAttribute), true /* inherit */); if (attrobjs.Length > 0 && attrobjs[0] != null) { var locAttr = (LocalizationAttribute)attrobjs[0]; string locGroupName = locAttr.locGroupName; if (locGroupName == null) locGroupName = assembly.GetName().Name; name = locGroupName; s_GroupNames[assembly] = name; } else { s_GroupNames[assembly] = null; } } return name; } } /// /// Get the translation for the given argument. /// The original string to be translated. /// public static string Tr(string str) { return Tr(str, Assembly.GetCallingAssembly()); } internal static string Tr(string str, object context) { return Tr(str, context?.GetType().Assembly); } internal static string Tr(string str, Assembly groupAssembly) { if (!LocalizationDatabase.enableEditorLocalization) return str; if (string.IsNullOrEmpty(str)) return str; lock (lockObject) { var groupName = GetGroupName(groupAssembly); var key = new LocKey(str, groupName); if (s_LocalizedStringCache.TryGetValue(key, out var localized)) return localized; localized = (groupName != null) ? LocalizationDatabase.GetLocalizedStringWithGroupName(str, groupName) : LocalizationDatabase.GetLocalizedString(str); s_LocalizedStringCache[key] = localized; return localized; } } /// /// Get the translation array for the given argument array. /// The original strings to be translated. /// public static string[] Tr(string[] str_list) { var res = new string[str_list.Length]; for (var i = 0; i < res.Length; ++i) res[i] = Tr(str_list[i]); return res; } /// /// Get the translation for the given argument. /// The original string to be translated. /// The specified group name for the translation. /// public static string Tr(string str, string groupName) { var new_str = LocalizationDatabase.GetLocalizedStringWithGroupName(str, groupName); return new_str; } [ExcludeFromDocs] public static string TrPath(string path) { string[] separatingChars = { "/" }; var result = new System.Text.StringBuilder(256); var items = path.Split(separatingChars, System.StringSplitOptions.RemoveEmptyEntries); for (var i = 0; i < items.Length; ++i) { result.Append(Tr(items[i])); if (i < items.Length - 1) result.Append("/"); } return result.ToString(); } [ExcludeFromDocs] public static GUIContent TextContent(string text, string tooltip = null, Texture icon = null) { if (!LocalizationDatabase.enableEditorLocalization) return EditorGUIUtility.TrTextContent(text, tooltip, icon); var groupName = GetGroupName(Assembly.GetCallingAssembly()); if (groupName != null) { var new_text = LocalizationDatabase.GetLocalizedStringWithGroupName(text, groupName); var new_tooltip = LocalizationDatabase.GetLocalizedStringWithGroupName(tooltip, groupName); var gc = new GUIContent(new_text); gc.tooltip = new_tooltip; gc.image = icon; return gc; } else { return EditorGUIUtility.TrTextContent(text, tooltip, icon); } } [ExcludeFromDocs] public static GUIContent TextContent(string text, string tooltip, string iconName) { if (!LocalizationDatabase.enableEditorLocalization) return EditorGUIUtility.TrTextContent(text, tooltip, iconName); var groupName = GetGroupName(Assembly.GetCallingAssembly()); if (groupName != null) { var new_text = LocalizationDatabase.GetLocalizedStringWithGroupName(text, groupName); var new_tooltip = LocalizationDatabase.GetLocalizedStringWithGroupName(tooltip, groupName); var gc = new GUIContent(new_text); gc.tooltip = new_tooltip; gc.image = EditorGUIUtility.LoadIconRequired(iconName); return gc; } else { return EditorGUIUtility.TrTextContent(text, tooltip, iconName); } } [ExcludeFromDocs] public static GUIContent TextContent(string text, Texture icon) { if (!LocalizationDatabase.enableEditorLocalization) return EditorGUIUtility.TrTextContentWithIcon(text, icon); var groupName = GetGroupName(Assembly.GetCallingAssembly()); if (groupName != null) { var new_text = LocalizationDatabase.GetLocalizedStringWithGroupName(text, groupName); var gc = new GUIContent(new_text); gc.image = icon; return gc; } else { return EditorGUIUtility.TrTextContentWithIcon(text, icon); } } [ExcludeFromDocs] public static GUIContent TextContentWithIcon(string text, Texture icon) { if (!LocalizationDatabase.enableEditorLocalization) return EditorGUIUtility.TrTextContentWithIcon(text, icon); var groupName = GetGroupName(Assembly.GetCallingAssembly()); if (groupName != null) { var new_text = LocalizationDatabase.GetLocalizedStringWithGroupName(text, groupName); var gc = new GUIContent(new_text); gc.image = icon; return gc; } else { return EditorGUIUtility.TrTextContentWithIcon(text, icon); } } [ExcludeFromDocs] public static GUIContent TextContentWithIcon(string text, string iconName) { if (!LocalizationDatabase.enableEditorLocalization) return EditorGUIUtility.TextContentWithIcon(text, iconName); var groupName = GetGroupName(Assembly.GetCallingAssembly()); if (groupName != null) { var new_text = LocalizationDatabase.GetLocalizedStringWithGroupName(text, groupName); var gc = new GUIContent(new_text); gc.image = EditorGUIUtility.LoadIconRequired(iconName); return gc; } else { return EditorGUIUtility.TextContentWithIcon(text, iconName); } } [ExcludeFromDocs] public static GUIContent TextContentWithIcon(string text, string tooltip, string iconName) { if (!LocalizationDatabase.enableEditorLocalization) return EditorGUIUtility.TrTextContentWithIcon(text, tooltip, iconName); var groupName = GetGroupName(Assembly.GetCallingAssembly()); if (groupName != null) { var new_text = LocalizationDatabase.GetLocalizedStringWithGroupName(text, groupName); var new_tooltip = LocalizationDatabase.GetLocalizedStringWithGroupName(tooltip, groupName); var gc = new GUIContent(new_text); gc.tooltip = new_tooltip; gc.image = EditorGUIUtility.LoadIconRequired(iconName); return gc; } else { return EditorGUIUtility.TrTextContentWithIcon(text, tooltip, iconName); } } [ExcludeFromDocs] public static GUIContent TextContentWithIcon(string text, string tooltip, Texture icon) { if (!LocalizationDatabase.enableEditorLocalization) return EditorGUIUtility.TrTextContentWithIcon(text, tooltip, icon); var groupName = GetGroupName(Assembly.GetCallingAssembly()); if (groupName != null) { var new_text = LocalizationDatabase.GetLocalizedStringWithGroupName(text, groupName); var new_tooltip = LocalizationDatabase.GetLocalizedStringWithGroupName(tooltip, groupName); var gc = new GUIContent(new_text); gc.tooltip = new_tooltip; gc.image = icon; return gc; } else { return EditorGUIUtility.TrTextContentWithIcon(text, tooltip, icon); } } [ExcludeFromDocs] public static GUIContent TextContentWithIcon(string text, string tooltip, MessageType messageType) { if (!LocalizationDatabase.enableEditorLocalization) return EditorGUIUtility.TrTextContentWithIcon(text, tooltip, messageType); var groupName = GetGroupName(Assembly.GetCallingAssembly()); if (groupName != null) { var new_text = LocalizationDatabase.GetLocalizedStringWithGroupName(text, groupName); var new_tooltip = LocalizationDatabase.GetLocalizedStringWithGroupName(tooltip, groupName); var gc = new GUIContent(new_text); gc.tooltip = new_tooltip; gc.image = EditorGUIUtility.GetHelpIcon(messageType); return gc; } else { return EditorGUIUtility.TrTextContentWithIcon(text, tooltip, messageType); } } [ExcludeFromDocs] public static GUIContent TextContentWithIcon(string text, MessageType messageType) { if (!LocalizationDatabase.enableEditorLocalization) return EditorGUIUtility.TrTextContentWithIcon(text, messageType); var groupName = GetGroupName(Assembly.GetCallingAssembly()); if (groupName != null) { var new_text = LocalizationDatabase.GetLocalizedStringWithGroupName(text, groupName); var gc = new GUIContent(new_text); gc.image = EditorGUIUtility.GetHelpIcon(messageType); return gc; } else { return EditorGUIUtility.TrTextContentWithIcon(text, messageType); } } [ExcludeFromDocs] public static GUIContent IconContent(string iconName, string tooltip = null) { if (!LocalizationDatabase.enableEditorLocalization) return EditorGUIUtility.TrIconContent(iconName, tooltip); var groupName = GetGroupName(Assembly.GetCallingAssembly()); if (groupName != null) { var new_tooltip = LocalizationDatabase.GetLocalizedStringWithGroupName(tooltip, groupName); var gc = new GUIContent(); gc.tooltip = new_tooltip; gc.image = EditorGUIUtility.LoadIconRequired(iconName); return gc; } else { return EditorGUIUtility.TrIconContent(iconName, tooltip); } } [ExcludeFromDocs] public static GUIContent IconContent(Texture icon, string tooltip = null) { if (!LocalizationDatabase.enableEditorLocalization) return EditorGUIUtility.TrIconContent(icon, tooltip); var groupName = GetGroupName(Assembly.GetCallingAssembly()); if (groupName != null) { var new_tooltip = LocalizationDatabase.GetLocalizedStringWithGroupName(tooltip, groupName); var gc = new GUIContent(); gc.tooltip = new_tooltip; gc.image = icon; return gc; } else { return EditorGUIUtility.TrIconContent(icon, tooltip); } } [ExcludeFromDocs] public static GUIContent TempContent(string t) { if (!LocalizationDatabase.enableEditorLocalization) return EditorGUIUtility.TempContent(t); var groupName = GetGroupName(Assembly.GetCallingAssembly()); if (groupName != null) { var new_t = LocalizationDatabase.GetLocalizedStringWithGroupName(t, groupName); return EditorGUIUtility.TempContent(new_t); } else { return EditorGUIUtility.TempContent(t); } } [ExcludeFromDocs] public static GUIContent[] TempContent(string[] texts) { if (!LocalizationDatabase.enableEditorLocalization) return EditorGUIUtility.TempContent(texts); var groupName = GetGroupName(Assembly.GetCallingAssembly()); if (groupName != null) { GUIContent[] retval = new GUIContent[texts.Length]; for (int i = 0; i < texts.Length; i++) { var new_t = LocalizationDatabase.GetLocalizedStringWithGroupName(texts[i], groupName); retval[i] = new GUIContent(new_t); } return retval; } else { return EditorGUIUtility.TempContent(texts); } } [ExcludeFromDocs] public static GUIContent[] TempContent(string[] texts, string[] tooltips) { if (!LocalizationDatabase.enableEditorLocalization) return EditorGUIUtility.TempContent(texts, tooltips); var groupName = GetGroupName(Assembly.GetCallingAssembly()); if (groupName != null) { GUIContent[] retval = new GUIContent[texts.Length]; for (int i = 0; i < texts.Length; i++) { var new_t = LocalizationDatabase.GetLocalizedStringWithGroupName(texts[i], groupName); var new_tooltip = LocalizationDatabase.GetLocalizedStringWithGroupName(tooltips[i], groupName); retval[i] = new GUIContent(new_t, new_tooltip); } return retval; } else { return EditorGUIUtility.TempContent(texts); } } } internal static class LocalizationGroupStack { static Stack s_GroupNameStack; public static void Push(string groupName) { if (s_GroupNameStack == null) s_GroupNameStack = new Stack(); if (s_GroupNameStack.Count >= 16) Assert.IsTrue(false); // check the leak. s_GroupNameStack.Push(groupName); LocalizationDatabase.SetContextGroupName(groupName); } public static void Pop() { if (s_GroupNameStack == null || s_GroupNameStack.Count <= 0) Assert.IsTrue(false); s_GroupNameStack.Pop(); if (s_GroupNameStack.Count > 0) { string top = s_GroupNameStack.Peek(); LocalizationDatabase.SetContextGroupName(top); } else LocalizationDatabase.SetContextGroupName(null); } } /// /// This provides an auto dispose Localization system. /// This can be called recursively. /// public class LocalizationGroup : IDisposable { string m_LocGroupName; bool m_Pushed = false; /// /// a current group name for the localization. /// public string locGroupName { get { return m_LocGroupName; } } /// /// Default constructor. /// public LocalizationGroup() { initialize(Assembly.GetCallingAssembly()); } /// /// constructor. /// group name will become the name of Assembly the behaviour belongs to. /// public LocalizationGroup(Behaviour behaviour) { if (behaviour != null) { System.Type type = behaviour.GetType(); initialize(type.Assembly); } } /// /// constructor. /// group name will become the name of Assembly the type belongs to. /// public LocalizationGroup(System.Type type) { initialize(type.Assembly); } /// /// constructor. /// group name will become the name of Assembly the obj belongs to. /// public LocalizationGroup(System.Object obj) { if (obj == null) return; initialize(obj.GetType().Assembly); } void initialize(System.Reflection.Assembly assembly) { string groupName = L10n.GetGroupName(assembly); LocalizationGroupStack.Push(groupName); m_Pushed = true; m_LocGroupName = groupName; } /// /// dispose current state. /// public void Dispose() { if (m_Pushed) LocalizationGroupStack.Pop(); } } } namespace UnityEditor.Localization.Editor { /// /// This provides Localization function for Packages. /// [System.Obsolete("Localization has been deprecated. Please use UnityEditor.L10n instead", true)] public static class Localization { /// /// get proper translation for the given argument. /// [System.Obsolete("Obsolete msg (UnityUpgradable) -> UnityEditor.L10n.Tr(*)", true)] public static string Tr(string str) { if (!LocalizationDatabase.enableEditorLocalization) return str; var assembly = Assembly.GetCallingAssembly(); object[] attrobjs = assembly.GetCustomAttributes(typeof(LocalizationAttribute), true /* inherit */); if (attrobjs != null && attrobjs.Length > 0 && attrobjs[0] != null) { LocalizationAttribute locAttr = (LocalizationAttribute)attrobjs[0]; string locGroupName = locAttr.locGroupName; if (locGroupName == null) locGroupName = assembly.GetName().Name; var new_str = LocalizationDatabase.GetLocalizedStringWithGroupName(str, locGroupName); return new_str; } return str; } } /// /// This provides an auto dispose Localization system. /// This can be called recursively. /// [System.Obsolete("LocalizationGroup has been deprecated. Please use UnityEditor.LocalizationGroup instead", true)] public class LocalizationGroup : IDisposable { string m_LocGroupName; bool m_Pushed = false; /// /// a current group name for the localization. /// public string locGroupName { get { return m_LocGroupName; } } /// /// Default constructor. /// public LocalizationGroup() { initialize(Assembly.GetCallingAssembly()); } /// /// constructor. /// group name will become the name of Assembly the behaviour belongs to. /// public LocalizationGroup(Behaviour behaviour) { if (behaviour != null) { System.Type type = behaviour.GetType(); initialize(type.Assembly); } } /// /// constructor. /// group name will become the name of Assembly the type belongs to. /// public LocalizationGroup(System.Type type) { initialize(type.Assembly); } /// /// constructor. /// group name will become the name of Assembly the obj belongs to. /// public LocalizationGroup(System.Object obj) { if (obj == null) return; initialize(obj.GetType().Assembly); } void initialize(System.Reflection.Assembly assembly) { string groupName = null; object[] attrobjs = assembly.GetCustomAttributes(typeof(LocalizationAttribute), true /* inherit */); if (attrobjs != null && attrobjs.Length > 0 && attrobjs[0] != null) // focus on only the first. { LocalizationAttribute locAttr = (LocalizationAttribute)attrobjs[0]; groupName = locAttr.locGroupName; if (groupName == null) groupName = assembly.GetName().Name; } LocalizationGroupStack.Push(groupName); m_Pushed = true; m_LocGroupName = groupName; } /// /// dispose current state. /// public void Dispose() { if (m_Pushed) LocalizationGroupStack.Pop(); } } }