初始化

This commit is contained in:
come
2025-07-26 16:56:42 +08:00
parent 8291dbb91c
commit fa81439a8c
2574 changed files with 328492 additions and 2170 deletions

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c123c665b73ed7c4999162c0d009550d
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,753 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
using UnityEngine.SceneManagement;
using Object = UnityEngine.Object;
namespace I2.Loc
{
public class GUITools
{
static public Color White = Color.white;
static public Color LightGray = Color.Lerp(Color.gray, Color.white, 0.5f);
static public Color DarkGray = Color.Lerp(Color.gray, Color.white, 0.2f);
static public Color LightYellow = Color.Lerp(Color.yellow, Color.white, 0.5f);
static public GUILayoutOption DontExpandWidth = GUILayout.ExpandWidth(false);
static public GUIContent EmptyContent = new GUIContent ();
static List<Action> mDelayedEditorCallbacks = new List<Action>();
#region Delayed Editor Callback
public static void DelayedCall( Action action )
{
if (mDelayedEditorCallbacks.Count == 0)
EditorApplication.update += OnDelayedCall;
mDelayedEditorCallbacks.Add(action);
}
static void OnDelayedCall()
{
EditorApplication.update -= OnDelayedCall;
var calls = mDelayedEditorCallbacks.ToArray();
mDelayedEditorCallbacks.Clear();
foreach (var call in calls)
call();
}
#endregion
#region Header
public delegate void fnOnToggled(bool enabled);
static public bool DrawHeader (string text, string key, bool ShowToggle=false, bool ToggleState=false, fnOnToggled OnToggle = null, string HelpURL=default(string), Color disabledColor = default(Color))
{
bool state = EditorPrefs.GetBool(key, false);
bool newState = DrawHeader (text, state, ShowToggle, ToggleState, OnToggle, HelpURL, disabledColor);
if (state!=newState) EditorPrefs.SetBool(key, newState);
return newState;
}
static public bool DrawHeader (string text, bool state, bool ShowToggle=false, bool ToggleState=false, fnOnToggled OnToggle = null, string HelpURL=default(string), Color disabledColor = default(Color), bool allowCollapsing = true)
{
GUIStyle Style = new GUIStyle(EditorStyles.foldout);
Style.richText = true;
EditorStyles.foldout.richText = true;
if (state)
{
//GUI.backgroundColor=DarkGray;
GUILayout.BeginVertical(LocalizeInspector.GUIStyle_OldTextArea/*, GUILayout.Height(1)*/);
GUILayout.BeginHorizontal();
if (!string.IsNullOrEmpty(text))
{
if (allowCollapsing)
state = GUILayout.Toggle(state, text, Style, GUILayout.ExpandWidth(true));
else
GUILayout.Label(text, GUILayout.ExpandWidth(true));
}
if (!string.IsNullOrEmpty(HelpURL))
{
if (GUILayout.Button (Icon_Help, EditorStyles.label, GUILayout.ExpandWidth(false)))
Application.OpenURL(HelpURL);
}
if (ShowToggle)
{
GUI.changed = false;
bool newBool = GUILayout.Toggle(ToggleState, "", "OL Toggle", GUILayout.ExpandWidth(false));
if (GUI.changed && OnToggle!=null)
OnToggle(newBool);
}
GUILayout.EndHorizontal();
GUILayout.Space(2);
//GUI.backgroundColor = Color.white;
}
else
{
if (ShowToggle && !ToggleState)
GUI.color = disabledColor;
GUILayout.BeginHorizontal("Box");
//GUILayout.BeginHorizontal(EditorStyles.toolbar);
state = GUILayout.Toggle(state, text, Style, GUILayout.ExpandWidth(true));
if (ShowToggle)
{
GUI.changed = false;
bool newBool = GUILayout.Toggle(ToggleState, "", "OL Toggle", GUILayout.ExpandWidth(false));
if (GUI.changed && OnToggle!=null)
OnToggle(newBool);
}
GUILayout.EndHorizontal();
GUI.color = White;
}
return state;
}
static public void CloseHeader()
{
GUILayout.EndHorizontal();
}
public static void OnGUI_Footer(string pluginName, string pluginVersion, string helpURL, string documentationURL, string assetStoreURL)
{
GUILayout.BeginHorizontal();
string versionTip = "";
/*if (I2Analytics.HasNewVersion(pluginName))
{
versionTip = "There is a new version of " + pluginName + ".\nClick here for more details";
if (GUILayout.Button(new GUIContent("", versionTip), EditorStyles.label, GUILayout.Width(25)))
I2AboutWindow.DoShowScreen();
var rect = GUILayoutUtility.GetLastRect();
rect.yMin = rect.yMax - 25;
rect.xMax = rect.xMin + 25;
rect.y += 3;
GUITools.DrawSkinIcon(rect, "CN EntryWarnIcon", "CN EntryWarn");
}*/
if (GUILayout.Button(new GUIContent("v" + pluginVersion, versionTip), EditorStyles.miniLabel))
{
Application.OpenURL(assetStoreURL);
//I2AboutWindow.DoShowScreen();
}
GUILayout.FlexibleSpace();
if (GUILayout.Button("Ask a Question", EditorStyles.miniLabel))
Application.OpenURL(helpURL);
GUILayout.Space(10);
if (GUILayout.Button("Documentation", EditorStyles.miniLabel))
Application.OpenURL(documentationURL);
GUILayout.EndHorizontal();
}
#endregion
#region Content
static public void BeginContents ()
{
EditorGUILayout.BeginHorizontal(LocalizeInspector.GUIStyle_OldTextArea, GUILayout.MinHeight(10f));
GUILayout.Space(2f);
EditorGUILayout.BeginVertical();
GUILayout.Space(2f);
}
static public void EndContents () { EndContents(true); }
static public void EndContents ( bool closeHeader )
{
GUILayout.Space(2f);
EditorGUILayout.EndVertical();
GUILayout.Space(3f);
GUILayout.EndHorizontal();
if (closeHeader) CloseHeader();
}
#endregion
#region Tabs
static public void DrawTabs( SerializedProperty mProperty, GUIStyle Style=null, int height=25 )
{
int curIndex = mProperty.enumValueIndex;
int newIndex = DrawTabs( curIndex, mProperty.enumNames, Style, height);
if (curIndex!=newIndex)
mProperty.enumValueIndex = newIndex;
}
static public int DrawTabs( int Index, string[] Tabs, GUIStyle Style=null, int height=25, bool expand = true)
{
GUIStyle MyStyle = new GUIStyle(Style!=null?Style:GUI.skin.FindStyle("dragtab"));
MyStyle.fixedHeight=0;
GUILayout.BeginHorizontal();
for (int i=0; i<Tabs.Length; ++i)
{
int idx = Tabs[i].IndexOf('|');
if (idx>0)
{
string text = Tabs[i].Substring(0, idx);
string tooltip = Tabs[i].Substring(idx+1);
if ( GUILayout.Toggle(Index==i, new GUIContent(text, tooltip), MyStyle, GUILayout.Height(height), GUILayout.ExpandWidth(expand)) && Index!=i)
{
Index=i;
GUI.FocusControl(string.Empty);
}
}
else
{
if ( GUILayout.Toggle(Index==i, Tabs[i], MyStyle, GUILayout.Height(height), GUILayout.ExpandWidth(expand)) && Index!=i)
{
Index=i;
GUI.FocusControl(string.Empty);
}
}
}
GUILayout.EndHorizontal();
return Index;
}
static public void DrawShadowedTabs( SerializedProperty mProperty, GUIStyle Style=null, int height=25, bool expand=true )
{
int curIndex = mProperty.enumValueIndex;
int newIndex = DrawShadowedTabs( curIndex, mProperty.enumNames, height, expand);
if (curIndex!=newIndex)
mProperty.enumValueIndex = newIndex;
}
static public int DrawShadowedTabs( int Index, string[] Tabs, int height = 25, bool expand=true )
{
GUI.backgroundColor=Color.Lerp (Color.gray, Color.white, 0.2f);
GUILayout.BeginVertical(LocalizeInspector.GUIStyle_OldTextArea, GUILayout.Height(1));
GUI.backgroundColor=Color.white;
GUILayout.Space(2);
Index = DrawTabs( Index, Tabs, height: height, expand:expand );
GUILayout.EndVertical();
return Index;
}
static public int DrawTabs( int Index, Texture2D[] Tabs, GUIStyle Style, int height )
{
GUIStyle MyStyle = new GUIStyle(Style!=null?Style:GUI.skin.FindStyle("dragtab"));
MyStyle.fixedHeight=0;
//width = Mathf.Max (width, height * Tabs[0].width/(float)Tabs[0].height);
GUILayout.BeginHorizontal();
float width = (EditorGUIUtility.currentViewWidth-(MyStyle.border.left+MyStyle.border.right)*(Tabs.Length-1)) / Tabs.Length;
for (int i=0; i<Tabs.Length; ++i)
{
if ( GUILayout.Toggle(Index==i, Tabs[i], MyStyle, GUILayout.Height(height), GUILayout.Width(width)) && Index!=i)
{
Index=i;
GUI.changed = true;
}
}
GUILayout.EndHorizontal();
return Index;
}
#endregion
#region Object Array
static public bool DrawObjectsArray( SerializedProperty PropArray, bool allowDuplicates=false, bool allowResources=false, bool allowSceneObj=false, Object testAdd=null, Object testReplace=null, int testReplaceIndex=-1, int testDeleteIndex=-1 )
{
bool hasChanged = false;
GUILayout.BeginVertical();
int DeleteElement = -1, MoveUpElement = -1;
for (int i=0, imax=PropArray.arraySize; i<imax; ++i)
{
SerializedProperty Prop = PropArray.GetArrayElementAtIndex(i);
GUILayout.BeginHorizontal();
//--[ Delete Button ]-------------------
if (GUILayout.Button("X", EditorStyles.toolbarButton, GUILayout.ExpandWidth(false)) || i == testDeleteIndex)
DeleteElement = i;
GUILayout.Space(2);
//--[ Object ]--------------------------
GUILayout.BeginHorizontal(EditorStyles.toolbar);
GUI.changed = false;
Object Obj = EditorGUILayout.ObjectField( Prop.objectReferenceValue, typeof(Object), allowSceneObj, GUILayout.ExpandWidth(true));
if (testReplaceIndex == i)
{
Obj = testReplace;
GUI.changed = true;
}
if (!allowResources && Obj != null)
{
var path = AssetDatabase.GetAssetPath(Obj);
if (path != null && path.Contains("/Resources/"))
Obj = null;
}
if (Obj==null)
DeleteElement = i;
else
if (GUI.changed && (allowDuplicates || !ObjectsArrayHasReference(PropArray, Obj)))
{
Prop.objectReferenceValue = Obj;
hasChanged = true;
}
GUILayout.EndHorizontal();
//--[ MoveUp Button ]-------------------
if (i==0)
{
if (imax>1)
GUILayout.Space (18);
}
else
{
if (GUILayout.Button( "\u25B2", EditorStyles.toolbarButton, GUILayout.Width(18)))
MoveUpElement = i;
}
GUILayout.EndHorizontal();
}
GUILayout.BeginHorizontal(EditorStyles.toolbar);
Object NewObj = EditorGUILayout.ObjectField( null, typeof(Object), allowSceneObj, GUILayout.ExpandWidth(true));
if (testAdd != null)
{
NewObj = testAdd;
}
if (!allowResources && NewObj != null)
{
var path = AssetDatabase.GetAssetPath(NewObj);
if (path != null && path.Contains("/Resources/"))
NewObj = null;
}
if (NewObj && (allowDuplicates || !ObjectsArrayHasReference(PropArray, NewObj)))
{
int Index = PropArray.arraySize;
PropArray.InsertArrayElementAtIndex( Index );
PropArray.GetArrayElementAtIndex(Index).objectReferenceValue = NewObj;
hasChanged = true;
}
GUILayout.EndHorizontal();
if (DeleteElement>=0)
{
PropArray.DeleteArrayElementAtIndex( DeleteElement );
//PropArray.DeleteArrayElementAtIndex( DeleteElement );
hasChanged = true;
}
if (MoveUpElement>=0)
{
PropArray.MoveArrayElement(MoveUpElement, MoveUpElement-1);
hasChanged = true;
}
GUILayout.EndVertical();
return hasChanged;
}
static public bool ObjectsArrayHasReference(SerializedProperty PropArray, Object obj)
{
for (int i = 0, imax = PropArray.arraySize; i < imax; ++i)
{
SerializedProperty Prop = PropArray.GetArrayElementAtIndex(i);
if (Prop.objectReferenceValue == obj)
return true;
}
return false;
}
#endregion
#region Toggle
static public int ToggleToolbar( int Index, string[] Options )
{
GUILayout.BeginHorizontal();
for (int i=0; i<Options.Length; ++i)
{
if ( GUILayout.Toggle(Index==i, Options[i], EditorStyles.toolbarButton))
Index=i;
}
GUILayout.EndHorizontal();
return Index;
}
static public void ToggleToolbar( SerializedProperty EnumVar )
{
int index = ToggleToolbar( EnumVar.enumValueIndex, EnumVar.enumNames);
if (EnumVar.enumValueIndex != index)
EnumVar.enumValueIndex = index;
}
#endregion
#region Misc
public static bool ObjectExistInScene( GameObject Obj )
{
return Obj.scene.IsValid() && Obj.scene.isLoaded;
/* //if (Obj.transform.root != Obj.transform)
// continue;
// We are only interested in GameObjects that are visible in the Hierachy panel and are persitent
if ((Obj.hideFlags & (HideFlags.DontSave|HideFlags.HideInHierarchy)) > 0)
return false;
// We are not interested in Prefab, unless they are Prefab Instances
PrefabType pfType = PrefabUtility.GetPrefabType(Obj);
if(pfType == PrefabType.Prefab || pfType == PrefabType.ModelPrefab)
return false;
// If the database contains the object then its not an scene object,
// but the previous test should get rid of them, so I will just comment this
// unless an false positive object is found in the future
//if (AssetDatabase.Contains(Obj))
// return false;
return true;*/
}
public static IEnumerable<GameObject> SceneRoots()
{
var prop = new HierarchyProperty(HierarchyType.GameObjects);
var expanded = new int[0];
while (prop.Next(expanded)) {
yield return prop.pptrValue as GameObject;
}
}
public static List<GameObject> SceneRootsList()
{
return new List<GameObject>(SceneRoots());
}
public static IEnumerable<Transform> AllSceneObjects()
{
var queue = new Queue<Transform>();
foreach (var root in SceneRoots()) {
var tf = root.transform;
yield return tf;
queue.Enqueue(tf);
}
while (queue.Count > 0) {
foreach (Transform child in queue.Dequeue()) {
yield return child;
queue.Enqueue(child);
}
}
}
public static string GetScenePath(Transform tr)
{
if (tr==null)
return string.Empty;
string path = tr.name;
while (tr.parent != null)
{
tr = tr.parent;
path = tr.name + "/" + path;
}
return path;
}
public static Transform FindObjectInEditor( string scenePath )
{
if (string.IsNullOrEmpty(scenePath))
return null;
int index = scenePath.IndexOfAny("/\\".ToCharArray());
string first = index<0 ? scenePath : scenePath.Substring(0, index);
foreach (var root in AllSceneObjects())
if (root.name==first)
{
if (index<0)
return root;
return root.Find(scenePath.Substring(index+1));
}
return null;
}
public static GUIContent Icon_Help {
get{
if (mIconHelp == null)
mIconHelp = EditorGUIUtility.IconContent("_Help");
return mIconHelp;
}
}
static GUIContent mIconHelp;
public static GUIStyle FindSkinStyle(string name)
{
var allStyles = GUI.skin.customStyles;
for (int i = 0, imax = allStyles.Length; i < imax; ++i)
{
if (allStyles[i].name == name)
return allStyles[i];
}
return null;
}
public static void DrawSkinIcon(Rect rect, params string[] iconNames)
{
foreach (var icon in iconNames)
{
var style = FindSkinStyle(icon);
if (style == null || style.normal == null || style.normal.background == null)
continue;
GUI.DrawTexture(rect, style.normal.background);
return;
}
//Debug.Log("unable to find icon");
}
#endregion
#region Angle Drawer
private static Vector2 mAngle_lastMousePosition;
static Texture mAngle_TextureCircle;
static Texture pAngle_TextureCircle {
get{
if (mAngle_TextureCircle) return mAngle_TextureCircle;
mAngle_TextureCircle = GUI.skin.GetStyle("CN CountBadge").normal.background;
return mAngle_TextureCircle;
}
}
public static float FloatAngle(Rect rect, float value)
{
return FloatAngle(rect, value, -1, -1, -1);
}
public static float FloatAngle(Rect rect, float value, float snap)
{
return FloatAngle(rect, value, snap, -1, -1);
}
public static float FloatAngle(Rect rect, float value, float snap, float min, float max)
{
int id = GUIUtility.GetControlID(FocusType.Passive, rect);
Rect knobRect = new Rect(rect.x, rect.y, rect.height, rect.height);
float delta;
if (min != max)
delta = (max - min) / 360;
else
delta = 1;
if (Event.current != null)
{
if (Event.current.type == EventType.MouseDown && knobRect.Contains(Event.current.mousePosition))
{
GUIUtility.hotControl = id;
mAngle_lastMousePosition = Event.current.mousePosition;
}
else if (Event.current.type == EventType.MouseUp && GUIUtility.hotControl == id)
GUIUtility.hotControl = -1;
else if (Event.current.type == EventType.MouseDrag && GUIUtility.hotControl == id)
{
Vector2 move = mAngle_lastMousePosition - Event.current.mousePosition;
value += delta * (-move.x - move.y);
if (snap > 0)
{
float mod = value % snap;
if (mod < delta * 3 || Mathf.Abs(mod - snap) < delta * 3)
value = Mathf.Round(value / snap) * snap;
}
mAngle_lastMousePosition = Event.current.mousePosition;
GUI.changed = true;
}
}
if (pAngle_TextureCircle) GUI.DrawTexture(knobRect, pAngle_TextureCircle);
Matrix4x4 matrix = GUI.matrix;
if (min != max)
GUIUtility.RotateAroundPivot(value * (360 / (max - min)), knobRect.center);
else
GUIUtility.RotateAroundPivot(value, knobRect.center);
knobRect.height = 5;
knobRect.width = 5;
if (pAngle_TextureCircle) GUI.DrawTexture(knobRect, pAngle_TextureCircle);
GUI.matrix = matrix;
Rect label = new Rect(rect.x + rect.height, rect.y + rect.height / 2 - 9, rect.height, 18);
value = EditorGUI.FloatField(label, value);
if (min != max)
value = Mathf.Clamp(value, min, max);
return value;
}
public static float AngleCircle(Rect rect, float angle, float snap, float min, float max, Texture background=null, Texture knobLine=null)
{
Rect knobRect = new Rect(rect.x, rect.y, rect.height, rect.height);
float delta;
if (min != max)
delta = (max - min) / 360;
else
delta = 1;
if (Event.current != null && GUIUtility.hotControl<=0 && (Event.current.type==EventType.MouseDown || Event.current.type==EventType.MouseDrag) && knobRect.Contains(Event.current.mousePosition))
{
angle = Vector2.Angle( Vector2.right, Event.current.mousePosition-knobRect.center);
if (Event.current.mousePosition.y<knobRect.center.y) angle = 360-angle;
if (Event.current.alt || Event.current.control)
snap = 5;
if (snap > 0)
{
float mod = Mathf.Repeat(angle, snap);
if (mod < delta * 3 || Mathf.Abs(mod - snap) < delta * 3)
angle = Mathf.Round(angle / snap) * snap;
}
GUI.changed = true;
}
if (background==null) background = pAngle_TextureCircle;
if (background) GUI.DrawTexture (knobRect, background);
Matrix4x4 matrix = GUI.matrix;
if (min != max)
GUIUtility.RotateAroundPivot(angle * (360 / (max - min))+90, knobRect.center);
else
GUIUtility.RotateAroundPivot(angle+90, knobRect.center);
float Radius = Mathf.Min (knobRect.width, knobRect.height) * 0.5f;
knobRect.x = knobRect.x + 0.5f * knobRect.width - 4;
knobRect.y += 2;
knobRect.width = 8;
knobRect.height = Radius+2;
if (knobLine == null)
knobLine = GUI.skin.FindStyle ("MeBlendPosition").normal.background;
if (knobLine) GUI.DrawTexture(knobRect, knobLine);
GUI.matrix = matrix;
return Mathf.Repeat(angle, 360);
}
#endregion
#region Unity Version branching
public static string Editor_GetCurrentScene()
{
#if UNITY_4_6 || UNITY_4_7 || UNITY_4_8 || UNITY_4_9 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2
return EditorApplication.currentScene;
#else
return SceneManager.GetActiveScene().path;
#endif
}
public static void Editor_MarkSceneDirty()
{
#if UNITY_5_3 || UNITY_5_3_OR_NEWER
EditorSceneManager.MarkSceneDirty(SceneManager.GetActiveScene());
#else
EditorApplication.MarkSceneDirty();
#endif
}
public static void Editor_SaveScene()
{
#if UNITY_4_6 || UNITY_4_7 || UNITY_4_8 || UNITY_4_9 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2
EditorApplication.SaveScene ();
#else
EditorSceneManager.SaveOpenScenes();
#endif
}
public static void Editor_OpenScene( string sceneName )
{
#if UNITY_4_6 || UNITY_4_7 || UNITY_4_8 || UNITY_4_9 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2
EditorApplication.OpenScene( sceneName );
#else
EditorSceneManager.OpenScene(sceneName);
#endif
}
#endregion
#region Reflection
static public object Reflection_InvokeMethod ( object instanceObject, string methodName, params object[] p_args )
{
BindingFlags _flags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static;
MethodInfo mi = instanceObject.GetType().GetMethods( _flags ).Where( x => x.Name==methodName ).FirstOrDefault();
if (mi == null) return null;
return mi.Invoke( instanceObject, p_args );
}
static public object Reflection_InvokeMethod ( Type targetType, string methodName, params object[] p_args )
{
BindingFlags _flags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static;
MethodInfo mi = targetType.GetMethods( _flags ).Where( x => x.Name==methodName ).FirstOrDefault();
if (mi == null) return null;
return mi.Invoke( null, p_args );
}
public static object s_RecycledEditor;
public static string TextField ( Rect position, string text, int maxLength, GUIStyle style, int controlID )
{
if (s_RecycledEditor==null)
{
FieldInfo info = typeof(EditorGUI).GetField("s_RecycledEditor", BindingFlags.NonPublic | BindingFlags.Static);
s_RecycledEditor = info.GetValue(null);
}
if (s_RecycledEditor == null)
return "";
return Reflection_InvokeMethod( typeof( EditorGUI ), "DoTextField", s_RecycledEditor, controlID, position, text, style, null, false, false, false, false ) as string;
}
static public void RepaintInspectors()
{
EditorApplication.update -= RepaintInspectors;
var assemblyEditor = Assembly.GetAssembly(typeof(Editor));
var typeInspectorWindow = assemblyEditor.GetType("UnityEditor.InspectorWindow");
typeInspectorWindow.GetMethod("RepaintAllInspectors", BindingFlags.NonPublic | BindingFlags.Static).Invoke(null, null);
}
public static void ScheduleRepaintInspectors()
{
EditorApplication.update += RepaintInspectors;
}
#endregion
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: df33c1000ac895241a433812e40a2096
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,19 @@
{
"name": "I2Localization.Editor",
"rootNamespace": "",
"references": [
"GUID:6055be8ebefd69e48b49212b09b47b2f",
"GUID:066973baa5a5b4943a2744b71a191628"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 6fde2318276ffa54ea24278440b996f0
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: a500716e59f61824ba1fa6b418ce31a7
folderAsset: yes
timeCreated: 1461137613
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,20 @@
using UnityEditor;
namespace I2.Loc
{
[CustomEditor(typeof(LanguageSourceAsset))]
public class LanguageSourceAssetInspector : LocalizationEditor
{
void OnEnable()
{
var newSource = target as LanguageSourceAsset;
SerializedProperty propSource = serializedObject.FindProperty("mSource");
Custom_OnEnable(newSource.mSource, propSource);
}
public override LanguageSourceData GetSourceData()
{
return (target as LanguageSourceAsset).mSource;
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: f03a75bf70a306a4fb36646f24c1c1f1
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,22 @@
using UnityEditor;
namespace I2.Loc
{
[CustomEditor(typeof(LanguageSource))]
public class LanguageSourceInspector : LocalizationEditor
{
void OnEnable()
{
var newSource = target as LanguageSource;
SerializedProperty propSource = serializedObject.FindProperty("mSource");
Custom_OnEnable(newSource.mSource, propSource);
}
public override LanguageSourceData GetSourceData()
{
return (target as LanguageSource).mSource;
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: a441ed994a43a0a4a9d33be67a8d3f15
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,199 @@
using UnityEditor;
using UnityEngine;
namespace I2.Loc
{
public abstract partial class LocalizationEditor : Editor
{
#region Variables
SerializedProperty mProp_Assets, mProp_Languages,
mProp_Google_WebServiceURL, mProp_GoogleUpdateFrequency, mProp_GoogleUpdateDelay, mProp_Google_SpreadsheetKey, mProp_Google_SpreadsheetName, mProp_Google_Password,
mProp_Spreadsheet_LocalFileName, mProp_Spreadsheet_LocalCSVSeparator, mProp_CaseInsensitiveTerms, mProp_Spreadsheet_LocalCSVEncoding,
mProp_OnMissingTranslation, mProp_AppNameTerm, mProp_IgnoreDeviceLanguage, mProp_Spreadsheet_SpecializationAsRows, mProp_GoogleInEditorCheckFrequency,
mProp_HighlightLocalizedTargets, mProp_GoogleLiveSyncIsUptoDate, mProp_AllowUnloadingLanguages, mProp_GoogleUpdateSynchronization;
public static LanguageSourceData mLanguageSource;
public static Object mLanguageSourceObject;
public static LocalizationEditor mLanguageSourceEditor;
public static Editor mCurrentInspector;
static bool mIsParsing; // This is true when the editor is opening several scenes to avoid reparsing objects
#endregion
#region Variables GUI
GUIStyle Style_ToolBar_Big, Style_ToolBarButton_Big;
public GUISkin CustomSkin;
static Vector3 mScrollPos_Languages;
public static string mLanguages_NewLanguage = "";
#endregion
#region Styles
public static GUIStyle Style_WrapTextField {
get{
if (mStyle_WrapTextField==null)
{
mStyle_WrapTextField = new GUIStyle(EditorStyles.textArea);
mStyle_WrapTextField.wordWrap = true;
mStyle_WrapTextField.fixedHeight = 0;
}
return mStyle_WrapTextField;
}
}
static GUIStyle mStyle_WrapTextField;
#endregion
#region Inspector
public void Custom_OnEnable( LanguageSourceData sourceData, SerializedProperty propSource)
{
bool ForceParse = mLanguageSource != sourceData;
mLanguageSource = sourceData;
mLanguageSourceEditor = this;
mCurrentInspector = this;
if (!LocalizationManager.Sources.Contains(mLanguageSource))
LocalizationManager.UpdateSources();
mProp_Assets = propSource.FindPropertyRelative("Assets");
mProp_Languages = propSource.FindPropertyRelative("mLanguages");
mProp_Google_WebServiceURL = propSource.FindPropertyRelative("Google_WebServiceURL");
mProp_GoogleUpdateFrequency = propSource.FindPropertyRelative("GoogleUpdateFrequency");
mProp_GoogleUpdateSynchronization = propSource.FindPropertyRelative("GoogleUpdateSynchronization");
mProp_GoogleInEditorCheckFrequency = propSource.FindPropertyRelative("GoogleInEditorCheckFrequency");
mProp_GoogleUpdateDelay = propSource.FindPropertyRelative("GoogleUpdateDelay");
mProp_Google_SpreadsheetKey = propSource.FindPropertyRelative("Google_SpreadsheetKey");
mProp_Google_SpreadsheetName = propSource.FindPropertyRelative("Google_SpreadsheetName");
mProp_Google_Password = propSource.FindPropertyRelative("Google_Password");
mProp_CaseInsensitiveTerms = propSource.FindPropertyRelative("CaseInsensitiveTerms");
mProp_Spreadsheet_LocalFileName = propSource.FindPropertyRelative("Spreadsheet_LocalFileName");
mProp_Spreadsheet_LocalCSVSeparator = propSource.FindPropertyRelative("Spreadsheet_LocalCSVSeparator");
mProp_Spreadsheet_LocalCSVEncoding = propSource.FindPropertyRelative("Spreadsheet_LocalCSVEncoding");
mProp_Spreadsheet_SpecializationAsRows = propSource.FindPropertyRelative("Spreadsheet_SpecializationAsRows");
mProp_OnMissingTranslation = propSource.FindPropertyRelative("OnMissingTranslation");
mProp_AppNameTerm = propSource.FindPropertyRelative("mTerm_AppName");
mProp_IgnoreDeviceLanguage = propSource.FindPropertyRelative("IgnoreDeviceLanguage");
mProp_GoogleLiveSyncIsUptoDate = propSource.FindPropertyRelative("GoogleLiveSyncIsUptoDate");
mProp_AllowUnloadingLanguages = propSource.FindPropertyRelative("_AllowUnloadingLanguages");
if (!mIsParsing)
{
if (string.IsNullOrEmpty(mLanguageSource.Google_SpreadsheetKey))
mSpreadsheetMode = eSpreadsheetMode.Local;
else
mSpreadsheetMode = eSpreadsheetMode.Google;
mCurrentViewMode = mLanguageSource.mLanguages.Count>0 ? eViewMode.Keys : eViewMode.Languages;
UpdateSelectedKeys();
if (ForceParse || mParsedTerms.Count < mLanguageSource.mTerms.Count)
{
mSelectedCategories.Clear();
ParseTerms(true, false, true);
}
}
ScheduleUpdateTermsToShowInList();
LoadSelectedCategories();
//UpgradeManager.EnablePlugins();
}
void OnDisable()
{
//LocalizationManager.LocalizeAll();
SaveSelectedCategories();
mLanguageSourceEditor = null;
if (mCurrentInspector==this) mCurrentInspector = null;
}
void UpdateSelectedKeys()
{
// Remove all keys that are not in this source
string trans;
for (int i=mSelectedKeys.Count-1; i>=0; --i)
if (!mLanguageSource.TryGetTranslation(mSelectedKeys[i], out trans))
mSelectedKeys.RemoveAt(i);
// Remove all Categories that are not in this source
/*var mCateg = mLanguageSource.GetCategories();
for (int i=mSelectedCategories.Count-1; i>=0; --i)
if (!mCateg.Contains(mSelectedCategories[i]))
mSelectedCategories.RemoveAt(i);
if (mSelectedCategories.Count==0)
mSelectedCategories = mCateg;*/
if (mSelectedScenes.Count==0)
mSelectedScenes.Add (Editor_GetCurrentScene());
}
public override void OnInspectorGUI()
{
// Load Test:
/*if (mLanguageSource.mTerms.Count<40000)
{
mLanguageSource.mTerms.Clear();
for (int i=0; i<40020; ++i)
mLanguageSource.AddTerm("ahh"+i.ToString("00000"), eTermType.Text, false);
mLanguageSource.UpdateDictionary();
}*/
//Profiler.maxNumberOfSamplesPerFrame = -1; // REMOVE ---------------------------------------------------
mIsParsing = false;
//#if UNITY_5_6_OR_NEWER
// serializedObject.UpdateIfRequiredOrScript();
//#else
// serializedObject.UpdateIfDirtyOrScript();
//#endif
if (mLanguageSource.mTerms.Count<1000)
Undo.RecordObject(target, "LanguageSource");
//GUI.backgroundColor = Color.Lerp (Color.black, Color.gray, 1);
//GUILayout.BeginVertical(LocalizeInspector.GUIStyle_Background);
//GUI.backgroundColor = Color.white;
if (GUILayout.Button("Language Source", LocalizeInspector.GUIStyle_Header))
{
Application.OpenURL(LocalizeInspector.HelpURL_Documentation);
}
InitializeStyles();
GUILayout.Space(10);
//GUI.backgroundColor = Color.Lerp(GUITools.LightGray, Color.white, 0.5f);
//GUILayout.BeginVertical(LocalizeInspector.GUIStyle_Background);
//GUI.backgroundColor = Color.white;
OnGUI_Main();
//GUILayout.EndVertical();
GUILayout.Space (10);
GUILayout.FlexibleSpace();
GUITools.OnGUI_Footer("I2 Localization", LocalizationManager.GetVersion(), LocalizeInspector.HelpURL_forum, LocalizeInspector.HelpURL_Documentation, LocalizeInspector.HelpURL_AssetStore);
//GUILayout.EndVertical();
serializedObject.ApplyModifiedProperties();
if (Event.current.type == EventType.Repaint)
{
mTestAction = eTest_ActionType.None;
mTestActionArg = null;
mTestActionArg2 = null;
}
}
#endregion
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 90c932abd0dc445448366dfe101408ba
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,107 @@
using UnityEditor;
using UnityEditorInternal;
using UnityEngine;
namespace I2.Loc
{
[CustomEditor(typeof(LocalizationParamsManager))]
public class LocalizationParamsManagerInspector : Editor
{
private ReorderableList mList;
private SerializedProperty mProp_IsGlobalManager;
private ReorderableList getList(SerializedObject serObject)
{
if (mList == null) {
mList = new ReorderableList (serObject, serObject.FindProperty ("_Params"), true, true, true, true);
mList.drawElementCallback = drawElementCallback;
mList.drawHeaderCallback = drawHeaderCallback;
mList.onAddCallback = addElementCallback;
mList.onRemoveCallback = removeElementCallback;
}
else
{
mList.serializedProperty = serObject.FindProperty ("_Params");
}
return mList;
}
private void addElementCallback( ReorderableList list )
{
serializedObject.ApplyModifiedProperties();
var objParams = target as LocalizationParamsManager;
objParams._Params.Add(new LocalizationParamsManager.ParamValue());
list.index = objParams._Params.Count - 1;
serializedObject.Update();
}
private void removeElementCallback( ReorderableList list )
{
if (list.index < 0)
return;
serializedObject.ApplyModifiedProperties();
var objParams = target as LocalizationParamsManager;
objParams._Params.RemoveAt(list.index);
serializedObject.Update();
}
private void drawHeaderCallback(Rect rect)
{
GUI.Label(rect, "Parameters:");
}
private void drawElementCallback(Rect rect, int index, bool isActive, bool isFocused)
{
var serializedElement = mList.serializedProperty.GetArrayElementAtIndex (index);
var content = new GUIContent ();
Rect r = rect; r.xMax = r.xMin+40;
GUI.Label(r, "Name");
r = rect; r.xMax = (r.xMax + r.xMin)/2 - 2; r.xMin = r.xMin+40;
EditorGUI.PropertyField (r, serializedElement.FindPropertyRelative ("Name"),content);
r = rect; r.xMin = (r.xMax + r.xMin) / 2 + 2; r.xMax = r.xMin+40;
GUI.Label(r, "Value");
r = rect; r.xMin = (r.xMax + r.xMin)/2 + 2 + 40;
EditorGUI.PropertyField (r, serializedElement.FindPropertyRelative ("Value"), content);
}
void OnEnable()
{
mList = getList(serializedObject);
mProp_IsGlobalManager = serializedObject.FindProperty("_IsGlobalManager");
}
public override void OnInspectorGUI()
{
#if UNITY_5_6_OR_NEWER
serializedObject.UpdateIfRequiredOrScript();
#else
serializedObject.UpdateIfDirtyOrScript();
#endif
GUI.backgroundColor = Color.Lerp (Color.black, Color.gray, 1);
GUILayout.BeginVertical(LocalizeInspector.GUIStyle_Background);
GUI.backgroundColor = Color.white;
if (GUILayout.Button("Dynamic Parameters", LocalizeInspector.GUIStyle_Header))
{
Application.OpenURL(LocalizeInspector.HelpURL_Documentation);
}
GUILayout.Space(5);
mProp_IsGlobalManager.boolValue = EditorGUILayout.Popup(new GUIContent("Manager Type", "本地管理器只对同一个游戏对象中的本地化组件应用参数\nLocal Manager only apply parameters to the Localize component in the same GameObject\n\n全局管理器将参数应用于所有本地化组件\nGlobal Manager apply parameters to all Localize components"), mProp_IsGlobalManager.boolValue ? 1 : 0, new[] { new GUIContent("Local"), new GUIContent("Global") }) == 1;
GUILayout.Space(5);
mList.DoLayoutList();
//EditorGUILayout.PropertyField(serializedObject.FindProperty("_AutoRegister"), new GUIContent("Auto Register"));
GUILayout.EndVertical();
serializedObject.ApplyModifiedProperties();
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 93f1f9aecf6f7ed40ad1a082c22c47e5
timeCreated: 1468111539
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,131 @@
using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEditorInternal;
using UnityEngine;
namespace I2.Loc
{
#if !UNITY_5_0 && !UNITY_5_1
[CustomEditor(typeof(LocalizeDropdown))]
public class LocalizeDropdownInspector : Editor
{
private ReorderableList mList;
private List<string> terms;
private ReorderableList getList(SerializedObject serObject)
{
if (mList == null) {
mList = new ReorderableList (serObject, serObject.FindProperty ("_Terms"), true, true, true, true);
mList.drawElementCallback = drawElementCallback;
mList.drawHeaderCallback = drawHeaderCallback;
mList.onAddCallback = addElementCallback;
mList.onRemoveCallback = removeElementCallback;
}
else
{
mList.serializedProperty = serObject.FindProperty ("_Terms");
}
return mList;
}
private void addElementCallback( ReorderableList list )
{
serializedObject.ApplyModifiedProperties();
var objParams = target as LocalizeDropdown;
objParams._Terms.Add(string.Empty);
list.index = objParams._Terms.Count - 1;
serializedObject.Update();
}
private void removeElementCallback( ReorderableList list )
{
if (list.index < 0)
return;
serializedObject.ApplyModifiedProperties();
var objParams = target as LocalizeDropdown;
objParams._Terms.RemoveAt(list.index);
serializedObject.Update();
}
private void drawHeaderCallback(Rect rect)
{
GUI.Label(rect, "Terms:");
}
private void drawElementCallback(Rect rect, int index, bool isActive, bool isFocused)
{
var serializedElement = mList.serializedProperty.GetArrayElementAtIndex (index);
EditorGUI.BeginChangeCheck ();
var prvIndex = serializedElement.stringValue == "-" || serializedElement.stringValue == "" ? terms.Count - 1 :
serializedElement.stringValue == " " ? terms.Count - 2 :
terms.IndexOf(serializedElement.stringValue);
var newIndex = EditorGUI.Popup(rect, prvIndex, terms.ToArray());
if (EditorGUI.EndChangeCheck ())
{
if (newIndex == terms.Count - 1)
serializedElement.stringValue = "-";
else
if (newIndex < 0 || newIndex == terms.Count - 2)
serializedElement.stringValue = string.Empty;
else
serializedElement.stringValue = terms[newIndex];
}
}
void OnEnable()
{
mList = getList(serializedObject);
}
public override void OnInspectorGUI()
{
#if UNITY_5_6_OR_NEWER
serializedObject.UpdateIfRequiredOrScript();
#else
serializedObject.UpdateIfDirtyOrScript();
#endif
terms = LocalizationManager.GetTermsList ();
terms.Sort(StringComparer.OrdinalIgnoreCase);
terms.Add("");
terms.Add("<inferred from text>");
terms.Add("<none>");
GUI.backgroundColor = Color.Lerp (Color.black, Color.gray, 1);
GUILayout.BeginVertical(LocalizeInspector.GUIStyle_Background);
GUI.backgroundColor = Color.white;
if (GUILayout.Button("Localize DropDown", LocalizeInspector.GUIStyle_Header))
{
Application.OpenURL(LocalizeInspector.HelpURL_Documentation);
}
GUILayout.Space(5);
mList.DoLayoutList();
GUILayout.Space (10);
GUITools.OnGUI_Footer("I2 Localization", LocalizationManager.GetVersion(), LocalizeInspector.HelpURL_forum, LocalizeInspector.HelpURL_Documentation, LocalizeInspector.HelpURL_AssetStore);
EditorGUIUtility.labelWidth = 0;
GUILayout.EndVertical();
serializedObject.ApplyModifiedProperties();
terms = null;
}
}
#endif
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 65bbef08e6e42d24d9834945c3769202
timeCreated: 1468111539
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,896 @@
//#define UGUI
//#define NGUI
//#define DFGUI
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEngine;
using Object = UnityEngine.Object;
namespace I2.Loc
{
[CustomEditor(typeof(Localize))]
[CanEditMultipleObjects]
public class LocalizeInspector : Editor
{
#region Variables
Localize mLocalize;
SerializedProperty mProp_mTerm, mProp_mTermSecondary,
mProp_TranslatedObjects, mProp_LocalizeOnAwake, mProp_AlwaysForceLocalize, mProp_AllowLocalizedParameters, mProp_AllowParameters,
mProp_IgnoreRTL, mProp_MaxCharactersInRTL, mProp_CorrectAlignmentForRTL, mProp_IgnoreNumbersInRTL, mProp_TermSuffix, mProp_TermPrefix, mProp_SeparateWords,
mProp_CallbackEvent;
bool mAllowEditKeyName;
string mNewKeyName = "";
string[] mTermsArray;
public static string HelpURL_forum = "http://goo.gl/Uiyu8C";//http://www.inter-illusion.com/forum/i2-localization";
public static string HelpURL_Documentation = "http://www.inter-illusion.com/assets/I2LocalizationManual/I2LocalizationManual.html";
public static string HelpURL_Tutorials = "http://inter-illusion.com/tools/i2-localization";
public static string HelpURL_ReleaseNotes = "http://inter-illusion.com/forum/i2-localization/26-release-notes";
public static string HelpURL_AssetStore = "https://www.assetstore.unity3d.com/#!/content/14884";
public static LocalizeInspector mLocalizeInspector;
#endregion
#region Inspector
void OnEnable()
{
mLocalize = (Localize)target;
mLocalizeInspector = this;
LocalizationEditor.mCurrentInspector = this;
mProp_mTerm = serializedObject.FindProperty("mTerm");
mProp_mTermSecondary = serializedObject.FindProperty("mTermSecondary");
mProp_TranslatedObjects = serializedObject.FindProperty("TranslatedObjects");
mProp_IgnoreRTL = serializedObject.FindProperty("IgnoreRTL");
mProp_SeparateWords = serializedObject.FindProperty("AddSpacesToJoinedLanguages");
mProp_MaxCharactersInRTL = serializedObject.FindProperty ("MaxCharactersInRTL");
mProp_IgnoreNumbersInRTL = serializedObject.FindProperty("IgnoreNumbersInRTL");
mProp_CorrectAlignmentForRTL = serializedObject.FindProperty ("CorrectAlignmentForRTL");
mProp_LocalizeOnAwake = serializedObject.FindProperty("LocalizeOnAwake");
mProp_AlwaysForceLocalize = serializedObject.FindProperty("AlwaysForceLocalize");
mProp_TermSuffix = serializedObject.FindProperty("TermSuffix");
mProp_TermPrefix = serializedObject.FindProperty("TermPrefix");
mProp_CallbackEvent = serializedObject.FindProperty("LocalizeEvent");
mProp_AllowLocalizedParameters = serializedObject.FindProperty("AllowLocalizedParameters");
mProp_AllowParameters = serializedObject.FindProperty("AllowParameters");
if (LocalizationManager.Sources.Count==0)
LocalizationManager.UpdateSources();
//LocalizationEditor.ParseTerms (true);
//mGUI_ShowReferences = (mLocalize.TranslatedObjects!=null && mLocalize.TranslatedObjects.Length>0);
//mGUI_ShowCallback = (mLocalize.LocalizeCallBack.Target!=null);
//mGUI_ShowTems = true;
LocalizationEditor.mKeysDesc_AllowEdit = false;
GUI_SelectedTerm = 0;
mNewKeyName = mLocalize.Term;
if (mLocalize.Source != null)
LocalizationEditor.mLanguageSource = mLocalize.Source.SourceData;
else
{
if (LocalizationManager.Sources.Count==0)
LocalizationManager.UpdateSources();
LocalizationEditor.mLanguageSource = LocalizationManager.GetSourceContaining( mLocalize.Term );
}
//UpgradeManager.EnablePlugins();
LocalizationEditor.ApplyInferredTerm (mLocalize);
RemoveUnusedReferences(mLocalize);
}
void OnDisable()
{
mLocalizeInspector = null;
if (LocalizationEditor.mCurrentInspector == this) LocalizationEditor.mCurrentInspector = null;
if (mLocalize == null)
return;
//#if TextMeshPro
//string previous = null;
//if (!Application.isPlaying && !string.IsNullOrEmpty(mLocalize.TMP_previewLanguage))
//{
// previous = LocalizationManager.CurrentLanguage;
// LocalizationManager.PreviewLanguage( mLocalize.TMP_previewLanguage );
//}
//#endif
//mLocalize.OnLocalize();
// Revert the preview language
// except when in TMPro and not changing to another GameObject (TMPro has a bug where any change causes the inspector to Disable and Enable)
if (!mLocalize.mLocalizeTargetName.Contains("LocalizeTarget_TextMeshPro") || Selection.activeGameObject==null || !Selection.gameObjects.Contains(mLocalize.gameObject))
{
LocalizationManager.LocalizeAll();
}
//#if TextMeshPro
//if (!string.IsNullOrEmpty(previous))
//{
// LocalizationManager.PreviewLanguage(previous);
// mLocalize.TMP_previewLanguage = null;
//}
//#endif
RemoveUnusedReferences(mLocalize);
}
#endregion
#region GUI
public override void OnInspectorGUI()
{
Undo.RecordObject(target, "Localize");
//GUI.backgroundColor = Color.Lerp (Color.black, Color.gray, 1);
//GUILayout.BeginVertical(GUIStyle_Background, GUILayout.Height(1));
//GUI.backgroundColor = Color.white;
if (GUILayout.Button("Localize", GUIStyle_Header))
{
//Application.OpenURL(HelpURL_Documentation);
}
GUILayout.Space(-10);
LocalizationManager.UpdateSources();
if (LocalizationManager.Sources.Count==0)
{
EditorGUILayout.HelpBox("无法找到语言来源。\nUnable to find a Language Source.", MessageType.Warning);
}
else
{
GUILayout.Space(10);
OnGUI_Target ();
GUILayout.Space(10);
OnGUI_Terms();
//if (mGUI_ShowTems || mGUI_ShowReferences) GUILayout.Space(5);
OnGUI_References();
if (mLocalize.mGUI_ShowReferences || mLocalize.mGUI_ShowCallback) GUILayout.Space(10);
//Localize loc = target as Localize;
//--[ Localize Callback ]----------------------
EditorGUILayout.PropertyField(mProp_CallbackEvent, new GUIContent("On Localize Callback"));
//string HeaderTitle = "On Localize Call:";
//if (!mLocalize.mGUI_ShowCallback && loc.LocalizeCallBack.Target!=null && !string.IsNullOrEmpty(loc.LocalizeCallBack.MethodName))
// HeaderTitle = string.Concat(HeaderTitle, " <b>",loc.LocalizeCallBack.Target.name, ".</b><i>", loc.LocalizeCallBack.MethodName, "</i>");
//mLocalize.mGUI_ShowCallback = GUITools.DrawHeader(HeaderTitle, mLocalize.mGUI_ShowCallback);
//if (mLocalize.mGUI_ShowCallback)
//{
// GUITools.BeginContents();
// DrawEventCallBack( loc.LocalizeCallBack, loc );
// GUITools.EndContents();
//}
}
OnGUI_Source ();
GUILayout.Space (10);
GUITools.OnGUI_Footer("I2 Localization", LocalizationManager.GetVersion(), HelpURL_forum, HelpURL_Documentation, HelpURL_AssetStore);
//GUILayout.EndVertical();
serializedObject.ApplyModifiedProperties();
if (Event.current.type == EventType.Repaint)
{
LocalizationEditor.mTestAction = LocalizationEditor.eTest_ActionType.None;
LocalizationEditor.mTestActionArg = null;
LocalizationEditor.mTestActionArg2 = null;
}
}
#endregion
#region References
void OnGUI_References()
{
if (mLocalize.mGUI_ShowReferences = GUITools.DrawHeader ("References", mLocalize.mGUI_ShowReferences))
{
GUITools.BeginContents();
bool canTest = Event.current.type == EventType.Repaint;
var testAddObj = canTest && LocalizationEditor.mTestAction == LocalizationEditor.eTest_ActionType.Button_Assets_Add ? (Object)LocalizationEditor.mTestActionArg : null;
var testReplaceIndx = canTest && LocalizationEditor.mTestAction == LocalizationEditor.eTest_ActionType.Button_Assets_Replace ? (int)LocalizationEditor.mTestActionArg : -1;
var testReplaceObj = canTest && LocalizationEditor.mTestAction == LocalizationEditor.eTest_ActionType.Button_Assets_Replace ? (Object)LocalizationEditor.mTestActionArg2 : null;
var testDeleteIndx = canTest && LocalizationEditor.mTestAction == LocalizationEditor.eTest_ActionType.Button_Assets_Delete ? (int)LocalizationEditor.mTestActionArg : -1;
bool changed = GUITools.DrawObjectsArray( mProp_TranslatedObjects, false, false, true, testAddObj, testReplaceObj, testReplaceIndx, testDeleteIndx);
if (changed)
{
serializedObject.ApplyModifiedProperties();
foreach (var obj in serializedObject.targetObjects)
(obj as Localize).UpdateAssetDictionary();
}
GUITools.EndContents();
}
}
void RemoveUnusedReferences(Localize cmp)
{
cmp.TranslatedObjects.RemoveAll(x => !IsUsingReference(LocalizationManager.GetTermData(cmp.Term), x) && !IsUsingReference(LocalizationManager.GetTermData(cmp.SecondaryTerm), x));
if (cmp.TranslatedObjects.Count != cmp.mAssetDictionary.Count)
cmp.UpdateAssetDictionary();
}
bool IsUsingReference(TermData termData, Object obj )
{
if (obj == null || termData==null) return false;
string objName = obj.name;
foreach (string translation in termData.Languages)
{
if (translation != null && translation.Contains(objName))
return true;
}
return false;
}
#endregion
#region Terms
int GUI_SelectedTerm;
void OnGUI_Terms()
{
if ((mLocalize.mGUI_ShowTems=GUITools.DrawHeader ("Terms", mLocalize.mGUI_ShowTems)))
{
//--[ tabs: Main and Secondary Terms ]----------------
int oldTab = GUI_SelectedTerm;
if (mLocalize.mLocalizeTarget!=null && mLocalize.mLocalizeTarget.CanUseSecondaryTerm())
{
GUI_SelectedTerm = GUITools.DrawTabs (GUI_SelectedTerm, new[]{"Main", "Secondary"});
}
else
{
GUI_SelectedTerm = 0;
GUITools.DrawTabs (GUI_SelectedTerm, new[]{"Main", ""});
}
GUITools.BeginContents();
TermData termData = null;
if (GUI_SelectedTerm==0) termData = OnGUI_PrimaryTerm( oldTab!=GUI_SelectedTerm );
else termData = OnGUI_SecondaryTerm(oldTab!=GUI_SelectedTerm);
GUITools.EndContents();
//--[ Modifier ]-------------
if (mLocalize.Term != "-" && termData!=null && termData.TermType==eTermType.Text)
{
EditorGUI.BeginChangeCheck();
GUILayout.BeginHorizontal();
GUILayout.Label("Prefix:");
EditorGUILayout.PropertyField(mProp_TermPrefix, GUITools.EmptyContent);
GUILayout.Label("Suffix:");
EditorGUILayout.PropertyField(mProp_TermSuffix, GUITools.EmptyContent);
GUILayout.EndHorizontal();
if (EditorGUI.EndChangeCheck())
{
EditorApplication.delayCall += () =>
{
if (targets != null)
{
foreach (var t in targets)
if (t as Localize != null)
(t as Localize).OnLocalize(true);
}
};
}
EditorGUI.BeginChangeCheck();
int val = EditorGUILayout.Popup("Modifier", GUI_SelectedTerm == 0 ? (int)mLocalize.PrimaryTermModifier : (int)mLocalize.SecondaryTermModifier, Enum.GetNames(typeof(Localize.TermModification)));
if (EditorGUI.EndChangeCheck())
{
serializedObject.FindProperty(GUI_SelectedTerm == 0 ? "PrimaryTermModifier" : "SecondaryTermModifier").enumValueIndex = val;
GUI.changed = false;
}
}
OnGUI_Options();
//--[ OnAwake vs OnEnable ]-------------
//GUILayout.BeginHorizontal();
//mProp_LocalizeOnAwake.boolValue = GUILayout.Toggle(mProp_LocalizeOnAwake.boolValue, new GUIContent(" Pre-Localize on Awake", "Localizing on Awake could result in a lag when the level is loaded but faster later when objects are enabled. If false, it will Localize OnEnable, so will yield faster level load but could have a lag when screens are enabled"));
//GUILayout.FlexibleSpace();
//if (mLocalize.HasCallback())
//{
// GUI.enabled = false;
// GUILayout.Toggle(true, new GUIContent(" Force Localize", "Enable this when the translations have parameters (e.g. Thew winner is {[WINNER}]) to prevent any optimization that could prevent updating the translation when the object is enabled"));
// GUI.enabled = true;
//}
//else
//{
// mProp_AlwaysForceLocalize.boolValue = GUILayout.Toggle(mProp_AlwaysForceLocalize.boolValue, new GUIContent(" Force Localize", "Enable this when the translations have parameters (e.g. Thew winner is {[WINNER}]) to prevent any optimization that could prevent updating the translation when the object is enabled"));
//}
//GUILayout.EndHorizontal();
//--[ Right To Left ]-------------
if (!mLocalize.IgnoreRTL && mLocalize.Term!="-" && termData != null && termData.TermType == eTermType.Text)
{
GUILayout.BeginVertical("Box");
//GUILayout.BeginHorizontal();
// mProp_IgnoreRTL.boolValue = GUILayout.Toggle(mProp_IgnoreRTL.boolValue, new GUIContent(" Ignore Right To Left", "Arabic and other RTL languages require processing them so they render correctly, this toogle allows ignoring that processing (in case you are doing it manually during a callback)"));
// GUILayout.FlexibleSpace();
// mProp_SeparateWords.boolValue = GUILayout.Toggle(mProp_SeparateWords.boolValue, new GUIContent(" Separate Words", " Some languages (e.g. Chinese, Japanese and Thai) don't add spaces to their words (all characters are placed toguether), enabling this checkbox, will add spaces to all characters to allow wrapping long texts into multiple lines."));
//GUILayout.EndHorizontal();
{
mProp_MaxCharactersInRTL.intValue = EditorGUILayout.IntField( new GUIContent("最大线长 Max line length", "如果语言是从右到左那么长行将按此长度分割并且RTL修复将应用于每行则应将其设置为适合此文本宽度的最大字符数。0禁用每行修复\nIf the language is Right To Left, long lines will be split at this length and the RTL fix will be applied to each line, this should be set to the maximum number of characters that fit in this text width. 0 disables the per line fix"), mProp_MaxCharactersInRTL.intValue );
GUILayout.BeginHorizontal();
mProp_CorrectAlignmentForRTL.boolValue = GUILayout.Toggle(mProp_CorrectAlignmentForRTL.boolValue, new GUIContent(" 调整对齐 Adjust Alignment", "当从右到左语言时为右对齐,否则为左对齐\nRight-align when Right-To-Left Language, and Left-Align otherwise") );
GUILayout.FlexibleSpace();
mProp_IgnoreNumbersInRTL.boolValue = GUILayout.Toggle(mProp_IgnoreNumbersInRTL.boolValue, new GUIContent(" 忽略数字 Ignore Numbers", "将数字保留为拉丁字符,而不是转换它们\nPreserve numbers as latin characters instead of converting them"));
GUILayout.EndHorizontal();
}
GUILayout.EndVertical();
}
////GUILayout.EndHorizontal();
}
}
void OnGUI_Options()
{
int mask = 0;
if (mProp_LocalizeOnAwake.boolValue) mask |= 1 << 0;
if (mProp_AlwaysForceLocalize.boolValue) mask |= 1 << 1;
if (mProp_AllowParameters.boolValue) mask |= 1 << 2;
if (mProp_AllowLocalizedParameters.boolValue) mask |= 1 << 3;
if (mProp_SeparateWords.boolValue) mask |= 1 << 4;
if (mProp_IgnoreRTL.boolValue) mask |= 1 << 5;
EditorGUI.BeginChangeCheck();
mask = EditorGUILayout.MaskField(new GUIContent("Options"), mask, new []{
"Localize On Awake",
"Force Localize",
"Allow Parameters",
"Allow Localized Parameters",
"Separate Words",
"Ignore RTL"
});
if (EditorGUI.EndChangeCheck())
{
mProp_LocalizeOnAwake.boolValue = (mask & (1 << 0))> 0;
mProp_AlwaysForceLocalize.boolValue = (mask & (1 << 1))> 0;
mProp_AllowParameters.boolValue = (mask & (1 << 2))> 0;
mProp_AllowLocalizedParameters.boolValue = (mask & (1 << 3))> 0;
mProp_SeparateWords.boolValue = (mask & (1 << 4))> 0;
mProp_IgnoreRTL.boolValue = (mask & (1 << 5))> 0;
}
}
TermData OnGUI_PrimaryTerm( bool OnOpen )
{
string Key = mLocalize.mTerm;
if (string.IsNullOrEmpty(Key))
{
string SecondaryTerm;
mLocalize.GetFinalTerms( out Key, out SecondaryTerm );
}
if (OnOpen) mNewKeyName = Key;
if ( OnGUI_SelectKey( ref Key, string.IsNullOrEmpty(mLocalize.mTerm)))
mProp_mTerm.stringValue = Key;
return LocalizationEditor.OnGUI_Keys_Languages( Key, mLocalize );
}
TermData OnGUI_SecondaryTerm( bool OnOpen )
{
string Key = mLocalize.mTermSecondary;
if (string.IsNullOrEmpty(Key))
{
string ss;
mLocalize.GetFinalTerms( out ss, out Key );
}
if (OnOpen) mNewKeyName = Key;
if ( OnGUI_SelectKey( ref Key, string.IsNullOrEmpty(mLocalize.mTermSecondary)))
mProp_mTermSecondary.stringValue = Key;
return LocalizationEditor.OnGUI_Keys_Languages( Key, mLocalize, false );
}
bool OnGUI_SelectKey( ref string Term, bool Inherited ) // Inherited==true means that the mTerm is empty and we are using the Label.text instead
{
GUILayout.Space (5);
GUILayout.BeginHorizontal();
GUI.changed = false;
mAllowEditKeyName = GUILayout.Toggle(mAllowEditKeyName, "Term:", EditorStyles.foldout, GUILayout.ExpandWidth(false));
if (GUI.changed && mAllowEditKeyName) {
mNewKeyName = Term;
mTermsArray = null;
}
bool bChanged = false;
if (mTermsArray==null || Term!="-" && Array.IndexOf(mTermsArray, Term)<0)
UpdateTermsList(Term);
if (Inherited)
GUI.contentColor = Color.Lerp (Color.gray, Color.yellow, 0.1f);
int Index = Term=="-" || Term=="" ? mTermsArray.Length-1 : Array.IndexOf( mTermsArray, Term );
GUI.changed = false;
int newIndex = EditorGUILayout.Popup( Index, mTermsArray);
GUI.contentColor = Color.white;
if (/*newIndex != Index && newIndex>=0*/GUI.changed)
{
GUI.changed = false;
if (mLocalize.Source != null && newIndex == mTermsArray.Length - 4) //< show terms from all sources >
{
mLocalize.Source = null;
mTermsArray = null;
}
else
if (newIndex == mTermsArray.Length - 2) //<inferred from text>
mNewKeyName = Term = string.Empty;
else
if (newIndex == mTermsArray.Length - 1) //<none>
mNewKeyName = Term = "-";
else
mNewKeyName = Term = mTermsArray[newIndex];
if (GUI_SelectedTerm==0)
mLocalize.SetTerm (mNewKeyName);
else
mLocalize.SetTerm (null, mNewKeyName);
mAllowEditKeyName = false;
bChanged = true;
}
LanguageSourceData source = LocalizationManager.GetSourceContaining(Term);
TermData termData = source.GetTermData(Term);
if (termData!=null)
{
if (Inherited)
bChanged = true; // if the term its inferred and a matching term its found, then use that
eTermType NewType = (eTermType)EditorGUILayout.EnumPopup(termData.TermType, GUILayout.Width(90));
if (termData.TermType != NewType)
termData.TermType = NewType;
}
GUILayout.EndHorizontal();
if (mAllowEditKeyName)
{
GUILayout.BeginHorizontal(GUILayout.Height (1));
GUILayout.BeginHorizontal(EditorStyles.toolbar);
if(mNewKeyName==null) mNewKeyName = string.Empty;
GUI.changed = false;
mNewKeyName = EditorGUILayout.TextField(mNewKeyName, new GUIStyle("ToolbarSeachTextField"), GUILayout.ExpandWidth(true));
if (GUI.changed)
{
mTermsArray = null; // regenerate this array to apply filtering
GUI.changed = false;
}
if (GUILayout.Button (string.Empty, string.IsNullOrEmpty(mNewKeyName) ? "ToolbarSeachCancelButtonEmpty" : "ToolbarSeachCancelButton", GUILayout.ExpandWidth(false)))
{
mTermsArray = null; // regenerate this array to apply filtering
mNewKeyName = string.Empty;
}
GUILayout.EndHorizontal();
string ValidatedName = mNewKeyName;
LanguageSourceData.ValidateFullTerm( ref ValidatedName );
bool CanUseNewName = source.GetTermData(ValidatedName)==null;
GUI.enabled = !string.IsNullOrEmpty(mNewKeyName) && CanUseNewName;
if (GUILayout.Button ("Create", EditorStyles.toolbarButton, GUILayout.ExpandWidth(false)))
{
mNewKeyName = ValidatedName;
mTermsArray=null; // this recreates that terms array
LanguageSourceData Source = null;
#if UNITY_EDITOR
if (mLocalize.Source!=null)
Source = mLocalize.Source.SourceData;
#endif
if (Source==null)
Source = LocalizationManager.Sources[0];
Term = mNewKeyName;
var data = Source.AddTerm( mNewKeyName, eTermType.Text, false );
if (data.Languages.Length > 0)
data.Languages[0] = mLocalize.GetMainTargetsText();
Source.Editor_SetDirty();
AssetDatabase.SaveAssets();
mAllowEditKeyName = false;
bChanged = true;
GUIUtility.keyboardControl = 0;
}
GUI.enabled = termData!=null && !string.IsNullOrEmpty(mNewKeyName) && CanUseNewName;
if (GUILayout.Button (new GUIContent("Rename","重命名源中的术语并更新当前场景中使用它的每个对象\nRenames the term in the source and updates every object using it in the current scene"), EditorStyles.toolbarButton, GUILayout.ExpandWidth(false)))
{
mNewKeyName = ValidatedName;
Term = mNewKeyName;
mTermsArray=null; // this recreates that terms array
mAllowEditKeyName = false;
bChanged = true;
LocalizationEditor.TermReplacements = new Dictionary<string, string>(StringComparer.Ordinal);
LocalizationEditor.TermReplacements[ termData.Term ] = mNewKeyName;
termData.Term = mNewKeyName;
source.UpdateDictionary(true);
LocalizationEditor.ReplaceTermsInCurrentScene();
GUIUtility.keyboardControl = 0;
EditorApplication.update += LocalizationEditor.DoParseTermsInCurrentScene;
}
GUI.enabled = true;
GUILayout.EndHorizontal();
bChanged |= OnGUI_SelectKey_PreviewTerms ( ref Term);
}
GUILayout.Space (5);
return bChanged;
}
void UpdateTermsList( string currentTerm )
{
List<string> Terms = mLocalize.Source==null ? LocalizationManager.GetTermsList() : mLocalize.Source.SourceData.GetTermsList();
// If there is a filter, remove all terms not matching that filter
if (mAllowEditKeyName && !string.IsNullOrEmpty(mNewKeyName))
{
string Filter = mNewKeyName.ToUpper();
for (int i=Terms.Count-1; i>=0; --i)
if (!Terms[i].ToUpper().Contains(Filter) && Terms[i]!=currentTerm)
Terms.RemoveAt(i);
}
if (!string.IsNullOrEmpty(currentTerm) && currentTerm!="-" && !Terms.Contains(currentTerm))
Terms.Add (currentTerm);
Terms.Sort(StringComparer.OrdinalIgnoreCase);
Terms.Add("");
if (mLocalize.Source != null)
{
Terms.Add("< Show Terms from all sources >");
Terms.Add("");
}
Terms.Add("<inferred from text>");
Terms.Add("<none>");
mTermsArray = Terms.ToArray();
}
bool OnGUI_SelectKey_PreviewTerms ( ref string Term)
{
if (mTermsArray==null)
UpdateTermsList(Term);
int nTerms = mTermsArray.Length;
if (nTerms<=0)
return false;
if (nTerms==1 && mTermsArray[0]==Term)
return false;
bool bChanged = false;
GUI.backgroundColor = Color.gray;
GUILayout.BeginVertical (GUIStyle_OldTextArea);
for (int i = 0, imax = Mathf.Min (nTerms, 3); i < imax; ++i)
{
ParsedTerm parsedTerm;
int nUses = -1;
if (LocalizationEditor.mParsedTerms.TryGetValue (mTermsArray [i], out parsedTerm))
nUses = parsedTerm.Usage;
string FoundText = mTermsArray [i];
if (nUses > 0)
FoundText = string.Concat ("(", nUses, ") ", FoundText);
if (GUILayout.Button (FoundText, EditorStyles.miniLabel, GUILayout.MaxWidth(EditorGUIUtility.currentViewWidth - 70)))
{
if (mTermsArray[i] == "<inferred from text>")
mNewKeyName = Term = string.Empty;
else
if (mTermsArray[i] == "<none>")
mNewKeyName = Term = "-";
else
if (mTermsArray[i] != "< Show Terms from all sources >")
mNewKeyName = Term = mTermsArray[i];
//mNewKeyName = Term = (mTermsArray [i]=="<inferred from text>" ? string.Empty : mTermsArray [i]);
GUIUtility.keyboardControl = 0;
mAllowEditKeyName = false;
bChanged = true;
}
}
if (nTerms > 3)
GUILayout.Label ("...");
GUILayout.EndVertical ();
GUI.backgroundColor = Color.white;
return bChanged;
}
#endregion
#region Target
void OnGUI_Target()
{
List<string> TargetTypes = new List<string>();
int CurrentTarget = -1;
mLocalize.FindTarget();
foreach (var desc in LocalizationManager.mLocalizeTargets)
{
if (desc.CanLocalize(mLocalize))
{
TargetTypes.Add(desc.Name);
if (mLocalize.mLocalizeTarget!=null && desc.GetTargetType() == mLocalize.mLocalizeTarget.GetType())
CurrentTarget = TargetTypes.Count - 1;
}
}
if (CurrentTarget==-1)
{
CurrentTarget = TargetTypes.Count;
TargetTypes.Add("None");
}
GUILayout.BeginHorizontal();
GUILayout.Label ("Target:", GUILayout.Width (60));
EditorGUI.BeginChangeCheck();
int index = EditorGUILayout.Popup(CurrentTarget, TargetTypes.ToArray());
if (EditorGUI.EndChangeCheck())
{
serializedObject.ApplyModifiedProperties();
foreach (var obj in serializedObject.targetObjects)
{
var cmp = obj as Localize;
if (cmp == null)
continue;
if (cmp.mLocalizeTarget != null)
DestroyImmediate(cmp.mLocalizeTarget);
cmp.mLocalizeTarget = null;
foreach (var desc in LocalizationManager.mLocalizeTargets)
{
if (desc.Name == TargetTypes[index])
{
cmp.mLocalizeTarget = desc.CreateTarget(cmp);
cmp.mLocalizeTargetName = desc.GetTargetType().ToString();
break;
}
}
}
serializedObject.Update();
}
GUILayout.EndHorizontal();
}
#endregion
#region Source
void OnGUI_Source()
{
GUILayout.BeginHorizontal();
ILanguageSource currentSource = mLocalize.Source;
if (currentSource==null)
{
LanguageSourceData source = LocalizationManager.GetSourceContaining(mLocalize.Term);
currentSource = source==null ? null : source.owner;
}
if (GUILayout.Button("Open Source", EditorStyles.toolbarButton, GUILayout.Width (100)))
{
Selection.activeObject = currentSource as Object;
string sTerm, sSecondary;
mLocalize.GetFinalTerms( out sTerm, out sSecondary );
if (GUI_SelectedTerm==1) sTerm = sSecondary;
LocalizationEditor.mKeyToExplore = sTerm;
}
GUILayout.Space (2);
GUILayout.BeginHorizontal(EditorStyles.toolbar);
EditorGUI.BeginChangeCheck ();
if (mLocalize.Source == null)
{
GUI.contentColor = Color.Lerp (Color.gray, Color.yellow, 0.1f);
}
Object obj = EditorGUILayout.ObjectField(currentSource as Object, typeof(Object), true);
GUI.contentColor = Color.white;
if (EditorGUI.EndChangeCheck())
{
ILanguageSource NewSource = obj as ILanguageSource;
if (NewSource == null && obj as GameObject != null)
{
NewSource = (obj as GameObject).GetComponent<LanguageSource>();
}
mLocalize.Source = NewSource;
string sTerm, sSecondary;
mLocalize.GetFinalTerms(out sTerm, out sSecondary);
if (GUI_SelectedTerm == 1) sTerm = sSecondary;
UpdateTermsList(sTerm);
}
if (GUILayout.Button(new GUIContent("Detect", "找到包含所选术语的LanguageSource术语列表现在将只显示该源中的术语。\nFinds the LanguageSource containing the selected term, the term list will now only show terms inside that source."), EditorStyles.toolbarButton, GUILayout.ExpandWidth(false)))
{
string sTerm, sSecondary;
mLocalize.GetFinalTerms(out sTerm, out sSecondary);
if (GUI_SelectedTerm == 1) sTerm = sSecondary;
var data = LocalizationManager.GetSourceContaining(sTerm, false);
mLocalize.Source = data==null ? null : data.owner;
mTermsArray = null;
}
GUILayout.EndHorizontal();
GUILayout.EndHorizontal();
}
#endregion
#region Event CallBack
//public void DrawEventCallBack( EventCallback CallBack, Localize loc )
//{
//if (CallBack==null)
// return;
//GUI.changed = false;
//GUILayout.BeginHorizontal();
//GUILayout.Label("Target:", GUILayout.ExpandWidth(false));
//CallBack.Target = EditorGUILayout.ObjectField( CallBack.Target, typeof(MonoBehaviour), true) as MonoBehaviour;
//GUILayout.EndHorizontal();
//if (CallBack.Target!=null)
//{
// GameObject GO = CallBack.Target.gameObject;
// List<MethodInfo> Infos = new List<MethodInfo>();
// var targets = GO.GetComponents(typeof(MonoBehaviour));
// foreach (var behavior in targets)
// Infos.AddRange( behavior.GetType().GetMethods() );
// List<string> Methods = new List<string>();
// for (int i = 0, imax=Infos.Count; i<imax; ++i)
// {
// MethodInfo mi = Infos[i];
// if (IsValidMethod(mi))
// Methods.Add (mi.Name);
// }
// int Index = Methods.IndexOf(CallBack.MethodName);
// int NewIndex = EditorGUILayout.Popup(Index, Methods.ToArray(), GUILayout.ExpandWidth(true));
// if (NewIndex!=Index)
// CallBack.MethodName = Methods[ NewIndex ];
//}
//if (GUI.changed)
//{
// GUI.changed = false;
// EditorUtility.SetDirty(loc);
// //UnityEditor.SceneManagement.EditorSceneManager.MarkSceneDirty() EditorApplication.MakeSceneDirty();
//}
//}
static bool IsValidMethod( MethodInfo mi )
{
if (mi.DeclaringType == typeof(MonoBehaviour) || mi.ReturnType != typeof(void))
return false;
ParameterInfo[] Params = mi.GetParameters ();
if (Params.Length == 0) return true;
if (Params.Length > 1) return false;
if (Params [0].ParameterType.IsSubclassOf (typeof(Object))) return true;
if (Params [0].ParameterType == typeof(Object)) return true;
return false;
}
#endregion
#region Styles
public static GUIStyle GUIStyle_Header {
get{
if (mGUIStyle_Header==null)
{
mGUIStyle_Header = new GUIStyle("HeaderLabel");
mGUIStyle_Header.fontSize = 25;
mGUIStyle_Header.normal.textColor = Color.Lerp(Color.white, Color.gray, 0.5f);
mGUIStyle_Header.fontStyle = FontStyle.BoldAndItalic;
mGUIStyle_Header.alignment = TextAnchor.UpperCenter;
}
return mGUIStyle_Header;
}
}
static GUIStyle mGUIStyle_Header;
public static GUIStyle GUIStyle_SubHeader {
get{
if (mGUIStyle_SubHeader==null)
{
mGUIStyle_SubHeader = new GUIStyle("HeaderLabel");
mGUIStyle_SubHeader.fontSize = 13;
mGUIStyle_SubHeader.fontStyle = FontStyle.Normal;
mGUIStyle_SubHeader.margin.top = -50;
mGUIStyle_SubHeader.alignment = TextAnchor.UpperCenter;
}
return mGUIStyle_SubHeader;
}
}
static GUIStyle mGUIStyle_SubHeader;
public static GUIStyle GUIStyle_Background {
get{
if (mGUIStyle_Background==null)
{
mGUIStyle_Background = new GUIStyle(EditorStyles.textArea);
mGUIStyle_Background.fixedHeight = 0;
mGUIStyle_Background.overflow.left = 50;
mGUIStyle_Background.overflow.right = 50;
mGUIStyle_Background.overflow.top = -5;
mGUIStyle_Background.overflow.bottom = 0;
}
return mGUIStyle_Background;
}
}
static GUIStyle mGUIStyle_Background;
public static GUIStyle GUIStyle_OldTextArea
{
get
{
if (mGUIStyle_OldTextArea == null)
{
mGUIStyle_OldTextArea = new GUIStyle(EditorStyles.textArea);
mGUIStyle_OldTextArea.fixedHeight = 0;
}
return mGUIStyle_OldTextArea;
}
}
static GUIStyle mGUIStyle_OldTextArea;
#endregion
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 675119279b2a30245801272112cfbe38
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,29 @@
using UnityEditor;
using UnityEngine;
namespace I2.Loc
{
[CustomEditor(typeof(ResourceManager))]
public class ResourceManagerInspector : Editor
{
SerializedProperty mAssets;
void OnEnable()
{
UpgradeManager.EnablePlugins();
mAssets = serializedObject.FindProperty("Assets");
}
public override void OnInspectorGUI()
{
GUILayout.Space(5);
GUITools.DrawHeader("Assets:", true);
GUITools.BeginContents();
///GUILayout.Label ("Assets:");
GUITools.DrawObjectsArray( mAssets );
GUITools.EndContents();
serializedObject.ApplyModifiedProperties();
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: ba2fdf8face79dd4f9e1ed80448db843
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,60 @@
using System;
using UnityEditor;
using UnityEngine;
namespace I2.Loc
{
[CustomEditor(typeof(SetLanguage))]
public class SetLanguageInspector : Editor
{
public SetLanguage setLan;
public SerializedProperty mProp_Language;
public void OnEnable()
{
setLan = (SetLanguage)target;
mProp_Language = serializedObject.FindProperty("_Language");
}
public override void OnInspectorGUI()
{
string[] Languages;
LanguageSource sourceObj = setLan.mSource;
if (sourceObj == null)
{
LocalizationManager.UpdateSources();
Languages = LocalizationManager.GetAllLanguages().ToArray();
Array.Sort(Languages);
}
else
{
Languages = sourceObj.mSource.GetLanguages().ToArray();
Array.Sort(Languages);
}
int index = Array.IndexOf(Languages, mProp_Language.stringValue);
GUI.changed = false;
index = EditorGUILayout.Popup("Language", index, Languages);
if (GUI.changed)
{
if (index<0 || index>=Languages.Length)
mProp_Language.stringValue = string.Empty;
else
mProp_Language.stringValue = Languages[index];
GUI.changed = false;
serializedObject.ApplyModifiedProperties();
}
GUILayout.Space(5);
if (setLan.mSource==null) GUI.contentColor = Color.Lerp (Color.gray, Color.yellow, 0.1f);
sourceObj = EditorGUILayout.ObjectField("Language Source:", sourceObj, typeof(LanguageSource), true) as LanguageSource;
GUI.contentColor = Color.white;
if (GUI.changed)
setLan.mSource = sourceObj;
serializedObject.ApplyModifiedProperties();
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 7af58b4da44670e47a509c59754e8c2b
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,164 @@
using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
namespace I2.Loc
{
[CustomPropertyDrawer (typeof (TermsPopup))]
public class TermsPopup_Drawer : PropertyDrawer
{
GUIContent[] mTerms_Context;
int nFramesLeftBeforeUpdate;
string mPrevFilter;
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
var filter = ((TermsPopup)attribute).Filter;
ShowGUICached(position, property, label, null, filter, ref mTerms_Context, ref nFramesLeftBeforeUpdate, ref mPrevFilter);
}
public static bool ShowGUI(Rect position, SerializedProperty property, GUIContent label, LanguageSourceData source, string filter = "")
{
GUIContent[] terms=null;
int framesLeftBeforeUpdate=0;
string prevFilter = null;
return ShowGUICached(position, property, label, source, filter, ref terms, ref framesLeftBeforeUpdate, ref prevFilter);
}
public static bool ShowGUICached(Rect position, SerializedProperty property, GUIContent label, LanguageSourceData source, string filter, ref GUIContent[] terms_Contexts, ref int framesBeforeUpdating, ref string prevFilter)
{
UpdateTermsCache(source, filter, ref terms_Contexts, ref framesBeforeUpdating, ref prevFilter);
label = EditorGUI.BeginProperty(position, label, property);
EditorGUI.BeginChangeCheck ();
var index = property.stringValue == "-" || property.stringValue == "" ? terms_Contexts.Length - 1 :
property.stringValue == " " ? terms_Contexts.Length - 2 :
GetTermIndex(terms_Contexts, property.stringValue);
var newIndex = EditorGUI.Popup(position, label, index, terms_Contexts);
if (EditorGUI.EndChangeCheck())
{
property.stringValue = newIndex < 0 || newIndex == terms_Contexts.Length - 1 ? string.Empty : terms_Contexts[newIndex].text;
if (newIndex == terms_Contexts.Length - 1)
property.stringValue = "-";
else
if (newIndex < 0 || newIndex == terms_Contexts.Length - 2)
property.stringValue = string.Empty;
else
property.stringValue = terms_Contexts[newIndex].text;
EditorGUI.EndProperty();
return true;
}
EditorGUI.EndProperty();
return false;
}
static int GetTermIndex(GUIContent[] terms_Contexts, string term )
{
for (int i = 0; i < terms_Contexts.Length; ++i)
if (terms_Contexts[i].text == term)
return i;
return -1;
}
static void UpdateTermsCache(LanguageSourceData source, string filter, ref GUIContent[] terms_Contexts, ref int framesBeforeUpdating, ref string prevFilter)
{
framesBeforeUpdating--;
if (terms_Contexts!=null && framesBeforeUpdating>0 && filter==prevFilter)
{
return;
}
framesBeforeUpdating = 60;
prevFilter = filter;
var Terms = source == null ? LocalizationManager.GetTermsList() : source.GetTermsList();
if (string.IsNullOrEmpty(filter) == false)
{
Terms = Filter(Terms, filter);
}
Terms.Sort(StringComparer.OrdinalIgnoreCase);
Terms.Add("");
Terms.Add("<inferred from text>");
Terms.Add("<none>");
terms_Contexts = DisplayOptions(Terms);
}
private static List<string> Filter(List<string> terms, string filter)
{
var filtered = new List<string>();
for (var i = 0; i < terms.Count; i++)
{
var term = terms[i];
if (term.Contains(filter))
{
filtered.Add(term);
}
}
return filtered;
}
private static GUIContent[] DisplayOptions(IList<string> terms)
{
var options = new GUIContent[terms.Count];
for (var i = 0; i < terms.Count; i++)
{
options[i] = new GUIContent(terms[i]);
}
return options;
}
}
[CustomPropertyDrawer(typeof(LocalizedString))]
public class LocalizedStringDrawer : PropertyDrawer
{
GUIContent[] mTerms_Context;
int nFramesLeftBeforeUpdate;
string mPrevFilter;
public override void OnGUI(Rect rect, SerializedProperty property, GUIContent label)
{
var termRect = rect; termRect.xMax -= 50;
var termProp = property.FindPropertyRelative("mTerm");
TermsPopup_Drawer.ShowGUICached(termRect, termProp, label, null, "", ref mTerms_Context, ref nFramesLeftBeforeUpdate, ref mPrevFilter);
var maskRect = rect; maskRect.xMin = maskRect.xMax - 30;
var termIgnoreRTL = property.FindPropertyRelative("mRTL_IgnoreArabicFix");
var termConvertNumbers = property.FindPropertyRelative("mRTL_ConvertNumbers");
var termDontLocalizeParams = property.FindPropertyRelative("m_DontLocalizeParameters");
int mask = (termIgnoreRTL.boolValue ? 0 : 1) +
(termConvertNumbers.boolValue ? 0 : 2) +
(termDontLocalizeParams.boolValue ? 0 : 4);
int newMask = EditorGUI.MaskField(maskRect, mask, new[] { "Arabic Fix", "Ignore Numbers in RTL", "Localize Parameters" });
if (newMask != mask)
{
termIgnoreRTL.boolValue = (newMask & 1) == 0;
termConvertNumbers.boolValue = (newMask & 2) == 0;
termDontLocalizeParams.boolValue = (newMask & 4) == 0;
}
var showRect = rect; showRect.xMin = termRect.xMax; showRect.xMax=maskRect.xMin;
bool enabled = GUI.enabled;
GUI.enabled = enabled & (!string.IsNullOrEmpty (termProp.stringValue) && termProp.stringValue!="-");
if (GUI.Button (showRect, "?"))
{
var source = LocalizationManager.GetSourceContaining(termProp.stringValue);
LocalizationEditor.mKeyToExplore = termProp.stringValue;
Selection.activeObject = source.ownerObject;
}
GUI.enabled = enabled;
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 51c22a426b92fa84cb6ca7b75176da8a
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 8ad136296e8e6e14eaa2726ac1992b6c
folderAsset: yes
timeCreated: 1461137613
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,308 @@
using System.Collections.Generic;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace I2.Loc
{
public partial class LocalizationEditor
{
#region Variables
public enum eViewMode { ImportExport, Keys, Languages, Tools, References }
public static eViewMode mCurrentViewMode = eViewMode.Keys;
public enum eSpreadsheetMode { Local, Google }
public eSpreadsheetMode mSpreadsheetMode = eSpreadsheetMode.Google;
public static string mLocalizationMsg = "";
public static MessageType mLocalizationMessageType = MessageType.None;
// These variables are for executing action from Unity Tests
public enum eTest_ActionType { None, Button_AddLanguageFromPopup, Button_AddLanguageManual,
Button_AddTerm_InTermsList, Button_AddSelectedTerms,
Button_RemoveSelectedTerms, Button_DeleteTerm,
Button_SelectTerms_All, Button_SelectTerms_None, Button_SelectTerms_Used, Button_SelectTerms_Missing,
Button_Term_Translate, Button_Term_TranslateAll, Button_Languages_TranslateAll,
Button_Assets_Add, Button_Assets_Replace, Button_Assets_Delete,
Button_GoogleSpreadsheet_RefreshList, Button_GoogleSpreadsheet_Export, Button_GoogleSpreadsheet_Import
}
public static eTest_ActionType mTestAction = eTest_ActionType.None;
public static object mTestActionArg, mTestActionArg2;
#endregion
#region Editor
/*[MenuItem("Window/Localization", false)]
public static void OpenLocalizationEditor()
{
EditorWindow.GetWindow<LocalizationEditor>(false, "Localization", true);
}*/
#endregion
#region GUI
void InitializeStyles()
{
Style_ToolBar_Big = new GUIStyle(EditorStyles.toolbar);
Style_ToolBar_Big.fixedHeight = Style_ToolBar_Big.fixedHeight*1.5f;
Style_ToolBarButton_Big = new GUIStyle(EditorStyles.toolbarButton);
Style_ToolBarButton_Big.fixedHeight = Style_ToolBarButton_Big.fixedHeight*1.5f;
}
void OnGUI_Main()
{
OnGUI_Warning_SourceInScene();
OnGUI_Warning_SourceInsidePluginsFolder();
OnGUI_Warning_SourceNotUpToDate();
var prevViewMode = mCurrentViewMode;
GUILayout.BeginHorizontal();
//OnGUI_ToggleEnumBig( "Spreadsheets", ref mCurrentViewMode, eViewMode.ImportExport, GUI.skin.GetStyle("CN EntryWarn").normal.background, "External Spreadsheet File or Service" );
OnGUI_ToggleEnumBig( "表格 Spreadsheets", ref mCurrentViewMode, eViewMode.ImportExport, null, "外部电子表格文件或服务\nExternal Spreadsheet File or Service" );
OnGUI_ToggleEnumBig( "术语 Terms", ref mCurrentViewMode, eViewMode.Keys, null, null );
OnGUI_ToggleEnumBig( "语言 Languages", ref mCurrentViewMode, eViewMode.Languages, null, null );
OnGUI_ToggleEnumBig( "工具 Tools", ref mCurrentViewMode, eViewMode.Tools, null, null );
OnGUI_ToggleEnumBig( "资源 Assets", ref mCurrentViewMode, eViewMode.References, null, null );
GUILayout.EndHorizontal();
//GUILayout.Space(10);
switch (mCurrentViewMode)
{
case eViewMode.ImportExport : OnGUI_ImportExport(); break;
case eViewMode.Keys : OnGUI_KeysList(); break;
case eViewMode.Languages : OnGUI_Languages(); break;
case eViewMode.Tools : OnGUI_Tools(prevViewMode != mCurrentViewMode); break;
case eViewMode.References : OnGUI_References(); break;
}
}
void OnGUI_ImportExport()
{
eSpreadsheetMode OldMode = mSpreadsheetMode;
mSpreadsheetMode = (eSpreadsheetMode)GUITools.DrawShadowedTabs ((int)mSpreadsheetMode, new[]{"Local", "Google"});
if (mSpreadsheetMode != OldMode)
ClearErrors();
GUITools.BeginContents();
switch (mSpreadsheetMode)
{
case eSpreadsheetMode.Local : OnGUI_Spreadsheet_Local(); break;
case eSpreadsheetMode.Google : OnGUI_Spreadsheet_Google(); break;
}
GUITools.EndContents(false);
}
void OnGUI_References()
{
EditorGUILayout.HelpBox("这些是由Terms引用的资产而不是在Resources文件夹中 \nThese are the assets that are referenced by the Terms and not in the Resources folder", MessageType.Info);
bool canTest = Event.current.type == EventType.Repaint;
var testAddObj = canTest && mTestAction == eTest_ActionType.Button_Assets_Add ? (Object)mTestActionArg : null;
var testReplaceIndx = canTest && mTestAction == eTest_ActionType.Button_Assets_Replace ? (int)mTestActionArg : -1;
var testReplaceObj = canTest && mTestAction == eTest_ActionType.Button_Assets_Replace ? (Object)mTestActionArg2 : null;
var testDeleteIndx = canTest && mTestAction == eTest_ActionType.Button_Assets_Delete ? (int)mTestActionArg : -1;
bool changed = GUITools.DrawObjectsArray( mProp_Assets, false, false, false, testAddObj, testReplaceObj, testReplaceIndx, testDeleteIndx);
if (changed)
{
serializedObject.ApplyModifiedProperties();
foreach (var obj in serializedObject.targetObjects)
(obj as LanguageSource).mSource.UpdateAssetDictionary();
}
}
#endregion
#region Misc
void OnGUI_ToggleEnumBig<Enum>( string text, ref Enum currentMode, Enum newMode, Texture texture, string tooltip) { OnGUI_ToggleEnum( text, ref currentMode, newMode, texture, tooltip, Style_ToolBarButton_Big); }
void OnGUI_ToggleEnumSmall<Enum>( string text, ref Enum currentMode, Enum newMode, Texture texture, string tooltip) { OnGUI_ToggleEnum( text, ref currentMode, newMode, texture, tooltip, EditorStyles.toolbarButton); }
void OnGUI_ToggleEnum<Enum>( string text, ref Enum currentMode, Enum newMode, Texture texture, string tooltip, GUIStyle style)
{
GUI.changed = false;
if (GUILayout.Toggle( currentMode.Equals(newMode), new GUIContent(text, texture, tooltip), style, GUILayout.ExpandWidth(true)))
{
currentMode = newMode;
if (GUI.changed)
ClearErrors();
}
}
int OnGUI_FlagToogle( string Text, string tooltip, int flags, int bit )
{
bool State = (flags & bit)>0;
bool NewState = GUILayout.Toggle(State, new GUIContent(Text, tooltip), "toolbarbutton");
if (State!=NewState)
{
if (!NewState && flags==bit)
return flags;
flags = NewState ? flags | bit : flags & ~bit;
}
return flags;
}
void OnGUI_SelectableToogleListItem( string Element, ref List<string> Selections, string Style )
{
bool WasEnabled = Selections.Contains(Element);
bool IsEnabled = GUILayout.Toggle( WasEnabled, "", Style, GUILayout.ExpandWidth(false) );
if (IsEnabled && !WasEnabled)
Selections.Add(Element);
else
if (!IsEnabled && WasEnabled)
Selections.Remove(Element);
}
void OnGUI_SelectableToogleListItem( Rect rect, string Element, ref List<string> Selections, string Style )
{
bool WasEnabled = Selections.Contains(Element);
bool IsEnabled = GUI.Toggle( rect, WasEnabled, "", Style );
if (IsEnabled && !WasEnabled)
Selections.Add(Element);
else
if (!IsEnabled && WasEnabled)
Selections.Remove(Element);
}
static bool InTestAction( eTest_ActionType testType )
{
return mTestAction == testType && Event.current.type == EventType.Repaint;
}
static bool TestButton(eTest_ActionType action, string text, GUIStyle style, params GUILayoutOption[] options)
{
return GUILayout.Button(text, style, options) || mTestAction == action && Event.current.type == EventType.Repaint;
}
static bool TestButtonArg(eTest_ActionType action, object arg, string text, GUIStyle style, params GUILayoutOption[] options)
{
return GUILayout.Button(text, style, options) || mTestAction == action && (mTestActionArg==null || mTestActionArg.Equals(arg)) && Event.current.type == EventType.Repaint;
}
static bool TestButton(eTest_ActionType action, GUIContent text, GUIStyle style, params GUILayoutOption[] options)
{
return GUILayout.Button(text, style, options) || mTestAction == action && Event.current.type == EventType.Repaint;
}
static bool TestButtonArg(eTest_ActionType action, object arg, GUIContent text, GUIStyle style, params GUILayoutOption[] options)
{
return GUILayout.Button(text, style, options) || mTestAction == action && (mTestActionArg == null || mTestActionArg.Equals(arg)) && Event.current.type == EventType.Repaint;
}
#endregion
#region Error Management
static void OnGUI_ShowMsg()
{
if (!string.IsNullOrEmpty(mLocalizationMsg))
{
GUILayout.BeginHorizontal();
EditorGUILayout.HelpBox(mLocalizationMsg, mLocalizationMessageType);
GUILayout.Space(-5);
GUILayout.BeginVertical(GUILayout.Width(15), GUILayout.ExpandHeight(false));
GUILayout.Space(15);
if (GUILayout.Button("X", GUILayout.ExpandWidth(false)))
ClearErrors();
GUILayout.EndVertical();
GUILayout.EndHorizontal();
GUILayout.Space(8);
}
}
static void ShowError ( string Error, bool ShowInConsole = true ) { ShowMessage ( Error, MessageType.Error, ShowInConsole ); }
static void ShowInfo ( string Msg, bool ShowInConsole = false ) { ShowMessage ( Msg, MessageType.Info, ShowInConsole ); }
static void ShowWarning( string Msg, bool ShowInConsole = true) { ShowMessage ( Msg, MessageType.Warning, ShowInConsole ); }
static void ShowMessage( string Msg, MessageType msgType, bool ShowInConsole )
{
if (string.IsNullOrEmpty(Msg))
Msg = string.Empty;
mLocalizationMsg = Msg;
mLocalizationMessageType = msgType;
if (ShowInConsole)
{
switch (msgType)
{
case MessageType.Error : Debug.LogError(Msg); break;
case MessageType.Warning : Debug.LogWarning(Msg); break;
default : Debug.Log(Msg); break;
}
}
}
public static void ClearErrors()
{
GUI.FocusControl(null);
mLocalizationMsg = string.Empty;
}
#endregion
#region Unity Version branching
public static string Editor_GetCurrentScene()
{
#if UNITY_4_6 || UNITY_4_7 || UNITY_4_8 || UNITY_4_9 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2
return EditorApplication.currentScene;
#else
return SceneManager.GetActiveScene().path;
#endif
}
public static void Editor_MarkSceneDirty()
{
#if UNITY_5_3 || UNITY_5_3_OR_NEWER
EditorSceneManager.MarkSceneDirty(SceneManager.GetActiveScene());
#else
EditorApplication.MarkSceneDirty();
#endif
}
public static void Editor_SaveScene(bool force=false)
{
if (force)
Editor_MarkSceneDirty();
#if UNITY_4_6 || UNITY_4_7 || UNITY_4_8 || UNITY_4_9 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2
EditorApplication.SaveScene ();
#else
EditorSceneManager.SaveOpenScenes();
#endif
}
public static void Editor_OpenScene( string sceneName )
{
#if UNITY_4_6 || UNITY_4_7 || UNITY_4_8 || UNITY_4_9 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2
if (string.IsNullOrEmpty(sceneName))
EditorApplication.NewEmptyScene();
else
EditorApplication.OpenScene(sceneName);
#else
if (string.IsNullOrEmpty(sceneName))
EditorSceneManager.NewScene(NewSceneSetup.DefaultGameObjects, NewSceneMode.Single);
else
EditorSceneManager.OpenScene(sceneName);
#endif
}
#endregion
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: ffd53aaaf6936407d8b087583b0626e9
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,477 @@
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
namespace I2.Loc
{
public partial class LocalizationEditor
{
#region Variables
private List<string> mTranslationTerms = new List<string>();
private Dictionary<string, TranslationQuery> mTranslationRequests = new Dictionary<string, TranslationQuery> ();
private bool mAppNameTerm_Expanded;
private List<string> mLanguageCodePopupList;
#endregion
void OnGUI_Languages()
{
//GUILayout.Space(5);
OnGUI_ShowMsg();
OnGUI_LanguageList();
OnGUI_StoreIntegration();
GUILayout.BeginHorizontal();
GUILayout.Label(new GUIContent("论翻译缺失 On Missing Translation:", "当一个术语还没有翻译成当前语言时,游戏中应该发生什么\nWhat should happen IN-GAME when a term is not yet translated to the current language?"), EditorStyles.boldLabel, GUILayout.Width(200));
GUILayout.BeginVertical();
GUILayout.Space(7);
EditorGUILayout.PropertyField(mProp_OnMissingTranslation, GUITools.EmptyContent, GUILayout.Width(165));
GUILayout.EndVertical();
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.Label(new GUIContent("在运行时卸载语言 Unload Languages At Runtime:", "当玩游戏时,插件将卸载所有未使用的语言,只在需要时加载它们\nWhen playing the game, the plugin will unload all unused languages and only load them when needed"), EditorStyles.boldLabel, GUILayout.Width(200));
GUILayout.BeginVertical();
GUILayout.Space(7);
EditorGUILayout.PropertyField(mProp_AllowUnloadingLanguages, GUITools.EmptyContent, GUILayout.Width(165));
GUILayout.EndVertical();
GUILayout.EndHorizontal();
string firstLanguage = "";
if (mLanguageSource.mLanguages.Count > 0)
firstLanguage = " (" + mLanguageSource.mLanguages [0].Name + ")";
GUILayout.BeginHorizontal();
GUILayout.Label(new GUIContent("默认语言:Default Language:", "当游戏开始时,这是将被使用的语言,直到玩家手动选择语言\nWhen the game starts this is the language that will be used until the player manually selects a language"), EditorStyles.boldLabel, GUILayout.Width(160));
GUILayout.BeginVertical();
GUILayout.Space(7);
mProp_IgnoreDeviceLanguage.boolValue = EditorGUILayout.Popup(mProp_IgnoreDeviceLanguage.boolValue?1:0, new[]{"Device Language", "First in List"+firstLanguage}, GUILayout.ExpandWidth(true))==1;
GUILayout.EndVertical();
GUILayout.EndHorizontal();
}
#region GUI Languages
void OnGUI_LanguageList()
{
GUILayout.BeginHorizontal(EditorStyles.toolbar);
GUILayout.FlexibleSpace();
GUILayout.Label ("Languages:", EditorStyles.miniLabel, GUILayout.ExpandWidth(false));
GUILayout.FlexibleSpace();
GUILayout.Label ("Code:", EditorStyles.miniLabel);
GUILayout.Space(170);
GUILayout.EndHorizontal();
//--[ Language List ]--------------------------
int IndexLanguageToDelete = -1;
int LanguageToMoveUp = -1;
int LanguageToMoveDown = -1;
GUI.backgroundColor = Color.Lerp(GUITools.LightGray, Color.white, 0.5f);
mScrollPos_Languages = GUILayout.BeginScrollView( mScrollPos_Languages, LocalizeInspector.GUIStyle_OldTextArea, GUILayout.MinHeight (200), /*GUILayout.MaxHeight(Screen.height),*/ GUILayout.ExpandHeight(false));
GUI.backgroundColor = Color.white;
if (mLanguageCodePopupList == null || mLanguageCodePopupList.Count==0)
{
mLanguageCodePopupList = GoogleLanguages.GetLanguagesForDropdown("", "");
mLanguageCodePopupList.Sort();
mLanguageCodePopupList.Insert(0, string.Empty);
}
for (int i=0, imax=mProp_Languages.arraySize; i<imax; ++i)
{
SerializedProperty Prop_Lang = mProp_Languages.GetArrayElementAtIndex(i);
SerializedProperty Prop_LangName = Prop_Lang.FindPropertyRelative("Name");
SerializedProperty Prop_LangCode = Prop_Lang.FindPropertyRelative("Code");
SerializedProperty Prop_Flags = Prop_Lang.FindPropertyRelative("Flags");
bool isLanguageEnabled = (Prop_Flags.intValue & (int)eLanguageDataFlags.DISABLED)==0;
GUI.color = isLanguageEnabled ? Color.white : new Color(1, 1, 1, 0.3f);
GUILayout.BeginHorizontal();
if (GUILayout.Button ("X", "toolbarbutton", GUILayout.ExpandWidth(false)))
{
IndexLanguageToDelete = i;
}
GUILayout.BeginHorizontal(EditorStyles.toolbar);
EditorGUI.BeginChangeCheck();
string LanName = EditorGUILayout.TextField(Prop_LangName.stringValue, GUILayout.ExpandWidth(true));
if (EditorGUI.EndChangeCheck() && !string.IsNullOrEmpty(LanName))
{
Prop_LangName.stringValue = LanName;
}
var currentCode = "[" + Prop_LangCode.stringValue + "]";
if (isLanguageEnabled)
{
int Index = Mathf.Max(0, mLanguageCodePopupList.FindIndex(c => c.Contains(currentCode)));
EditorGUI.BeginChangeCheck();
Index = EditorGUILayout.Popup(Index, mLanguageCodePopupList.ToArray(), EditorStyles.toolbarPopup, GUILayout.Width(60));
if (EditorGUI.EndChangeCheck() && Index >= 0)
{
currentCode = mLanguageCodePopupList[Index];
int i0 = currentCode.IndexOf("[");
int i1 = currentCode.IndexOf("]");
if (i0 >= 0 && i1 > i0)
Prop_LangCode.stringValue = currentCode.Substring(i0 + 1, i1 - i0 - 1);
else
Prop_LangCode.stringValue = string.Empty;
}
var rect = GUILayoutUtility.GetLastRect();
GUI.Label(rect, Prop_LangCode.stringValue, EditorStyles.toolbarPopup);
}
else
{
GUILayout.Label(Prop_LangCode.stringValue, EditorStyles.toolbarPopup, GUILayout.Width(60));
}
GUILayout.EndHorizontal();
GUI.enabled = i<imax-1;
if (GUILayout.Button( "\u25BC", EditorStyles.toolbarButton, GUILayout.Width(18))) LanguageToMoveDown = i;
GUI.enabled = i>0;
if (GUILayout.Button( "\u25B2", EditorStyles.toolbarButton, GUILayout.Width(18))) LanguageToMoveUp = i;
GUI.enabled = true;
if (GUILayout.Button( new GUIContent("预览 Show", "预览该语言的所有本地化\nPreview all localizations into this language"), EditorStyles.toolbarButton, GUILayout.Width(35)))
{
LocalizationManager.SetLanguageAndCode( LanName, Prop_LangCode.stringValue, false, true);
}
if (TestButtonArg( eTest_ActionType.Button_Languages_TranslateAll, i, new GUIContent("翻译 Translate", "翻译所有空词\nTranslate all empty terms"), EditorStyles.toolbarButton, GUILayout.ExpandWidth(false)))
{
GUITools.DelayedCall( () => TranslateAllToLanguage(LanName));
}
GUI.enabled = true;
GUI.color = Color.white;
EditorGUI.BeginChangeCheck();
isLanguageEnabled = EditorGUILayout.Toggle(isLanguageEnabled, GUILayout.Width(15));
var r = GUILayoutUtility.GetLastRect();
GUI.Label(r, new GUIContent("", "启用/禁用语言\nEnable/Disable the language.\n禁用语言可用于存储数据值或避免显示仍在开发中的语言\nDisabled languages can be used to store data values or to avoid showing Languages that are stil under development"));
if (EditorGUI.EndChangeCheck())
{
Prop_Flags.intValue = (Prop_Flags.intValue & ~(int)eLanguageDataFlags.DISABLED) | (isLanguageEnabled ? 0 : (int)eLanguageDataFlags.DISABLED);
}
GUILayout.EndHorizontal();
}
GUILayout.EndScrollView();
OnGUI_AddLanguage( mProp_Languages );
if (mConnection_WWW!=null || mConnection_Text.Contains("Translating"))
{
// Connection Status Bar
int time = (int)(Time.realtimeSinceStartup % 2 * 2.5);
string Loading = mConnection_Text + ".....".Substring(0, time);
GUI.color = Color.gray;
GUILayout.BeginHorizontal(LocalizeInspector.GUIStyle_OldTextArea);
GUILayout.Label (Loading, EditorStyles.miniLabel);
GUI.color = Color.white;
if (GUILayout.Button("Cancel", EditorStyles.toolbarButton, GUILayout.ExpandWidth(false)))
{
GoogleTranslation.CancelCurrentGoogleTranslations ();
StopConnectionWWW();
}
GUILayout.EndHorizontal();
Repaint();
}
if (IndexLanguageToDelete>=0)
{
if (EditorUtility.DisplayDialog ("确认删除 Confirm delete", "您确定要删除所选语言吗\nAre you sure you want to delete the selected language", "Yes", "Cancel"))
{
mLanguageSource.RemoveLanguage (mLanguageSource.mLanguages [IndexLanguageToDelete].Name);
serializedObject.Update ();
ParseTerms (true, false, false);
}
}
if (LanguageToMoveUp>=0) SwapLanguages( LanguageToMoveUp, LanguageToMoveUp-1 );
if (LanguageToMoveDown>=0) SwapLanguages( LanguageToMoveDown, LanguageToMoveDown+1 );
}
void SwapLanguages( int iFirst, int iSecond )
{
serializedObject.ApplyModifiedProperties();
LanguageSourceData Source = mLanguageSource;
SwapValues( Source.mLanguages, iFirst, iSecond );
foreach (TermData termData in Source.mTerms)
{
SwapValues ( termData.Languages, iFirst, iSecond );
SwapValues ( termData.Flags, iFirst, iSecond );
}
serializedObject.Update();
}
void SwapValues( List<LanguageData> mList, int Index1, int Index2 )
{
LanguageData temp = mList[Index1];
mList[Index1] = mList[Index2];
mList[Index2] = temp;
}
void SwapValues( string[] mList, int Index1, int Index2 )
{
string temp = mList[Index1];
mList[Index1] = mList[Index2];
mList[Index2] = temp;
}
void SwapValues( byte[] mList, int Index1, int Index2 )
{
byte temp = mList[Index1];
mList[Index1] = mList[Index2];
mList[Index2] = temp;
}
void OnGUI_AddLanguage( SerializedProperty Prop_Languages)
{
//--[ Add Language Upper Toolbar ]-----------------
GUILayout.BeginVertical();
GUILayout.BeginHorizontal();
GUILayout.BeginHorizontal(EditorStyles.toolbar);
mLanguages_NewLanguage = EditorGUILayout.TextField("", mLanguages_NewLanguage, EditorStyles.toolbarTextField, GUILayout.ExpandWidth(true));
GUILayout.EndHorizontal();
GUI.enabled = !string.IsNullOrEmpty (mLanguages_NewLanguage);
if (TestButton(eTest_ActionType.Button_AddLanguageManual,"Add", EditorStyles.toolbarButton, GUILayout.Width(50)))
{
Prop_Languages.serializedObject.ApplyModifiedProperties();
mLanguageSource.AddLanguage( mLanguages_NewLanguage, GoogleLanguages.GetLanguageCode(mLanguages_NewLanguage) );
Prop_Languages.serializedObject.Update();
mLanguages_NewLanguage = "";
GUI.FocusControl(string.Empty);
}
GUI.enabled = true;
GUILayout.EndHorizontal();
//--[ Add Language Bottom Toolbar ]-----------------
GUILayout.BeginHorizontal();
//-- Language Dropdown -----------------
string CodesToExclude = string.Empty;
foreach (var LanData in mLanguageSource.mLanguages)
CodesToExclude = string.Concat(CodesToExclude, "[", LanData.Code, "]");
List<string> Languages = GoogleLanguages.GetLanguagesForDropdown(mLanguages_NewLanguage, CodesToExclude);
GUI.changed = false;
int index = EditorGUILayout.Popup(0, Languages.ToArray(), EditorStyles.toolbarDropDown);
if (GUI.changed && index>=0)
{
mLanguages_NewLanguage = GoogleLanguages.GetFormatedLanguageName( Languages[index] );
}
if (TestButton(eTest_ActionType.Button_AddLanguageFromPopup, "Add", EditorStyles.toolbarButton, GUILayout.Width(50)) && index>=0)
{
Prop_Languages.serializedObject.ApplyModifiedProperties();
mLanguages_NewLanguage = GoogleLanguages.GetFormatedLanguageName(Languages[index]);
if (!string.IsNullOrEmpty(mLanguages_NewLanguage))
mLanguageSource.AddLanguage(mLanguages_NewLanguage, GoogleLanguages.GetLanguageCode(mLanguages_NewLanguage));
Prop_Languages.serializedObject.Update();
mLanguages_NewLanguage = "";
GUI.FocusControl(string.Empty);
}
GUILayout.EndHorizontal();
GUILayout.EndVertical();
GUI.color = Color.white;
}
void TranslateAllToLanguage (string lanName)
{
if (!GoogleTranslation.CanTranslate ())
{
ShowError ("WebService设置不正确或需要重新安装。\nWebService is not set correctly or needs to be reinstalled");
return;
}
ClearErrors();
int LanIndex = mLanguageSource.GetLanguageIndex (lanName);
string code = mLanguageSource.mLanguages [LanIndex].Code;
string googleCode = GoogleLanguages.GetGoogleLanguageCode(code);
if (string.IsNullOrEmpty(googleCode))
{
ShowError("Language '" + code + "' 不支持谷歌翻译 is not supported by google translate");
return;
}
googleCode = code;
mTranslationTerms.Clear ();
mTranslationRequests.Clear ();
foreach (var termData in mLanguageSource.mTerms)
{
if (termData.TermType != eTermType.Text)
continue;
if (!string.IsNullOrEmpty(termData.Languages[LanIndex]))
continue;
string sourceCode, sourceText;
FindTranslationSource( LanguageSourceData.GetKeyFromFullTerm(termData.Term), termData, code, null, out sourceText, out sourceCode );
mTranslationTerms.Add (termData.Term);
GoogleTranslation.CreateQueries(sourceText, sourceCode, googleCode, mTranslationRequests); // can split plurals into several queries
}
if (mTranslationRequests.Count == 0)
{
StopConnectionWWW ();
return;
}
mConnection_WWW = null;
mConnection_Text = "Translating"; if (mTranslationRequests.Count > 1) mConnection_Text += " (" + mTranslationRequests.Count + ")";
mConnection_Callback = null;
//EditorApplication.update += CheckForConnection;
GoogleTranslation.Translate (mTranslationRequests, OnLanguageTranslated);
}
void OnLanguageTranslated( Dictionary<string, TranslationQuery> requests, string Error )
{
//Debug.Log (Result);
//if (Result.Contains("Service invoked too many times"))
//{
// TimeStartTranslation = EditorApplication.timeSinceStartup + 1;
// EditorApplication.update += DelayedStartTranslation;
// mConnection_Text = "Translating (" + mTranslationRequests.Count + ")";
// return;
//}
//if (!string.IsNullOrEmpty(Error))/* || !Result.Contains("<i2>")*/
//{
// Debug.LogError("WEB ERROR: " + Error);
// ShowError ("Unable to access Google or not valid request");
// return;
//}
ClearErrors();
StopConnectionWWW();
if (!string.IsNullOrEmpty(Error))
{
ShowError (Error);
return;
}
if (requests.Values.Count == 0)
return;
var langCode = requests.Values.First().TargetLanguagesCode [0];
//langCode = GoogleLanguages.GetGoogleLanguageCode(langCode);
int langIndex = mLanguageSource.GetLanguageIndexFromCode (langCode, false);
//if (langIndex >= 0)
{
foreach (var term in mTranslationTerms)
{
var termData = mLanguageSource.GetTermData(term);
if (termData == null)
continue;
if (termData.TermType != eTermType.Text)
continue;
//if (termData.Languages.Length <= langIndex)
// continue;
string sourceCode, sourceText;
FindTranslationSource(LanguageSourceData.GetKeyFromFullTerm(termData.Term), termData, langCode, null, out sourceText, out sourceCode);
string result = GoogleTranslation.RebuildTranslation(sourceText, mTranslationRequests, langCode); // gets the result from google and rebuilds the text from multiple queries if its is plurals
termData.Languages[langIndex] = result;
}
}
mTranslationTerms.Clear ();
mTranslationRequests.Clear ();
StopConnectionWWW ();
}
#endregion
#region Store Integration
void OnGUI_StoreIntegration()
{
GUIStyle lstyle = new GUIStyle (EditorStyles.label);
lstyle.richText = true;
GUILayout.BeginHorizontal ();
GUILayout.Label (new GUIContent("Store Integration:", "设置商店来检测游戏的本地化Android为每种语言添加字符串xml。Ios修改了Info列表\nSetups the stores to detect that the game has localization, Android adds strings.xml for each language. IOS modifies the Info.plist"), EditorStyles.boldLabel, GUILayout.Width(160));
GUILayout.FlexibleSpace();
GUILayout.Label( new GUIContent( "<color=green><size=16>\u2713</size></color> IOS", "Setups the stores to show in iTunes and the Appstore all the languages that this app supports, also localizes the app name if available" ), lstyle, GUILayout.Width( 90 ) );
GUILayout.Label( new GUIContent( "<color=green><size=16>\u2713</size></color> Android", "Setups the stores to show in GooglePlay all the languages this app supports, also localizes the app name if available" ), lstyle, GUILayout.Width( 90 ) );
GUILayout.EndHorizontal ();
GUILayout.BeginHorizontal();
mAppNameTerm_Expanded = GUILayout.Toggle(mAppNameTerm_Expanded, new GUIContent( "应用名称翻译:\nApp Name translations:", "根据设备的语言,游戏应该如何命名\nHow should the game be named in the devices based on their language" ), EditorStyles.foldout, GUILayout.Width( 160 ) );
GUILayout.Label("", GUILayout.ExpandWidth(true));
var rect = GUILayoutUtility.GetLastRect();
TermsPopup_Drawer.ShowGUI( rect, mProp_AppNameTerm, GUITools.EmptyContent, mLanguageSource);
if (GUILayout.Button("New Term", EditorStyles.miniButton, GUILayout.ExpandWidth(false)))
{
AddLocalTerm("App_Name");
mProp_AppNameTerm.stringValue = "App_Name";
mAppNameTerm_Expanded = true;
}
GUILayout.EndHorizontal();
if (mAppNameTerm_Expanded)
{
GUILayout.BeginHorizontal();
GUILayout.Space(10);
GUILayout.BeginVertical("Box");
var termName = mProp_AppNameTerm.stringValue;
if (!string.IsNullOrEmpty(termName))
{
var termData = LocalizationManager.GetTermData(termName);
if (termData != null)
OnGUI_Keys_Languages(mProp_AppNameTerm.stringValue, ref termData, null, true, mLanguageSource);
}
GUILayout.Space(10);
GUILayout.BeginHorizontal();
GUILayout.Label("<b>Default App Name:</b>", lstyle, GUITools.DontExpandWidth);
GUILayout.Label(Application.productName);
GUILayout.EndHorizontal();
GUILayout.EndVertical();
GUILayout.EndHorizontal();
}
}
#endregion
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 304783c1e95d94a598aecd17728c8556
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,717 @@
using System;
using System.Collections.Generic;
using System.Text;
using I2.Loc.SimpleJSON;
using UnityEditor;
using UnityEngine;
using UnityEngine.Networking;
namespace I2.Loc
{
public partial class LocalizationEditor
{
#region Variables
public static Dictionary<string, string> mGoogleSpreadsheets = new Dictionary<string, string>(StringComparer.Ordinal);
public UnityWebRequest mConnection_WWW;
delegate void fnConnectionCallback(string Result, string Error);
event fnConnectionCallback mConnection_Callback;
//float mConnection_TimeOut;
string mConnection_Text = string.Empty;
string mWebService_Status;
#endregion
#region GUI
void OnGUI_Spreadsheet_Google()
{
GUILayout.Space(20);
#if UNITY_WEBPLAYER
mConnection_Text = string.Empty;
EditorGUILayout.HelpBox("在WebPlayer模式下不支持Google同步\nGoogle Synchronization is not supported when in WebPlayer mode." + mConnection_Text, MessageType.Info);
mProp_GoogleUpdateFrequency.enumValueIndex = mProp_GoogleUpdateFrequency.enumValueIndex; // to avoid the warning "unused"
mProp_GoogleUpdateSynchronization.enumValueIndex = mProp_GoogleUpdateSynchronization.enumValueIndex;
#else
OnGUI_GoogleCredentials();
OnGUI_ShowMsg();
if (string.IsNullOrEmpty(mProp_Google_WebServiceURL.stringValue))
return;
if (mWebService_Status == "Offline")
return;
GUILayout.Space(20);
GUI.backgroundColor = Color.Lerp(Color.gray, Color.white, 0.5f);
GUILayout.BeginVertical(LocalizeInspector.GUIStyle_OldTextArea, GUILayout.Height (1));
GUI.backgroundColor = Color.white;
GUILayout.Space(10);
GUILayout.BeginHorizontal();
GUILayout.Label(new GUIContent(" Password", "This should match the value of the LocalizationPassword variable in the WebService Script in your Google Drive"), GUILayout.Width(108));
mProp_Google_Password.stringValue = EditorGUILayout.TextField(mProp_Google_Password.stringValue, GUILayout.ExpandWidth(true));
GUILayout.EndHorizontal();
OnGUI_GoogleSpreadsheetsInGDrive();
GUILayout.EndVertical();
if (mConnection_WWW!=null)
{
// Connection Status Bar
int time = (int)(Time.realtimeSinceStartup % 2 * 2.5);
string Loading = mConnection_Text + ".....".Substring(0, time);
GUI.color = Color.gray;
GUILayout.BeginHorizontal(LocalizeInspector.GUIStyle_OldTextArea);
GUILayout.Label (Loading, EditorStyles.miniLabel);
GUI.color = Color.white;
if (GUILayout.Button("Cancel", EditorStyles.toolbarButton, GUILayout.ExpandWidth(false)))
StopConnectionWWW();
GUILayout.EndHorizontal();
Repaint();
}
//else
// GUILayout.Space(10);
EditorGUI.BeginChangeCheck();
GUILayout.Space(5);
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
LanguageSourceData.eGoogleUpdateFrequency GoogleUpdateFrequency = (LanguageSourceData.eGoogleUpdateFrequency)mProp_GoogleUpdateFrequency.enumValueIndex;
GoogleUpdateFrequency = (LanguageSourceData.eGoogleUpdateFrequency)EditorGUILayout.EnumPopup("Auto Update Frequency", GoogleUpdateFrequency, GUILayout.ExpandWidth(true));
if (EditorGUI.EndChangeCheck())
{
mProp_GoogleUpdateFrequency.enumValueIndex = (int)GoogleUpdateFrequency;
}
GUILayout.Space(10);
GUILayout.Label("Delay:");
mProp_GoogleUpdateDelay.floatValue = EditorGUILayout.FloatField(mProp_GoogleUpdateDelay.floatValue, GUILayout.Width(30));
GUILayout.Label("secs");
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
var GoogleInEditorCheckFrequency = (LanguageSourceData.eGoogleUpdateFrequency)mProp_GoogleInEditorCheckFrequency.enumValueIndex;
EditorGUI.BeginChangeCheck();
GoogleInEditorCheckFrequency = (LanguageSourceData.eGoogleUpdateFrequency)EditorGUILayout.EnumPopup(new GUIContent("In-Editor Check Frequency", "How often the editor will verify that the Spreadsheet is up-to-date with the LanguageSource. Having un-synchronized Spreadsheets can lead to issues when playing in the device as the download data will override the one in the build"), GoogleInEditorCheckFrequency, GUILayout.ExpandWidth(false));
if (EditorGUI.EndChangeCheck())
{
mProp_GoogleInEditorCheckFrequency.enumValueIndex = (int)GoogleInEditorCheckFrequency;
}
GUILayout.Space(122);
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
GUILayout.Label("Update Synchronization", GUILayout.Width(180));
EditorGUI.BeginChangeCheck();
LanguageSourceData.eGoogleUpdateSynchronization GoogleUpdateSynchronization = (LanguageSourceData.eGoogleUpdateSynchronization)mProp_GoogleUpdateSynchronization.enumValueIndex;
GoogleUpdateSynchronization = (LanguageSourceData.eGoogleUpdateSynchronization)EditorGUILayout.EnumPopup(GoogleUpdateSynchronization, GUILayout.Width(178));
if (EditorGUI.EndChangeCheck())
{
mProp_GoogleUpdateSynchronization.enumValueIndex = (int)GoogleUpdateSynchronization;
}
GUILayout.EndHorizontal();
GUILayout.Space(5);
GUI.changed = false;
bool OpenDataSourceAfterExport = EditorPrefs.GetBool("I2Loc OpenDataSourceAfterExport", true);
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
OpenDataSourceAfterExport = GUILayout.Toggle(OpenDataSourceAfterExport, "Open Spreadsheet after Export");
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
if (GUI.changed)
{
GUI.changed = false;
EditorPrefs.SetBool("I2Loc OpenDataSourceAfterExport", OpenDataSourceAfterExport);
}
#endif
GUILayout.Space(5);
}
void OnGUI_GoogleCredentials()
{
GUI.enabled = mConnection_WWW==null;
GUI.changed = false;
string WebServiceHelp = "The web service is a script running on the google drive where the spreadsheet you want to use is located.\nThat script allows the game to synchronize the localization even after the game is published.";
GUILayout.BeginHorizontal();
GUILayout.Label (new GUIContent("Web Service URL:", WebServiceHelp), GUILayout.Width(110));
GUI.SetNextControlName ("WebServiceURL");
mProp_Google_WebServiceURL.stringValue = EditorGUILayout.TextField(mProp_Google_WebServiceURL.stringValue);
if (!string.IsNullOrEmpty(mWebService_Status))
{
if (mWebService_Status=="Online")
{
GUI.color = Color.green;
GUILayout.Label( "", GUILayout.Width(17));
Rect r = GUILayoutUtility.GetLastRect(); r.xMin += 3; r.yMin-= 3; r.xMax+= 2; r.yMax+=2;
GUI.Label( r, new GUIContent("\u2713", "Online"), EditorStyles.whiteLargeLabel);
GUI.color = Color.white;
}
else
if (mWebService_Status=="Offline")
{
GUI.color = Color.red;
GUILayout.Label( "", GUILayout.Width(17));
Rect r = GUILayoutUtility.GetLastRect(); r.xMin += 3; r.yMin-= 3; r.xMax+= 2; r.yMax+=2;
GUI.Label( r, new GUIContent("\u2717", mWebService_Status), EditorStyles.whiteLargeLabel);
GUI.color = Color.white;
}
else
if (mWebService_Status=="UnsupportedVersion")
{
Rect rect = GUILayoutUtility.GetLastRect();
float Width = 15;
rect.xMin = rect.xMax+1;
rect.xMax = rect.xMin + rect.height;
GUITools.DrawSkinIcon(rect, "CN EntryWarnIcon", "CN EntryWarn");
GUI.Label(rect, new GUIContent("\u2717", "The current Google WebService is not supported.\nPlease, delete the WebService from the Google Drive and Install the latest version."));
GUILayout.Space (Width);
}
}
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.Space (118);
if (GUILayout.Button(new GUIContent("Install", "This opens the Web Service Script and shows you steps to install and authorize it on your Google Drive"), EditorStyles.toolbarButton))
{
ClearErrors();
Application.OpenURL("https://script.google.com/d/1zcsLSmq3Oddd8AsLuoKNDG1Y0eYBOHzyvGT7v94u1oN6igmsZb_PJzEm/newcopy"); // V5
//Application.OpenURL("https://goo.gl/RBCO0o"); // V4:https://script.google.com/d/1T7e5_40NcgRyind-yeg4PAkHz9TNZJ22F4RcbOvCpAs03JNf1vKNNTZB/newcopy
//Application.OpenURL("https://goo.gl/wFSbv2");// V3:https://script.google.com/d/1CxQDSXflsXRaH3M7xGfrIDrFwOIHWPsYTWi4mRZ_k77nyIInTgIk63Kd/newcopy");
}
if (GUILayout.Button("Verify", EditorStyles.toolbarButton))
{
ClearErrors();
VerifyGoogleService(mProp_Google_WebServiceURL.stringValue);
GUI.changed = false;
}
GUILayout.EndHorizontal();
if (string.IsNullOrEmpty(mProp_Google_WebServiceURL.stringValue))
{
EditorGUILayout.HelpBox(WebServiceHelp, MessageType.Info);
}
if (GUI.changed)
{
if (string.IsNullOrEmpty(mProp_Google_WebServiceURL.stringValue))
{
mProp_Google_SpreadsheetKey.stringValue = string.Empty;
mProp_Google_SpreadsheetName.stringValue = string.Empty;
}
// If the web service changed then clear the cached spreadsheet keys
mGoogleSpreadsheets.Clear();
GUI.changed = false;
ClearErrors();
}
GUI.enabled = true;
}
void OnGUI_GoogleSpreadsheetsInGDrive()
{
GUI.enabled = mConnection_WWW==null;
string[] Spreadsheets;
string[] SpreadsheetsKey;
if (mGoogleSpreadsheets.Count>0 || string.IsNullOrEmpty(mProp_Google_SpreadsheetKey.stringValue))
{
Spreadsheets = new List<string>(mGoogleSpreadsheets.Keys).ToArray();
SpreadsheetsKey = new List<string>(mGoogleSpreadsheets.Values).ToArray();
}
else
{
Spreadsheets = new[]{mProp_Google_SpreadsheetName.stringValue ?? string.Empty};
SpreadsheetsKey = new[]{mProp_Google_SpreadsheetKey.stringValue ?? string.Empty};
}
int mSpreadsheetIndex = Array.IndexOf(SpreadsheetsKey, mProp_Google_SpreadsheetKey.stringValue);
//--[ Spreadsheets ]------------------
GUILayout.BeginHorizontal();
GUILayout.Space(10);
GUILayout.Label ("In Google Drive:", GUILayout.Width(100));
GUI.changed = false;
GUI.enabled = Spreadsheets != null && Spreadsheets.Length>0;
mSpreadsheetIndex = EditorGUILayout.Popup(mSpreadsheetIndex, Spreadsheets, EditorStyles.toolbarPopup);
if (GUI.changed && mSpreadsheetIndex >= 0)
{
mProp_Google_SpreadsheetKey.stringValue = SpreadsheetsKey[mSpreadsheetIndex];
mProp_Google_SpreadsheetName.stringValue = Spreadsheets[mSpreadsheetIndex];
GUI.changed = false;
}
GUI.enabled = true;
GUI.enabled = !string.IsNullOrEmpty(mProp_Google_SpreadsheetKey.stringValue) && mConnection_WWW==null;
if (GUILayout.Button("X", EditorStyles.toolbarButton,GUILayout.ExpandWidth(false)))
mProp_Google_SpreadsheetKey.stringValue = string.Empty;
GUI.enabled = true;
GUILayout.Space(10);
GUILayout.EndHorizontal();
GUILayout.Space(2);
//--[ Spreadsheets Operations ]------------------
GUILayout.BeginHorizontal();
GUILayout.Space(114);
if (GUILayout.Button("New", EditorStyles.toolbarButton,GUILayout.ExpandWidth(true)))
Google_NewSpreadsheet();
GUI.enabled = !string.IsNullOrEmpty(mProp_Google_SpreadsheetKey.stringValue) && mConnection_WWW==null;
if (GUILayout.Button("Open", EditorStyles.toolbarButton,GUILayout.ExpandWidth(true)))
OpenGoogleSpreadsheet(mProp_Google_SpreadsheetKey.stringValue);
GUI.enabled = mConnection_WWW==null;
GUILayout.Space(5);
if (TestButton(eTest_ActionType.Button_GoogleSpreadsheet_RefreshList, "Refresh", EditorStyles.toolbarButton,GUILayout.ExpandWidth(true)))
EditorApplication.update+=Google_FindSpreadsheets;
GUILayout.Space(10);
GUILayout.EndHorizontal();
GUILayout.Space(15);
if (!string.IsNullOrEmpty(mProp_Google_SpreadsheetKey.stringValue))
OnGUI_GoogleButtons_ImportExport( mProp_Google_SpreadsheetKey.stringValue );
GUI.enabled = true;
}
private void OnGUI_ImportButtons()
{
eSpreadsheetUpdateMode Mode = SynchronizationButtons("Import");
if (Mode != eSpreadsheetUpdateMode.None || InTestAction(eTest_ActionType.Button_GoogleSpreadsheet_Import))
{
if (mTestAction == eTest_ActionType.Button_GoogleSpreadsheet_Import)
Mode = (eSpreadsheetUpdateMode)mTestActionArg;
serializedObject.ApplyModifiedProperties();
var modeCopy = Mode;
GUITools.DelayedCall(() => Import_Google(modeCopy));
}
}
private void OnGUI_ExportButtons()
{
eSpreadsheetUpdateMode Mode = SynchronizationButtons("Export");
if (Mode != eSpreadsheetUpdateMode.None || InTestAction(eTest_ActionType.Button_GoogleSpreadsheet_Export))
{
if (mTestAction == eTest_ActionType.Button_GoogleSpreadsheet_Export)
Mode = (eSpreadsheetUpdateMode)mTestActionArg;
serializedObject.ApplyModifiedProperties();
var modeCopy = Mode;
GUITools.DelayedCall(() => Export_Google(modeCopy));
}
}
void OnGUI_GoogleButtons_ImportExport( string SpreadsheetKey )
{
GUI.enabled = !string.IsNullOrEmpty(SpreadsheetKey) && mConnection_WWW==null;
bool vertical = EditorGUIUtility.currentViewWidth < 450;
if (vertical)
{
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
OnGUI_ImportButtons();
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
OnGUI_ExportButtons();
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
}
else
{
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
OnGUI_ImportButtons();
GUILayout.FlexibleSpace();
OnGUI_ExportButtons();
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
}
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
EditorGUIUtility.labelWidth += 10;
EditorGUILayout.PropertyField(mProp_Spreadsheet_SpecializationAsRows, new GUIContent("Show Specializations as Rows", "true: Make each specialization a separate row (e.g. Term[VR]..., Term[Touch]....\nfalse: Merge specializations into same cell separated by [i2s_XXX]"));
EditorGUIUtility.labelWidth -= 10;
GUILayout.EndHorizontal();
GUILayout.Space(10);
GUI.enabled = true;
}
eSpreadsheetUpdateMode SynchronizationButtons( string Operation, bool ForceReplace = false )
{
eSpreadsheetUpdateMode Result = eSpreadsheetUpdateMode.None;
GUILayout.BeginVertical(LocalizeInspector.GUIStyle_OldTextArea, GUILayout.Width (1));
GUI.backgroundColor = Color.white;
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
GUILayout.Label(Operation, EditorStyles.miniLabel);
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
if (GUILayout.Button( "替换 Replace", EditorStyles.toolbarButton, GUILayout.Width(100)))
Result = eSpreadsheetUpdateMode.Replace;
if (ForceReplace) GUI.enabled = false;
if (GUILayout.Button( "合并 Merge", EditorStyles.toolbarButton, GUILayout.Width(100)))
Result = eSpreadsheetUpdateMode.Merge;
if (GUILayout.Button( "新建 Add New", EditorStyles.toolbarButton, GUILayout.Width(100)))
Result = eSpreadsheetUpdateMode.AddNewTerms;
GUI.enabled = mConnection_WWW==null;
GUILayout.Space(1);
GUILayout.EndHorizontal();
GUILayout.Space(2);
GUILayout.EndVertical();
if (Result != eSpreadsheetUpdateMode.None)
ClearErrors();
return Result;
}
#endregion
void VerifyGoogleService( string WebServiceURL )
{
#if UNITY_WEBPLAYER
ShowError ("Contacting google translation is not yet supported on WebPlayer" );
#else
StopConnectionWWW();
mWebService_Status = null;
mConnection_WWW = UnityWebRequest.Get(WebServiceURL + "?action=Ping");
I2Utils.SendWebRequest(mConnection_WWW);
mConnection_Callback = OnVerifyGoogleService;
EditorApplication.update += CheckForConnection;
mConnection_Text = "Verifying Web Service";
//mConnection_TimeOut = Time.realtimeSinceStartup + 10;
#endif
}
void OnVerifyGoogleService( string Result, string Error )
{
if (Result.Contains("Authorization is required to perform that action"))
{
ShowWarning("You need to authorize the webservice before using it. Check the steps 4 and 5 in the WebService Script");
mWebService_Status = "Offline";
return;
}
try
{
var data = JSON.Parse(Result).AsObject;
int version = 0;
if (!int.TryParse(data["script_version"], out version))
version = 0;
int requiredVersion = LocalizationManager.GetRequiredWebServiceVersion();
if (requiredVersion == version)
{
mWebService_Status = "Online";
ClearErrors();
}
else
{
mWebService_Status = "UnsupportedVersion";
ShowError("The current Google WebService is not supported.\nPlease, delete the WebService from the Google Drive and Install the latest version.");
}
}
catch (Exception)
{
ShowError("Unable to access the WebService");
mWebService_Status = "Offline";
}
}
void Export_Google( eSpreadsheetUpdateMode UpdateMode )
{
StopConnectionWWW();
LanguageSourceData source = GetSourceData();
mConnection_WWW = source.Export_Google_CreateWWWcall( UpdateMode );
if (mConnection_WWW==null)
{
OnExported_Google(string.Empty, "WebPlayer can't contact Google");
}
else
{
mConnection_Callback = OnExported_Google;
EditorApplication.update += CheckForConnection;
mConnection_Text = "Uploading spreadsheet";
//mConnection_TimeOut = Time.realtimeSinceStartup + 10;
}
}
void OnExported_Google( string Result, string Error )
{
// Checkf or error, but discard the "necessary data rewind wasn't possible" as thats not a real error, just a bug in Unity with POST redirects
if (!string.IsNullOrEmpty(Error) && !Error.Contains("rewind"))
{
Debug.Log (Error);
ShowError("Unable to access google");
return;
}
if (EditorPrefs.GetBool("I2Loc OpenDataSourceAfterExport", true) && !string.IsNullOrEmpty(GetSourceData().Google_SpreadsheetName))
OpenGoogleSpreadsheet(GetSourceData().Google_SpreadsheetKey );
mProp_GoogleLiveSyncIsUptoDate.boolValue = true;
}
static void OpenGoogleSpreadsheet( string SpreadsheetKey )
{
ClearErrors();
string SpreadsheetUrl = "https://docs.google.com/spreadsheet/ccc?key=" + SpreadsheetKey;
Application.OpenURL(SpreadsheetUrl);
}
public abstract LanguageSourceData GetSourceData();
void Import_Google( eSpreadsheetUpdateMode UpdateMode )
{
StopConnectionWWW();
LanguageSourceData source = GetSourceData();
mConnection_WWW = source.Import_Google_CreateWWWcall(true, false);
if (mConnection_WWW==null)
{
OnImported_Google(string.Empty, "Unable to import from google", eSpreadsheetUpdateMode.Replace);
}
else
{
mConnection_Callback=null;
switch (UpdateMode)
{
case eSpreadsheetUpdateMode.Replace : mConnection_Callback += OnImported_Google_Replace; break;
case eSpreadsheetUpdateMode.Merge : mConnection_Callback += OnImported_Google_Merge; break;
case eSpreadsheetUpdateMode.AddNewTerms : mConnection_Callback += OnImported_Google_AddNewTerms; break;
}
EditorApplication.update += CheckForConnection;
mConnection_Text = "Downloading spreadsheet";
//mConnection_TimeOut = Time.realtimeSinceStartup + 10;
}
}
void OnImported_Google_Replace( string Result, string Error ) { OnImported_Google(Result, Error, eSpreadsheetUpdateMode.Replace); }
void OnImported_Google_Merge( string Result, string Error ) { OnImported_Google(Result, Error, eSpreadsheetUpdateMode.Merge); }
void OnImported_Google_AddNewTerms( string Result, string Error ) { OnImported_Google(Result, Error, eSpreadsheetUpdateMode.AddNewTerms); }
void OnImported_Google( string Result, string Error, eSpreadsheetUpdateMode UpdateMode )
{
if (!string.IsNullOrEmpty(Error))
{
Debug.Log(Error);
ShowError("Unable to access google");
return;
}
LanguageSourceData source = GetSourceData();
string ErrorMsg = source.Import_Google_Result(Result, UpdateMode);
bool HasErrors = !string.IsNullOrEmpty(ErrorMsg);
if (HasErrors)
ShowError(ErrorMsg);
serializedObject.Update();
ParseTerms(true, false, !HasErrors);
mSelectedKeys.Clear ();
mSelectedCategories.Clear();
ScheduleUpdateTermsToShowInList();
mLanguageSource.GetCategories(false, mSelectedCategories);
EditorUtility.SetDirty (target);
AssetDatabase.SaveAssets();
}
void CheckForConnection()
{
if (mConnection_WWW!=null && mConnection_WWW.isDone)
{
fnConnectionCallback callback = mConnection_Callback;
string Result = string.Empty;
string Error = mConnection_WWW.error;
if (string.IsNullOrEmpty(Error))
{
Result = Encoding.UTF8.GetString(mConnection_WWW.downloadHandler.data); //mConnection_WWW.text;
}
StopConnectionWWW();
if (callback!=null)
callback(Result, Error);
}
/*else
if (Time.realtimeSinceStartup > mConnection_TimeOut+30)
{
fnConnectionCallback callback = mConnection_Callback;
StopConnectionWWW();
if (callback!=null)
callback(string.Empty, "Time Out");
}*/
}
void StopConnectionWWW()
{
EditorApplication.update -= CheckForConnection;
mConnection_WWW = null;
mConnection_Callback = null;
mConnection_Text = string.Empty;
}
#region New Spreadsheet
void Google_NewSpreadsheet()
{
#if UNITY_WEBPLAYER
ShowError ("Contacting google translation is not yet supported on WebPlayer" );
#else
ClearErrors();
string SpreadsheetName;
LanguageSourceData source = GetSourceData();
if (source.IsGlobalSource())
SpreadsheetName = string.Format("{0} Localization", PlayerSettings.productName);
else
SpreadsheetName = string.Format("{0} {1} {2}", PlayerSettings.productName, Editor_GetCurrentScene(), source.ownerObject.name);
string query = mProp_Google_WebServiceURL.stringValue + "?action=NewSpreadsheet&name=" + Uri.EscapeDataString(SpreadsheetName) + "&password="+ Uri.EscapeDataString(mProp_Google_Password.stringValue);
mConnection_WWW = UnityWebRequest.Get(query);
I2Utils.SendWebRequest(mConnection_WWW);
mConnection_Callback = Google_OnNewSpreadsheet;
EditorApplication.update += CheckForConnection;
mConnection_Text = "Creating Spreadsheet";
//mConnection_TimeOut = Time.realtimeSinceStartup + 10;
#endif
}
void Google_OnNewSpreadsheet( string Result, string Error )
{
if (!string.IsNullOrEmpty(Error))
{
ShowError("Unable to access google");
return;
}
if (Result=="Wrong Password")
{
ShowError(Result);
return;
}
try
{
var data = JSON.Parse(Result).AsObject;
string name = data["name"];
string key = data["id"];
serializedObject.Update();
mProp_Google_SpreadsheetKey.stringValue = key;
mProp_Google_SpreadsheetName.stringValue = name;
serializedObject.ApplyModifiedProperties();
mGoogleSpreadsheets[name] = key;
LanguageSourceData source = GetSourceData();
if (source.mTerms.Count>0 || source.mLanguages.Count>0)
Export_Google( eSpreadsheetUpdateMode.Replace );
else
if (EditorPrefs.GetBool("I2Loc OpenDataSourceAfterExport", true))
OpenGoogleSpreadsheet( key );
}
catch(Exception e)
{
ShowError (e.Message);
}
}
#endregion
#region FindSpreadsheets
void Google_FindSpreadsheets()
{
ClearErrors();
EditorApplication.update -= Google_FindSpreadsheets;
string query = mProp_Google_WebServiceURL.stringValue + "?action=GetSpreadsheetList&password="+ Uri.EscapeDataString(mProp_Google_Password.stringValue);
mConnection_WWW = UnityWebRequest.Get(query);
I2Utils.SendWebRequest(mConnection_WWW);
mConnection_Callback = Google_OnFindSpreadsheets;
EditorApplication.update += CheckForConnection;
mConnection_Text = "Accessing google";
//mConnection_TimeOut = Time.realtimeSinceStartup + 10;
}
void Google_OnFindSpreadsheets( string Result, string Error)
{
if (!string.IsNullOrEmpty(Error))
{
ShowError("Unable to access google");
return;
}
if (Result=="Wrong Password")
{
ShowError(Result);
return;
}
try
{
mGoogleSpreadsheets.Clear();
var data = JSON.Parse(Result).AsObject;
foreach (KeyValuePair<string, JSONNode> element in data)
mGoogleSpreadsheets[element.Key] = element.Value;
}
catch(Exception e)
{
ShowError (e.Message);
}
}
#endregion
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 800caf7e364ec2947be099b4f9ed976d
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,335 @@
using System;
using System.IO;
using System.Linq;
using System.Text;
using UnityEditor;
using UnityEngine;
namespace I2.Loc
{
public partial class LocalizationEditor
{
enum eLocalSpreadsheeet { CSV, XLS, XLSX, NONE }
void OnGUI_Spreadsheet_Local()
{
GUILayout.Space(10);
GUILayout.BeginVertical();
GUILayout.BeginHorizontal();
GUILayout.Label ("File:", GUILayout.ExpandWidth(false));
mProp_Spreadsheet_LocalFileName.stringValue = EditorGUILayout.TextField(mProp_Spreadsheet_LocalFileName.stringValue);
/*if (GUILayout.Button("...", "toolbarbutton", GUILayout.ExpandWidth(false)))
{
string sFileName = mProp_Spreadsheet_LocalFileName.stringValue;
string sPath = string.Empty;
try {
sPath = System.IO.Path.GetDirectoryName(sFileName);
}
catch( System.Exception e){}
if (string.IsNullOrEmpty(sPath))
sPath = Application.dataPath + "/";
sFileName = System.IO.Path.GetFileName(sFileName);
if (string.IsNullOrEmpty(sFileName))
sFileName = "Localization.csv";
string FullFileName = EditorUtility.SaveFilePanel("Select CSV File", sPath, sFileName, "csv");
//string FullFileName = EditorUtility.OpenFilePanel("Select CSV, XLS or XLSX File", sFileName, "csv;*.xls;*.xlsx");
if (!string.IsNullOrEmpty(FullFileName))
{
Prop_LocalFileName.stringValue = TryMakingPathRelativeToProject(FullFileName);
}
}*/
GUILayout.EndHorizontal();
//--[ Find current extension ]---------------
eLocalSpreadsheeet CurrentExtension = eLocalSpreadsheeet.NONE;
//string FileNameLower = Prop_LocalFileName.stringValue.ToLower();
/*if (FileNameLower.EndsWith(".csv")) */CurrentExtension = eLocalSpreadsheeet.CSV;
/*if (FileNameLower.EndsWith(".xls")) CurrentExtension = eLocalSpreadsheeet.XLS;
if (FileNameLower.EndsWith(".xlsx")) CurrentExtension = eLocalSpreadsheeet.XLSX;*/
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
switch (CurrentExtension)
{
case eLocalSpreadsheeet.NONE :
case eLocalSpreadsheeet.CSV :
{
string FileTypesDesc = "选择或拖动下列类型的文件:\nSelect or Drag any file of the following types:\n\n";
FileTypesDesc+= "*.csv (逗号分隔值)(Comma Separated Values)\n";
FileTypesDesc+= "*.txt (CSV文件重命名为txt)(CSV file renamed as txt)\n";
//FileTypesDesc+= "\n*.xls (Excel 97-2003)";
//FileTypesDesc+= "\n*.xlsx (Excel Open XML format)";
EditorGUILayout.HelpBox(FileTypesDesc, MessageType.None);
}
break;
case eLocalSpreadsheeet.XLS : EditorGUILayout.HelpBox("Excel 97-2003", MessageType.None); break;
case eLocalSpreadsheeet.XLSX : EditorGUILayout.HelpBox("Excel Open XML format", MessageType.None); break;
}
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
GUILayout.EndVertical();
//--[ Allow Dragging files ]-----------------
if (GUILayoutUtility.GetLastRect().Contains (Event.current.mousePosition) && IsValidDraggedLoadSpreadsheet())
{
if (Event.current.type == EventType.DragUpdated)
DragAndDrop.visualMode = DragAndDropVisualMode.Link;
if (Event.current.type == EventType.DragPerform)
{
mProp_Spreadsheet_LocalFileName.stringValue = TryMakingPathRelativeToProject( DragAndDrop.paths[0] );
DragAndDrop.AcceptDrag();
Event.current.Use();
}
}
GUILayout.Space(10);
OnGUI_Spreadsheet_Local_ImportExport( CurrentExtension, mProp_Spreadsheet_LocalFileName.stringValue );
//if (Application.platform == RuntimePlatform.OSXEditor)
//-- CSV Separator ----------------
GUI.changed = false;
var CSV_Separator = mProp_Spreadsheet_LocalCSVSeparator.stringValue;
if (string.IsNullOrEmpty (CSV_Separator))
CSV_Separator = ",";
GUILayout.Space(10);
GUILayout.BeginVertical("Box");
GUILayout.BeginHorizontal();
GUILayout.Label("分隔符 Separator:");
GUILayout.FlexibleSpace();
if (GUILayout.Toggle(CSV_Separator==",", "逗号 Comma(,)") && CSV_Separator!=",")
CSV_Separator = ",";
GUILayout.FlexibleSpace();
if (GUILayout.Toggle(CSV_Separator==";", "分号 Semicolon(;)") && CSV_Separator!=";")
CSV_Separator = ";";
GUILayout.FlexibleSpace();
if (GUILayout.Toggle(CSV_Separator=="\t", "换行 TAB(\\t)") && CSV_Separator!="\t")
CSV_Separator = "\t";
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
//--[ Encoding ]---------------
var encodings = Encoding.GetEncodings ().OrderBy(e=>e.Name).ToArray();
var encodingNames = encodings.Select(e=>e.Name).ToArray();
int idx = Array.IndexOf (encodingNames, mProp_Spreadsheet_LocalCSVEncoding.stringValue);
if (idx == -1)
idx = Array.IndexOf (encodingNames, "utf-8");
EditorGUIUtility.labelWidth = 80;
idx = EditorGUILayout.Popup (" 编码 Encoding:", idx, encodingNames);
if (GUILayout.Button("默认 Default", GUILayout.ExpandWidth(false)))
idx = Array.IndexOf (encodingNames, "utf-8");
if (idx>=0 && mProp_Spreadsheet_LocalCSVEncoding.stringValue != encodings [idx].Name)
mProp_Spreadsheet_LocalCSVEncoding.stringValue = encodings [idx].Name;
GUILayout.EndHorizontal();
GUILayout.EndVertical();
if (GUI.changed)
{
mProp_Spreadsheet_LocalCSVSeparator.stringValue = CSV_Separator;
}
GUILayout.Space(10);
EditorGUILayout.HelpBox("在某些Mac Os上Unity存在一个Bug当在打开/保存文件对话框中选择CSV文件时IDE会崩溃\nOn some Mac OS, there is a Unity Bug that makes the IDE crash when selecting a CSV file in the Open/Save File Dialog.\n只要点击文件unity就会尝试预览内容并崩溃。\nJust by clicking the file, unity tries to preview the content and crashes.\n\n如果您的团队成员使用Mac建议导入/导出扩展名为TXT的csV文件\nIf any of your the team members use Mac, its adviced to import/export the CSV Files with TXT extension.", MessageType.Warning);
GUILayout.Space(10);
OnGUI_ShowMsg();
}
bool IsValidDraggedLoadSpreadsheet()
{
if (DragAndDrop.paths==null || DragAndDrop.paths.Length!=1)
return false;
string sPath = DragAndDrop.paths[0].ToLower();
if (sPath.EndsWith(".csv")) return true;
if (sPath.EndsWith(".txt")) return true;
//if (sPath.EndsWith(".xls")) return true;
//if (sPath.EndsWith(".xlsx")) return true;
/*int iChar = sPath.LastIndexOfAny( "/\\.".ToCharArray() );
if (iChar<0 || sPath[iChar]!='.')
return true;
return false;*/
return false;
}
string TryMakingPathRelativeToProject( string FileName )
{
string ProjectPath = Application.dataPath.ToLower();
string FileNameLower = FileName.ToLower();
if (FileNameLower.StartsWith(ProjectPath))
FileName = FileName.Substring(ProjectPath.Length+1);
else
if (FileNameLower.StartsWith("assets/"))
FileName = FileName.Substring("assets/".Length);
return FileName;
}
void OnGUI_Spreadsheet_Local_ImportExport( eLocalSpreadsheeet CurrentExtension, string File )
{
GUI.enabled = CurrentExtension!=eLocalSpreadsheeet.NONE;
GUILayout.BeginHorizontal();
GUILayout.Space(10);
GUI.backgroundColor = Color.Lerp(Color.gray, Color.white, 0.5f);
eSpreadsheetUpdateMode Mode = SynchronizationButtons("导入 Import");
if ( Mode!= eSpreadsheetUpdateMode.None)
Import_Local(File, CurrentExtension, Mode);
GUILayout.FlexibleSpace();
GUI.backgroundColor = Color.Lerp(Color.gray, Color.white, 0.5f);
Mode = SynchronizationButtons("导出 Export", true);
if ( Mode != eSpreadsheetUpdateMode.None)
Export_Local(File, CurrentExtension, Mode);
GUILayout.Space(10);
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
EditorGUIUtility.labelWidth += 10;
EditorGUILayout.PropertyField(mProp_Spreadsheet_SpecializationAsRows, new GUIContent("将特殊转换为行 Show Specializations as Rows", "true:将每个专业化单独放在一行(例如Term[VR]…,任期(触摸)……\ntrue: Make each specialization a separate row (e.g. Term[VR]..., Term[Touch]....\nfalse:将专门化合并到由[i2s_xxx]分隔的相同单元格中\nfalse: Merge specializations into same cell separated by [i2s_XXX]"));
EditorGUIUtility.labelWidth -= 10;
GUILayout.EndHorizontal();
GUI.enabled = true;
}
void Import_Local( string File, eLocalSpreadsheeet CurrentExtension, eSpreadsheetUpdateMode UpdateMode )
{
try
{
serializedObject.ApplyModifiedProperties();
serializedObject.Update();
ClearErrors();
if (string.IsNullOrEmpty(File))
File = Application.dataPath + "/Localization.csv";
else
if (!Path.IsPathRooted(File))
File = string.Concat(Application.dataPath, "/", File);
// On Mac there is an issue with previewing CSV files, so its forced to only TXT
if (Application.platform == RuntimePlatform.OSXEditor)
File = EditorUtility.OpenFilePanel("Select a CSV file renamed as TXT", File, "txt");
else
File = EditorUtility.OpenFilePanel("Select a CSV file or a CSV file renamed as TXT", File, "csv;*.txt");
//File = EditorUtility.OpenFilePanel("Select CSV, XLS or XLSX File", File, "csv;*.xls;*.xlsx");
if (!string.IsNullOrEmpty(File))
{
mLanguageSource.Spreadsheet_LocalFileName = TryMakingPathRelativeToProject(File);
switch (CurrentExtension)
{
case eLocalSpreadsheeet.CSV : Import_CSV(File, UpdateMode); break;
}
ParseTerms(true, false, true);
EditorUtility.SetDirty (target);
AssetDatabase.SaveAssets();
}
}
catch (Exception ex)
{
ShowError("Unable to import file");
Debug.LogError(ex.Message);
}
}
void Import_CSV( string FileName, eSpreadsheetUpdateMode UpdateMode )
{
LanguageSourceData source = GetSourceData();
var encoding = Encoding.GetEncoding (mProp_Spreadsheet_LocalCSVEncoding.stringValue);
if (encoding == null)
encoding = Encoding.UTF8;
string CSVstring = LocalizationReader.ReadCSVfile (FileName, encoding);
char Separator = mProp_Spreadsheet_LocalCSVSeparator.stringValue.Length>0 ? mProp_Spreadsheet_LocalCSVSeparator.stringValue[0] : ',';
string sError = source.Import_CSV( string.Empty, CSVstring, UpdateMode, Separator);
if (!string.IsNullOrEmpty(sError))
ShowError(sError);
mSelectedCategories = source.GetCategories();
}
void Export_Local( string File, eLocalSpreadsheeet CurrentExtension, eSpreadsheetUpdateMode UpdateMode )
{
try
{
serializedObject.ApplyModifiedProperties();
serializedObject.Update();
ClearErrors();
string sPath = string.Empty;
if (!Path.IsPathRooted(File))
File = string.Concat(Application.dataPath, "/", File);
try {
sPath = Path.GetDirectoryName(File);
}
catch( Exception){}
if (string.IsNullOrEmpty(sPath))
sPath = Application.dataPath + "/";
File = Path.GetFileName(File);
if (string.IsNullOrEmpty(File))
File = "Localization.csv";
if (Application.platform == RuntimePlatform.OSXEditor)
File = EditorUtility.SaveFilePanel("Select a CSV file renamed as TXT", sPath, File, "txt");
else
File = EditorUtility.SaveFilePanel("Select a CSV or TXT file", sPath, File, "csv;*.txt");
if (!string.IsNullOrEmpty(File))
{
mLanguageSource.Spreadsheet_LocalFileName = TryMakingPathRelativeToProject(File);
char Separator = mProp_Spreadsheet_LocalCSVSeparator.stringValue.Length>0 ? mProp_Spreadsheet_LocalCSVSeparator.stringValue[0] : ',';
var encoding = Encoding.GetEncoding (mProp_Spreadsheet_LocalCSVEncoding.stringValue);
if (encoding == null)
encoding = Encoding.UTF8;
switch (CurrentExtension)
{
case eLocalSpreadsheeet.CSV : Export_CSV(File, UpdateMode, Separator, encoding); break;
}
}
}
catch (Exception)
{
ShowError("Unable to export file\nCheck it is not READ-ONLY and that\nits not opened in an external viewer");
}
}
public void Export_CSV( string FileName, eSpreadsheetUpdateMode UpdateMode, char Separator, Encoding encoding )
{
LanguageSourceData source = GetSourceData();
string CSVstring = source.Export_CSV(null, Separator, mProp_Spreadsheet_SpecializationAsRows.boolValue);
File.WriteAllText (FileName, CSVstring, encoding);
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: fdca66efafe784661b464934cacff065
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,820 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
namespace I2.Loc
{
public partial class LocalizationEditor
{
#region Variables
Vector2 mScrollPos_Keys = Vector2.zero;
public static string mKeyToExplore; // Key that should show all the language details
static string KeyList_Filter = "";
float mRowSize=-1;
float ScrollHeight;
float mTermList_MaxWidth = -1;
public static List<string> mSelectedKeys = new List<string>(); // Selected Keys in the list of mParsedKeys
public static List<string> mSelectedCategories = new List<string>();
public enum eFlagsViewKeys
{
Used = 1<<1,
Missing = 1<<2,
NotUsed = 1<<3
}
public static int mFlagsViewKeys = (int)eFlagsViewKeys.Used | (int)eFlagsViewKeys.NotUsed;
public static string mTermsList_NewTerm;
Rect mKeyListFilterRect;
#endregion
#region GUI Key List
float ExpandedViewHeight;
float TermsListHeight;
void OnGUI_KeysList(bool AllowExpandKey = true, float Height = 300.0f, bool ShowTools=true)
{
///if (mTermList_MaxWidth<=0)
CalculateTermsListMaxWidth();
//--[ List Filters ]--------------------------------------
// The ID of this control is registered here to avoid losing focus when the terms list grows in the scrollbox
// This control is drawn later on
int KeyListFilterID = GUIUtility.GetControlID( FocusType.Keyboard );
OnGUI_ShowMsg();
GUILayout.BeginHorizontal();
GUIStyle bstyle = new GUIStyle ("toolbarbutton");
bstyle.fontSize = 15;
if (GUILayout.Button (new GUIContent("\u21ea", "解析场景并更新缺少和未使用术语的术语列表\nParse Scene and update terms list with missing and unused terms"), bstyle, GUILayout.Width(40)))
EditorApplication.update += DoParseTermsInCurrentSceneAndScripts;
if (GUILayout.Button(new GUIContent("\u21bb", "刷新所有本地化对象的翻译\nRefresh the translation of all Localize objects"), bstyle, GUILayout.Width(40)))
CallLocalizeAll();
GUILayout.Space (1);
var oldFlags = mFlagsViewKeys;
mFlagsViewKeys = OnGUI_FlagToogle("使用 Used","显示已解析场景中引用的所有术语\nShows All Terms referenced in the parsed scenes", mFlagsViewKeys, (int)eFlagsViewKeys.Used);
mFlagsViewKeys = OnGUI_FlagToogle("未使用 Not Used", "显示源中未使用的所有术语\nShows all Terms from the Source that are not been used", mFlagsViewKeys, (int)eFlagsViewKeys.NotUsed);
mFlagsViewKeys = OnGUI_FlagToogle("未定义 Missing","显示所有已使用但未在源代码中定义的术语。\nShows all Terms Used but not defined in the Source", mFlagsViewKeys, (int)eFlagsViewKeys.Missing);
if (oldFlags!=mFlagsViewKeys)
ScheduleUpdateTermsToShowInList();
OnGUI_SelectedCategories();
GUILayout.EndHorizontal();
/*//if (Event.current.type == EventType.Repaint)
TermsListHeight = Screen.height - 400;
Debug.Log(Event.current.type + " " + TermsListHeight + " " + Screen.height + " " + GUILayoutUtility.GetLastRect().yMax);
//TermsListHeight = Mathf.Min(Screen.height*0.5f, TermsListHeight);
mScrollPos_Keys = GUILayout.BeginScrollView(mScrollPos_Keys, false, false, "horizontalScrollbar", "verticalScrollbar", LocalizeInspector.GUIStyle_OldTextArea, GUILayout.Height(TermsListHeight));
for (int i = 0; i < 1000; ++i)
GUILayout.Label("ahhh" + i);
GUILayout.EndScrollView();
return;*/
TermsListHeight = Mathf.Min(Screen.height*0.5f, TermsListHeight);
//--[ Keys List ]-----------------------------------------
GUI.backgroundColor = Color.Lerp(GUITools.LightGray, Color.white, 0.5f);
mScrollPos_Keys = GUILayout.BeginScrollView( mScrollPos_Keys, false, false, "horizontalScrollbar", "verticalScrollbar", LocalizeInspector.GUIStyle_OldTextArea ,GUILayout.Height(TermsListHeight)/*GUILayout.MinHeight(Height), GUILayout.MaxHeight(Screen.height), GUILayout.ExpandHeight(true)*/);
GUI.backgroundColor = Color.white;
bool bAnyValidUsage = false;
mRowSize = EditorStyles.toolbar.fixedHeight;
if (Event.current!=null && Event.current.type == EventType.Layout)
ScrollHeight = mScrollPos_Keys.y;
float YPosMin = -ScrollHeight;
int nSkip = 0;
int nDraw = 0;
if (mShowableTerms.Count == 0 && Event.current.type == EventType.Layout)
UpdateTermsToShownInList ();
float SkipSize = 0;
foreach (var parsedTerm in mShowableTerms)
{
string sKey = parsedTerm.Term;
string sCategory = parsedTerm.Category;
string FullKey = parsedTerm.FullTerm;
int nUses = parsedTerm.Usage;
bAnyValidUsage = bAnyValidUsage | (nUses>=0);
ShowTerm_termData = parsedTerm.termData;
// Skip lines outside the view -----------------------
YPosMin += mRowSize;
SkipSize += mRowSize;
float YPosMax = YPosMin + mRowSize;
bool isExpanded = AllowExpandKey && mKeyToExplore==FullKey;
if (!isExpanded && (YPosMax<-2*mRowSize || YPosMin>/*Screen.height*/TermsListHeight+mRowSize))
{
if (YPosMin>TermsListHeight+mRowSize)
break;
nSkip++;
continue;
}
nDraw++;
//------------------------------------------------------
OnGUI_KeyHeader (sKey, sCategory, FullKey, nUses, YPosMin-mRowSize+mScrollPos_Keys.y);
//--[ Key Details ]-------------------------------
if (isExpanded)
{
GUILayout.Space(SkipSize);
SkipSize = 0;
OnGUI_KeyList_ShowKeyDetails();
Rect rect = GUILayoutUtility.GetLastRect();
if (rect.height>5)
ExpandedViewHeight = rect.height;
YPosMin += ExpandedViewHeight;
}
}
SkipSize += (mShowableTerms.Count - nDraw-nSkip) * mRowSize;
GUILayout.Space(SkipSize+2);
if (mSelectedCategories.Count < mParsedCategories.Count)
{
SkipSize += 25;
if (GUILayout.Button ("...", EditorStyles.label))
{
mSelectedCategories.Clear ();
mSelectedCategories.AddRange (mParsedCategories);
}
}
OnGUI_KeysList_AddKey();
GUILayout.Label("", GUILayout.Width(mTermList_MaxWidth+10+30), GUILayout.Height(1));
GUILayout.EndScrollView();
TermsListHeight = YPosMin + mRowSize + 25;//SkipSize+25;
//Rect ListRect = GUILayoutUtility.GetLastRect();
//if (ListRect.height>5)
// TermsListHeight = ListRect.height;
//Debug.Log(nDraw + " " + nSkip + " " + Screen.height + " " + TermsListHeight);
OnGUI_Keys_ListSelection( KeyListFilterID ); // Selection Buttons
// if (!bAnyValidUsage)
// EditorGUILayout.HelpBox("Use (Tools\\Parse Terms) to find how many times each of the Terms are used", UnityEditor.MessageType.Info);
if (ShowTools)
{
GUILayout.BeginHorizontal();
GUI.enabled = mSelectedKeys.Count>0 || !string.IsNullOrEmpty(mKeyToExplore);
if (TestButton (eTest_ActionType.Button_AddSelectedTerms, new GUIContent("添加 Add Terms", "向源中添加术语 Add terms to Source"), "Button", GUITools.DontExpandWidth)) AddTermsToSource();
if (TestButton (eTest_ActionType.Button_RemoveSelectedTerms, new GUIContent("移除 Remove Terms", "从源中删除术语 Remove Terms from Source"), "Button", GUITools.DontExpandWidth)) RemoveTermsFromSource();
GUILayout.FlexibleSpace ();
if (GUILayout.Button ("改变类别 Change Category")) OpenTool_ChangeCategoryOfSelectedTerms();
GUI.enabled = true;
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace ();
bool newBool = GUILayout.Toggle(mLanguageSource.CaseInsensitiveTerms, "不区分大小写的术语 Case Insensitive Terms");
if (newBool != mLanguageSource.CaseInsensitiveTerms)
{
mProp_CaseInsensitiveTerms.boolValue = newBool;
}
GUILayout.FlexibleSpace ();
GUILayout.EndHorizontal();
}
//Debug.Log ("Draw: " + nDraw + " Skip: " + nSkip);
}
static void ScheduleUpdateTermsToShowInList()
{
if (!mUpdateShowTermIsScheduled)
{
EditorApplication.update += UpdateTermsToShownInList;
mUpdateShowTermIsScheduled = true;
}
}
static bool mUpdateShowTermIsScheduled;
static void UpdateTermsToShownInList()
{
EditorApplication.update -= UpdateTermsToShownInList;
mUpdateShowTermIsScheduled = false;
mShowableTerms.Clear ();
mSelectedCategories.Sort();
foreach (KeyValuePair<string, ParsedTerm> kvp in mParsedTerms)
{
ParsedTerm parsedTerm = kvp.Value;
if (ShouldShowTerm (parsedTerm.Term, parsedTerm.Category, parsedTerm.Usage, parsedTerm))
mShowableTerms.Add(parsedTerm);
}
GUITools.RepaintInspectors();
GUITools.ScheduleRepaintInspectors();
}
void OnGUI_KeyHeader (string sKey, string sCategory, string FullKey, int nUses, float YPosMin)
{
//--[ Toggle ]---------------------
GUI.Box(new Rect(2, YPosMin+2, 18, mRowSize), "", "Toolbar");
OnGUI_SelectableToogleListItem (new Rect(2, YPosMin+3, 15, mRowSize), FullKey, ref mSelectedKeys, "OL Toggle");
bool bEnabled = mSelectedKeys.Contains (FullKey);
//--[ Number of Objects using this key ]---------------------
if (nUses >= 0)
{
if (nUses == 0)
{
GUI.color = Color.Lerp (Color.gray, Color.white, 0.5f);
GUI.Label (new Rect(20, YPosMin+2, 30, mRowSize), nUses.ToString (), "toolbarbutton");
}
else
{
if (GUI.Button(new Rect(20, YPosMin + 2, 30, mRowSize), nUses.ToString(), "toolbarbutton"))
{
List<string> selection = new List<string>(mSelectedKeys);
if (!selection.Contains(FullKey))
selection.Add(FullKey);
List<GameObject> selGOs = new List<GameObject>();
for (int i=0; i<selection.Count; ++i)
selGOs.AddRange( FindObjectsUsingKey(selection[i]) );
if (selGOs.Count > 0)
Selection.objects = selGOs.ToArray();
else
ShowWarning("The selected Terms are not used in this Scene. Try opening other scenes");
}
}
}
else
{
GUI.color = Color.Lerp (Color.red, Color.white, 0.6f);
if (GUI.Button (new Rect(20, YPosMin+2, 30, mRowSize), "", "toolbarbutton"))
{
mCurrentToolsMode = eToolsMode.Parse;
mCurrentViewMode = eViewMode.Tools;
}
}
GUI.color = Color.white;
TermData termData = ShowTerm_termData!=null ? ShowTerm_termData : mLanguageSource.GetTermData (FullKey);
bool bKeyIsMissing = termData == null;
float MinX = 50;
if (bKeyIsMissing)
{
Rect rect = new Rect(50, YPosMin+2, mRowSize, mRowSize+2);
GUITools.DrawSkinIcon(rect, "CN EntryWarnIcon", "CN EntryWarn");
GUI.Label (rect, new GUIContent ("", "This term is used in the scene, but its not localized in the Language Source"));
MinX += rect.width;
}
else MinX += 3;
float listWidth = Mathf.Max(EditorGUIUtility.currentViewWidth / EditorGUIUtility.pixelsPerPoint, mTermList_MaxWidth);
Rect rectKey = new Rect(MinX, YPosMin+2, listWidth-MinX, mRowSize);
if (sCategory != LanguageSourceData.EmptyCategory)
rectKey.width -= 130;
if (mKeyToExplore == FullKey)
{
GUI.backgroundColor = Color.Lerp (Color.blue, Color.white, 0.8f);
if (GUI.Button (rectKey, new GUIContent (sKey, EditorStyles.foldout.onNormal.background), LocalizeInspector.GUIStyle_OldTextArea))
{
mKeyToExplore = string.Empty;
ScheduleUpdateTermsToShowInList();
ClearErrors ();
}
GUI.backgroundColor = Color.white;
}
else
{
GUIStyle LabelStyle = EditorStyles.label;
if (!bKeyIsMissing && !TermHasAllTranslations (mLanguageSource, termData))
{
LabelStyle = new GUIStyle (EditorStyles.label);
LabelStyle.fontStyle = FontStyle.Italic;
GUI.color = Color.Lerp (Color.white, Color.yellow, 0.5f);
}
if (!bEnabled)
GUI.contentColor = Color.Lerp (Color.gray, Color.white, 0.3f);
if (GUI.Button (rectKey, sKey, LabelStyle))
{
SelectTerm (FullKey);
ClearErrors ();
}
if (!bEnabled)
GUI.contentColor = Color.white;
GUI.color = Color.white;
}
//--[ Category ]--------------------------
if (sCategory != LanguageSourceData.EmptyCategory)
{
if (mKeyToExplore == FullKey)
{
rectKey.x = listWidth - 100-38-20;
rectKey.width = 130;
if (GUI.Button (rectKey, sCategory, EditorStyles.toolbarButton))
OpenTool_ChangeCategoryOfSelectedTerms ();
}
else
{
GUIStyle stl = new GUIStyle(EditorStyles.miniLabel);
stl.alignment = TextAnchor.MiddleRight;
rectKey.width = 130;//EditorStyles.miniLabel.CalcSize(new GUIContent(sCategory)).x;
rectKey.x = listWidth - rectKey.width - 38-20;
if (GUI.Button (rectKey, sCategory, stl))
{
SelectTerm (FullKey);
ClearErrors ();
}
}
}
}
void CalculateTermsListMaxWidth()
{
mTermList_MaxWidth = EditorGUIUtility.currentViewWidth / EditorGUIUtility.pixelsPerPoint - 120;
/*float maxWidth = Screen.width / 18;
foreach (KeyValuePair<string, ParsedTerm> kvp in mParsedTerms)
{
var txt = kvp.Key;
if (txt.Length > 100)
txt = txt.Substring(0, 100);
var size = EditorStyles.label.CalcSize(new GUIContent(txt));
mTermList_MaxWidth = Mathf.Max (mTermList_MaxWidth, size.x);
}*/
}
bool TermHasAllTranslations( LanguageSourceData source, TermData data )
{
if (source==null) source = LocalizationManager.Sources[0];
for (int i=0, imax=data.Languages.Length; i<imax; ++i)
{
bool isLangEnabled = source.mLanguages.Count>i ? source.mLanguages[i].IsEnabled() : true;
if (string.IsNullOrEmpty(data.Languages[i]) && isLangEnabled)
return false;
}
return true;
}
void OnGUI_KeysList_AddKey()
{
GUILayout.BeginHorizontal();
GUI.color = Color.Lerp(Color.gray, Color.white, 0.5f);
bool bWasEnabled = mTermsList_NewTerm!=null;
bool bEnabled = !GUILayout.Toggle (!bWasEnabled, "+", EditorStyles.toolbarButton, GUILayout.Width(30));
GUI.color = Color.white;
if (bWasEnabled && !bEnabled) mTermsList_NewTerm = null;
if (!bWasEnabled && bEnabled) mTermsList_NewTerm = string.Empty;
if (bEnabled)
{
GUILayout.BeginHorizontal(EditorStyles.toolbar);
mTermsList_NewTerm = EditorGUILayout.TextField(mTermsList_NewTerm, EditorStyles.toolbarTextField, GUILayout.ExpandWidth(true));
GUILayout.EndHorizontal();
LanguageSourceData.ValidateFullTerm( ref mTermsList_NewTerm );
if (string.IsNullOrEmpty(mTermsList_NewTerm) || mLanguageSource.ContainsTerm(mTermsList_NewTerm) || mTermsList_NewTerm=="-")
GUI.enabled = false;
if (TestButton (eTest_ActionType.Button_AddTerm_InTermsList, "Create Key", "toolbarbutton", GUILayout.ExpandWidth(false)))
{
AddLocalTerm(mTermsList_NewTerm);
SelectTerm( mTermsList_NewTerm );
ClearErrors();
mTermsList_NewTerm = null;
SetAllTerms_When_InferredTerms_IsInSource ();
}
GUI.enabled = true;
}
GUILayout.EndHorizontal();
}
void OpenTool_ChangeCategoryOfSelectedTerms()
{
mCurrentViewMode = eViewMode.Tools;
mCurrentToolsMode = eToolsMode.Categorize;
if (!string.IsNullOrEmpty(mKeyToExplore) && !mSelectedKeys.Contains(mKeyToExplore))
mSelectedKeys.Add(mKeyToExplore);
mSelectedKeys.Sort();
}
void OnGUI_SelectedCategories()
{
if (mParsedCategories.Count == 0)
return;
string text = "Categories";
if (mSelectedCategories.Count() == 0)
text = "无 Nothing";
else
if (mSelectedCategories.Count() == mParsedCategories.Count)
text = "所有 Everything";
else
text = mSelectedCategories.Count + " categories";
if (GUILayout.Button(new GUIContent(text), "toolbarbutton", GUILayout.Width(100)))
{
var menu = new GenericMenu();
menu.AddItem(new GUIContent("所有 Everything"), false, () =>
{
mSelectedCategories.Clear();
mSelectedCategories.AddRange(mParsedCategories);
ScheduleUpdateTermsToShowInList();
});
menu.AddItem(new GUIContent("无 Nothing"), false, () =>
{
mSelectedCategories.Clear();
ScheduleUpdateTermsToShowInList();
});
menu.AddSeparator("");
var parsedList = mParsedCategories.OrderBy(x=>x).ToList();
for (int i=0, imax=parsedList.Count; i<imax ; ++i)
{
var category = parsedList[i];
var nextCategory = i + 1 < imax ? parsedList[i + 1] : null;
bool isHeader = nextCategory != null && nextCategory.StartsWith(category + "/");
var displayName = category;
var categoryRoot = category;
if (isHeader)
{
categoryRoot += "/";
var newCateg = !category.Contains('/') ? category : category.Substring(category.LastIndexOf('/') + 1);
displayName = categoryRoot + newCateg;
}
menu.AddItem(new GUIContent(displayName), !string.IsNullOrEmpty(mSelectedCategories.FirstOrDefault(x=>x.StartsWith(categoryRoot))), () =>
{
var CatHeader = category + "/";
if (mSelectedCategories.Contains(category))
{
mSelectedCategories.Remove(category);
if (isHeader)
{
mSelectedCategories.RemoveAll(x => x.StartsWith(CatHeader));
}
}
else
{
mSelectedCategories.Add(category);
if (isHeader)
{
mSelectedCategories.AddRange( parsedList.Where(x=>x.StartsWith(CatHeader)));
}
}
ScheduleUpdateTermsToShowInList();
});
if (isHeader)
{
menu.AddSeparator(category+"/");
}
}
menu.ShowAsContext();
}
}
void SaveSelectedCategories()
{
if (mSelectedCategories.Count == 0) {
EditorPrefs.DeleteKey ("I2 CategoryFilter");
} else {
var data = string.Join(",", mSelectedCategories.ToArray());
EditorPrefs.SetString ("I2 CategoryFilter", data);
}
}
void LoadSelectedCategories()
{
var data = EditorPrefs.GetString ("I2 CategoryFilter", null);
if (!string.IsNullOrEmpty(data))
{
mSelectedCategories.Clear ();
mSelectedCategories.AddRange( data.Split(",".ToCharArray(), StringSplitOptions.RemoveEmptyEntries));
}
}
// Bottom part of the Key list (buttons: All, None, Used,... to select the keys)
void OnGUI_Keys_ListSelection ( int KeyListFilterID )
{
GUILayout.BeginHorizontal( "toolbarbutton" );
if (TestButton( eTest_ActionType.Button_SelectTerms_All, new GUIContent( "所有 All", "选择列表中的所有\nTerms Selects All Terms in the list" ), "toolbarbutton", GUILayout.ExpandWidth( false ) ))
{
mSelectedKeys.Clear();
foreach (var kvp in mParsedTerms)
if (ShouldShowTerm( kvp.Value.Term, kvp.Value.Category, kvp.Value.Usage ))
mSelectedKeys.Add( kvp.Key );
}
if (GUILayout.Button( new GUIContent( "清除 None", "清除选区\nClears the selection" ), "toolbarbutton", GUILayout.ExpandWidth( false ) )) { mSelectedKeys.Clear(); }
GUILayout.Space( 5 );
GUI.enabled = (mFlagsViewKeys & (int)eFlagsViewKeys.Used)>1;
if (TestButton(eTest_ActionType.Button_SelectTerms_Used, new GUIContent( "选择 Used", "选择已解析场景中引用的所有Terms\nSelects All Terms referenced in the parsed scenes" ), "toolbarbutton", GUILayout.ExpandWidth( false ) ))
{
mSelectedKeys.Clear();
foreach (var kvp in mParsedTerms)
if (kvp.Value.Usage > 0 && ShouldShowTerm( kvp.Value.Term, kvp.Value.Category, kvp.Value.Usage ))
mSelectedKeys.Add( kvp.Key );
}
GUI.enabled = (mFlagsViewKeys & (int)eFlagsViewKeys.NotUsed)>1;
if (GUILayout.Button( new GUIContent( "未使用 Not Used", "从源中选择所有未使用的术语。\nSelects all Terms from the Source that are not been used" ), "toolbarbutton", GUILayout.ExpandWidth( false ) ))
{
mSelectedKeys.Clear();
foreach (var kvp in mParsedTerms)
if (kvp.Value.Usage == 0 && ShouldShowTerm( kvp.Value.Term, kvp.Value.Category, kvp.Value.Usage ))
mSelectedKeys.Add( kvp.Key );
}
GUI.enabled = (mFlagsViewKeys & (int)eFlagsViewKeys.Missing)>1;
if (TestButton(eTest_ActionType.Button_SelectTerms_Missing, new GUIContent( "未定义 Missing", "选择所有已使用但未在源中定义的术语\nSelects all Terms Used but not defined in the Source" ), "toolbarbutton", GUILayout.ExpandWidth( false ) ))
{
mSelectedKeys.Clear();
foreach (var kvp in mParsedTerms)
if (!mLanguageSource.ContainsTerm( kvp.Key ) && ShouldShowTerm( kvp.Value.Term, kvp.Value.Category, kvp.Value.Usage ))
mSelectedKeys.Add( kvp.Key );
}
GUI.enabled = true;
EditorGUI.BeginChangeCheck();
// Terms Filter
{
//KeyList_Filter = EditorGUILayout.TextField(KeyList_Filter, GUI.skin.GetStyle("ToolbarSeachTextField"), GUILayout.ExpandWidth(true));
GUILayout.Label( "", GUILayout.ExpandWidth( true ) );
mKeyListFilterRect = GUILayoutUtility.GetLastRect();
mKeyListFilterRect.xMax += 4;
KeyList_Filter = GUITools.TextField( mKeyListFilterRect, KeyList_Filter, 255, GUI.skin.GetStyle( "ToolbarSeachTextField" ), KeyListFilterID );
}
if (GUILayout.Button( string.Empty, string.IsNullOrEmpty( KeyList_Filter ) ? "ToolbarSeachCancelButtonEmpty" : "ToolbarSeachCancelButton", GUILayout.ExpandWidth( false ) ))
{
KeyList_Filter = string.Empty;
EditorApplication.update += RepaintScene;
GUI.FocusControl( "" );
}
string filterHelp = "国际规则的选项:\n文本-显示所有匹配文本的键/类别\nc文本-显示文本类别的所有条款\nf文本-显示翻译中有“文本”的术语\n\nFiter Options:\ntext - shows all key/categories matching text\nc text - shows all terms of the text category\nf text - show terms having 'text' in their translations";
GUILayout.Space(-5);
GUI.contentColor = new Color(1, 1, 1, 0.5f);
GUILayout.Label(new GUIContent(GUITools.Icon_Help.image, filterHelp), GUITools.DontExpandWidth);
GUI.contentColor = GUITools.White;
GUILayout.Space(-5);
if (EditorGUI.EndChangeCheck())
{
mShowableTerms.Clear();
GUI.changed = false;
}
GUILayout.EndHorizontal();
}
#endregion
#region Filtering
public bool ShouldShowTerm (string FullTerm)
{
ParsedTerm termData;
if (!mParsedTerms.TryGetValue(FullTerm, out termData))
return false;
return ShouldShowTerm (termData.Term, termData.Category, termData.Usage, termData);
}
private static TermData ShowTerm_termData;
public static bool ShouldShowTerm (string Term, string Category, int nUses, ParsedTerm parsedTerm=null )
{
if (!string.IsNullOrEmpty(Category) && !mSelectedCategories.Contains(Category))
return false;
if (Term == "-")
return false;
var fullTerm = Term;
if (!string.IsNullOrEmpty(Category) && Category != LanguageSourceData.EmptyCategory)
fullTerm = Category + "/" + Term;
if (parsedTerm != null && parsedTerm.termData != null)
ShowTerm_termData = parsedTerm.termData;
else
{
ShowTerm_termData = mLanguageSource.GetTermData (fullTerm);
if (parsedTerm!=null)
parsedTerm.termData = ShowTerm_termData;
}
var filter = KeyList_Filter.Trim();
bool useTranslation = filter.StartsWith("f ", StringComparison.OrdinalIgnoreCase);
if (useTranslation)
{
if (ShowTerm_termData == null)
return false;
filter = filter.Substring(2).Trim();
if (!string.IsNullOrEmpty(filter))
{
bool hasFilter = false;
for (int i = 0; i < ShowTerm_termData.Languages.Length; ++i)
{
if (!string.IsNullOrEmpty(ShowTerm_termData.Languages[i]) && StringContainsFilter(ShowTerm_termData.Languages[i], filter))
{
hasFilter = true;
break;
}
}
if (!hasFilter)
return false;
}
}
else
{
bool onlyCategory = filter.StartsWith("c ", StringComparison.OrdinalIgnoreCase);
if (onlyCategory)
filter = filter.Substring(2).Trim();
if (!string.IsNullOrEmpty(filter))
{
bool matchesCategory = StringContainsFilter(Category, filter);
bool matchesName = !onlyCategory && StringContainsFilter(Term, filter);
if (!matchesCategory && !matchesName)
return false;
}
}
bool bIsMissing = ShowTerm_termData == null;
if (nUses<0) return true;
if ((mFlagsViewKeys & (int)eFlagsViewKeys.Missing)>0 && bIsMissing) return true;
if ((mFlagsViewKeys & (int)eFlagsViewKeys.Missing)==0 && bIsMissing) return false;
if ((mFlagsViewKeys & (int)eFlagsViewKeys.Used)>0 && nUses>0) return true;
if ((mFlagsViewKeys & (int)eFlagsViewKeys.NotUsed)>0 && nUses==0) return true;
return false;
}
static bool StringContainsFilter( string Term, string Filter )
{
if (string.IsNullOrEmpty(Filter) || string.IsNullOrEmpty(Term))
return true;
if (Term == "-")
return false;
Term = Term.ToLower();
string[] Filters = Filter.ToLower().Split(";, ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
for (int i = 0, imax = Filters.Length; i < imax; ++i)
if (Term.Contains(Filters[i]))
return true;
return false;
}
#endregion
#region Add/Remove Keys to DB
void AddTermsToSource()
{
if (!string.IsNullOrEmpty (mKeyToExplore) && !mSelectedKeys.Contains(mKeyToExplore))
mSelectedKeys.Add (mKeyToExplore);
for (int i=mSelectedKeys.Count-1; i>=0; --i)
{
string key = mSelectedKeys[i];
if (!ShouldShowTerm(key))
continue;
AddLocalTerm(key);
mSelectedKeys.RemoveAt(i);
}
SetAllTerms_When_InferredTerms_IsInSource ();
}
void RemoveTermsFromSource()
{
if (mTestAction==eTest_ActionType.None && !EditorUtility.DisplayDialog("Confirm delete", "Are you sure you want to delete the selected terms", "Yes", "Cancel"))
return;
if (!string.IsNullOrEmpty (mKeyToExplore) && !mSelectedKeys.Contains(mKeyToExplore))
mSelectedKeys.Add (mKeyToExplore);
for (int i=mSelectedKeys.Count-1; i>=0; --i)
{
string key = mSelectedKeys[i];
if (!ShouldShowTerm(key))
continue;
mLanguageSource.RemoveTerm(key);
RemoveParsedTerm(key);
mSelectedKeys.Remove(key);
}
mKeyToExplore = string.Empty;
mTermList_MaxWidth = -1;
serializedObject.ApplyModifiedProperties();
mLanguageSource.Editor_SetDirty();
EditorApplication.update += DoParseTermsInCurrentScene;
EditorApplication.update += RepaintScene;
}
#endregion
#region Select Objects in Current Scene
public static void SelectTerm( string Key, bool SwitchToKeysTab=false )
{
GUI.FocusControl(null);
mKeyToExplore = Key;
mKeysDesc_AllowEdit = false;
if (SwitchToKeysTab)
mCurrentViewMode = eViewMode.Keys;
}
void SelectObjectsUsingKey( string Key )
{
List<GameObject> SelectedObjs = FindObjectsUsingKey(Key);
if (SelectedObjs.Count>0)
Selection.objects = SelectedObjs.ToArray();
else
ShowWarning("The selected Terms are not used in this Scene. Try opening other scenes");
}
List<GameObject> FindObjectsUsingKey(string Key)
{
List<GameObject> SelectedObjs = new List<GameObject>();
Localize[] Locals = (Localize[])Resources.FindObjectsOfTypeAll(typeof(Localize));
if (Locals == null)
return SelectedObjs;
for (int i = 0, imax = Locals.Length; i < imax; ++i)
{
Localize localize = Locals[i];
if (localize == null || localize.gameObject == null || !GUITools.ObjectExistInScene(localize.gameObject))
continue;
string Term, SecondaryTerm;
localize.GetFinalTerms(out Term, out SecondaryTerm);
if (Key == Term || Key == SecondaryTerm)
SelectedObjs.Add(localize.gameObject);
}
return SelectedObjs;
}
#endregion
[MenuItem("Tools/I2 Localization/Refresh Localizations", false, 16)]
public static void CallLocalizeAll()
{
LocalizationManager.LocalizeAll(true);
HandleUtility.Repaint();
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 9f0230a94fc864d5bb1f2261de16edce
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,785 @@
//#define UGUI
//#define NGUI
using System;
using TMPro;
using UnityEditor;
using UnityEngine;
using Object = UnityEngine.Object;
namespace I2.Loc
{
public partial class LocalizationEditor
{
#region Variables
internal static bool mKeysDesc_AllowEdit;
internal static string GUI_SelectedSpecialization
{
get{
if (string.IsNullOrEmpty(mGUI_SelectedSpecialization))
mGUI_SelectedSpecialization = EditorPrefs.GetString ("I2Loc Specialization", "Any");
return mGUI_SelectedSpecialization;
}
set{
if (value!=mGUI_SelectedSpecialization)
EditorPrefs.SetString ("I2Loc Specialization", value);
mGUI_SelectedSpecialization = value;
}
}
internal static string mGUI_SelectedSpecialization;
internal static bool GUI_ShowDisabledLanguagesTranslation = true;
internal static int mShowPlural = -1;
#endregion
#region Key Description
void OnGUI_KeyList_ShowKeyDetails()
{
GUI.backgroundColor = Color.Lerp(Color.blue, Color.white, 0.9f);
GUILayout.BeginVertical(LocalizeInspector.GUIStyle_OldTextArea, GUILayout.Height(1));
OnGUI_Keys_Languages(mKeyToExplore, null);
GUILayout.BeginHorizontal();
if (TestButton(eTest_ActionType.Button_DeleteTerm, "Delete", "Button", GUILayout.ExpandWidth(true)))
{
if (mTestAction != eTest_ActionType.None || EditorUtility.DisplayDialog("Confirm delete", "Are you sure you want to delete term '" + mKeyToExplore + "'", "Yes", "Cancel"))
EditorApplication.update += DeleteCurrentKey;
}
if (GUILayout.Button("Rename"))
{
mCurrentViewMode = eViewMode.Tools;
mCurrentToolsMode = eToolsMode.Merge;
if (!mSelectedKeys.Contains(mKeyToExplore))
mSelectedKeys.Add(mKeyToExplore);
}
GUILayout.EndHorizontal();
GUILayout.EndVertical();
GUI.backgroundColor = Color.white;
}
void DeleteTerm( string Term, bool updateStructures = true )
{
mLanguageSource.RemoveTerm (Term);
RemoveParsedTerm(Term);
mSelectedKeys.Remove(Term);
if (Term==mKeyToExplore)
mKeyToExplore = string.Empty;
if (updateStructures)
{
UpdateParsedCategories();
mTermList_MaxWidth = -1;
serializedObject.ApplyModifiedProperties();
mLanguageSource.Editor_SetDirty();
ScheduleUpdateTermsToShowInList();
}
EditorApplication.update += RepaintScene;
}
void RepaintScene()
{
EditorApplication.update -= RepaintScene;
Repaint();
}
void DeleteCurrentKey()
{
EditorApplication.update -= DeleteCurrentKey;
DeleteTerm (mKeyToExplore);
mKeyToExplore = "";
EditorApplication.update += DoParseTermsInCurrentScene;
}
TermData AddLocalTerm( string Term, bool AutoSelect = true )
{
var data = AddTerm(Term, AutoSelect);
if (data==null)
return null;
mTermList_MaxWidth = -1;
serializedObject.ApplyModifiedProperties();
mLanguageSource.Editor_SetDirty();
return data;
}
static TermData AddTerm(string Term, bool AutoSelect = true, eTermType termType = eTermType.Text)
{
if (Term == "-" || string.IsNullOrEmpty(Term))
return null;
Term = I2Utils.GetValidTermName(Term, true);
TermData data = mLanguageSource.AddTerm(Term, termType);
GetParsedTerm(Term);
string sCategory = LanguageSourceData.GetCategoryFromFullTerm(Term);
mParsedCategories.Add(sCategory);
if (AutoSelect)
{
if (!mSelectedKeys.Contains(Term))
mSelectedKeys.Add(Term);
if (!mSelectedCategories.Contains(sCategory))
mSelectedCategories.Add(sCategory);
}
ScheduleUpdateTermsToShowInList();
mLanguageSource.Editor_SetDirty();
return data;
}
// this method shows the key description and the localization to each language
public static TermData OnGUI_Keys_Languages( string Key, Localize localizeCmp, bool IsPrimaryKey=true )
{
if (Key==null)
Key = string.Empty;
TermData termdata = null;
LanguageSourceData source = mLanguageSource;
if (localizeCmp != null && localizeCmp.Source != null)
source = localizeCmp.Source.SourceData;
if (source==null)
source = LocalizationManager.GetSourceContaining(Key, false);
if (source==null)
{
if (localizeCmp == null)
source = LocalizationManager.Sources[0];
else
source = LocalizationManager.GetSourceContaining(IsPrimaryKey ? localizeCmp.SecondaryTerm : localizeCmp.Term);
}
if (string.IsNullOrEmpty(Key))
{
EditorGUILayout.HelpBox( "选择要本地化的术语\nSelect a Term to Localize", MessageType.Info );
return null;
}
termdata = source.GetTermData(Key);
if (termdata==null && localizeCmp!=null)
{
var realSource = LocalizationManager.GetSourceContaining(Key, false);
if (realSource != null)
{
termdata = realSource.GetTermData(Key);
source = realSource;
}
}
if (termdata==null)
{
if (Key == "-")
return null;
EditorGUILayout.HelpBox( string.Format("Key '{0}' 没有本地化,还是使用不同的语言源\nis not Localized or it is in a different Language Source", Key), MessageType.Error );
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
if (GUILayout.Button("Add Term to Source"))
{
var termType = eTermType.Text;
if (localizeCmp!=null && localizeCmp.mLocalizeTarget != null)
{
termType = IsPrimaryKey ? localizeCmp.mLocalizeTarget.GetPrimaryTermType(localizeCmp)
: localizeCmp.mLocalizeTarget.GetSecondaryTermType(localizeCmp);
}
AddTerm(Key, true, termType);
}
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
return null;
}
//--[ Type ]----------------------------------
if (localizeCmp==null)
{
GUILayout.BeginHorizontal();
GUILayout.Label ("Type:", GUILayout.ExpandWidth(false));
eTermType NewType = (eTermType)EditorGUILayout.EnumPopup(termdata.TermType, GUILayout.ExpandWidth(true));
if (termdata.TermType != NewType)
termdata.TermType = NewType;
GUILayout.EndHorizontal();
}
//--[ Description ]---------------------------
mKeysDesc_AllowEdit = GUILayout.Toggle(mKeysDesc_AllowEdit, "Description", EditorStyles.foldout, GUILayout.ExpandWidth(true));
if (mKeysDesc_AllowEdit)
{
string NewDesc = EditorGUILayout.TextArea( termdata.Description, Style_WrapTextField );
if (NewDesc != termdata.Description)
{
termdata.Description = NewDesc;
source.Editor_SetDirty();
}
}
else
EditorGUILayout.HelpBox( string.IsNullOrEmpty(termdata.Description) ? "没有描述 No description" : termdata.Description, MessageType.Info );
OnGUI_Keys_Language_SpecializationsBar (termdata, source);
OnGUI_Keys_Languages(Key, ref termdata, localizeCmp, IsPrimaryKey, source);
return termdata;
}
static void OnGUI_Keys_Languages( string Key, ref TermData termdata, Localize localizeCmp, bool IsPrimaryKey, LanguageSourceData source )
{
//--[ Languages ]---------------------------
GUILayout.BeginVertical(LocalizeInspector.GUIStyle_OldTextArea, GUILayout.Height(1));
OnGUI_Keys_LanguageTranslations(Key, localizeCmp, IsPrimaryKey, ref termdata, source);
if (termdata.TermType == eTermType.Text)
{
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
if (TestButton(eTest_ActionType.Button_Term_TranslateAll, "Translate All", "Button", GUILayout.Width(85)))
{
var termData = termdata;
GUITools.DelayedCall(() => TranslateLanguage( Key, termData, localizeCmp, source));
GUI.FocusControl(string.Empty);
}
GUILayout.EndHorizontal();
OnGUI_TranslatingMessage();
}
GUILayout.EndVertical();
}
static void TranslateLanguage( string Key, TermData termdata, Localize localizeCmp, LanguageSourceData source)
{
ClearErrors();
string mainText = localizeCmp == null ? LanguageSourceData.GetKeyFromFullTerm(Key) : localizeCmp.GetMainTargetsText();
for (int i = 0; i < source.mLanguages.Count; ++i)
if (source.mLanguages[i].IsEnabled() && string.IsNullOrEmpty(termdata.Languages[i]))
{
var langIdx = i;
var term = termdata;
var i2source = source;
Translate(mainText, ref termdata, source.mLanguages[i].Code,
(translation, error) =>
{
if (error != null)
ShowError(error);
else
if (translation != null)
{
term.Languages[langIdx] = translation; //SetTranslation(langIdx, translation);
i2source.Editor_SetDirty();
}
}, null);
}
}
static void OnGUI_TranslatingMessage()
{
if (GoogleTranslation.IsTranslating())
{
// Connection Status Bar
int time = (int)(Time.realtimeSinceStartup % 2 * 2.5);
string Loading = "Translating" + ".....".Substring(0, time);
GUI.color = Color.gray;
GUILayout.BeginHorizontal(LocalizeInspector.GUIStyle_OldTextArea);
GUILayout.Label(Loading, EditorStyles.miniLabel);
GUI.color = Color.white;
if (GUILayout.Button("Cancel", EditorStyles.toolbarButton, GUILayout.ExpandWidth(false)))
{
GoogleTranslation.CancelCurrentGoogleTranslations();
}
GUILayout.EndHorizontal();
HandleUtility.Repaint ();
}
}
static void OnGUI_Keys_Language_SpecializationsBar(TermData termData, LanguageSourceData source)
{
var activeSpecializations = termData.GetAllSpecializations();
GUILayout.BeginHorizontal();
var TabStyle = new GUIStyle(GUI.skin.FindStyle("dragtab"));
TabStyle.fixedHeight = 0;
//var ss = GUI.skin.FindStyle("TL tab left");
var TabOpenStyle = new GUIStyle(GUI.skin.FindStyle("minibuttonmid"));
TabOpenStyle.margin.right = -1;
var TabCloseStyle = new GUIStyle(EditorStyles.label);
//var TabCloseStyle = new GUIStyle(GUI.skin.FindStyle("TL tab right"));
TabCloseStyle.margin.left = -1;
TabCloseStyle.padding.left=4;
//-- Specialization Tabs -----
var prevSpecialization = "Any";
foreach (var specialization in SpecializationManager.Singleton.mSpecializations)
{
if (!activeSpecializations.Contains(specialization) && specialization != GUI_SelectedSpecialization)
continue;
bool isActive = specialization == GUI_SelectedSpecialization;
var labelContent = new GUIContent(specialization, "Specialization of the main translation (i.e. variants that show only on specific platforms or devices)\nThis allows using 'tap' instead of 'click' for touch devices.");
if (isActive && activeSpecializations.Count>1)
{
GUILayout.BeginHorizontal(TabOpenStyle);
GUILayout.Toggle(isActive, labelContent, TabStyle, GUILayout.Height(20), GUILayout.ExpandWidth(false));
//GUILayout.Label(labelContent, TabOpenStyle);
if (specialization != "Any" && GUILayout.Button("x", TabCloseStyle, GUILayout.Width(15)))
{
termData.RemoveSpecialization(specialization);
GUI_SelectedSpecialization = prevSpecialization;
GUI.FocusControl(null);
}
GUILayout.EndHorizontal();
}
else
if (GUILayout.Toggle(isActive, labelContent, TabStyle, GUILayout.Height(25), GUILayout.ExpandWidth(false)) && !isActive)
{
GUI_SelectedSpecialization = specialization;
GUI.FocusControl(null);
}
}
//-- Add new Specialization -----
int newIndex = EditorGUILayout.Popup(-1, SpecializationManager.Singleton.mSpecializations, "DropDown", GUILayout.Width(20));
if (newIndex>=0)
{
string newSpecialization = SpecializationManager.Singleton.mSpecializations[newIndex];
if (!activeSpecializations.Contains(newSpecialization))
{
for (int iLang = 0; iLang < source.mLanguages.Count; ++iLang)
{
string Translation = termData.GetTranslation(iLang, GUI_SelectedSpecialization, editMode: true);
termData.SetTranslation(iLang, Translation, GUI_SelectedSpecialization);
}
GUI_SelectedSpecialization = newSpecialization;
}
}
GUILayout.FlexibleSpace();
GUI_ShowDisabledLanguagesTranslation = GUILayout.Toggle(GUI_ShowDisabledLanguagesTranslation, new GUIContent("L", "Show Disabled Languages"), "Button", GUILayout.ExpandWidth(false));
GUILayout.EndHorizontal();
GUILayout.Space(-3);
}
static void OnGUI_Keys_LanguageTranslations (string Key, Localize localizeCmp, bool IsPrimaryKey, ref TermData termdata, LanguageSourceData source)
{
bool IsSelect = Event.current.type==EventType.MouseUp;
for (int i=0; i< source.mLanguages.Count; ++ i)
{
bool forcePreview = false;
bool isEnabledLanguage = source.mLanguages[i].IsEnabled();
if (!isEnabledLanguage)
{
if (!GUI_ShowDisabledLanguagesTranslation)
continue;
GUI.color = new Color(GUI.color.r, GUI.color.g, GUI.color.b, 0.35f);
}
GUILayout.BeginHorizontal();
if (GUILayout.Button(source.mLanguages[i].Name, EditorStyles.label, GUILayout.Width(100)))
forcePreview = true;
string Translation = termdata.GetTranslation(i, GUI_SelectedSpecialization, editMode:true);
if (Translation == null) Translation = string.Empty;
// if (termdata.Languages[i] != termdata.Languages_Touch[i] && !string.IsNullOrEmpty(termdata.Languages[i]) && !string.IsNullOrEmpty(termdata.Languages_Touch[i]))
// GUI.contentColor = GUITools.LightYellow;
if (termdata.TermType == eTermType.Text || termdata.TermType==eTermType.Child)
{
EditorGUI.BeginChangeCheck ();
string CtrName = "TranslatedText"+i;
GUI.SetNextControlName(CtrName);
EditPluralTranslations (ref Translation, i, source.mLanguages[i].Code);
//Translation = EditorGUILayout.TextArea(Translation, Style_WrapTextField, GUILayout.Width(Screen.width - 260 - (autoTranslated ? 20 : 0)));
if (EditorGUI.EndChangeCheck ())
{
termdata.SetTranslation(i, Translation, GUI_SelectedSpecialization);
source.Editor_SetDirty();
forcePreview = true;
}
if (localizeCmp!=null &&
(forcePreview || /*GUI.changed || */GUI.GetNameOfFocusedControl()==CtrName && IsSelect))
{
if (IsPrimaryKey && string.IsNullOrEmpty(localizeCmp.Term))
{
localizeCmp.mTerm = Key;
}
if (!IsPrimaryKey && string.IsNullOrEmpty(localizeCmp.SecondaryTerm))
{
localizeCmp.mTermSecondary = Key;
}
string PreviousLanguage = LocalizationManager.CurrentLanguage;
LocalizationManager.PreviewLanguage(source.mLanguages[i].Name);
if (forcePreview || IsSelect)
LocalizationManager.LocalizeAll();
else
localizeCmp.OnLocalize(true);
LocalizationManager.PreviewLanguage(PreviousLanguage);
EditorUtility.SetDirty(localizeCmp);
}
GUI.contentColor = Color.white;
//if (autoTranslated)
//{
// if (GUILayout.Button(new GUIContent("\u2713"/*"A"*/,"Translated by Google Translator\nClick the button to approve the translation"), EditorStyles.toolbarButton, GUILayout.Width(autoTranslated ? 20 : 0)))
// {
// termdata.Flags[i] &= (byte)(byte.MaxValue ^ (byte)(GUI_SelectedSpecialization==0 ? TranslationFlag.AutoTranslated_Normal : TranslationFlag.AutoTranslated_Touch));
// }
//}
if (termdata.TermType == eTermType.Text)
{
if (TestButtonArg(eTest_ActionType.Button_Term_Translate, i, new GUIContent("T", "Translate"), EditorStyles.toolbarButton, GUILayout.Width(20)))
{
var termData = termdata;
var indx = i;
var key = Key;
GUITools.DelayedCall(()=>TranslateTerm(key, termData, source, indx));
GUI.FocusControl(string.Empty);
}
}
}
else
{
string MultiSpriteName = string.Empty;
if (termdata.TermType==eTermType.Sprite && Translation.EndsWith("]", StringComparison.Ordinal)) // Handle sprites of type (Multiple): "SpritePath[SpriteName]"
{
int idx = Translation.LastIndexOf("[", StringComparison.Ordinal);
int len = Translation.Length-idx-2;
MultiSpriteName = Translation.Substring(idx+1, len);
Translation = Translation.Substring(0, idx);
}
Object Obj = null;
// Try getting the asset from the References section
if (localizeCmp!=null)
Obj = localizeCmp.FindTranslatedObject<Object>(Translation);
if (Obj==null && source != null)
Obj = source.FindAsset(Translation);
// If it wasn't in the references, Load it from Resources
if (Obj==null && localizeCmp==null)
Obj = ResourceManager.pInstance.LoadFromResources<Object>(Translation);
Type ObjType = typeof(Object);
switch (termdata.TermType)
{
case eTermType.Font : ObjType = typeof(Font); break;
case eTermType.Texture : ObjType = typeof(Texture); break;
case eTermType.AudioClip : ObjType = typeof(AudioClip); break;
case eTermType.GameObject : ObjType = typeof(GameObject); break;
case eTermType.Sprite : ObjType = typeof(Sprite); break;
case eTermType.Material : ObjType = typeof(Material); break;
case eTermType.Mesh : ObjType = typeof(Mesh); break;
#if NGUI
case eTermType.UIAtlas : ObjType = typeof(UIAtlas); break;
case eTermType.UIFont : ObjType = typeof(UIFont); break;
#endif
#if TK2D
case eTermType.TK2dFont : ObjType = typeof(tk2dFont); break;
case eTermType.TK2dCollection : ObjType = typeof(tk2dSpriteCollection); break;
#endif
#if TextMeshPro
case eTermType.TextMeshPFont : ObjType = typeof(TMP_FontAsset); break;
#endif
#if SVG
case eTermType.SVGAsset : ObjType = typeof(SVGImporter.SVGAsset); break;
#endif
case eTermType.Object : ObjType = typeof(Object); break;
}
if (Obj!=null && !string.IsNullOrEmpty(MultiSpriteName))
{
string sPath = AssetDatabase.GetAssetPath(Obj);
Object[] objs = AssetDatabase.LoadAllAssetRepresentationsAtPath(sPath);
Obj = null;
for (int j=0, jmax=objs.Length; j<jmax; ++j)
if (objs[j].name.Equals(MultiSpriteName))
{
Obj = objs[j];
break;
}
}
bool bShowTranslationLabel = Obj==null && !string.IsNullOrEmpty(Translation);
if (bShowTranslationLabel)
{
GUI.backgroundColor=GUITools.DarkGray;
GUILayout.BeginVertical(LocalizeInspector.GUIStyle_OldTextArea, GUILayout.Height(1));
GUILayout.Space(2);
GUI.backgroundColor = Color.white;
}
Object NewObj = EditorGUILayout.ObjectField(Obj, ObjType, true, GUILayout.ExpandWidth(true));
if (Obj!=NewObj)
{
string sPath = null;
if (NewObj != null)
{
sPath = AssetDatabase.GetAssetPath(NewObj);
mCurrentInspector.serializedObject.ApplyModifiedProperties();
foreach (var cmp in mCurrentInspector.serializedObject.targetObjects)
{
AddObjectPath(ref sPath, cmp as Localize, NewObj);
}
mCurrentInspector.serializedObject.ApplyModifiedProperties();
if (HasObjectInReferences(NewObj, localizeCmp))
sPath = NewObj.name;
else
if (termdata.TermType == eTermType.Sprite)
sPath += "[" + NewObj.name + "]";
}
termdata.SetTranslation(i, sPath, GUI_SelectedSpecialization);
source.Editor_SetDirty();
}
if (bShowTranslationLabel)
{
GUILayout.BeginHorizontal();
GUI.color = Color.red;
GUILayout.FlexibleSpace();
GUILayout.Label (Translation, EditorStyles.miniLabel);
GUILayout.FlexibleSpace();
GUI.color = Color.white;
GUILayout.EndHorizontal();
GUILayout.EndVertical();
}
}
GUILayout.EndHorizontal();
GUI.color = Color.white;
}
}
private static void TranslateTerm(string Key, TermData termdata, LanguageSourceData source, int i)
{
string sourceText = null;
string sourceLangCode = null;
FindTranslationSource(Key, termdata, source.mLanguages[i].Code, null, out sourceText, out sourceLangCode);
var term = termdata;
var specialization = GUI_SelectedSpecialization;
var langIdx = i;
var i2source = source;
Translate(sourceText, ref termdata, source.mLanguages[i].Code, (translation, error) =>
{
term.SetTranslation(langIdx, translation, specialization);
i2source.Editor_SetDirty();
}, specialization);
}
static void EditPluralTranslations( ref string translation, int langIdx, string langCode )
{
bool hasParameters = false;
int paramStart = translation.IndexOf("{[");
hasParameters = paramStart >= 0 && translation.IndexOf ("]}", paramStart) > 0;
if (mShowPlural == langIdx && string.IsNullOrEmpty (translation))
mShowPlural = -1;
bool allowPlural = hasParameters || translation.Contains("[i2p_");
if (allowPlural)
{
if (GUILayout.Toggle (mShowPlural == langIdx, "", EditorStyles.foldout, GUILayout.Width (13)))
mShowPlural = langIdx;
else if (mShowPlural == langIdx)
mShowPlural = -1;
GUILayout.Space (-5);
}
string finalTranslation = "";
bool unfolded = mShowPlural == langIdx;
bool isPlural = allowPlural && translation.Contains("[i2p_");
if (unfolded)
GUILayout.BeginVertical ("Box");
ShowPluralTranslation("Plural", langCode, translation, ref finalTranslation, true, unfolded, unfolded|isPlural );
ShowPluralTranslation("Zero", langCode, translation, ref finalTranslation, unfolded, true, true );
ShowPluralTranslation("One", langCode, translation, ref finalTranslation, unfolded, true, true );
ShowPluralTranslation("Two", langCode, translation, ref finalTranslation, unfolded, true, true );
ShowPluralTranslation("Few", langCode, translation, ref finalTranslation, unfolded, true, true );
ShowPluralTranslation("Many", langCode, translation, ref finalTranslation, unfolded, true, true );
if (unfolded)
GUILayout.EndVertical ();
translation = finalTranslation;
}
static void ShowPluralTranslation(string pluralType, string langCode, string translation, ref string finalTranslation, bool show, bool allowDelete, bool showTag )
{
string tag = "[i2p_" + pluralType + "]";
int idx0 = translation.IndexOf (tag, StringComparison.OrdinalIgnoreCase);
bool hasTranslation = idx0 >= 0 || pluralType=="Plural";
if (idx0 < 0) idx0 = 0;
else idx0 += tag.Length;
int idx1 = translation.IndexOf ("[i2p_", idx0, StringComparison.OrdinalIgnoreCase);
if (idx1 < 0) idx1 = translation.Length;
var pluralTranslation = translation.Substring(idx0, idx1-idx0);
var newTrans = pluralTranslation;
bool allowPluralForm = GoogleLanguages.LanguageHasPluralType (langCode, pluralType);
if (hasTranslation && !allowPluralForm) {
newTrans = "";
GUI.changed = true;
}
if (show && allowPluralForm)
{
if (!hasTranslation)
GUI.color = new Color(GUI.color.r, GUI.color.g, GUI.color.b, 0.35f);
GUILayout.BeginHorizontal ();
if (showTag)
GUILayout.Label (pluralType, EditorStyles.miniLabel, GUILayout.Width(35));
newTrans = EditorGUILayout.TextArea (pluralTranslation, Style_WrapTextField);
if (allowDelete && GUILayout.Button("X", EditorStyles.toolbarButton, GUILayout.Width(15)))
{
newTrans = string.Empty;
GUI.changed = true;
GUIUtility.keyboardControl = 0;
}
GUILayout.EndHorizontal ();
if (!hasTranslation)
GUI.color = new Color(GUI.color.r, GUI.color.g, GUI.color.b, 1);
}
if (!string.IsNullOrEmpty (newTrans))
{
if (hasTranslation || newTrans != pluralTranslation)
{
if (pluralType != "Plural")
finalTranslation += tag;
finalTranslation += newTrans;
}
}
}
/*static public int DrawTranslationTabs( int Index )
{
GUIStyle MyStyle = new GUIStyle(GUI.skin.FindStyle("dragtab"));
MyStyle.fixedHeight=0;
GUILayout.BeginHorizontal();
for (int i=0; i<Tabs.Length; ++i)
{
if ( GUILayout.Toggle(Index==i, Tabs[i], MyStyle, GUILayout.Height(height)) && Index!=i)
Index=i;
}
GUILayout.EndHorizontal();
return Index;
}*/
static bool HasObjectInReferences( Object obj, Localize localizeCmp )
{
if (localizeCmp!=null && localizeCmp.TranslatedObjects.Contains(obj))
return true;
if (mLanguageSource!=null && mLanguageSource.Assets.Contains(obj))
return true;
return false;
}
static void AddObjectPath( ref string sPath, Localize localizeCmp, Object NewObj )
{
if (I2Utils.RemoveResourcesPath (ref sPath))
return;
// If its not in the Resources folder and there is no object reference already in the
// Reference array, then add that to the Localization component or the Language Source
if (HasObjectInReferences(NewObj, localizeCmp))
return;
if (localizeCmp!=null)
{
localizeCmp.AddTranslatedObject(NewObj);
EditorUtility.SetDirty(localizeCmp);
}
else
if (mLanguageSource!=null)
{
mLanguageSource.AddAsset(NewObj);
mLanguageSource.Editor_SetDirty();
}
}
static void Translate ( string Key, ref TermData termdata, string TargetLanguageCode, GoogleTranslation.fnOnTranslated onTranslated, string overrideSpecialization )
{
#if UNITY_WEBPLAYER
ShowError ("Contacting google translation is not yet supported on WebPlayer" );
#else
if (!GoogleTranslation.CanTranslate())
{
ShowError ("WebService is not set correctly or needs to be reinstalled");
return;
}
// Translate first language that has something
// If no language found, translation will fallback to autodetect language from key
string sourceCode, sourceText;
FindTranslationSource( Key, termdata, TargetLanguageCode, overrideSpecialization, out sourceText, out sourceCode );
GoogleTranslation.Translate( sourceText, sourceCode, TargetLanguageCode, onTranslated );
#endif
}
static void FindTranslationSource( string Key, TermData termdata, string TargetLanguageCode, string forceSpecialization, out string sourceText, out string sourceLanguageCode )
{
sourceLanguageCode = "auto";
sourceText = Key;
for (int i = 0, imax = termdata.Languages.Length; i < imax; ++i)
{
if (mLanguageSource.mLanguages[i].IsEnabled() && !string.IsNullOrEmpty(termdata.Languages[i]))
{
sourceText = forceSpecialization==null ? termdata.Languages[i] : termdata.GetTranslation(i, forceSpecialization, editMode:true);
if (mLanguageSource.mLanguages[i].Code != TargetLanguageCode)
{
sourceLanguageCode = mLanguageSource.mLanguages[i].Code;
return;
}
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 3efc8937ee2fcab49a6b6c1c9a1ed051
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,49 @@
using System.Collections.Generic;
using UnityEngine;
namespace I2.Loc
{
public partial class LocalizationEditor
{
#region Variables
Vector2 mScrollPos_BuildScenes = Vector2.zero;
static List<string> mSelectedScenes = new List<string>();
public enum eToolsMode { Parse, Categorize, Merge, NoLocalized, Script, CharSet }
public eToolsMode mCurrentToolsMode = eToolsMode.Parse;
#endregion
#region GUI
void OnGUI_Tools( bool reset )
{
GUILayout.Space(10);
eToolsMode OldMode = mCurrentToolsMode;
mCurrentToolsMode = (eToolsMode)GUITools.DrawShadowedTabs ((int)mCurrentToolsMode, new[]{"解析Parse", "分类Categorize", "合并Merge", "无本地化 No Localized", "脚本Script", "字符CharSet"}, 30);
if (mCurrentToolsMode != OldMode || reset)
{
ClearErrors();
if (mCurrentToolsMode == eToolsMode.Script)
SelectTermsFromScriptLocalization();
OnGUI_ScenesList_SelectAllScenes(true);
}
switch (mCurrentToolsMode)
{
case eToolsMode.Parse : OnGUI_Tools_ParseTerms(); break;
case eToolsMode.Categorize : OnGUI_Tools_Categorize(); break;
case eToolsMode.Merge : OnGUI_Tools_MergeTerms(); break;
case eToolsMode.NoLocalized : OnGUI_Tools_NoLocalized(); break;
case eToolsMode.Script : OnGUI_Tools_Script(); break;
case eToolsMode.CharSet : OnGUI_Tools_CharSet(); break;
}
OnGUI_ShowMsg();
}
#endregion
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 3fa4621ebd4134e1989b73eb3f7b864f
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,226 @@
using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
namespace I2.Loc
{
public partial class LocalizationEditor
{
#region Variables
Vector2 mScrollPos_CategorizedKeys = Vector2.zero;
string mNewCategory = string.Empty;
#endregion
#region GUI
void OnGUI_Tools_Categorize()
{
OnGUI_ScenesList(true);
GUI.backgroundColor = Color.Lerp (Color.gray, Color.white, 0.2f);
GUILayout.BeginVertical(LocalizeInspector.GUIStyle_OldTextArea, GUILayout.Height(1));
GUI.backgroundColor = Color.white;
GUILayout.Space (5);
EditorGUILayout.HelpBox("此工具更改所选术语的类别并更新高亮显示的场景。\nThis tool changes the category of the selected Terms and updates the highlighted scenes", MessageType.Info);
GUILayout.Space (5);
GUITools.CloseHeader();
OnGUI_Tools_Categorize_Terms();
OnGUI_NewOrExistingCategory();
}
void OnGUI_Tools_Categorize_Terms()
{
GUILayout.Label("Change Category of the following Terms:", EditorStyles.toolbarButton, GUILayout.ExpandWidth(true));
GUI.backgroundColor = Color.Lerp(GUITools.LightGray, Color.white, 0.5f);
mScrollPos_CategorizedKeys = GUILayout.BeginScrollView( mScrollPos_CategorizedKeys, LocalizeInspector.GUIStyle_OldTextArea, GUILayout.Height ( 100));
GUI.backgroundColor = Color.white;
if (mSelectedKeys.Count==0)
{
GUILayout.FlexibleSpace();
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
//GUILayout.BeginVertical();
EditorGUILayout.HelpBox("没有选择任何条款 No Terms has been selected", MessageType.Warning);
/*if (GUILayout.Button("Select Terms", EditorStyles.toolbarButton, GUILayout.ExpandWidth(true)))
mCurrentViewMode = eViewMode.Keys;*/
//GUILayout.EndVertical();
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
GUILayout.FlexibleSpace();
}
else
{
bool DoubleColumn = mSelectedKeys.Count>5;
int HalfCount = Mathf.CeilToInt(mSelectedKeys.Count/2.0f);
for (int i=0, imax=mSelectedKeys.Count; i<imax; ++i)
{
if (DoubleColumn && i>=HalfCount) break;
GUILayout.BeginHorizontal();
OnGUI_CategorizedTerm(mSelectedKeys[i]);
if (DoubleColumn && i+HalfCount<mSelectedKeys.Count)
OnGUI_CategorizedTerm(mSelectedKeys[i+HalfCount]);
GUILayout.EndHorizontal();
}
}
GUILayout.EndScrollView();
}
void OnGUI_CategorizedTerm( string Term )
{
GUILayout.BeginHorizontal();
string sKey, sCategory;
LanguageSourceData.DeserializeFullTerm(Term, out sKey, out sCategory);
if (!string.IsNullOrEmpty(sCategory))
{
GUI.color = Color.gray;
GUILayout.Label(sCategory+"/");
GUI.color = Color.white;
}
GUILayout.Label(sKey);
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
}
void OnGUI_NewOrExistingCategory()
{
//--[ Create Category ]------------------------
GUILayout.BeginHorizontal();
mNewCategory = GUILayout.TextField(mNewCategory, EditorStyles.toolbarTextField, GUILayout.ExpandWidth(true));
if (GUILayout.Button("Create", "toolbarbutton", GUILayout.Width(60)))
{
EditorApplication.update += AssignCategoryToSelectedTerms;
}
GUILayout.EndHorizontal();
//--[ Existing Category ]------------------------
int Index = 0;
List<string> Categories = LocalizationManager.GetCategories();
for (int i=0, imax=Categories.Count; i<imax; ++i)
if (Categories[i].ToLower().Contains(mNewCategory.ToLower()))
{
Index = i;
break;
}
GUILayout.BeginHorizontal();
int NewIndex = EditorGUILayout.Popup(Index, Categories.ToArray(), EditorStyles.toolbarPopup, GUILayout.ExpandWidth(true));
if (NewIndex!=Index)
mNewCategory = Categories[ NewIndex ];
if (GUILayout.Button("Use", "toolbarbutton", GUILayout.Width(60)))
{
mNewCategory = Categories[ NewIndex ];
EditorApplication.update += AssignCategoryToSelectedTerms;
}
GUILayout.EndHorizontal();
}
#endregion
#region Assigning Category
public static Dictionary<string, string> TermReplacements;
void AssignCategoryToSelectedTerms()
{
mIsParsing = true;
EditorApplication.update -= AssignCategoryToSelectedTerms;
mNewCategory = mNewCategory.Trim (LanguageSourceData.CategorySeparators);
if (mNewCategory==LanguageSourceData.EmptyCategory)
mNewCategory = string.Empty;
TermReplacements = new Dictionary<string, string>(StringComparer.Ordinal);
for (int i=mSelectedKeys.Count-1; i>=0; --i)
{
string sKey, sCategory;
string OldTerm = mSelectedKeys[i];
LanguageSourceData.DeserializeFullTerm( OldTerm, out sKey, out sCategory );
if (!string.IsNullOrEmpty(mNewCategory))
sKey = string.Concat(mNewCategory, "/", sKey);
if (OldTerm == sKey)
continue;
TermReplacements[ OldTerm ] = sKey;
if (!mLanguageSource.ContainsTerm(sKey))
{
TermData termData = mLanguageSource.GetTermData( OldTerm );
if (termData != null)
termData.Term = sKey;
else
TermReplacements.Remove (OldTerm);
mLanguageSource.Editor_SetDirty();
}
}
if (TermReplacements.Count<=0)
{
ShowError ("Unable to assign category: Terms were not found in the selected LanguageSource");
}
else
{
mLanguageSource.UpdateDictionary(true);
ExecuteActionOnSelectedScenes( ReplaceTermsInCurrentScene );
ParseTerms(true, false, true);
if (string.IsNullOrEmpty(mNewCategory))
mNewCategory = LanguageSourceData.EmptyCategory;
if (!mSelectedCategories.Contains(mNewCategory))
mSelectedCategories.Add (mNewCategory);
//RemoveUnusedCategoriesFromSelected();
ScheduleUpdateTermsToShowInList();
}
TermReplacements = null;
mIsParsing = false;
}
public static void ReplaceTermsInCurrentScene()
{
Localize[] Locals = (Localize[])Resources.FindObjectsOfTypeAll(typeof(Localize));
if (Locals==null)
return;
bool changed = false;
for (int i=0, imax=Locals.Length; i<imax; ++i)
{
Localize localize = Locals[i];
if (localize==null || localize.gameObject==null || !GUITools.ObjectExistInScene(localize.gameObject))
continue;
string NewTerm;
if (TermReplacements.TryGetValue(localize.Term, out NewTerm))
{
localize.mTerm = NewTerm;
changed = true;
}
if (TermReplacements.TryGetValue(localize.SecondaryTerm, out NewTerm))
{
localize.mTermSecondary = NewTerm;
changed = true;
}
}
if (changed)
Editor_SaveScene(true);
}
#endregion
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 690f28955e250544a9bfaf741e4cced7
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,190 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEditor;
using UnityEngine;
namespace I2.Loc
{
public partial class LocalizationEditor
{
#region Variables
List<string> mCharSetTool_Languages = new List<string>();
string mCharSet = string.Empty;
bool mCharSetTool_CaseSensitive;
#endregion
#region GUI Generate Script
void OnGUI_Tools_CharSet()
{
bool computeSet = false;
// remove missing languages
for (int i=mCharSetTool_Languages.Count-1; i>=0; --i)
{
if (mLanguageSource.GetLanguageIndex(mCharSetTool_Languages[i])<0)
mCharSetTool_Languages.RemoveAt(i);
}
GUILayout.BeginHorizontal (EditorStyles.toolbar);
GUILayout.Label ("Languages:", EditorStyles.miniLabel, GUILayout.ExpandWidth(true));
if (GUILayout.Button ("All", EditorStyles.toolbarButton, GUILayout.ExpandWidth(false)))
{
mCharSetTool_Languages.Clear ();
mCharSetTool_Languages.AddRange (mLanguageSource.mLanguages.Select(x=>x.Name));
computeSet = true;
}
if (GUILayout.Button ("None", EditorStyles.toolbarButton, GUILayout.ExpandWidth(false)))
{
mCharSetTool_Languages.Clear ();
computeSet = true;
}
if (GUILayout.Button ("Invert", EditorStyles.toolbarButton, GUILayout.ExpandWidth(false)))
{
var current = mCharSetTool_Languages.ToList ();
mCharSetTool_Languages.Clear ();
mCharSetTool_Languages.AddRange (mLanguageSource.mLanguages.Select(x=>x.Name).Where(j=>!current.Contains(j)));
computeSet = true;
}
GUILayout.EndHorizontal ();
//--[ Language List ]--------------------------
GUI.backgroundColor = Color.Lerp(GUITools.LightGray, Color.white, 0.5f);
mScrollPos_Languages = GUILayout.BeginScrollView( mScrollPos_Languages, LocalizeInspector.GUIStyle_OldTextArea, GUILayout.MinHeight (100), GUILayout.MaxHeight(Screen.height), GUILayout.ExpandHeight(false));
GUI.backgroundColor = Color.white;
for (int i=0, imax=mLanguageSource.mLanguages.Count; i<imax; ++i)
{
GUILayout.BeginHorizontal();
var language = mLanguageSource.mLanguages[i].Name;
bool hasLanguage = mCharSetTool_Languages.Contains(language);
bool newValue = GUILayout.Toggle (hasLanguage, "", "OL Toggle", GUILayout.ExpandWidth(false));
GUILayout.Label(language);
GUILayout.EndHorizontal();
if (hasLanguage != newValue)
{
if (newValue)
mCharSetTool_Languages.Add(language);
else
mCharSetTool_Languages.Remove(language);
computeSet = true;
}
}
GUILayout.EndScrollView();
//GUILayout.Space (5);
GUI.backgroundColor = Color.Lerp (Color.gray, Color.white, 0.2f);
GUILayout.BeginVertical(LocalizeInspector.GUIStyle_OldTextArea, GUILayout.Height(1));
GUI.backgroundColor = Color.white;
EditorGUILayout.HelpBox("此工具显示在所选语言中使用的所有字符\nThis tool shows all characters used in the selected languages", MessageType.Info);
GUILayout.Space (5);
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
GUI.changed = false;
mCharSetTool_CaseSensitive = GUILayout.Toggle(mCharSetTool_CaseSensitive, "Case-Sensitive", GUILayout.ExpandWidth(false));
if (GUI.changed)
computeSet = true;
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
GUILayout.Space (5);
if (computeSet)
UpdateCharSets();
int numUsedChars = string.IsNullOrEmpty (mCharSet) ? 0 : mCharSet.Length;
GUILayout.Label ("Used Characters: (" + numUsedChars+")");
EditorGUILayout.TextArea (mCharSet ?? "");
GUILayout.BeginHorizontal ();
GUILayout.FlexibleSpace ();
if (GUILayout.Button ("Copy To Clipboard", GUITools.DontExpandWidth))
EditorGUIUtility.systemCopyBuffer = mCharSet;
GUILayout.EndHorizontal ();
GUILayout.EndVertical ();
}
#endregion
#region Generate Char Set
void UpdateCharSets ()
{
mCharSet = "";
var sb = new HashSet<char> ();
var LanIndexes = new List<int> ();
for (int i=0; i<mLanguageSource.mLanguages.Count; ++i)
if (mCharSetTool_Languages.Contains(mLanguageSource.mLanguages[i].Name))
LanIndexes.Add(i);
foreach (var termData in mLanguageSource.mTerms)
{
for (int i=0; i<LanIndexes.Count; ++i)
{
int iLanguage = LanIndexes[i];
bool isRTL = LocalizationManager.IsRTL( mLanguageSource.mLanguages[iLanguage].Code );
AppendToCharSet( sb, termData.Languages[iLanguage], isRTL );
}
}
var bytes = Encoding.UTF8.GetBytes( sb.ToArray().OrderBy(c => c).ToArray() );
mCharSet = Encoding.UTF8.GetString(bytes);
}
void AppendToCharSet( HashSet<char> sb, string text, bool isRTL )
{
if (string.IsNullOrEmpty (text))
return;
text = RemoveTagsPrefix(text, "[i2p_");
text = RemoveTagsPrefix(text, "[i2s_");
if (isRTL)
text = RTLFixer.Fix( text );
foreach (char c in text)
{
if (!mCharSetTool_CaseSensitive)
{
sb.Add(char.ToLowerInvariant(c));
sb.Add(char.ToUpperInvariant(c));
}
else
sb.Add(c);
}
}
// Given "[i2p_" it removes all tags that start with that (e.g. [i2p_Zero] [i2p_One], etc)
string RemoveTagsPrefix(string text, string tagPrefix)
{
int idx = 0;
while (idx < text.Length)
{
idx = text.IndexOf(tagPrefix);
if (idx < 0)
break;
int idx2 = text.IndexOf(']', idx);
if (idx2 < 0)
break;
text = text.Remove(idx, idx2 - idx+1);
}
return text;
}
#endregion
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 104713279df05ac4b96f5a76ab621c8a
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,157 @@
using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
namespace I2.Loc
{
public partial class LocalizationEditor
{
#region Variables
#endregion
#region GUI
void OnGUI_Tools_MergeTerms()
{
OnGUI_ScenesList(true);
GUI.backgroundColor = Color.Lerp (Color.gray, Color.white, 0.2f);
GUILayout.BeginVertical(LocalizeInspector.GUIStyle_OldTextArea, GUILayout.Height(1));
GUI.backgroundColor = Color.white;
GUILayout.Space (5);
EditorGUILayout.HelpBox("此选项替换所选场景中该键的所有出现\nThis option replace all occurrences of this key in the selected scenes", MessageType.Info);
GUILayout.Space (5);
GUITools.CloseHeader();
OnGUI_Tools_Categorize_Terms();
OnGUI_NewOrExistingTerm();
}
void OnGUI_NewOrExistingTerm()
{
if (mKeyToExplore==null)
mKeyToExplore = string.Empty;
GUI.backgroundColor = Color.Lerp (Color.gray, Color.white, 0.2f);
GUILayout.BeginVertical(LocalizeInspector.GUIStyle_OldTextArea, GUILayout.Height(1));
GUI.backgroundColor = Color.white;
GUILayout.Space(5);
GUILayout.Label("Replace By:");
GUILayout.EndVertical();
//--[ Create Term ]------------------------
GUILayout.BeginHorizontal();
mKeyToExplore = GUILayout.TextField(mKeyToExplore, EditorStyles.toolbarTextField, GUILayout.ExpandWidth(true));
if (GUILayout.Button("Create", "toolbarbutton", GUILayout.Width(60)))
{
LanguageSourceData.ValidateFullTerm( ref mKeyToExplore );
EditorApplication.update += ReplaceSelectedTerms;
}
GUILayout.EndHorizontal();
//--[ Existing Term ]------------------------
int Index = 0;
List<string> Terms = mLanguageSource.GetTermsList();
for (int i=0, imax=Terms.Count; i<imax; ++i)
if (Terms[i].ToLower().Contains(mKeyToExplore.ToLower()))
{
Index = i;
break;
}
GUILayout.BeginHorizontal();
int NewIndex = EditorGUILayout.Popup(Index, Terms.ToArray(), EditorStyles.toolbarPopup, GUILayout.ExpandWidth(true));
if (NewIndex != Index)
{
SelectTerm (Terms [NewIndex]);
ClearErrors();
}
if (GUILayout.Button("Use", "toolbarbutton", GUILayout.Width(60)))
{
SelectTerm( Terms[ NewIndex ] );
EditorApplication.update += ReplaceSelectedTerms;
}
GUILayout.EndHorizontal();
}
#endregion
#region Merge Terms
void ReplaceSelectedTerms()
{
EditorApplication.update -= ReplaceSelectedTerms;
if (string.IsNullOrEmpty(mKeyToExplore))
return;
mIsParsing = true;
string sNewKey = mKeyToExplore;
//--[ Create new Term ]-----------------------
if (mLanguageSource.GetTermData(sNewKey)==null)
{
TermData termData = AddLocalTerm(sNewKey);
//--[ Copy the values from any existing term if the target is a new term
TermData oldTerm = null;
for (int i=0, imax=mSelectedKeys.Count; i<imax; ++i)
{
oldTerm = mLanguageSource.GetTermData(mSelectedKeys[i]);
if (oldTerm!=null) break;
}
if (oldTerm!=null)
{
termData.TermType = oldTerm.TermType;
termData.Description = oldTerm.Description;
Array.Copy(oldTerm.Languages, termData.Languages, oldTerm.Languages.Length);
}
}
//--[ Delete the selected Terms from the source ]-----------------
TermReplacements = new Dictionary<string, string>(StringComparer.Ordinal);
for (int i=mSelectedKeys.Count-1; i>=0; --i)
{
string OldTerm = mSelectedKeys[i];
if (OldTerm == sNewKey)
continue;
TermReplacements[ OldTerm ] = mKeyToExplore;
DeleteTerm(OldTerm);
}
ExecuteActionOnSelectedScenes( ReplaceTermsInCurrentScene );
DoParseTermsInCurrentScene();
//--[ Update Selected Categories ]-------------
string mNewCategory = LanguageSourceData.GetCategoryFromFullTerm(sNewKey);
if (mNewCategory == string.Empty)
mNewCategory = LanguageSourceData.EmptyCategory;
if (!mSelectedCategories.Contains(mNewCategory))
mSelectedCategories.Add (mNewCategory);
//RemoveUnusedCategoriesFromSelected();
ScheduleUpdateTermsToShowInList();
TermReplacements = null;
mIsParsing = false;
}
void RemoveUnusedCategoriesFromSelected()
{
List<string> Categories = LocalizationManager.GetCategories();
for (int i=mSelectedCategories.Count-1; i>=0; --i)
if (!Categories.Contains( mSelectedCategories[i] ))
mSelectedCategories.RemoveAt(i);
if (mSelectedCategories.Count == 0)
mSelectedCategories.AddRange(Categories);
ScheduleUpdateTermsToShowInList();
}
#endregion
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: d59fa53e0df75a34693c4673bba5ed94
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,163 @@
using System.Collections.Generic;
using TMPro;
using UnityEditor;
using UnityEngine;
using UnityEngine.UI;
namespace I2.Loc
{
public partial class LocalizationEditor
{
#region Variables
static string _Tools_NoLocalized_Include,
_Tools_NoLocalized_Exclude;
const string _Help_Tool_NoLocalized = "This selects all labels in the current scene that don't have a Localized component.\n\nWhen Include or Exclude are set, labels will be filtered based on those settings.Separate by (,) if multiple strings are used.\n(e.g. Include:\"example,tutorial\")";
#endregion
#region GUI Find NoLocalized Terms
void OnGUI_Tools_NoLocalized()
{
//OnGUI_ScenesList();
if (_Tools_NoLocalized_Include==null)
{
_Tools_NoLocalized_Include = EditorPrefs.GetString ("_Tools_NoLocalized_Include", string.Empty);
_Tools_NoLocalized_Exclude = EditorPrefs.GetString ("_Tools_NoLocalized_Exclude", string.Empty);
}
GUILayout.Space (5);
GUI.backgroundColor = Color.Lerp (Color.gray, Color.white, 0.2f);
GUILayout.BeginVertical(LocalizeInspector.GUIStyle_OldTextArea, GUILayout.Height(1));
GUI.backgroundColor = Color.white;
EditorGUILayout.HelpBox(_Help_Tool_NoLocalized, MessageType.Info);
GUILayout.Space(5);
GUILayout.BeginHorizontal();
GUILayout.Label ("Include:", GUILayout.Width(60));
_Tools_NoLocalized_Include = EditorGUILayout.TextArea(_Tools_NoLocalized_Include, GUILayout.ExpandWidth(true));
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.Label ("Exclude:", GUILayout.Width(60));
_Tools_NoLocalized_Exclude = EditorGUILayout.TextArea(_Tools_NoLocalized_Exclude, GUILayout.ExpandWidth(true));
GUILayout.EndHorizontal();
GUILayout.Space (5);
GUILayout.BeginHorizontal ();
GUILayout.FlexibleSpace();
if (GUILayout.Button("Select No Localized Labels"))
EditorApplication.update += SelectNoLocalizedLabels;
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
GUILayout.EndVertical();
}
#endregion
#region Find No Localized
void SelectNoLocalizedLabels()
{
EditorPrefs.SetString ("_Tools_NoLocalized_Include", _Tools_NoLocalized_Include);
EditorPrefs.SetString ("_Tools_NoLocalized_Exclude", _Tools_NoLocalized_Exclude);
EditorApplication.update -= SelectNoLocalizedLabels;
List<Component> labels = new List<Component>();
TextMesh[] textMeshes = (TextMesh[])Resources.FindObjectsOfTypeAll(typeof(TextMesh));
if (textMeshes!=null && textMeshes.Length>0)
labels.AddRange(textMeshes);
#if NGUI
UILabel[] uiLabels = (UILabel[])Resources.FindObjectsOfTypeAll(typeof(UILabel));
if (uiLabels!=null && uiLabels.Length>0)
labels.AddRange(uiLabels);
#endif
Text[] uiTexts = (Text[])Resources.FindObjectsOfTypeAll(typeof(Text));
if (uiTexts!=null && uiTexts.Length>0)
labels.AddRange(uiTexts);
#if TextMeshPro
TextMeshPro[] tmpText = (TextMeshPro[])Resources.FindObjectsOfTypeAll(typeof(TextMeshPro));
if (tmpText!=null && tmpText.Length>0)
labels.AddRange(tmpText);
TextMeshProUGUI[] uiTextsUGUI = (TextMeshProUGUI[])Resources.FindObjectsOfTypeAll(typeof(TextMeshProUGUI));
if (uiTextsUGUI!=null && uiTextsUGUI.Length>0)
labels.AddRange(uiTextsUGUI);
#endif
#if TK2D
tk2dTextMesh[] tk2dTM = (tk2dTextMesh[])Resources.FindObjectsOfTypeAll(typeof(tk2dTextMesh));
if (tk2dTM!=null && tk2dTM.Length>0)
labels.AddRange(tk2dTM);
#endif
if (labels.Count==0)
return;
string[] Includes = null;
string[] Excludes = null;
if (!string.IsNullOrEmpty (_Tools_NoLocalized_Include))
Includes = _Tools_NoLocalized_Include.ToLower().Split(',', ';');
if (!string.IsNullOrEmpty (_Tools_NoLocalized_Exclude))
Excludes = _Tools_NoLocalized_Exclude.ToLower().Split(',', ';');
List<GameObject> Objs = new List<GameObject>();
for (int i=0, imax=labels.Count; i<imax; ++i)
{
Component label = labels[i];
if (label==null || label.gameObject==null || !GUITools.ObjectExistInScene(label.gameObject))
continue;
if (labels[i].GetComponent<Localize>()!=null)
continue;
if (ShouldFilter(label.name.ToLower(), Includes, Excludes))
continue;
Objs.Add( labels[i].gameObject );
}
if (Objs.Count>0)
Selection.objects = Objs.ToArray();
else
ShowWarning("All labels in this scene have a Localize component assigned");
}
bool ShouldFilter( string Text, string[] Includes, string[] Excludes )
{
if (Includes!=null && Includes.Length>0)
{
bool hasAny = false;
for (int j=0; j<Includes.Length; ++j)
if (Text.Contains(Includes[j]))
{
hasAny = true;
break;
}
if (!hasAny)
return true;
}
if (Excludes!=null && Excludes.Length>0)
{
for (int j=0; j<Excludes.Length; ++j)
if (Text.Contains(Excludes[j]))
return true;
}
return false;
}
#endregion
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 18d48e525beac1e4baff73e509fc246d
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,378 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using UnityEditor;
using UnityEngine;
namespace I2.Loc
{
public class ParsedTerm
{
public string Category, Term, FullTerm;
public int Usage;
public TermData termData;
}
public partial class LocalizationEditor
{
#region Variables
public static SortedDictionary<string, ParsedTerm> mParsedTerms = new SortedDictionary<string, ParsedTerm>(StringComparer.Ordinal); // All Terms resulted from parsing the scenes and collecting the Localize.Term and how many times the terms are used
public static HashSet<string> mParsedCategories = new HashSet<string>(StringComparer.Ordinal);
public static List<ParsedTerm> mShowableTerms = new List<ParsedTerm> (); // this contains the terms from mParsedTerms that should be shown in the list (filtered by search string, usage, etc)
public static bool mParseTermsIn_Scenes = true;
public static bool mParseTermsIn_Scripts = true;
#endregion
#region GUI Parse Keys
void OnGUI_Tools_ParseTerms()
{
OnGUI_ScenesList();
GUI.backgroundColor = Color.Lerp (Color.gray, Color.white, 0.2f);
GUILayout.BeginVertical(LocalizeInspector.GUIStyle_OldTextArea, GUILayout.Height(1));
GUI.backgroundColor = Color.white;
GUILayout.Space (5);
EditorGUILayout.HelpBox("此工具搜索所选场景中使用的所有术语,并在术语选项卡中更新使用计数器\nThis tool searches all Terms used in the selected scenes and updates the usage counter in the Terms Tab", MessageType.Info);
GUILayout.Space (5);
GUILayout.BeginHorizontal ();
GUILayout.FlexibleSpace();
GUILayout.BeginHorizontal ("Box");
mParseTermsIn_Scenes = GUILayout.Toggle(mParseTermsIn_Scenes, new GUIContent("解析场景 Parse SCENES", "打开选定的场景并找到所有使用的术语\nOpens the selected scenes and finds all the used terms"));
GUILayout.FlexibleSpace();
mParseTermsIn_Scripts = GUILayout.Toggle(mParseTermsIn_Scripts, new GUIContent("解析脚本 Parse SCRIPTS", "搜索所有.cs文件并计算所有术语如:ScriptLocalization.Get(\"xxx\")\nSearches all .cs files and counts all terms like: ScriptLocalization.Get(\"xxx\")"));
GUILayout.EndHorizontal();
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal ();
GUILayout.FlexibleSpace();
if (GUILayout.Button("解析本地化术语\nParse Localized Terms"))
{
EditorApplication.update += ParseTermsInSelectedScenes;
if (mParseTermsIn_Scripts)
EditorApplication.update += ParseTermsInScripts;
}
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
GUILayout.EndVertical();
}
#endregion
#region Parsed Terms Handlers
public static ParsedTerm GetParsedTerm( string Term )
{
ParsedTerm data;
if (!mParsedTerms.TryGetValue(Term, out data))
data = AddParsedTerm(Term, null, null, 0);
return data;
}
static ParsedTerm AddParsedTerm( string FullTerm, string TermKey, string Category, int Usage )
{
if (TermKey==null)
LanguageSourceData.DeserializeFullTerm(FullTerm, out TermKey, out Category);
var data = new ParsedTerm();
data.Usage = Usage;
data.FullTerm = FullTerm;
data.Term = TermKey;
data.Category = Category;
mParsedTerms[FullTerm] = data;
return data;
}
public static void RemoveParsedTerm( string Term )
{
mParsedTerms.Remove(Term);
}
public static void DecreaseParsedTerm( string Term )
{
ParsedTerm data = GetParsedTerm(Term);
data.Usage = Mathf.Max (0, data.Usage-1);
}
static void UpdateParsedCategories()
{
mParsedCategories.Clear();
mParsedCategories.UnionWith( mParsedTerms.Select(x=>x.Value.Category) );
mSelectedCategories.RemoveAll(x=>!mParsedCategories.Contains(x));
}
#endregion
#region ParseKeys
public static void ParseTermsInSelectedScenes()
{
EditorApplication.update -= ParseTermsInSelectedScenes;
ParseTerms(false, false, true);
}
public static void DoParseTermsInCurrentScene()
{
EditorApplication.update -= DoParseTermsInCurrentScene;
ParseTerms(true, false, true);
}
public static void DoParseTermsInCurrentSceneAndScripts()
{
EditorApplication.update -= DoParseTermsInCurrentSceneAndScripts;
ParseTerms(true, true, true);
}
static void ParseTerms(bool OnlyCurrentScene, bool ParseScripts, bool OpenTermsTab)
{
mIsParsing = true;
mParsedTerms.Clear();
mSelectedKeys.Clear();
mParsedCategories.Clear();
if (ParseScripts)
{
ParseTermsInScripts();
FindTermsInLocalizedStrings();
}
if (mParseTermsIn_Scenes)
{
if (!OnlyCurrentScene)
ExecuteActionOnSelectedScenes(FindTermsInCurrentScene);
else
FindTermsInCurrentScene();
}
FindTermsNotUsed();
ScheduleUpdateTermsToShowInList();
if (mParsedTerms.Count <= 0)
{
ShowInfo("解析过程中没有找到任何术语\nNo terms where found during parsing");
return;
}
UpdateParsedCategories();
{
mSelectedCategories.Clear();
mSelectedCategories.AddRange(mParsedCategories);
}
if (mLanguageSource!=null)
{
var sourceCategories = mLanguageSource.GetCategories();
mSelectedCategories.RemoveAll(x => !sourceCategories.Contains(x));
}
if (OpenTermsTab)
{
if ((mFlagsViewKeys & (int)eFlagsViewKeys.Missing) > 0)
{
mFlagsViewKeys = (int)eFlagsViewKeys.Used | (int)eFlagsViewKeys.NotUsed | (int)eFlagsViewKeys.Missing;
}
else
{
mFlagsViewKeys = (int)eFlagsViewKeys.Used | (int)eFlagsViewKeys.NotUsed;
}
mCurrentViewMode = eViewMode.Keys;
}
mIsParsing = false;
}
static void FindTermsInCurrentScene()
{
Localize[] Locals = (Localize[])Resources.FindObjectsOfTypeAll(typeof(Localize));
if (Locals==null)
return;
for (int i=0, imax=Locals.Length; i<imax; ++i)
{
Localize localize = Locals[i];
if (localize==null || localize.Source!=null && localize.Source.SourceData!=mLanguageSource || localize.gameObject==null || !GUITools.ObjectExistInScene(localize.gameObject))
continue;
string Term, SecondaryTerm;
//Term = localize.Term;
//SecondaryTerm = localize.SecondaryTerm;
localize.GetFinalTerms( out Term, out SecondaryTerm );
if (!string.IsNullOrEmpty(Term))
GetParsedTerm(Term).Usage++;
if (!string.IsNullOrEmpty(SecondaryTerm))
GetParsedTerm(SecondaryTerm).Usage++;
}
}
static void FindTermsInLocalizedStrings()
{
MonoBehaviour[] behaviors = (MonoBehaviour[])Resources.FindObjectsOfTypeAll(typeof(MonoBehaviour));
Type Type_localizedString = typeof(LocalizedString);
foreach (var cmp in behaviors)
{
if (cmp.GetType().Name.Contains("Example_LocalizedString"))
continue;
var props = cmp.GetType()
.GetProperties()
.Where(x=> Type_localizedString.IsAssignableFrom(x.PropertyType) ||
Attribute.IsDefined(x, typeof(TermsPopup)));
foreach (var p in props)
{
string value = null;
if (Type_localizedString.IsAssignableFrom(p.PropertyType))
{
var varObj = p.GetValue(cmp,null);
value = Convert.ToString(varObj.GetType().GetField("mTerm").GetValue(varObj));
}
else
{
value = Convert.ToString(p.GetValue(cmp,null));
}
if (!string.IsNullOrEmpty(value))
{
GetParsedTerm(value).Usage++;
}
//Debug.LogFormat("{0} ({1})", p.Name, p.PropertyType);
//Debug.Log(value);
}
var variables = cmp.GetType()
.GetFields()
.Where(x => Type_localizedString.IsAssignableFrom(x.FieldType) ||
Attribute.IsDefined(x, typeof(TermsPopup)));
foreach (var v in variables)
{
string value = null;
if (Type_localizedString.IsAssignableFrom(v.FieldType))
{
var varObj = v.GetValue(cmp);
value = Convert.ToString(varObj.GetType().GetField("mTerm").GetValue(varObj));
}
else
{
value = Convert.ToString(v.GetValue(cmp));
}
if (!string.IsNullOrEmpty(value))
{
GetParsedTerm(value).Usage++;
}
//Debug.LogFormat("{0} ({1})", v.Name, v.FieldType);
//Debug.Log(value);
}
}
}
static void FindTermsNotUsed()
{
// every Term that is in the DB but not in mParsedTerms
if (mLanguageSource == null)
return;
//string lastCategory = null;
foreach (TermData termData in mLanguageSource.mTerms)
GetParsedTerm(termData.Term);
}
static void ParseTermsInScripts()
{
EditorApplication.update -= ParseTermsInScripts;
string[] scriptFiles = AssetDatabase.GetAllAssetPaths().Where(path => path.ToLower().EndsWith(".cs")).ToArray();
string mLocalizationManager = @"GetTranslation\s?\(\s?\""(.*?)\""";
string mLocalizationManagerOld = @"GetTermTranslation\s?\(\s?\""(.*?)\""";
string mLocalizationManagerTry = @"TryGetTranslation\s?\(\s?\""(.*?)\""";
string mSetTerm = @"SetTerm\s?\(\s?\""(.*?)\""";
Regex regex = new Regex(mLocalizationManager + "|" + mLocalizationManagerTry + "|" + mLocalizationManagerOld + "|" + mSetTerm, RegexOptions.Multiline);
foreach (string scriptFile in scriptFiles)
{
string scriptContents = File.ReadAllText(scriptFile);
MatchCollection matches = regex.Matches(scriptContents);
for (int matchNum = 0; matchNum < matches.Count; matchNum++)
{
Match match = matches[matchNum];
string term = I2Utils.GetCaptureMatch(match);
GetParsedTerm(term).Usage++;
}
}
ScheduleUpdateTermsToShowInList();
}
#endregion
#region Misc
public static void SetAllTerms_When_InferredTerms_IsInSource()
{
var Locals = Resources.FindObjectsOfTypeAll(typeof(Localize)) as Localize[];
if (Locals==null)
return;
foreach (var localize in Locals)
{
if (localize == null || localize.Source != null && localize.Source.SourceData != mLanguageSource || localize.gameObject == null || !GUITools.ObjectExistInScene (localize.gameObject))
continue;
if (!string.IsNullOrEmpty (localize.mTerm) && !string.IsNullOrEmpty (localize.SecondaryTerm))
continue;
ApplyInferredTerm( localize );
}
ParseTerms (true, false, true);
}
public static void ApplyInferredTerm( Localize localize)
{
if (mLanguageSource==null)
return;
if (!string.IsNullOrEmpty (localize.mTerm) && !string.IsNullOrEmpty (localize.mTermSecondary))
return;
string sTerm, sSecTerm;
localize.GetFinalTerms (out sTerm, out sSecTerm);
if (string.IsNullOrEmpty (localize.mTerm))
{
var termData = mLanguageSource.GetTermData (sTerm, true);
if (termData!=null)
localize.mTerm = termData.Term;
}
if (string.IsNullOrEmpty (localize.mTermSecondary))
{
var termData = mLanguageSource.GetTermData (sSecTerm, true);
if (termData!=null)
localize.mTermSecondary = termData.Term;
}
//localize.Source = mLanguageSource;
}
#endregion
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 697e1bc5d373845df927c0da625b7cad
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,179 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
namespace I2.Loc
{
public partial class LocalizationEditor
{
#region Variables
EditorBuildSettingsScene[] mScenesInBuildSettings;
bool Tools_ShowScenesList;
#endregion
#region GUI
void OnGUI_ScenesList( bool SmallSize = false )
{
mScenesInBuildSettings = EditorBuildSettings.scenes;
string currentScene = Editor_GetCurrentScene ();
List<string> sceneList = mScenesInBuildSettings.Select(x=>x.path).ToList();
if (!sceneList.Contains (currentScene))
sceneList.Insert (0, currentScene);
mSelectedScenes.RemoveAll (x => !sceneList.Contains(x));
if (mSelectedScenes.Count==0)
mSelectedScenes.Add (currentScene);
if (!Tools_ShowScenesList)
{
GUILayout.Space(5);
GUILayout.BeginHorizontal();
Tools_ShowScenesList = GUILayout.Toggle(Tools_ShowScenesList, "", EditorStyles.foldout, GUILayout.ExpandWidth(false));
string sceneText = string.Empty;
if (mSelectedScenes.Count==1 && mSelectedScenes[0]== currentScene)
sceneText = "Current Scene";
else
sceneText = string.Format("{0} of {1} Scenes", mSelectedScenes.Count, Mathf.Max(mScenesInBuildSettings.Length, mSelectedScenes.Count));
var stl = new GUIStyle("toolbarbutton");
stl.richText = true;
if (GUILayout.Button("Scenes to Parse: <i>"+sceneText+"</i>", stl))
Tools_ShowScenesList = true;
GUILayout.EndHorizontal();
GUILayout.Space(10);
return;
}
OnGUI_ScenesList_TitleBar();
GUI.backgroundColor = Color.Lerp(GUITools.LightGray, Color.white, 0.5f);
mScrollPos_BuildScenes = GUILayout.BeginScrollView( mScrollPos_BuildScenes, LocalizeInspector.GUIStyle_OldTextArea, GUILayout.Height ( SmallSize ? 100 : 200));
GUI.backgroundColor = Color.white;
for (int i=0, imax=sceneList.Count; i<imax; ++i)
{
GUILayout.BeginHorizontal();
OnGUI_SelectableToogleListItem( sceneList[i], ref mSelectedScenes, "OL Toggle" );
bool bSelected = mSelectedScenes.Contains(sceneList[i]);
GUI.color = bSelected ? Color.white : Color.Lerp(Color.gray, Color.white, 0.5f);
string scenePath = sceneList[i];
if (scenePath.StartsWith("assets/", StringComparison.OrdinalIgnoreCase))
scenePath = scenePath.Substring("Assets/".Length);
if (currentScene == sceneList[i])
scenePath = "[Current Scene] " + scenePath;
if (GUILayout.Button (scenePath, "Label"))
{
if (mSelectedScenes.Contains(sceneList[i]))
mSelectedScenes.Remove(sceneList[i]);
else
mSelectedScenes.Add(sceneList[i]);
}
GUI.color = Color.white;
GUILayout.EndHorizontal();
}
GUILayout.EndScrollView();
}
void OnGUI_ScenesList_TitleBar()
{
GUILayout.BeginHorizontal();
Tools_ShowScenesList = GUILayout.Toggle(Tools_ShowScenesList, "", EditorStyles.foldout, GUILayout.ExpandWidth(false));
if (GUILayout.Button("Scenes to Parse:", "toolbarbutton"))
Tools_ShowScenesList = false;
if (GUILayout.Button("All", "toolbarbutton", GUILayout.ExpandWidth(false)))
{
OnGUI_ScenesList_SelectAllScenes(false);
}
if (GUILayout.Button("None", "toolbarbutton", GUILayout.ExpandWidth(false)))
{
mSelectedScenes.Clear();
}
if (GUILayout.Button("Used", "toolbarbutton", GUILayout.ExpandWidth(false)))
{
mSelectedScenes.Clear();
for (int i=0, imax=mScenesInBuildSettings.Length; i<imax; ++i)
if (mScenesInBuildSettings[i].enabled)
mSelectedScenes.Add (mScenesInBuildSettings[i].path);
}
if (GUILayout.Button("Current", "toolbarbutton", GUILayout.ExpandWidth(false)))
{
mSelectedScenes.Clear();
mSelectedScenes.Add (Editor_GetCurrentScene());
}
GUILayout.EndHorizontal();
}
private void OnGUI_ScenesList_SelectAllScenes(bool reset)
{
if (reset || mScenesInBuildSettings == null)
{
mScenesInBuildSettings = EditorBuildSettings.scenes;
}
mSelectedScenes.Clear();
for (int i = 0, imax = mScenesInBuildSettings.Length; i < imax; ++i)
mSelectedScenes.Add(mScenesInBuildSettings[i].path);
if (!mSelectedScenes.Contains(Editor_GetCurrentScene()))
mSelectedScenes.Add(Editor_GetCurrentScene());
}
void SelectUsedScenes()
{
mSelectedScenes.Clear();
for (int i=0, imax=mScenesInBuildSettings.Length; i<imax; ++i)
if (mScenesInBuildSettings[i].enabled)
mSelectedScenes.Add( mScenesInBuildSettings[i].path );
}
#endregion
#region Iterate thru the Scenes
delegate void Delegate0();
static void ExecuteActionOnSelectedScenes( Delegate0 Action )
{
string InitialScene = Editor_GetCurrentScene();
if (mSelectedScenes.Count<=0)
mSelectedScenes.Add (InitialScene);
bool HasSaved = false;
foreach (string ScenePath in mSelectedScenes)
{
if (ScenePath != Editor_GetCurrentScene())
{
if (!HasSaved) // Saving the initial scene to avoid loosing changes
{
Editor_SaveScene ();
HasSaved = true;
}
Editor_OpenScene( ScenePath );
}
Action();
}
if (InitialScene != Editor_GetCurrentScene())
Editor_OpenScene( InitialScene );
if (mLanguageSource!=null)
Selection.activeObject = mLanguageSource.ownerObject;
}
#endregion
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 26e06d7fb9cef5341a791b25339444e0
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,298 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using UnityEditor;
using UnityEngine;
using UnityEngineInternal;
namespace I2.Loc
{
public partial class LocalizationEditor
{
#region Variables
int Script_Tool_MaxVariableLength = 50;
#endregion
#region GUI Generate Script
void OnGUI_Tools_Script()
{
OnGUI_KeysList (false, 200, false);
//GUILayout.Space (5);
GUI.backgroundColor = Color.Lerp (Color.gray, Color.white, 0.2f);
GUILayout.BeginVertical(LocalizeInspector.GUIStyle_OldTextArea, GUILayout.Height(1));
GUI.backgroundColor = Color.white;
EditorGUILayout.HelpBox("这个工具用所选的术语创建\nScriptLocalization.cs\n这允许对脚本中引用的已使用术语进行编译时检查\n\nScriptLocalization.cs。\nThis tool creates the ScriptLocalization.cs with the selected terms.\nThis allows for Compile Time Checking on the used Terms referenced in scripts", MessageType.Info);
GUILayout.Space (5);
GUILayout.BeginHorizontal ();
GUILayout.FlexibleSpace();
EditorGUIUtility.labelWidth = 240;
EditorGUILayout.IntField("生成的Term id的最大长度:Max Length of the Generated Term IDs:", Script_Tool_MaxVariableLength);
EditorGUIUtility.labelWidth = 0;
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
GUILayout.Space (10);
GUILayout.BeginHorizontal ();
GUILayout.FlexibleSpace();
if (GUILayout.Button(new GUIContent("选择烘焙术语\nSelect Baked Terms", "选择之前在ScriptLocalization.cs中构建的所有术语\nSelects all the terms previously built in ScriptLocalization.cs")))
SelectTermsFromScriptLocalization();
if (GUILayout.Button("使用选定的术语构建脚本\nBuild Script with Selected Terms"))
EditorApplication.update += BuildScriptWithSelectedTerms;
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
GUILayout.EndVertical();
}
void SelectTermsFromScriptLocalization()
{
var ScriptFile = GetPathToGeneratedScriptLocalization();
try
{
var text = File.ReadAllText(ScriptFile, Encoding.UTF8);
mSelectedKeys.Clear();
foreach (Match match in Regex.Matches(text, "\".+\""))
{
var term = match.Value.Substring(1, match.Value.Length - 2);
if (!mSelectedKeys.Contains(term))
{
mSelectedKeys.Add(term);
}
}
}
catch(Exception)
{ }
}
#endregion
#region Generate Script File
private static string I2LocalizeCS = "I2Localize";
private static string I2TermsCS = "I2Terms";
void BuildScriptWithSelectedTerms()
{
EditorApplication.update -= BuildScriptWithSelectedTerms;
var sbTrans = new StringBuilder();
var sbTerms = new StringBuilder();
sbTrans.AppendLine( "using UnityEngine;" );
sbTrans.AppendLine();
sbTrans.AppendLine( "namespace I2.Loc" );
sbTrans.AppendLine( "{" );
sbTrans.AppendLine( $" public static class {I2LocalizeCS}" );
sbTrans.AppendLine( " {" );
sbTerms.AppendLine();
sbTerms.AppendLine($" public static class {I2TermsCS}");
sbTerms.AppendLine(" {");
BuildScriptWithSelectedTerms( sbTrans, sbTerms );
sbTrans.AppendLine(" }"); // Closing both classes
sbTerms.AppendLine(" }");
string ScriptFile = GetPathToGeneratedScriptLocalization ();
Debug.Log ("Generating: " + ScriptFile);
var filePath = Application.dataPath + ScriptFile.Substring("Assets".Length);
string fileText = sbTrans + sbTerms.ToString() + "}";
File.WriteAllText(filePath, fileText, Encoding.UTF8);
AssetDatabase.ImportAsset(ScriptFile);
}
static string GetPathToGeneratedScriptLocalization()
{
/*string[] assets = AssetDatabase.FindAssets("ScriptLocalization");
if (assets.Length>0)
{
try
{
string FilePath = AssetDatabase.GUIDToAssetPath(assets[0]);
return FilePath;
}
catch(Exception)
{ }
}*/
var path = $"{YIUIFramework.UIStaticHelper.UIGenerationPath}/I2Localization";
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
return $"{path}/{I2LocalizeCS}.cs";
}
void BuildScriptWithSelectedTerms( StringBuilder sbTrans, StringBuilder sbTerms )
{
List<string> Categories = LocalizationManager.GetCategories();
foreach (string Category in Categories)
{
List<string> CategoryTerms = ScriptTool_GetSelectedTermsInCategory(Category);
if (CategoryTerms.Count<=0)
continue;
List<string> AdjustedCategoryTerms = new List<string>(CategoryTerms);
for (int i=0, imax=AdjustedCategoryTerms.Count; i<imax; ++i)
AdjustedCategoryTerms[i] = ScriptTool_AdjustTerm( AdjustedCategoryTerms[i] );
ScriptTool_EnumerateDuplicatedTerms(AdjustedCategoryTerms);
sbTrans.AppendLine();
sbTerms.AppendLine();
if (Category != LanguageSourceData.EmptyCategory)
{
sbTrans.AppendLine(" public static class " + ScriptTool_AdjustTerm(Category,true));
sbTrans.AppendLine(" {");
sbTerms.AppendLine(" public static class " + ScriptTool_AdjustTerm(Category, true));
sbTerms.AppendLine(" {");
}
BuildScriptCategory( sbTrans, sbTerms, Category, AdjustedCategoryTerms, CategoryTerms );
if (Category != LanguageSourceData.EmptyCategory)
{
sbTrans.AppendLine(" }");
sbTerms.AppendLine(" }");
}
}
}
List<string> ScriptTool_GetSelectedTermsInCategory( string Category )
{
List<string> list = new List<string>();
foreach (string FullKey in mSelectedKeys)
{
string categ = LanguageSourceData.GetCategoryFromFullTerm(FullKey);
if (categ == Category && ShouldShowTerm(FullKey))
{
list.Add( LanguageSourceData.GetKeyFromFullTerm(FullKey) );
}
}
return list;
}
void BuildScriptCategory( StringBuilder sbTrans, StringBuilder sbTerms, string Category, List<string> AdjustedTerms, List<string> Terms )
{
if (Category==LanguageSourceData.EmptyCategory)
{
for (int i = 0; i < Terms.Count; ++i)
{
if (Terms[i] == Category)
{
Debug.LogError($"分组名称与术语相同 请修改 {Category}");
continue;
}
sbTrans.AppendLine( " public static string " + AdjustedTerms[i] + " \t\t{ get{ return LocalizationManager.GetTranslation (\"" + Terms[i] + "\"); } }");
sbTerms.AppendLine(" public const string " + AdjustedTerms[i] + " = \"" + Terms[i] + "\";");
}
}
else
for (int i=0; i<Terms.Count; ++i)
{
if (Terms[i] == Category)
{
Debug.LogError($"分组名称与术语相同 请修改 {Category}");
continue;
}
sbTrans.AppendLine(" public static string "+AdjustedTerms[i]+ " \t\t{ get{ return LocalizationManager.GetTranslation (\"" + Category+"/"+Terms[i]+"\"); } }");
sbTerms.AppendLine(" public const string " + AdjustedTerms[i] + " = \"" + Category + "/" + Terms[i] + "\";");
}
}
string ScriptTool_AdjustTerm( string Term, bool allowFullLength = false )
{
Term = I2Utils.GetValidTermName(Term);
// C# IDs can't start with a number
if (I2Utils.NumberChars.IndexOf(Term[0])>=0)
Term = "_"+Term;
if (!allowFullLength && Term.Length>Script_Tool_MaxVariableLength)
Term = Term.Substring(0, Script_Tool_MaxVariableLength);
// Remove invalid characters
char[] chars = Term.ToCharArray();
for (int i=0, imax=chars.Length; i<imax; ++i)
{
if (!IsValidCharacter(chars[i]))
chars[i] = '_';
}
Term = new string(chars);
if (IsCSharpKeyword(Term)) return string.Concat('@', Term);
return Term;
bool IsValidCharacter(char c)
{
if (I2Utils.ValidChars.IndexOf(c)>=0) return true;
return c>='\u4e00' && c<='\u9fff'; // Chinese/Japanese characters
}
}
void ScriptTool_EnumerateDuplicatedTerms(List<string> AdjustedTerms)
{
string lastTerm = "$";
int Counter = 1;
for (int i=0, imax=AdjustedTerms.Count; i<imax; ++i)
{
string currentTerm = AdjustedTerms[i];
if (lastTerm == currentTerm || i<imax-1 && currentTerm==AdjustedTerms[i+1])
{
AdjustedTerms[i] = AdjustedTerms[i] + "_" + Counter;
Counter++;
}
else
Counter = 1;
lastTerm = currentTerm;
}
}
#endregion
bool IsCSharpKeyword(string variableName)
{
return variableName == "abstract" || variableName == "as" || variableName == "base" || variableName == "bool" ||
variableName == "break" || variableName == "byte" || variableName == "" || variableName == "case" ||
variableName == "catch" || variableName == "char" || variableName == "checked" || variableName == "class" ||
variableName == "const" || variableName == "continue" || variableName == "decimal" || variableName == "default" ||
variableName == "delegate" || variableName == "do" || variableName == "double" || variableName == "else" ||
variableName == "enum" || variableName == "event" || variableName == "explicit" || variableName == "extern" ||
variableName == "false" || variableName == "finally" || variableName == "fixed" || variableName == "float" ||
variableName == "for" || variableName == "foreach" || variableName == "goto" || variableName == "if" ||
variableName == "implicit" || variableName == "in" || variableName == "int" || variableName == "interface" ||
variableName == "internal" || variableName == "is" || variableName == "lock" || variableName == "long" ||
variableName == "namespace" || variableName == "new" || variableName == "null" || variableName == "object" ||
variableName == "operator" || variableName == "out" || variableName == "override" || variableName == "params" ||
variableName == "private" || variableName == "protected" || variableName == "public" || variableName == "readonly" ||
variableName == "ref" || variableName == "return" || variableName == "sbyte" || variableName == "sealed" ||
variableName == "short" || variableName == "sizeof" || variableName == "stackalloc" || variableName == "static" ||
variableName == "string" || variableName == "struct" || variableName == "switch" || variableName == "this" ||
variableName == "throw" || variableName == "true" || variableName == "try" || variableName == "typeof" ||
variableName == "uint" || variableName == "ulong" || variableName == "unchecked" || variableName == "unsafe" ||
variableName == "short" || variableName == "using" || variableName == "virtual" || variableName == "void" ||
variableName == "volatile" || variableName == "while";
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 634a9cc818031dd4c8ddf451d36abe00
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,173 @@
using System;
using System.IO;
using UnityEditor;
using UnityEngine;
namespace I2.Loc
{
public partial class LocalizationEditor
{
void OnGUI_Warning_SourceInScene()
{
// if (mLanguageSource.UserAgreesToHaveItOnTheScene) return;
// LanguageSourceData source = GetSourceData();
// if (source.IsGlobalSource() && !GUITools.ObjectExistInScene(source.gameObject))
// return;
// string Text = @"Its advised to only use the source in I2\Localization\Resources\I2Languages.prefab
//That works as a GLOBAL source accessible in ALL scenes. Thats why its recommended to add all your translations there.
//You don't need to instantiate that prefab into the scene, just click the prefab and add the Data.
//Only use Sources in the scene when the localization is meant to be ONLY used there.
//However, that's not advised and is only used in the Examples to keep them separated from your project localization.
//Furthermore, having a source in the scene require that any Localize component get a reference to that source to work properly. By dragging the source into the field at the bottom of the Localize component.";
// EditorGUILayout.HelpBox(Text, MessageType.Warning);
// GUILayout.BeginHorizontal();
// GUILayout.FlexibleSpace();
// if (GUILayout.Button("Keep as is"))
// {
// SerializedProperty Agree = serializedObject.FindProperty("UserAgreesToHaveItOnTheScene");
// Agree.boolValue = true;
// }
// GUILayout.FlexibleSpace();
// if (GUILayout.Button("Open the Global Source"))
// {
// GameObject Prefab = (Resources.Load(LocalizationManager.GlobalSources[0]) as GameObject);
// Selection.activeGameObject = Prefab;
// }
// GUILayout.FlexibleSpace();
// if (GUILayout.Button("Delete this and open the Global Source"))
// {
// EditorApplication.CallbackFunction Callback = null;
// EditorApplication.update += Callback = ()=>
// {
// EditorApplication.update -= Callback;
// if (source.GetComponents<Component>().Length<=2)
// {
// Debug.Log ("Deleting GameObject '" + source.name + "' and Openning the "+LocalizationManager.GlobalSources[0]+".prefab");
// DestroyImmediate (source.gameObject);
// }
// else
// {
// Debug.Log ("Deleting the LanguageSource inside GameObject " + source.name + " and Openning the "+LocalizationManager.GlobalSources[0] +".prefab");
// DestroyImmediate (source);
// }
// GameObject Prefab = (Resources.Load(LocalizationManager.GlobalSources[0]) as GameObject);
// Selection.activeGameObject = Prefab;
// };
// }
// GUILayout.FlexibleSpace();
// GUILayout.EndHorizontal();
// GUILayout.Space(10);
}
private bool bSourceInsidePluginsFolder = true;
public void OnGUI_Warning_SourceInsidePluginsFolder()
{
if (!bSourceInsidePluginsFolder || mLanguageSource.UserAgreesToHaveItInsideThePluginsFolder)
return;
if (!mLanguageSource.IsGlobalSource())
{
bSourceInsidePluginsFolder = false;
return;
}
string pluginPath = UpgradeManager.GetI2LocalizationPath();
string assetPath = AssetDatabase.GetAssetPath(target);
if (!assetPath.StartsWith(pluginPath, StringComparison.OrdinalIgnoreCase))
{
bSourceInsidePluginsFolder = false;
return;
}
string Text = @"Its advised to move this Global Source to a folder outside the I2 Localization.
For example (Assets/I2/Resources) instead of (Assets/I2/Localization/Resources)
That way upgrading the plugin its as easy as deleting the I2/Localization and I2/Common folders and reinstalling.
Do you want the plugin to automatically move the LanguageSource to a folder outside the plugin?";
EditorGUILayout.HelpBox(Text, MessageType.Warning);
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
if (GUILayout.Button("Keep as is"))
{
SerializedProperty Agree = serializedObject.FindProperty("UserAgreesToHaveItInsideThePluginsFolder");
Agree.boolValue = true;
bSourceInsidePluginsFolder = true;
}
GUILayout.FlexibleSpace();
if (GUILayout.Button("Ask me later"))
{
bSourceInsidePluginsFolder = false;
}
GUILayout.FlexibleSpace();
if (GUILayout.Button("Move to the Recommended Folder"))
EditorApplication.delayCall += MoveGlobalSource;
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
GUILayout.Space(10);
}
public bool OnGUI_Warning_SourceNotUpToDate()
{
if (mProp_GoogleLiveSyncIsUptoDate.boolValue)
{
return false;
}
string Text = "Spreadsheet is not up-to-date and Google Live Synchronization is enabled\n\nWhen playing in the device the Spreadsheet will be downloaded and override the translations built from the editor.\n\nTo fix this, Import or Export REPLACE to Google";
EditorGUILayout.HelpBox(Text, MessageType.Warning);
return true;
}
private static void MoveGlobalSource()
{
EditorApplication.delayCall -= MoveGlobalSource;
string pluginPath = UpgradeManager.GetI2LocalizationPath();
string assetPath = AssetDatabase.GetAssetPath(mLanguageSource.ownerObject);
string I2Path = pluginPath.Substring(0, pluginPath.Length-"/Localization".Length);
string newPath = I2Path + "/Resources/" + mLanguageSource.ownerObject.name + ".prefab";
string fullresFolder = Application.dataPath + I2Path.Replace("Assets","") + "/Resources";
bool folderExists = Directory.Exists (fullresFolder);
if (!folderExists)
AssetDatabase.CreateFolder(I2Path, "Resources");
AssetDatabase.MoveAsset(assetPath, newPath);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
var prefab = AssetDatabase.LoadAssetAtPath(newPath, typeof(GameObject)) as GameObject;
Selection.activeGameObject = prefab;
Debug.Log("LanguageSource moved to:" + newPath);
ShowInfo("Please, ignore some console warnings/errors produced by this operation, everything worked fine. In a new release those warnings will be cleared");
}
public static void DelayedDestroySource()
{
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 20e86d3a806624846bccd81bac9f935f
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,133 @@
#if UNITY_ANDROID
using UnityEditor.Callbacks;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
namespace I2.Loc
{
public class PostProcessBuild_Android
{
// Post Process Scene is a hack, because using PostProcessBuild will be called after the APK is generated, and so, I didn't find a way to copy the new files
[PostProcessScene]
public static void OnPostProcessScene()
{
#if UNITY_4_6 || UNITY_4_7 || UNITY_4_8 || UNITY_4_9 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2
bool isFirstScene = (EditorBuildSettings.scenes.Length>0 && EditorBuildSettings.scenes[0].path == EditorApplication.currentScene);
#else
bool isFirstScene = UnityEngine.SceneManagement.SceneManager.GetActiveScene().buildIndex <= 0;
#endif
if (!EditorApplication.isPlayingOrWillChangePlaymode &&
(EditorUserBuildSettings.activeBuildTarget == BuildTarget.Android) &&
isFirstScene)
{
string projPath = System.IO.Path.GetFullPath(Application.streamingAssetsPath + "/../../Temp/StagingArea");
//string projPath = System.IO.Path.GetFullPath(Application.dataPath+ "/Plugins/Android");
PostProcessAndroid(BuildTarget.Android, projPath);
}
}
//[PostProcessBuild(10000)]
public static void PostProcessAndroid(BuildTarget buildTarget, string pathToBuiltProject)
{
if (buildTarget!=BuildTarget.Android)
return;
if (LocalizationManager.Sources.Count <= 0)
LocalizationManager.UpdateSources();
// Get language with variants, but also add it without the variant to allow fallbacks (e.g. en-CA also adds en)
var langCodes = LocalizationManager.GetAllLanguagesCode(false).Concat( LocalizationManager.GetAllLanguagesCode(true) ).Distinct().ToList();
if (langCodes.Count <= 0)
return;
string stringXML = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"+
"<resources>\n"+
" <string name=\"app_name\">{0}</string>\n"+
"</resources>";
SetStringsFile( pathToBuiltProject+"/res/values", "strings.xml", stringXML, LocalizationManager.GetAppName(langCodes[0]) );
var list = new List<string>();
list.Add( pathToBuiltProject + "/res/values" );
foreach (var code in langCodes)
{
// Android doesn't use zh-CN or zh-TW, instead it uses: zh-rCN, zh-rTW, zh
string fixedCode = code;
if (fixedCode.StartsWith("zh", System.StringComparison.OrdinalIgnoreCase))
{
string googleCode = GoogleLanguages.GetGoogleLanguageCode(fixedCode);
if (googleCode==null) googleCode = fixedCode;
fixedCode = (googleCode == "zh-CN") ? "zh-CN" : googleCode;
}
fixedCode = fixedCode.Replace("-", "-r");
string dir = pathToBuiltProject + "/res/values-" + fixedCode;
SetStringsFile( dir, "strings.xml", stringXML, LocalizationManager.GetAppName(code) );
}
}
static void CreateFileIfNeeded ( string folder, string fileName, string text )
{
try
{
if (!System.IO.Directory.Exists( folder ))
System.IO.Directory.CreateDirectory( folder );
if (!System.IO.File.Exists( folder + "/"+fileName ))
System.IO.File.WriteAllText( folder + "/"+fileName, text );
}
catch (System.Exception e)
{
Debug.Log( e );
}
}
static void SetStringsFile(string folder, string fileName, string stringXML, string appName)
{
try
{
appName = appName.Replace("&", "&amp;").Replace("<", "&lt;").Replace(">", "&gt;").Replace("\"", "\\\"").Replace("'", "\\'");
appName = appName.Replace("\r\n", string.Empty).Replace("\n", string.Empty).Replace("\r", string.Empty);
if (!System.IO.Directory.Exists(folder))
System.IO.Directory.CreateDirectory(folder);
if (!System.IO.File.Exists(folder + "/" + fileName))
{
// create the string file if it doesn't exist
stringXML = string.Format(stringXML, appName);
}
else
{
stringXML = System.IO.File.ReadAllText(folder + "/" + fileName);
// find app_name
var pattern = "\"app_name\">(.*)<\\/string>";
var regexPattern = new System.Text.RegularExpressions.Regex(pattern);
if (regexPattern.IsMatch(stringXML))
{
// Override the AppName if it was found
stringXML = regexPattern.Replace(stringXML, string.Format("\"app_name\">{0}</string>", appName));
}
else
{
// insert the appName if it wasn't there
int idx = stringXML.IndexOf("<resources>");
if (idx > 0)
stringXML = stringXML.Insert(idx + "</resources>".Length, string.Format("\n <string name=\"app_name\">{0}</string>\n", appName));
}
}
System.IO.File.WriteAllText(folder + "/" + fileName, stringXML);
}
catch (System.Exception e)
{
Debug.Log(e);
}
}
}
}
#endif

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 4c8d936531867014da228239d095833c
timeCreated: 1489354551
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,102 @@
#if UNITY_IOS || UNITY_IPHONE
using UnityEditor.Callbacks;
using System.Collections;
using UnityEditor.iOS_I2Loc.Xcode;
using System.IO;
using UnityEditor;
using UnityEngine;
using System.Linq;
namespace I2.Loc
{
public class PostProcessBuild_IOS
{
[PostProcessBuild(10000)]
public static void ChangeXcodePlist(BuildTarget buildTarget, string pathToBuiltProject)
{
if (buildTarget != BuildTarget.iOS)
return;
if (LocalizationManager.Sources.Count <= 0)
LocalizationManager.UpdateSources();
var langCodes = LocalizationManager.GetAllLanguagesCode(false).Concat(LocalizationManager.GetAllLanguagesCode(true)).Distinct().ToList();
if (langCodes.Count <= 0)
return;
try
{
//----[ Export localized languages to the info.plist ]---------
string plistPath = pathToBuiltProject + "/Info.plist";
PlistDocument plist = new PlistDocument();
plist.ReadFromString(File.ReadAllText(plistPath));
PlistElementDict rootDict = plist.root;
// Get Language root
var langArray = rootDict.CreateArray("CFBundleLocalizations");
// Set the Language Codes
foreach (var code in langCodes)
{
if (code == null || code.Length < 2)
continue;
langArray.AddString(code);
}
rootDict.SetString("CFBundleDevelopmentRegion", langCodes[0]);
// Write to file
File.WriteAllText(plistPath, plist.WriteToString());
//--[ Localize App Name ]----------
string LocalizationRoot = pathToBuiltProject + "/I2Localization";
if (!Directory.Exists(LocalizationRoot))
Directory.CreateDirectory(LocalizationRoot);
var project = new PBXProject();
string projPath = PBXProject.GetPBXProjectPath(pathToBuiltProject);
//if (!projPath.EndsWith("xcodeproj"))
//projPath = projPath.Substring(0, projPath.LastIndexOfAny("/\\".ToCharArray()));
project.ReadFromFile(projPath);
//var targetName = PBXProject.GetUnityTargetName();
//string projBuild = project.TargetGuidByName( targetName );
project.RemoveLocalizationVariantGroup("I2 Localization");
// Set the Language Overrides
foreach (var code in langCodes)
{
if (code == null || code.Length < 2)
continue;
var LanguageDirRoot = LocalizationRoot + "/" + code + ".lproj";
if (!Directory.Exists(LanguageDirRoot))
Directory.CreateDirectory(LanguageDirRoot);
var infoPlistPath = LanguageDirRoot + "/InfoPlist.strings";
var InfoPlist = string.Format("CFBundleDisplayName = \"{0}\";", LocalizationManager.GetAppName(code));
File.WriteAllText(infoPlistPath, InfoPlist);
var langProjectRoot = "I2Localization/"+code+".lproj";
var stringPaths = LanguageDirRoot + "/Localizable.strings";
File.WriteAllText(stringPaths, string.Empty);
project.AddLocalization(langProjectRoot + "/Localizable.strings", langProjectRoot + "/Localizable.strings", "I2 Localization");
project.AddLocalization(langProjectRoot + "/InfoPlist.strings", langProjectRoot + "/InfoPlist.strings", "I2 Localization");
}
project.WriteToFile(projPath);
}
catch (System.Exception e)
{
Debug.Log (e);
}
}
}
}
#endif

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 2bf71e767aaa5a245b9d74f326a39549
timeCreated: 1489354551
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,30 @@
namespace I2.Loc
{
public class PostProcessBuild_UnloadLanguages
{
// [PostProcessBuild]
// public static void SaveGlobalSources(BuildTarget buildTarget, string pathToBuiltProject)
// {
//if (LocalizationManager.Sources.Count <= 0)
// LocalizationManager.UpdateSources();
// foreach (var source in LocalizationManager.Sources.Where(x=>x.IsGlobalSource()))
// {
// source.SaveLanguages(true, PersistentStorage.eFileType.Streaming);
// }
// }
// [PostProcessScene]
// public static void SaveLocalSources()
// {
// if (EditorApplication.isPlayingOrWillChangePlaymode)
// return;
// LanguageSource[] sceneSources = (LanguageSource[])Resources.FindObjectsOfTypeAll(typeof(LanguageSource));
// foreach (var source in sceneSources.Where(x=>!x.IsGlobalSource()))
// {
// source.SaveLanguages(true, PersistentStorage.eFileType.Streaming);
// }
// }
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 68151af3db9fb734fb3823c020c9b8c0
timeCreated: 1489354551
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: d9276efd8270b104ea614946e5787aa1
folderAsset: yes
timeCreated: 1489466610
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,33 @@
fileFormatVersion: 2
guid: 6bcca352fcef3034fb01650308bf47c2
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 1
settings:
DefaultValueInitialized: true
- first:
Windows Store Apps: WindowsStoreApps
second:
enabled: 0
settings:
CPU: AnyCPU
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
This is a copy of the Xcode Manipulation API
https://bitbucket.org/Unity-Technologies/xcodeapi/overview
This is already packed inside Unity under the UnityEditor.IOS.XCode namespace,
but I'm including here as well because the version that comes with unity doesn't handle
localized files.
This copy includes the pullrequest #13 (https://bitbucket.org/Unity-Technologies/xcodeapi/pull-requests/13/creation-of-variantgroup-and/diff)
Hopefully that will be integrated in Unity soon, but until then, I will be including this files here!

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 8f2eff1a75746804db6c0240420ebed9
timeCreated: 1489466907
licenseType: Store
TextScriptImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,351 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEngine;
using Object = UnityEngine.Object;
namespace I2.Loc
{
[InitializeOnLoad]
public class UpgradeManager
{
static bool mAlreadyCheckedPlugins;
static UpgradeManager()
{
EditorApplication.update += AutoCheckPlugins;
}
public static void AutoCheckPlugins()
{
CheckPlugins ();
}
public static void CheckPlugins( bool bForce = false )
{
EditorApplication.update -= AutoCheckPlugins;
if (mAlreadyCheckedPlugins && !bForce)
return;
mAlreadyCheckedPlugins = true;
EnablePlugins(bForce);
CreateLanguageSources();
//CreateScriptLocalization();
}
const string EditorPrefs_AutoEnablePlugins = "I2Loc AutoEnablePlugins";
[MenuItem( "Tools/I2 Localization/Enable Plugins/Force Detection", false, 0 )]
public static void ForceCheckPlugins()
{
CheckPlugins( true );
}
[MenuItem( "Tools/I2 Localization/Enable Plugins/Enable Auto Detection", false, 1 )]
public static void EnableAutoCheckPlugins()
{
EditorPrefs.SetBool(EditorPrefs_AutoEnablePlugins, true);
}
[MenuItem( "Tools/I2 Localization/Enable Plugins/Enable Auto Detection", true)]
public static bool ValidEnableAutoCheckPlugins()
{
return !EditorPrefs.GetBool(EditorPrefs_AutoEnablePlugins, true);
}
[MenuItem( "Tools/I2 Localization/Enable Plugins/Disable Auto Detection", false, 2 )]
public static void DisableAutoCheckPlugins()
{
EditorPrefs.SetBool(EditorPrefs_AutoEnablePlugins, false);
}
[MenuItem( "Tools/I2 Localization/Enable Plugins/Disable Auto Detection", true)]
public static bool ValidDisableAutoCheckPlugins()
{
return EditorPrefs.GetBool(EditorPrefs_AutoEnablePlugins, true);
}
[MenuItem("Tools/I2 Localization/Toggle Highlight Localized", false, 17)]
public static void ToogleH()
{
LocalizationManager.HighlightLocalizedTargets = !LocalizationManager.HighlightLocalizedTargets;
LocalizationManager.LocalizeAll(true);
}
[MenuItem("Tools/I2 Localization/Create Temp")]
public static void CreateTemp()
{
LanguageSourceData source = LocalizationManager.Sources[0];
for (int i = 0; i < 1000; ++i)
source.AddTerm("Term " + i, eTermType.Text, false);
source.UpdateDictionary(true);
}
public static void EnablePlugins( bool bForce = false )
{
if (!bForce)
{
bool AutoEnablePlugins = EditorPrefs.GetBool(EditorPrefs_AutoEnablePlugins, true);
if (!AutoEnablePlugins)
return;
}
//var tar = System.Enum.GetValues(typeof(BuildTargetGroup));
foreach (BuildTargetGroup target in Enum.GetValues(typeof(BuildTargetGroup)))
if (target!=BuildTargetGroup.Unknown && !target.HasAttributeOfType<ObsoleteAttribute>())
{
#if UNITY_5_6
if (target == BuildTargetGroup.Switch) continue; // some releases of 5.6 defined BuildTargetGroup.Switch but didn't handled it correctly
#endif
EnablePluginsOnPlatform( target );
}
// Force these one (iPhone has the same # than iOS and iPhone is deprecated, so iOS was been skipped)
EnablePluginsOnPlatform(BuildTargetGroup.iOS);
}
static void EnablePluginsOnPlatform( BuildTargetGroup Platform )
{
string Settings = PlayerSettings.GetScriptingDefineSymbolsForGroup(Platform );
bool HasChanged = false;
List<string> symbols = new List<string>( Settings.Split(';'));
HasChanged |= UpdateSettings("NGUI", "NGUIDebug", "", ref symbols);
HasChanged |= UpdateSettings("DFGUI", "dfPanel", "", ref symbols);
HasChanged |= UpdateSettings("TK2D", "tk2dTextMesh", "", ref symbols);
HasChanged |= UpdateSettings( "TextMeshPro", "TMPro.TMP_FontAsset", "TextMeshPro", ref symbols );
HasChanged |= UpdateSettings( "SVG", "SVGImporter.SVGAsset", "", ref symbols );
if (HasChanged)
{
try
{
Settings = string.Empty;
for (int i=0,imax=symbols.Count; i<imax; ++i)
{
if (i>0) Settings += ";";
Settings += symbols[i];
}
PlayerSettings.SetScriptingDefineSymbolsForGroup(Platform, Settings );
}
catch (Exception)
{
}
}
}
static bool UpdateSettings( string mPlugin, string mType, string AssemblyType, ref List<string> symbols)
{
try
{
bool hasPluginClass = false;
if (!string.IsNullOrEmpty( AssemblyType ))
{
var rtype = AppDomain.CurrentDomain.GetAssemblies()
.Where( assembly => assembly.FullName.Contains(AssemblyType) )
.Select( assembly => assembly.GetType( mType, false ) )
.Where( t => t!=null )
.FirstOrDefault();
if (rtype != null)
hasPluginClass = true;
}
if (!hasPluginClass)
hasPluginClass = typeof( Localize ).Assembly.GetType( mType, false )!=null;
bool hasPluginDef = symbols.IndexOf(mPlugin)>=0;
if (hasPluginClass != hasPluginDef)
{
if (hasPluginClass) symbols.Add(mPlugin);
else symbols.Remove(mPlugin);
return true;
}
}
catch(Exception)
{
}
return false;
}
//[MenuItem( "Tools/I2 Localization/Create I2Languages", false, 1)]
//方便查看与源码的区别所以保留源码之前的方法
/*public static void CreateLanguageSources()
{
if (LocalizationManager.GlobalSources==null || LocalizationManager.GlobalSources.Length==0)
return;
Object GlobalSource = Resources.Load(LocalizationManager.GlobalSources[0]);
LanguageSourceData sourceData = null;
string sourcePath = null;
if (GlobalSource != null)
{
if (GlobalSource is GameObject)
{
// I2Languages was a prefab before 2018.3, it should be converted to an ScriptableObject
sourcePath = AssetDatabase.GetAssetPath(GlobalSource);
LanguageSource langSourceObj = (GlobalSource as GameObject).GetComponent<LanguageSource>();
sourceData = langSourceObj.mSource;
}
else
{
return;
}
}
LanguageSourceAsset asset = ScriptableObject.CreateInstance<LanguageSourceAsset>();
if (sourceData != null)
{
asset.mSource = sourceData;
AssetDatabase.DeleteAsset(sourcePath);
}
if (string.IsNullOrEmpty(sourcePath))
{
//string PluginPath = GetI2LocalizationPath();
string ResourcesFolder = "Assets/Resources";//PluginPath.Substring(0, PluginPath.Length-"/Localization".Length) + "/Resources";
string fullresFolder = Application.dataPath + ResourcesFolder.Replace("Assets", "");
if (!Directory.Exists(fullresFolder))
Directory.CreateDirectory(fullresFolder);
sourcePath = ResourcesFolder + "/" + LocalizationManager.GlobalSources[0] + ".asset";
}
else
{
sourcePath = sourcePath.Replace(".prefab", ".asset");
}
AssetDatabase.CreateAsset(asset, sourcePath);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}*/
[MenuItem("Tools/I2 Localization/Help", false, 30)]
[MenuItem("Help/I2 Localization")]
public static void MainHelp()
{
Application.OpenURL(LocalizeInspector.HelpURL_Documentation);
}
/*[MenuItem("Tools/I2 Localization/Open I2Languages.asset", false, 0)]
//方便查看与源码的区别所以保留源码之前的方法
public static void OpenGlobalSource()
{
CreateLanguageSources();
LanguageSourceAsset GO = Resources.Load<LanguageSourceAsset>(LocalizationManager.GlobalSources[0]);
if (GO == null)
Debug.Log("Unable to find Global Language at Assets/Resources/" + LocalizationManager.GlobalSources[0] + ".asset");
Selection.activeObject = GO;
}*/
#region
//源码必须吧资源放在resources下
//根据自己的其他需求最后规划不需要 所以自行修改
//1 全局的asset 将会放到editor下 因为只有editor才使用
//2 平台时会自行管理 根据需求动态加载
//LocalizationManager.GlobalSources 不能有数据 请设置为 {}
private const string I2GlobalSourcesEditorFolderPath = "Assets/Editor/I2Localization";
private const string I2GlobalSourcesEditorPath = "Assets/Editor/I2Localization/I2Languages.asset";
[MenuItem("Tools/I2 Localization/Open I2Languages.asset", false, 0)]
public static void OpenGlobalSource()
{
var globalSourcesAsset = CreateLanguageSources();
if (globalSourcesAsset == null)
Debug.LogError($"没有找到数据源 {I2GlobalSourcesEditorPath}");
Selection.activeObject = globalSourcesAsset;
}
private static LanguageSourceAsset CreateLanguageSources()
{
var globalSourcesAsset = AssetDatabase.LoadAssetAtPath<LanguageSourceAsset>(I2GlobalSourcesEditorPath);
if (globalSourcesAsset != null)
{
return globalSourcesAsset;
}
var asset = ScriptableObject.CreateInstance<LanguageSourceAsset>();
var assetFolder = Application.dataPath + I2GlobalSourcesEditorFolderPath.Replace("Assets", "");
if (!Directory.Exists(assetFolder))
Directory.CreateDirectory(assetFolder);
AssetDatabase.CreateAsset(asset, I2GlobalSourcesEditorPath);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
return asset;
}
#endregion
/*static void CreateScriptLocalization()
{
string[] assets = AssetDatabase.FindAssets("ScriptLocalization");
if (assets.Length>0)
return;
string ScriptsFolder = "Assets";
string ScriptText = LocalizationEditor.mScriptLocalizationHeader + " }\n}";
System.IO.File.WriteAllText(ScriptsFolder + "/ScriptLocalization.cs", ScriptText);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}*/
public static string GetI2LocalizationPath()
{
string[] assets = AssetDatabase.FindAssets("LocalizationManager");
if (assets.Length==0)
return string.Empty;
string PluginPath = AssetDatabase.GUIDToAssetPath(assets[0]);
PluginPath = PluginPath.Substring(0, PluginPath.Length - "/Scripts/LocalizationManager.cs".Length);
return PluginPath;
}
public static string GetI2Path()
{
string pluginPath = GetI2LocalizationPath();
return pluginPath.Substring(0, pluginPath.Length-"/Localization".Length);
}
public static string GetI2CommonResourcesPath()
{
string I2Path = GetI2Path();
return I2Path + "/Resources";
}
}
public static class UpgradeManagerHelper
{
public static bool HasAttributeOfType<T>(this Enum enumVal) where T:Attribute
{
var type = enumVal.GetType();
var memInfo = type.GetMember(enumVal.ToString());
var attributes = memInfo[0].GetCustomAttributes(typeof(T), false);
return attributes.Length > 0;
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 6e61480936111c54883dc051751e0a5f
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 379147f1ab5034075a5b1578456aca00
folderAsset: yes
timeCreated: 1461137613
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 8f9a3530624fd5c47a2dc16eb641ddb8
folderAsset: yes
timeCreated: 1520745251
licenseType: Store
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,286 @@
using System;
using System.Globalization;
using System.IO;
using System.Text;
using UnityEngine;
namespace I2.Loc
{
public static class PersistentStorage
{
static I2CustomPersistentStorage mStorage;
public enum eFileType { Raw, Persistent, Temporal, Streaming }
#region PlayerPrefs
public static void SetSetting_String(string key, string value)
{
if (mStorage == null) mStorage = new I2CustomPersistentStorage();
mStorage.SetSetting_String(key, value);
}
public static string GetSetting_String(string key, string defaultValue)
{
if (mStorage == null) mStorage = new I2CustomPersistentStorage();
return mStorage.GetSetting_String(key, defaultValue);
}
public static void DeleteSetting(string key)
{
if (mStorage == null) mStorage = new I2CustomPersistentStorage();
mStorage.DeleteSetting(key);
}
public static bool HasSetting( string key )
{
if (mStorage == null) mStorage = new I2CustomPersistentStorage();
return mStorage.HasSetting(key);
}
public static void ForceSaveSettings()
{
if (mStorage == null) mStorage = new I2CustomPersistentStorage();
mStorage.ForceSaveSettings();
}
#endregion
#region File Management
public static bool CanAccessFiles()
{
if (mStorage == null) mStorage = new I2CustomPersistentStorage();
return mStorage.CanAccessFiles();
}
public static bool SaveFile(eFileType fileType, string fileName, string data, bool logExceptions = true)
{
if (mStorage == null) mStorage = new I2CustomPersistentStorage();
return mStorage.SaveFile(fileType, fileName, data, logExceptions);
}
public static string LoadFile(eFileType fileType, string fileName, bool logExceptions=true)
{
if (mStorage == null) mStorage = new I2CustomPersistentStorage();
return mStorage.LoadFile(fileType, fileName, logExceptions);
}
public static bool DeleteFile(eFileType fileType, string fileName, bool logExceptions = true)
{
if (mStorage == null) mStorage = new I2CustomPersistentStorage();
return mStorage.DeleteFile(fileType, fileName, logExceptions);
}
public static bool HasFile(eFileType fileType, string fileName, bool logExceptions = true)
{
if (mStorage == null) mStorage = new I2CustomPersistentStorage();
return mStorage.HasFile(fileType, fileName, logExceptions);
}
#endregion
}
public abstract class I2BasePersistentStorage
{
#region PlayerPrefs
public virtual void SetSetting_String(string key, string value)
{
try
{
// Use PlayerPrefs, but if the data is bigger than the limit, split it into multiple entries
var len = value.Length;
int maxLength = 8000;
if (len<=maxLength)
{
PlayerPrefs.SetString(key, value);
}
else
{
int numSections = Mathf.CeilToInt(len / (float)maxLength);
for (int i=0; i<numSections; ++i)
{
int iStart = maxLength * i;
PlayerPrefs.SetString($"[I2split]{i}{key}", value.Substring(iStart, Mathf.Min(maxLength, len-iStart)));
}
PlayerPrefs.SetString(key, "[$I2#@div$]" + numSections);
}
}
catch (Exception) { Debug.LogError("Error saving PlayerPrefs " + key); }
}
public virtual string GetSetting_String(string key, string defaultValue)
{
try
{
var data = PlayerPrefs.GetString(key, defaultValue);
// Check if the data is splitted, if so, concat all the sections
if (!string.IsNullOrEmpty(data) && data.StartsWith("[I2split]", StringComparison.Ordinal))
{
int nSections = int.Parse(data.Substring("[I2split]".Length), CultureInfo.InvariantCulture);
data = "";
for (int i=0; i<nSections; ++i)
{
data += PlayerPrefs.GetString($"[I2split]{i}{key}", "");
}
}
return data;
}
catch (Exception)
{
Debug.LogError("Error loading PlayerPrefs " + key);
return defaultValue;
}
}
public virtual void DeleteSetting( string key)
{
try
{
var data = PlayerPrefs.GetString(key, null);
// If the data is splitted, delete each section as well
if (!string.IsNullOrEmpty(data) && data.StartsWith("[I2split]", StringComparison.Ordinal))
{
int nSections = int.Parse(data.Substring("[I2split]".Length), CultureInfo.InvariantCulture);
for (int i = 0; i < nSections; ++i)
{
PlayerPrefs.DeleteKey($"[I2split]{i}{key}");
}
}
PlayerPrefs.DeleteKey(key);
}
catch (Exception)
{
Debug.LogError("Error deleting PlayerPrefs " + key);
}
}
public virtual void ForceSaveSettings()
{
PlayerPrefs.Save();
}
public virtual bool HasSetting(string key)
{
return PlayerPrefs.HasKey(key);
}
#endregion
#region Files
public virtual bool CanAccessFiles()
{
#if UNITY_SWITCH || UNITY_WSA
return false;
#else
return true;
#endif
}
string UpdateFilename(PersistentStorage.eFileType fileType, string fileName)
{
switch (fileType)
{
case PersistentStorage.eFileType.Persistent: fileName = Application.persistentDataPath + "/" + fileName; break;
case PersistentStorage.eFileType.Temporal: fileName = Application.temporaryCachePath + "/" + fileName; break;
case PersistentStorage.eFileType.Streaming: fileName = Application.streamingAssetsPath + "/" + fileName; break;
}
return fileName;
}
public virtual bool SaveFile(PersistentStorage.eFileType fileType, string fileName, string data, bool logExceptions = true)
{
if (!CanAccessFiles())
return false;
try
{
fileName = UpdateFilename(fileType, fileName);
File.WriteAllText(fileName, data, Encoding.UTF8);
return true;
}
catch (Exception e)
{
if (logExceptions)
Debug.LogError("Error saving file '" + fileName + "'\n" + e);
return false;
}
}
public virtual string LoadFile(PersistentStorage.eFileType fileType, string fileName, bool logExceptions = true)
{
if (!CanAccessFiles())
return null;
try
{
fileName = UpdateFilename(fileType, fileName);
return File.ReadAllText(fileName, Encoding.UTF8);
}
catch (Exception e)
{
if (logExceptions)
Debug.LogError("Error loading file '" + fileName + "'\n" + e);
return null;
}
}
public virtual bool DeleteFile(PersistentStorage.eFileType fileType, string fileName, bool logExceptions = true)
{
if (!CanAccessFiles())
return false;
try
{
fileName = UpdateFilename(fileType, fileName);
File.Delete(fileName);
return true;
}
catch (Exception e)
{
if (logExceptions)
Debug.LogError("Error deleting file '" + fileName + "'\n" + e);
return false;
}
}
public virtual bool HasFile(PersistentStorage.eFileType fileType, string fileName, bool logExceptions = true)
{
if (!CanAccessFiles())
return false;
try
{
fileName = UpdateFilename(fileType, fileName);
return File.Exists(fileName);
}
catch (Exception e)
{
if (logExceptions) Debug.LogError("Error requesting file '" + fileName + "'\n" + e);
return false;
}
}
#endregion
}
public class I2CustomPersistentStorage : I2BasePersistentStorage
{
//public override void SetSetting_String(string key, string value)
//public override string GetSetting_String(string key, string defaultValue)
//public override void DeleteSetting(string key)
//public override void ForceSaveSettings()
//public override bool HasSetting(string key)
//public virtual bool CanAccessFiles();
//public override bool SaveFile(PersistentStorage.eFileType fileType, string fileName, string data, bool logExceptions = true);
//public override string LoadFile(PersistentStorage.eFileType fileType, string fileName, bool logExceptions = true);
//public override bool DeleteFile(PersistentStorage.eFileType fileType, string fileName, bool logExceptions = true);
//public override bool HasFile(PersistentStorage.eFileType fileType, string fileName, bool logExceptions = true);
}
}

View File

@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: ec5b9e0d683ff2b409340ac814051bb8
timeCreated: 1507704861
licenseType: Store
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,188 @@
using System;
using System.Collections.Generic;
namespace I2.Loc
{
public class BaseSpecializationManager
{
public string[] mSpecializations;
public Dictionary<string, string> mSpecializationsFallbacks;
public virtual void InitializeSpecializations()
{
mSpecializations = new[] { "Any", "PC", "Touch", "Controller", "VR",
"XBox", "PS4", "OculusVR", "ViveVR", "GearVR", "Android", "IOS" };
mSpecializationsFallbacks = new Dictionary<string, string>(System.StringComparer.Ordinal)
{
{ "XBox", "Controller" }, { "PS4", "Controller" },
{ "OculusVR", "VR" }, { "ViveVR", "VR" }, { "GearVR", "VR" },
{ "Android", "Touch" }, { "IOS", "Touch" }
};
}
public virtual string GetCurrentSpecialization()
{
if (mSpecializations == null)
InitializeSpecializations();
#if UNITY_ANDROID
return "Android";
#elif UNITY_IOS
return "IOS";
#elif UNITY_PS4
return "PS4";
#elif UNITY_XBOXONE
return "XBox";
#elif UNITY_STANDALONE || UNITY_WEBGL
return "PC";
#else
return (Input.touchSupported ? "Touch" : "PC");
#endif
}
public virtual string GetFallbackSpecialization(string specialization)
{
if (mSpecializationsFallbacks == null)
InitializeSpecializations();
string fallback;
if (mSpecializationsFallbacks.TryGetValue(specialization, out fallback))
return fallback;
return "Any";
}
}
public class SpecializationManager : BaseSpecializationManager
{
public static SpecializationManager Singleton = new SpecializationManager();
private SpecializationManager()
{
InitializeSpecializations();
}
public static string GetSpecializedText(string text, string specialization = null)
{
var idxFirst = text.IndexOf("[i2s_", StringComparison.Ordinal);
if (idxFirst < 0)
return text;
if (string.IsNullOrEmpty(specialization))
specialization = Singleton.GetCurrentSpecialization();
while (!string.IsNullOrEmpty(specialization) && specialization != "Any")
{
var tag = "[i2s_" + specialization + "]";
int idx = text.IndexOf(tag, StringComparison.Ordinal);
if (idx < 0)
{
specialization = Singleton.GetFallbackSpecialization(specialization);
continue;
}
idx += tag.Length;
var idxEnd = text.IndexOf("[i2s_", idx, StringComparison.Ordinal);
if (idxEnd < 0) idxEnd = text.Length;
return text.Substring(idx, idxEnd - idx);
}
return text.Substring(0, idxFirst);
}
public static string SetSpecializedText(string text, string newText, string specialization)
{
if (string.IsNullOrEmpty(specialization))
specialization = "Any";
if ((text==null || !text.Contains("[i2s_")) && specialization=="Any")
{
return newText;
}
var dict = GetSpecializations(text);
dict[specialization] = newText;
return SetSpecializedText(dict);
}
public static string SetSpecializedText( Dictionary<string,string> specializations )
{
string text;
if (!specializations.TryGetValue("Any", out text))
text = string.Empty;
foreach (var kvp in specializations)
{
if (kvp.Key != "Any" && !string.IsNullOrEmpty(kvp.Value))
text += "[i2s_" + kvp.Key + "]" + kvp.Value;
}
return text;
}
public static Dictionary<string, string> GetSpecializations(string text, Dictionary<string, string> buffer = null)
{
if (buffer == null)
buffer = new Dictionary<string, string>(StringComparer.Ordinal);
else
buffer.Clear();
if (text==null)
{
buffer["Any"] = "";
return buffer;
}
var idxFirst = 0;
var idxEnd = text.IndexOf("[i2s_", StringComparison.Ordinal);
if (idxEnd < 0)
idxEnd=text.Length;
buffer["Any"] = text.Substring(0, idxEnd);
idxFirst = idxEnd;
while (idxFirst<text.Length)
{
idxFirst += "[i2s_".Length;
int idx = text.IndexOf(']', idxFirst);
if (idx < 0) break;
var tag = text.Substring(idxFirst, idx - idxFirst);
idxFirst = idx+1; // ']'
idxEnd = text.IndexOf("[i2s_", idxFirst, StringComparison.Ordinal);
if (idxEnd < 0) idxEnd = text.Length;
var value = text.Substring(idxFirst, idxEnd - idxFirst);
buffer[tag] = value;
idxFirst = idxEnd;
}
return buffer;
}
public static void AppendSpecializations(string text, List<string> list=null)
{
if (text == null)
return;
if (list == null)
list = new List<string>();
if (!list.Contains("Any"))
list.Add("Any");
var idxFirst = 0;
while (idxFirst<text.Length)
{
idxFirst = text.IndexOf("[i2s_", idxFirst, StringComparison.Ordinal);
if (idxFirst < 0)
break;
idxFirst += "[i2s_".Length;
int idx = text.IndexOf(']', idxFirst);
if (idx < 0)
break;
var tag = text.Substring(idxFirst, idx - idxFirst);
if (!list.Contains(tag))
list.Add(tag);
}
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: a72e5d6dba43bf249987cd37521e38bb
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,24 @@
using System;
using UnityEngine;
using Object = UnityEngine.Object;
namespace I2.Loc
{
[Serializable]
public class EventCallback
{
public MonoBehaviour Target;
public string MethodName = string.Empty;
public void Execute( Object Sender = null )
{
if (HasCallback() && Application.isPlaying)
Target.gameObject.SendMessage(MethodName, Sender, SendMessageOptions.DontRequireReceiver);
}
public bool HasCallback()
{
return Target != null && !string.IsNullOrEmpty (MethodName);
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 79fbe85a671c1254880b1fc083a723e5
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: dda5008126b59ad4bad4c9d2626a2345
folderAsset: yes
timeCreated: 1461137613
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,648 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace I2.Loc
{
public enum ePluralType { Zero, One, Two, Few, Many, Plural }
public static class GoogleLanguages
{
public static string GetLanguageCode(string Filter, bool ShowWarnings = false)
{
if (string.IsNullOrEmpty(Filter))
return string.Empty;
string[] Filters = Filter.ToLowerInvariant().Split(" /(),".ToCharArray());
foreach (var kvp in mLanguageDef)
if (LanguageMatchesFilter(kvp.Key, Filters))
return kvp.Value.Code;
if (ShowWarnings)
Debug.Log($"Language '{Filter}' not recognized. Please, add the language code to GoogleTranslation.cs");
return string.Empty;
}
public static List<string> GetLanguagesForDropdown(string Filter, string CodesToExclude)
{
string[] Filters = Filter.ToLowerInvariant().Split(" /(),".ToCharArray());
List<string> Languages = new List<string>();
foreach (var kvp in mLanguageDef)
if (string.IsNullOrEmpty(Filter) || LanguageMatchesFilter(kvp.Key, Filters))
{
string code = string.Concat("[" + kvp.Value.Code + "]");
if (!CodesToExclude.Contains(code))
Languages.Add(kvp.Key + " " + code);
}
// Add headers to variants (e.g. "English/English" before all English variants
for (int i = Languages.Count - 2; i >= 0; --i)
{
string Prefix = Languages[i].Substring(0, Languages[i].IndexOf(" ["));
if (Languages[i + 1].StartsWith(Prefix, StringComparison.Ordinal))
{
Languages[i] = Prefix + "/" + Languages[i];
Languages.Insert(i + 1, Prefix + "/");
}
}
return Languages;
}
// "Engl Unit" matches "English/United States"
static bool LanguageMatchesFilter(string Language, string[] Filters)
{
Language = Language.ToLowerInvariant();
for (int i = 0, imax = Filters.Length; i < imax; ++i)
if (Filters[i] != "")
{
if (!Language.Contains(Filters[i].ToLower()))
return false;
Language = Language.Remove(Language.IndexOf(Filters[i], StringComparison.Ordinal), Filters[i].Length);
}
return true;
}
// "Arabic/Algeria [ar-XX]" returns "Arabic (Algeria)"
// "English/English [en]" returns "English"
public static string GetFormatedLanguageName(string Language)
{
string BaseLanguage = string.Empty;
//-- Remove code --------
int Index = Language.IndexOf(" [", StringComparison.Ordinal);
if (Index > 0)
Language = Language.Substring(0, Index);
//-- Check for main language: "English/English [en]" returns "English" -----------
Index = Language.IndexOf('/');
if (Index > 0)
{
BaseLanguage = Language.Substring(0, Index);
if (Language == BaseLanguage + "/" + BaseLanguage)
return BaseLanguage;
//-- Convert variants into right format
Language = Language.Replace("/", " (") + ")";
}
return Language;
}
// English British -> "English Canada [en-CA]"
public static string GetCodedLanguage(string Language, string code)
{
string DefaultCode = GetLanguageCode(Language);
if (string.Compare(code, DefaultCode, StringComparison.OrdinalIgnoreCase) == 0)
return Language;
return string.Concat(Language, " [", code, "]");
}
// "English Canada [en-CA]" -> "English Canada", "en-CA"
public static void UnPackCodeFromLanguageName(string CodedLanguage, out string Language, out string code)
{
if (string.IsNullOrEmpty(CodedLanguage))
{
Language = string.Empty;
code = string.Empty;
return;
}
int Index = CodedLanguage.IndexOf("[", StringComparison.Ordinal);
if (Index < 0)
{
Language = CodedLanguage;
code = GetLanguageCode(Language);
}
else
{
Language = CodedLanguage.Substring(0, Index).Trim();
code = CodedLanguage.Substring(Index + 1, CodedLanguage.IndexOf("]", Index, StringComparison.Ordinal) - Index - 1);
}
}
public static string GetGoogleLanguageCode(string InternationalCode)
{
foreach (var kvp in mLanguageDef)
if (InternationalCode == kvp.Value.Code)
{
if (kvp.Value.GoogleCode == "-")
return null;
return !string.IsNullOrEmpty(kvp.Value.GoogleCode) ? kvp.Value.GoogleCode : InternationalCode;
}
return InternationalCode;
}
public static string GetLanguageName(string code, bool useParenthesesForRegion=false, bool allowDiscardRegion=true)
{
foreach (var kvp in mLanguageDef)
if (code == kvp.Value.Code)
{
var langName = kvp.Key;
if (useParenthesesForRegion)
{
int idx = langName.IndexOf('/');
if (idx > 0)
langName = langName.Substring(0, idx) + " (" + langName.Substring(idx + 1) + ")";
}
return langName;
}
if (allowDiscardRegion)
{
int iCode = code.IndexOf("-", StringComparison.Ordinal);
if (iCode > 0)
return GetLanguageName(code.Substring(0,iCode), useParenthesesForRegion, false);
}
return null;
}
public static List<string> GetAllInternationalCodes()
{
var set = new HashSet<string>(StringComparer.Ordinal);
foreach (var kvp in mLanguageDef)
set.Add(kvp.Value.Code);
return new List<string>(set);
}
public static bool LanguageCode_HasJoinedWord(string languageCode)
{
foreach (var kvp in mLanguageDef)
if (languageCode == kvp.Value.GoogleCode || languageCode==kvp.Value.Code )
return kvp.Value.HasJoinedWords;
return false;
}
public struct LanguageCodeDef
{
public string Code; // Language International Code
public string GoogleCode; // Google Translator doesn't support all languages, this is the code of closest supported language
public bool HasJoinedWords; // Some languages (e.g. Chinese, Japanese and Thai) don't add spaces to their words (all characters are placed toguether)
public int PluralRule;
}
public static Dictionary<string, LanguageCodeDef> mLanguageDef = new Dictionary<string, LanguageCodeDef>(StringComparer.Ordinal)
{
/**/{"Abkhazian", new LanguageCodeDef {PluralRule=1, Code="ab", GoogleCode="-"}},
/**/{"Afar", new LanguageCodeDef {PluralRule=1, Code="aa", GoogleCode="-"}},
{"Afrikaans", new LanguageCodeDef {PluralRule=1, Code="af"}},
/**/{"Akan", new LanguageCodeDef {PluralRule=1, Code="ak", GoogleCode="-"}},
{"Albanian", new LanguageCodeDef {PluralRule=1, Code="sq"}},
/**/{"Amharic", new LanguageCodeDef {PluralRule=1, Code="am"}},
{"Arabic", new LanguageCodeDef {PluralRule=11, Code="ar"}},
{"Arabic/Algeria", new LanguageCodeDef {PluralRule=11, Code="ar-DZ", GoogleCode="ar"}},
{"Arabic/Bahrain", new LanguageCodeDef {PluralRule=11, Code="ar-BH", GoogleCode="ar"}},
{"Arabic/Egypt", new LanguageCodeDef {PluralRule=11, Code="ar-EG", GoogleCode="ar"}},
{"Arabic/Iraq", new LanguageCodeDef {PluralRule=11, Code="ar-IQ", GoogleCode="ar"}},
{"Arabic/Jordan", new LanguageCodeDef {PluralRule=11, Code="ar-JO", GoogleCode="ar"}},
{"Arabic/Kuwait", new LanguageCodeDef {PluralRule=11, Code="ar-KW", GoogleCode="ar"}},
{"Arabic/Lebanon", new LanguageCodeDef {PluralRule=11, Code="ar-LB", GoogleCode="ar"}},
{"Arabic/Libya", new LanguageCodeDef {PluralRule=11, Code="ar-LY", GoogleCode="ar"}},
{"Arabic/Morocco", new LanguageCodeDef {PluralRule=11, Code="ar-MA", GoogleCode="ar"}},
{"Arabic/Oman", new LanguageCodeDef {PluralRule=11, Code="ar-OM", GoogleCode="ar"}},
{"Arabic/Qatar", new LanguageCodeDef {PluralRule=11, Code="ar-QA", GoogleCode="ar"}},
{"Arabic/Saudi Arabia", new LanguageCodeDef {PluralRule=11, Code="ar-SA", GoogleCode="ar"}},
{"Arabic/Syria", new LanguageCodeDef {PluralRule=11, Code="ar-SY", GoogleCode="ar"}},
{"Arabic/Tunisia", new LanguageCodeDef {PluralRule=11, Code="ar-TN", GoogleCode="ar"}},
{"Arabic/U.A.E.", new LanguageCodeDef {PluralRule=11, Code="ar-AE", GoogleCode="ar"}},
{"Arabic/Yemen", new LanguageCodeDef {PluralRule=11, Code="ar-YE", GoogleCode="ar"}},
/**/{"Aragonese", new LanguageCodeDef {PluralRule=1, Code="an", GoogleCode="-"}},
{"Armenian", new LanguageCodeDef {PluralRule=1, Code="hy"}},
/**/{"Assamese", new LanguageCodeDef {PluralRule=1, Code="as", GoogleCode="-"}},
/**/{"Avaric", new LanguageCodeDef {PluralRule=1, Code="av", GoogleCode="-"}},
/**/{"Avestan", new LanguageCodeDef {PluralRule=1, Code="ae", GoogleCode="-"}},
/**/{"Aymara", new LanguageCodeDef {PluralRule=1, Code="ay", GoogleCode="-"}},
{"Azerbaijani", new LanguageCodeDef {PluralRule=1, Code="az"}},
/**/{"Bambara", new LanguageCodeDef {PluralRule=1, Code="bm", GoogleCode="-"}},
/**/{"Bashkir", new LanguageCodeDef {PluralRule=1, Code="ba", GoogleCode="-"}},
{"Basque", new LanguageCodeDef {PluralRule=1, Code="eu"}},
{"Basque/Spain", new LanguageCodeDef {PluralRule=1, Code="eu-ES", GoogleCode="eu"}},
{"Belarusian", new LanguageCodeDef {PluralRule=6, Code="be"}},
/**/{"Bengali", new LanguageCodeDef {PluralRule=1, Code="bn"}},
/**/{"Bihari", new LanguageCodeDef {PluralRule=1, Code="bh", GoogleCode="-"}},
/**/{"Bislama", new LanguageCodeDef {PluralRule=1, Code="bi", GoogleCode="-"}},
{"Bosnian", new LanguageCodeDef {PluralRule=6, Code="bs"}},
/**/{"Breton", new LanguageCodeDef {PluralRule=1, Code="br", GoogleCode="-"}},
{"Bulgariaa", new LanguageCodeDef {PluralRule=1, Code="bg"}},
/**/{"Burmese", new LanguageCodeDef {PluralRule=1, Code="my"}},
{"Catalan", new LanguageCodeDef {PluralRule=1, Code="ca"}},
/**/{"Chamorro", new LanguageCodeDef {PluralRule=1, Code="ch", GoogleCode="-"}},
/**/{"Chechen", new LanguageCodeDef {PluralRule=1, Code="ce", GoogleCode="-"}},
/**/{"Chichewa", new LanguageCodeDef {PluralRule=1, Code="ny"}},
{"Chinese", new LanguageCodeDef {PluralRule=0, Code="zh", GoogleCode="zh-CN", HasJoinedWords=true}},
{"Chinese/Hong Kong", new LanguageCodeDef {PluralRule=0, Code="zh-HK", GoogleCode="zh-TW", HasJoinedWords=true}},
{"Chinese/Macau", new LanguageCodeDef {PluralRule=0, Code="zh-MO", GoogleCode="zh-CN", HasJoinedWords=true}},
{"Chinese/PRC", new LanguageCodeDef {PluralRule=0, Code="zh-CN", GoogleCode="zh-CN", HasJoinedWords=true}},
{"Chinese/Simplified", new LanguageCodeDef {PluralRule=0, Code="zh-CN", GoogleCode="zh-CN", HasJoinedWords=true}},
{"Chinese/Singapore", new LanguageCodeDef {PluralRule=0, Code="zh-SG", GoogleCode="zh-CN", HasJoinedWords=true}},
{"Chinese/Taiwan", new LanguageCodeDef {PluralRule=0, Code="zh-TW", GoogleCode="zh-TW", HasJoinedWords=true}},
{"Chinese/Traditional", new LanguageCodeDef {PluralRule=0, Code="zh-TW", GoogleCode="zh-TW", HasJoinedWords=true}},
/**/{"Chuvash", new LanguageCodeDef {PluralRule=1, Code="cv", GoogleCode="-"}},
/**/{"Cornish", new LanguageCodeDef {PluralRule=1, Code="kw", GoogleCode="-"}}, // Check plural
/**/{"Corsican", new LanguageCodeDef {PluralRule=1, Code="co"}},
/**/{"Cree", new LanguageCodeDef {PluralRule=1, Code="cr", GoogleCode="-"}},
{"Croatian", new LanguageCodeDef {PluralRule=6, Code="hr"}},
{"Croatian/Bosnia and Herzegovina", new LanguageCodeDef {PluralRule=5, Code="hr-BA", GoogleCode="hr"}},
{"Czech", new LanguageCodeDef {PluralRule=7, Code="cs"}},
{"Danish", new LanguageCodeDef {PluralRule=1, Code="da"}},
/**/{"Divehi", new LanguageCodeDef {PluralRule=1, Code="dv", GoogleCode="-"}},
{"Dutch", new LanguageCodeDef {PluralRule=1, Code="nl"}},
{"Dutch/Belgium", new LanguageCodeDef {PluralRule=1, Code="nl-BE", GoogleCode="nl"}},
{"Dutch/Netherlands", new LanguageCodeDef {PluralRule=1, Code="nl-NL", GoogleCode="nl"}},
/**/{"Dzongkha", new LanguageCodeDef {PluralRule=1, Code="dz", GoogleCode="-"}},
{"English", new LanguageCodeDef {PluralRule=1, Code="en"}},
{"English/Australia", new LanguageCodeDef {PluralRule=1, Code="en-AU", GoogleCode="en"}},
{"English/Belize", new LanguageCodeDef {PluralRule=1, Code="en-BZ", GoogleCode="en"}},
{"English/Canada", new LanguageCodeDef {PluralRule=1, Code="en-CA", GoogleCode="en"}},
{"English/Caribbean", new LanguageCodeDef {PluralRule=1, Code="en-CB", GoogleCode="en"}},
{"English/Ireland", new LanguageCodeDef {PluralRule=1, Code="en-IE", GoogleCode="en"}},
{"English/Jamaica", new LanguageCodeDef {PluralRule=1, Code="en-JM", GoogleCode="en"}},
{"English/New Zealand", new LanguageCodeDef {PluralRule=1, Code="en-NZ", GoogleCode="en"}},
{"English/Republic of the Philippines", new LanguageCodeDef {PluralRule=1, Code="en-PH", GoogleCode="en"}},
{"English/South Africa",new LanguageCodeDef {PluralRule=1, Code="en-ZA", GoogleCode="en"}},
{"English/Trinidad", new LanguageCodeDef {PluralRule=1, Code="en-TT", GoogleCode="en"}},
{"English/United Kingdom",new LanguageCodeDef {PluralRule=1, Code="en-GB", GoogleCode="en"}},
{"English/United States",new LanguageCodeDef {PluralRule=1, Code="en-US", GoogleCode="en"}},
{"English/Zimbabwe", new LanguageCodeDef {PluralRule=1, Code="en-ZW", GoogleCode="en"}},
{"Esperanto", new LanguageCodeDef {PluralRule=1, Code="eo"}},
{"Estonian", new LanguageCodeDef {PluralRule=1, Code="et"}},
/**/{"Ewe", new LanguageCodeDef {PluralRule=1, Code="ee", GoogleCode="-"}},
{"Faeroese", new LanguageCodeDef {PluralRule=1, Code="fo", GoogleCode="-"}},
/**/{"Fijian", new LanguageCodeDef {PluralRule=1, Code="fj", GoogleCode="-"}},
//{"Filipino", new LanguageCodeDef(){PluralRule=2, Code="tl"}},
{"Finnish", new LanguageCodeDef {PluralRule=1, Code="fi"}},
{"French", new LanguageCodeDef {PluralRule=2, Code="fr"}},
{"French/Belgium", new LanguageCodeDef {PluralRule=2, Code="fr-BE", GoogleCode="fr"}},
{"French/Canada", new LanguageCodeDef {PluralRule=2, Code="fr-CA", GoogleCode="fr"}},
{"French/France", new LanguageCodeDef {PluralRule=2, Code="fr-FR", GoogleCode="fr"}},
{"French/Luxembourg", new LanguageCodeDef {PluralRule=2, Code="fr-LU", GoogleCode="fr"}},
{"French/Principality of Monaco", new LanguageCodeDef {PluralRule=2, Code="fr-MC", GoogleCode="fr"}},
{"French/Switzerland", new LanguageCodeDef {PluralRule=2, Code="fr-CH", GoogleCode="fr"}},
/**/{"Fulah", new LanguageCodeDef {PluralRule=1, Code="ff", GoogleCode="-"}},
{"Galician", new LanguageCodeDef {PluralRule=1, Code="gl"}},
{"Galician/Spain", new LanguageCodeDef {PluralRule=1, Code="gl-ES", GoogleCode="gl"}},
{"Georgian", new LanguageCodeDef {PluralRule=0, Code="ka"}},
{"German", new LanguageCodeDef {PluralRule=1, Code="de"}},
{"German/Austria", new LanguageCodeDef {PluralRule=1, Code="de-AT", GoogleCode="de"}},
{"German/Germany", new LanguageCodeDef {PluralRule=1, Code="de-DE", GoogleCode="de"}},
{"German/Liechtenstein",new LanguageCodeDef {PluralRule=1, Code="de-LI", GoogleCode="de"}},
{"German/Luxembourg", new LanguageCodeDef {PluralRule=1, Code="de-LU", GoogleCode="de"}},
{"German/Switzerland", new LanguageCodeDef {PluralRule=1, Code="de-CH", GoogleCode="de"}},
{"Greek", new LanguageCodeDef {PluralRule=1, Code="el"}},
/**/{"Guaraní", new LanguageCodeDef {PluralRule=1, Code="gn", GoogleCode="-"}},
{"Gujarati", new LanguageCodeDef {PluralRule=1, Code="gu"}},
/**/{"Haitian", new LanguageCodeDef {PluralRule=1, Code="ht"}},
/**/{"Hausa", new LanguageCodeDef {PluralRule=1, Code="ha"}},
{"Hebrew", new LanguageCodeDef {PluralRule=1, Code="he", GoogleCode="iw"}},
/**/{"Herero", new LanguageCodeDef {PluralRule=1, Code="hz", GoogleCode="-"}},
{"Hindi", new LanguageCodeDef {PluralRule=1, Code="hi"}},
/**/{"Hiri Motu", new LanguageCodeDef {PluralRule=1, Code="ho", GoogleCode="-"}},
{"Hungarian", new LanguageCodeDef {PluralRule=1, Code="hu"}},
/**/{"Interlingua", new LanguageCodeDef {PluralRule=1, Code="ia", GoogleCode="-"}},
{"Indonesian", new LanguageCodeDef {PluralRule=0, Code="id"}},
/**/{"Interlingue", new LanguageCodeDef {PluralRule=1, Code="ie", GoogleCode="-"}},
{"Irish", new LanguageCodeDef {PluralRule=10, Code="ga"}},
/**/{"Igbo", new LanguageCodeDef {PluralRule=1, Code="ig"}},
/**/{"Inupiaq", new LanguageCodeDef {PluralRule=1, Code="ik", GoogleCode="-"}},
/**/{"Ido", new LanguageCodeDef {PluralRule=1, Code="io", GoogleCode="-"}},
{"Icelandic", new LanguageCodeDef {PluralRule=14, Code="is"}},
{"Italian", new LanguageCodeDef {PluralRule=1, Code="it"}},
{"Italian/Italy", new LanguageCodeDef {PluralRule=1, Code="it-IT", GoogleCode="it"}},
{"Italian/Switzerland", new LanguageCodeDef {PluralRule=1, Code="it-CH", GoogleCode="it"}},
/**/{"Inuktitut", new LanguageCodeDef {PluralRule=1, Code="iu", GoogleCode="-"}},
{"Japanese", new LanguageCodeDef {PluralRule=0, Code="ja", HasJoinedWords=true}},
/**/{"Javanese", new LanguageCodeDef {PluralRule=1, Code="jv"}},
/**/{"Kalaallisut", new LanguageCodeDef {PluralRule=1, Code="kl", GoogleCode="-"}},
{"Kannada", new LanguageCodeDef {PluralRule=1, Code="kn"}},
/**/{"Kanuri", new LanguageCodeDef {PluralRule=1, Code="kr", GoogleCode="-"}},
/**/{"Kashmiri", new LanguageCodeDef {PluralRule=1, Code="ks", GoogleCode="-"}},
{"Kazakh", new LanguageCodeDef {PluralRule=1, Code="kk"}},
/**/{"Central Khmer", new LanguageCodeDef {PluralRule=1, Code="km"}},
/**/{"Kikuyu", new LanguageCodeDef {PluralRule=1, Code="ki", GoogleCode="-"}},
/**/{"Kinyarwanda", new LanguageCodeDef {PluralRule=1, Code="rw", GoogleCode="-"}},
/**/{"Kirghiz", new LanguageCodeDef {PluralRule=1, Code="ky"}},
/**/{"Komi", new LanguageCodeDef {PluralRule=1, Code="kv", GoogleCode="-"}},
/**/{"Kongo", new LanguageCodeDef {PluralRule=1, Code="kg", GoogleCode="-"}},
{"Korean", new LanguageCodeDef {PluralRule=0, Code="ko"}},
{"Kurdish", new LanguageCodeDef {PluralRule=1, Code="ku"}},
/**/{"Kuanyama", new LanguageCodeDef {PluralRule=1, Code="kj", GoogleCode="-"}},
{"Latin", new LanguageCodeDef {PluralRule=1, Code="la"}},
/**/{"Luxembourgish", new LanguageCodeDef {PluralRule=1, Code="lb"}},
/**/{"Ganda", new LanguageCodeDef {PluralRule=1, Code="lg", GoogleCode="-"}},
/**/{"Limburgan", new LanguageCodeDef {PluralRule=1, Code="li", GoogleCode="-"}},
/**/{"Lingala", new LanguageCodeDef {PluralRule=1, Code="ln", GoogleCode="-"}},
/**/{"Lao", new LanguageCodeDef {PluralRule=1, Code="lo"}},
{"Latvian", new LanguageCodeDef {PluralRule=5, Code="lv"}},
/**/{"Luba-Katanga", new LanguageCodeDef {PluralRule=1, Code="lu", GoogleCode="-"}},
{"Lithuanian", new LanguageCodeDef {PluralRule=5, Code="lt"}},
/**/{"Manx", new LanguageCodeDef {PluralRule=1, Code="gv", GoogleCode="-"}},
{"Macedonian", new LanguageCodeDef {PluralRule=13, Code="mk"}},
/**/{"Malagasy", new LanguageCodeDef {PluralRule=1, Code="mg"}},
{"Malay", new LanguageCodeDef {PluralRule=0, Code="ms"}},
{"Malay/Brunei Darussalam", new LanguageCodeDef {PluralRule=0, Code="ms-BN", GoogleCode="ms"}},
{"Malay/Malaysia", new LanguageCodeDef {PluralRule=0, Code="ms-MY", GoogleCode="ms"}},
{"Malayalam", new LanguageCodeDef {PluralRule=1, Code="ml"}},
{"Maltese", new LanguageCodeDef {PluralRule=12, Code="mt"}},
{"Maori", new LanguageCodeDef {PluralRule=2, Code="mi"}},
{"Marathi", new LanguageCodeDef {PluralRule=1, Code="mr"}},
/**/{"Marshallese", new LanguageCodeDef {PluralRule=1, Code="mh", GoogleCode="-"}},
{"Mongolian", new LanguageCodeDef {PluralRule=1, Code="mn"}},
/**/{"Nauru", new LanguageCodeDef {PluralRule=1, Code="na", GoogleCode="-"}},
/**/{"Navajo", new LanguageCodeDef {PluralRule=1, Code="nv", GoogleCode="-"}},
/**/{"North Ndebele", new LanguageCodeDef {PluralRule=1, Code="nd", GoogleCode="-"}},
/**/{"Nepali", new LanguageCodeDef {PluralRule=1, Code="ne"}},
/**/{"Ndonga", new LanguageCodeDef {PluralRule=1, Code="ng", GoogleCode="-"}},
{"Northern Sotho", new LanguageCodeDef {PluralRule=1, Code="ns", GoogleCode="st"}},
{"Norwegian", new LanguageCodeDef {PluralRule=1, Code="nb", GoogleCode="no"}},
{"Norwegian/Nynorsk", new LanguageCodeDef {PluralRule=1, Code="nn", GoogleCode="no"}},
/**/{"Sichuan Yi", new LanguageCodeDef {PluralRule=1, Code="ii", GoogleCode="-"}},
/**/{"South Ndebele", new LanguageCodeDef {PluralRule=1, Code="nr", GoogleCode="-"}},
/**/{"Occitan", new LanguageCodeDef {PluralRule=1, Code="oc", GoogleCode="-"}},
/**/{"Ojibwa", new LanguageCodeDef {PluralRule=1, Code="oj", GoogleCode="-"}},
/**/{"Church Slavic", new LanguageCodeDef {PluralRule=1, Code="cu", GoogleCode="-"}},
/**/{"Oromo", new LanguageCodeDef {PluralRule=1, Code="om", GoogleCode="-"}},
/**/{"Oriya", new LanguageCodeDef {PluralRule=1, Code="or", GoogleCode="-"}},
/**/{"Ossetian", new LanguageCodeDef {PluralRule=1, Code="os", GoogleCode="-"}},
/**/{"Pali", new LanguageCodeDef {PluralRule=1, Code="pi", GoogleCode="-"}},
{"Pashto", new LanguageCodeDef {PluralRule=1, Code="ps"}},
{"Persian", new LanguageCodeDef {PluralRule=0, Code="fa"}},
{"Polish", new LanguageCodeDef {PluralRule=8, Code="pl"}},
{"Portuguese", new LanguageCodeDef {PluralRule=1, Code="pt"}},
{"Portuguese/Brazil", new LanguageCodeDef {PluralRule=2, Code="pt-BR", GoogleCode="pt"}},
{"Portuguese/Portugal", new LanguageCodeDef {PluralRule=1, Code="pt-PT", GoogleCode="pt"}},
{"Punjabi", new LanguageCodeDef {PluralRule=1, Code="pa"}},
{"Quechua", new LanguageCodeDef {PluralRule=1, Code="qu", GoogleCode="-"}},
{"Quechua/Bolivia", new LanguageCodeDef {PluralRule=1, Code="qu-BO", GoogleCode="-"}},
{"Quechua/Ecuador", new LanguageCodeDef {PluralRule=1, Code="qu-EC", GoogleCode="-"}},
{"Quechua/Peru", new LanguageCodeDef {PluralRule=1, Code="qu-PE", GoogleCode="-"}},
{"Rhaeto-Romanic", new LanguageCodeDef {PluralRule=1, Code="rm", GoogleCode="ro"}},
{"Romanian", new LanguageCodeDef {PluralRule=4, Code="ro"}},
/**/{"Rundi", new LanguageCodeDef {PluralRule=1, Code="rn", GoogleCode="-"}},
{"Russian", new LanguageCodeDef {PluralRule=6, Code="ru"}},
{"Russian/Republic of Moldova", new LanguageCodeDef {PluralRule=6, Code="ru-MO", GoogleCode="ru"}},
/**/{"Sanskrit", new LanguageCodeDef {PluralRule=1, Code="sa", GoogleCode="-"}},
/**/{"Sardinian", new LanguageCodeDef {PluralRule=1, Code="sc", GoogleCode="-"}},
/**/{"Sindhi", new LanguageCodeDef {PluralRule=1, Code="sd"}},
/**/{"Northern Sami", new LanguageCodeDef {PluralRule=1, Code="se", GoogleCode="-"}},
/**/{"Samoan", new LanguageCodeDef {PluralRule=1, Code="sm"}},
/**/{"Sango", new LanguageCodeDef {PluralRule=1, Code="sg", GoogleCode="-"}},
{"Serbian", new LanguageCodeDef {PluralRule=6, Code="sr"}},
{"Serbian/Bosnia and Herzegovina", new LanguageCodeDef {PluralRule=5, Code="sr-BA", GoogleCode="sr"}},
{"Serbian/Serbia and Montenegro", new LanguageCodeDef {PluralRule=5, Code="sr-SP", GoogleCode="sr"}},
/**/{"Scottish Gaelic", new LanguageCodeDef {PluralRule=1, Code="gd"}},
/**/{"Shona", new LanguageCodeDef {PluralRule=1, Code="sn"}},
/**/{"Sinhala", new LanguageCodeDef {PluralRule=1, Code="si"}},
{"Slovak", new LanguageCodeDef {PluralRule=7, Code="sk"}},
{"Slovenian", new LanguageCodeDef {PluralRule=9, Code="sl"}},
/**/{"Somali", new LanguageCodeDef {PluralRule=1, Code="so"}},
/**/{"Southern Sotho", new LanguageCodeDef {PluralRule=1, Code="st"}},
{"Spanish", new LanguageCodeDef {PluralRule=1, Code="es"}},
{"Spanish/Argentina", new LanguageCodeDef {PluralRule=1, Code="es-AR", GoogleCode="es"}},
{"Spanish/Bolivia", new LanguageCodeDef {PluralRule=1, Code="es-BO", GoogleCode="es"}},
{"Spanish/Castilian", new LanguageCodeDef {PluralRule=1, Code="es-ES", GoogleCode="es"}},
{"Spanish/Chile", new LanguageCodeDef {PluralRule=1, Code="es-CL", GoogleCode="es"}},
{"Spanish/Colombia", new LanguageCodeDef {PluralRule=1, Code="es-CO", GoogleCode="es"}},
{"Spanish/Costa Rica", new LanguageCodeDef {PluralRule=1, Code="es-CR", GoogleCode="es"}},
{"Spanish/Dominican Republic", new LanguageCodeDef {PluralRule=1, Code="es-DO", GoogleCode="es"}},
{"Spanish/Ecuador", new LanguageCodeDef {PluralRule=1, Code="es-EC", GoogleCode="es"}},
{"Spanish/El Salvador", new LanguageCodeDef {PluralRule=1, Code="es-SV", GoogleCode="es"}},
{"Spanish/Guatemala", new LanguageCodeDef {PluralRule=1, Code="es-GT", GoogleCode="es"}},
{"Spanish/Honduras", new LanguageCodeDef {PluralRule=1, Code="es-HN", GoogleCode="es"}},
{"Spanish/Mexico", new LanguageCodeDef {PluralRule=1, Code="es-MX", GoogleCode="es"}},
{"Spanish/Nicaragua", new LanguageCodeDef {PluralRule=1, Code="es-NI", GoogleCode="es"}},
{"Spanish/Panama", new LanguageCodeDef {PluralRule=1, Code="es-PA", GoogleCode="es"}},
{"Spanish/Paraguay", new LanguageCodeDef {PluralRule=1, Code="es-PY", GoogleCode="es"}},
{"Spanish/Peru", new LanguageCodeDef {PluralRule=1, Code="es-PE", GoogleCode="es"}},
{"Spanish/Puerto Rico", new LanguageCodeDef {PluralRule=1, Code="es-PR", GoogleCode="es"}},
{"Spanish/Spain", new LanguageCodeDef {PluralRule=1, Code="es-ES", GoogleCode="es"}},
{"Spanish/Uruguay", new LanguageCodeDef {PluralRule=1, Code="es-UY", GoogleCode="es"}},
{"Spanish/Venezuela", new LanguageCodeDef {PluralRule=1, Code="es-VE", GoogleCode="es"}},
{"Spanish/Latin Americas", new LanguageCodeDef {PluralRule=1, Code="es-US", GoogleCode="es"}},
/**/{"Sundanese", new LanguageCodeDef {PluralRule=1, Code="su"}},
{"Swahili", new LanguageCodeDef {Code="sw"}},
/**/{"Swati", new LanguageCodeDef {PluralRule=1, Code="ss", GoogleCode="-"}},
{"Swedish", new LanguageCodeDef {PluralRule=1, Code="sv"}},
{"Swedish/Finland", new LanguageCodeDef {PluralRule=1, Code="sv-FI", GoogleCode="sv"}},
{"Swedish/Sweden", new LanguageCodeDef {PluralRule=1, Code="sv-SE", GoogleCode="sv"}},
{"Tamil", new LanguageCodeDef {PluralRule=1, Code="ta"}},
{"Tatar", new LanguageCodeDef {PluralRule=0, Code="tt", GoogleCode="-"}},
{"Telugu", new LanguageCodeDef {PluralRule=1, Code="te"}},
/**/{"Tajik", new LanguageCodeDef {PluralRule=1, Code="tg"}},
{"Thai", new LanguageCodeDef {PluralRule=0, Code="th", HasJoinedWords=true}},
/**/{"Tigrinya", new LanguageCodeDef {PluralRule=1, Code="ti", GoogleCode="-"}},
/**/{"Tibetan", new LanguageCodeDef {PluralRule=1, Code="bo", GoogleCode="-"}},
/**/{"Turkmen", new LanguageCodeDef {PluralRule=1, Code="tk", GoogleCode="-"}},
/**/{"Tagalog", new LanguageCodeDef {PluralRule=1, Code="tl"}},
/**/{"Tswana", new LanguageCodeDef {PluralRule=1, Code="tn", GoogleCode="-"}},
/**/{"Tonga", new LanguageCodeDef {PluralRule=1, Code="to", GoogleCode="-"}},
{"Turkish", new LanguageCodeDef {PluralRule=0, Code="tr"}},
/**/{"Tsonga", new LanguageCodeDef {PluralRule=1, Code="ts", GoogleCode="-"}},
/**/{"Twi", new LanguageCodeDef {PluralRule=1, Code="tw", GoogleCode="-"}},
/**/{"Tahitian", new LanguageCodeDef {PluralRule=1, Code="ty", GoogleCode="-"}},
/**/{"Uighur", new LanguageCodeDef {PluralRule=1, Code="ug", GoogleCode="-"}},
{"Ukrainian", new LanguageCodeDef {PluralRule=6, Code="uk"}},
{"Urdu", new LanguageCodeDef {PluralRule=1, Code="ur"}},
{"Uzbek", new LanguageCodeDef {PluralRule=2, Code="uz"}},
/**/{"Venda", new LanguageCodeDef {PluralRule=1, Code="ve", GoogleCode="-"}},
{"Vietnamese", new LanguageCodeDef {PluralRule=1, Code="vi"}},
/**/{"Volapük", new LanguageCodeDef {PluralRule=1, Code="vo", GoogleCode="-"}},
/**/{"Walloon", new LanguageCodeDef {PluralRule=1, Code="wa", GoogleCode="-"}},
{"Welsh", new LanguageCodeDef {PluralRule=16, Code="cy"}},
/**/{"Wolof", new LanguageCodeDef {PluralRule=1, Code="wo", GoogleCode="-"}},
/**/{"Frisian", new LanguageCodeDef {PluralRule=1, Code="fy"}},
{"Xhosa", new LanguageCodeDef {PluralRule=1, Code="xh"}},
{"Yiddish", new LanguageCodeDef {PluralRule=1, Code="yi"}},
/**/{"Yoruba", new LanguageCodeDef {PluralRule=1, Code="yo"}},
/**/{"Zhuang", new LanguageCodeDef {PluralRule=1, Code="za", GoogleCode="-"}},
{"Zulu", new LanguageCodeDef {PluralRule=1, Code="zu"}}
};
static int GetPluralRule( string langCode )
{
if (langCode.Length > 2)
langCode = langCode.Substring(0, 2);
langCode = langCode.ToLower();
foreach (var kvp in mLanguageDef)
if (kvp.Value.Code == langCode)
{
return kvp.Value.PluralRule;
}
return 0;
}
//http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html
//http://cldr.unicode.org/cldr-features#TOC-Locale-specific-patterns-for-formatting-and-parsing:
//http://cldr.unicode.org/index/cldr-spec/plural-rules
public static bool LanguageHasPluralType( string langCode, string pluralType )
{
if (pluralType == "Plural" || pluralType=="Zero" || pluralType=="One")
return true;
int rule = GetPluralRule (langCode);
switch (rule)
{
case 3: // Celtic (Scottish Gaelic)
return pluralType=="Two" || pluralType=="Few";
case 4: // Families: Romanic (Romanian)
case 5: // Families: Baltic (Latvian, Lithuanian)
case 6: // Families: Slavic (Belarusian, Bosnian, Croatian, Serbian, Russian, Ukrainian)
case 7: // Families: Slavic (Slovak, Czech)
case 8: // Families: Slavic (Polish)
return pluralType=="Few";
case 9: // Families: Slavic (Slovenian, Sorbian)
return pluralType=="Two" || pluralType=="Few";
case 10: // Families: Celtic (Irish Gaelic)
case 11: // Families: Semitic (Arabic)
case 15: // Families: Celtic (Breton)
case 16: // Families: (Welsh)
return pluralType=="Two" || pluralType=="Few" || pluralType=="Many";
case 12: // Families: Semitic (Maltese)
return pluralType=="Few" || pluralType=="Many";
case 13: // Families: Slavic (Macedonian)
return pluralType=="Two";
}
return false;
}
// https://developer.mozilla.org/en-US/docs/Mozilla/Localization/Localization_and_Plurals
public static ePluralType GetPluralType( string langCode, int n )
{
if (n == 0) return ePluralType.Zero;
if (n == 1) return ePluralType.One;
int rule = GetPluralRule (langCode);
switch (rule)
{
case 0: // Families: Asian (Chinese, Japanese, Korean), Persian, Turkic/Altaic (Turkish), Thai, Lao
return ePluralType.Plural;
case 1: // Families: Germanic (Danish, Dutch, English, Faroese, Frisian, German, Norwegian, Swedish), Finno-Ugric (Estonian, Finnish, Hungarian), Language isolate (Basque), Latin/Greek (Greek), Semitic (Hebrew), Romanic (Italian, Portuguese, Spanish, Catalan), Vietnamese
return n==1 ? ePluralType.One : ePluralType.Plural;
case 2: // Families: Romanic (French, Brazilian Portuguese)
return n<=1 ? ePluralType.One : ePluralType.Plural;
case 3: // Celtic (Scottish Gaelic)
return n==1 || n==11 ? ePluralType.One :
n==2 || n==12 ? ePluralType.Two :
inRange(n,3,10) || inRange(n,13,19) ? ePluralType.Few : ePluralType.Plural;
case 4: // Families: Romanic (Romanian)
return n==1 ? ePluralType.One :
inRange(n%100, 1, 19) ? ePluralType.Few : ePluralType.Plural;
case 5: // Families: Baltic (Latvian, Lithuanian)
return n%10==1 && n%100!=11 ? ePluralType.One :
n%10>=2 && (n%100<10 || n%100>=20) ? ePluralType.Few : ePluralType.Plural;
case 6: // Families: Slavic (Belarusian, Bosnian, Croatian, Serbian, Russian, Ukrainian)
return n % 10 == 1 && n % 100 != 11 ? ePluralType.One :
inRange (n%10,2,4) && !inRange (n%100,12,14) ? ePluralType.Few : ePluralType.Plural;
case 7: // Families: Slavic (Slovak, Czech)
return n==1 ? ePluralType.One :
inRange(n,2,4) ? ePluralType.Few : ePluralType.Plural;
case 8: // Families: Slavic (Polish)
return n==1 ? ePluralType.One :
inRange (n%10,2,4) && !inRange (n%100,12,14) ? ePluralType.Few : ePluralType.Plural;
case 9: // Families: Slavic (Slovenian, Sorbian)
return n%100==1 ? ePluralType.One :
n%100==2 ? ePluralType.Two :
inRange(n%100,3,4) ? ePluralType.Few : ePluralType.Plural;
case 10: // Families: Celtic (Irish Gaelic)
return n==1 ? ePluralType.One :
n==2 ? ePluralType.Two :
inRange(n, 3,6) ? ePluralType.Few :
inRange(n, 7,10)? ePluralType.Many : ePluralType.Plural;
case 11: // Families: Semitic (Arabic)
return n==0 ? ePluralType.Zero :
n==1 ? ePluralType.One :
n==2 ? ePluralType.Two :
inRange(n%100,3,10) ? ePluralType.Few :
n%100>=11 ? ePluralType.Many : ePluralType.Plural;
case 12: // Families: Semitic (Maltese)
return n==1 ? ePluralType.One :
inRange(n%100, 1, 10) ? ePluralType.Few :
inRange(n%100, 11,19) ? ePluralType.Many : ePluralType.Plural;
case 13: // Families: Slavic (Macedonian)
return n % 10 == 1 ? ePluralType.One :
n % 10 == 2 ? ePluralType.Two : ePluralType.Plural;
case 14: // Plural rule #15 (2 forms)
return n%10==1 && n%100!=11 ? ePluralType.One : ePluralType.Plural;
case 15: // Families: Celtic (Breton)
return n % 10 == 1 && n % 100 != 11 && n % 100 != 71 && n % 100 != 91 ? ePluralType.One :
n % 10 == 2 && n % 100 != 12 && n % 100 != 72 && n % 100 != 92 ? ePluralType.Two :
(n % 10 == 3 || n % 10 == 4 || n % 10 == 9) && n % 100 != 13 && n % 100 != 14 && n % 100 != 19 && n % 100 != 73 && n % 100 != 74 && n % 100 != 79 && n % 100 != 93 && n % 100 != 94 && n % 100 != 99 ? ePluralType.Few :
n%1000000==0 ? ePluralType.Many : ePluralType.Plural;
case 16: // Families: (Welsh)
return n==0 ? ePluralType.Zero :
n==1 ? ePluralType.One :
n==2 ? ePluralType.Two :
n==3 ? ePluralType.Few :
n==6 ? ePluralType.Many : ePluralType.Plural;
}
return ePluralType.Plural;
}
// A number that belong to the pluralType form
public static int GetPluralTestNumber( string langCode, ePluralType pluralType )
{
switch (pluralType)
{
case ePluralType.Zero:
return 0;
case ePluralType.One:
return 1;
case ePluralType.Few:
return 3;
case ePluralType.Many:
{
int rule = GetPluralRule (langCode);
if (rule == 10) return 8;
if (rule == 11 || rule==12) return 13;
if (rule == 15) return 1000000;
return 6;
}
default:
return 936;
}
}
static bool inRange(int amount, int min, int max)
{
return amount >= min && amount <= max;
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 26e29b3e77176de4cbb64a3ec85beee6
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,86 @@
using System.Collections.Generic;
namespace I2.Loc
{
using TranslationDictionary = Dictionary<string, TranslationQuery>;
public static partial class GoogleTranslation
{
public delegate void fnOnTranslated(string Translation, string Error);
public static bool CanTranslate ()
{
return LocalizationManager.Sources.Count > 0 &&
!string.IsNullOrEmpty (LocalizationManager.GetWebServiceURL());
}
// LanguageCodeFrom can be "auto"
// After the translation is returned from Google, it will call OnTranslationReady(TranslationResult, ErrorMsg)
// TranslationResult will be null if translation failed
public static void Translate( string text, string LanguageCodeFrom, string LanguageCodeTo, fnOnTranslated OnTranslationReady )
{
LocalizationManager.InitializeIfNeeded();
if (!CanTranslate())
{
OnTranslationReady(null, "WebService is not set correctly or needs to be reinstalled");
return;
}
//LanguageCodeTo = GoogleLanguages.GetGoogleLanguageCode(LanguageCodeTo);
if (LanguageCodeTo==LanguageCodeFrom)
{
OnTranslationReady(text, null);
return;
}
TranslationDictionary queries = new TranslationDictionary(System.StringComparer.Ordinal);
// Unsupported language
if (string.IsNullOrEmpty(LanguageCodeTo))
{
OnTranslationReady(string.Empty, null);
return;
}
CreateQueries(text, LanguageCodeFrom, LanguageCodeTo, queries); // can split plurals and specializations into several queries
Translate(queries, (results,error)=>
{
if (!string.IsNullOrEmpty(error) || results.Count==0)
{
OnTranslationReady(null, error);
return;
}
string result = RebuildTranslation( text, queries, LanguageCodeTo); // gets the result from google and rebuilds the text from multiple queries if its is plurals
OnTranslationReady( result, null );
});
}
// Query google for the translation and waits until google returns
// On some Unity versions (e.g. 2017.1f1) unity doesn't handle well waiting for WWW in the main thread, so this call can fail
// In those cases, its advisable to use the Async version (GoogleTranslation.Translate(....))
public static string ForceTranslate ( string text, string LanguageCodeFrom, string LanguageCodeTo )
{
TranslationDictionary dict = new TranslationDictionary(System.StringComparer.Ordinal);
AddQuery(text, LanguageCodeFrom, LanguageCodeTo, dict);
var job = new TranslationJob_Main(dict, null);
while (true)
{
var state = job.GetState();
if (state == TranslationJob.eJobState.Running)
continue;
if (state == TranslationJob.eJobState.Failed)
return null;
//TranslationJob.eJobState.Succeeded
return GetQueryResult( text, "", dict);
}
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: cc4d0073f9e452047bd31b01de2bbd82
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,175 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine.Networking;
namespace I2.Loc
{
using TranslationDictionary = Dictionary<string, TranslationQuery>;
public static partial class GoogleTranslation
{
static List<UnityWebRequest> mCurrentTranslations = new List<UnityWebRequest>();
static List<TranslationJob> mTranslationJobs = new List<TranslationJob>();
public delegate void fnOnTranslationReady(TranslationDictionary dict, string error);
#region Multiple Translations
public static void Translate( TranslationDictionary requests, fnOnTranslationReady OnTranslationReady, bool usePOST = true )
{
//WWW www = GetTranslationWWW( requests, usePOST );
//I2.Loc.CoroutineManager.Start(WaitForTranslation(www, OnTranslationReady, requests));
AddTranslationJob( new TranslationJob_Main(requests, OnTranslationReady) );
}
public static bool ForceTranslate(TranslationDictionary requests, bool usePOST = true)
{
var job = new TranslationJob_Main(requests, null);
while (true)
{
var state = job.GetState();
if (state == TranslationJob.eJobState.Running)
continue;
if (state == TranslationJob.eJobState.Failed)
return false;
//TranslationJob.eJobState.Succeeded
return true;
}
}
public static List<string> ConvertTranslationRequest(TranslationDictionary requests, bool encodeGET)
{
List<string> results = new List<string>();
var sb = new StringBuilder();
foreach (var kvp in requests)
{
var request = kvp.Value;
if (sb.Length > 0)
sb.Append("<I2Loc>");
sb.Append(GoogleLanguages.GetGoogleLanguageCode(request.LanguageCode));
sb.Append(":");
for (int i = 0; i < request.TargetLanguagesCode.Length; ++i)
{
if (i != 0) sb.Append(",");
sb.Append(GoogleLanguages.GetGoogleLanguageCode(request.TargetLanguagesCode[i]));
}
sb.Append("=");
var text = TitleCase(request.Text) == request.Text ? request.Text.ToLowerInvariant() : request.Text;
if (!encodeGET)
{
sb.Append(text);
}
else
{
sb.Append(Uri.EscapeDataString(text));
if (sb.Length > 4000)
{
results.Add(sb.ToString());
sb.Length = 0;
}
}
}
results.Add(sb.ToString());
return results;
}
static void AddTranslationJob( TranslationJob job )
{
mTranslationJobs.Add(job);
if (mTranslationJobs.Count==1)
{
CoroutineManager.Start(WaitForTranslations());
}
}
static IEnumerator WaitForTranslations()
{
while (mTranslationJobs.Count > 0)
{
var jobs = mTranslationJobs.ToArray();
foreach (var job in jobs)
{
if (job.GetState() != TranslationJob.eJobState.Running)
mTranslationJobs.Remove(job);
}
yield return null;
}
}
public static string ParseTranslationResult( string html, TranslationDictionary requests )
{
//Debug.Log(html);
// Handle google restricting the webservice to run
if (html.StartsWith("<!DOCTYPE html>") || html.StartsWith("<HTML>"))
{
if (html.Contains("The script completed but did not return anything"))
return "The current Google WebService is not supported.\nPlease, delete the WebService from the Google Drive and Install the latest version.";
if (html.Contains("Service invoked too many times in a short time"))
return ""; // ignore and try again
return "There was a problem contacting the WebService. Please try again later\n" + html;
}
string[] texts = html.Split (new[]{"<I2Loc>"}, StringSplitOptions.None);
string[] splitter = {"<i2>"};
int i = 0;
var Keys = requests.Keys.ToArray();
foreach (var text in Keys)
{
var temp = FindQueryFromOrigText(text, requests);
var fullText = texts[i++];
if (temp.Tags != null)
{
//for (int j = 0, jmax = temp.Tags.Length; j < jmax; ++j)
for (int j = temp.Tags.Length-1; j>=0; --j)
{
fullText = fullText.Replace(GetGoogleNoTranslateTag(j), temp.Tags[j]);
//fullText = fullText.Replace( /*"{[" + j + "]}"*/ ((char)(0x2600+j)).ToString(), temp.Tags[j]);
}
}
temp.Results = fullText.Split (splitter, StringSplitOptions.None);
// Google has problem translating this "This Is An Example" but not this "this is an example"
if (TitleCase(text)==text)
{
for (int j=0; j<temp.Results.Length; ++j)
temp.Results[j] = TitleCase(temp.Results[j]);
}
requests[temp.OrigText] = temp;
}
return null;
}
public static bool IsTranslating()
{
return mCurrentTranslations.Count>0 || mTranslationJobs.Count > 0;
}
public static void CancelCurrentGoogleTranslations()
{
mCurrentTranslations.Clear ();
foreach (var job in mTranslationJobs)
{
job.Dispose();
}
mTranslationJobs.Clear();
}
#endregion
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 94b94d27ab6931c4abee1e4d3655b660
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,375 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace I2.Loc
{
using TranslationDictionary = Dictionary<string, TranslationQuery>;
public struct TranslationQuery
{
public string OrigText;
public string Text; // Text without Tags
public string LanguageCode;
public string[] TargetLanguagesCode;
public string[] Results; // This is filled google returns the translations
public string[] Tags; // This are the sections of the orignal text that shoudn't be translated
}
public static partial class GoogleTranslation
{
public static void CreateQueries(string text, string LanguageCodeFrom, string LanguageCodeTo, TranslationDictionary dict)
{
if (!text.Contains("[i2s_"))
{
CreateQueries_Plurals(text, LanguageCodeFrom, LanguageCodeTo, dict);
return;
}
var variants = SpecializationManager.GetSpecializations(text);
foreach (var kvp in variants)
{
CreateQueries_Plurals(kvp.Value, LanguageCodeFrom, LanguageCodeTo, dict);
}
}
static void CreateQueries_Plurals(string text, string LanguageCodeFrom, string LanguageCodeTo, TranslationDictionary dict)
{
bool hasPluralParams = text.Contains("{[#");
bool hasPluralTypes = text.Contains("[i2p_");
if (!HasParameters(text) || !hasPluralParams && !hasPluralTypes)
{
AddQuery(text, LanguageCodeFrom, LanguageCodeTo, dict);
return;
}
bool forcePluralParam = hasPluralParams;
for (var i = (ePluralType)0; i <= ePluralType.Plural; ++i)
{
var pluralType = i.ToString();
if (!GoogleLanguages.LanguageHasPluralType(LanguageCodeTo, pluralType))
continue;
var newText = GetPluralText(text, pluralType);
int testNumber = GoogleLanguages.GetPluralTestNumber(LanguageCodeTo, i);
var parameter = GetPluralParameter(newText, forcePluralParam);
if (!string.IsNullOrEmpty(parameter))
newText = newText.Replace(parameter, testNumber.ToString());
//Debug.Log("Translate: " + newText);
AddQuery(newText, LanguageCodeFrom, LanguageCodeTo, dict);
}
}
public static void AddQuery(string text, string LanguageCodeFrom, string LanguageCodeTo, TranslationDictionary dict)
{
if (string.IsNullOrEmpty(text))
return;
if (!dict.ContainsKey(text))
{
var query = new TranslationQuery { OrigText = text, LanguageCode = LanguageCodeFrom, TargetLanguagesCode = new[] { LanguageCodeTo } };
query.Text = text;
ParseNonTranslatableElements(ref query);
dict[text] = query;
}
else
{
var query = dict[text];
if (Array.IndexOf(query.TargetLanguagesCode, LanguageCodeTo) < 0)
{
query.TargetLanguagesCode = query.TargetLanguagesCode.Concat(new[] { LanguageCodeTo }).Distinct().ToArray();
}
dict[text] = query;
}
}
static string GetTranslation(string text, string LanguageCodeTo, TranslationDictionary dict)
{
if (!dict.ContainsKey(text))
return null;
var query = dict[text];
int langIdx = Array.IndexOf(query.TargetLanguagesCode, LanguageCodeTo);
if (langIdx < 0)
return "";
if (query.Results == null)
return "";
return query.Results[langIdx];
}
static TranslationQuery FindQueryFromOrigText(string origText, TranslationDictionary dict)
{
foreach (var kvp in dict)
{
if (kvp.Value.OrigText == origText)
return kvp.Value;
}
return default(TranslationQuery);
}
public static bool HasParameters( string text )
{
int idx = text.IndexOf("{[", StringComparison.Ordinal);
if (idx < 0) return false;
return text.IndexOf("]}", idx, StringComparison.Ordinal) > 0;
}
public static string GetPluralParameter(string text, bool forceTag) // force tag requires that the parameter has the form {[#param]}
{
// Try finding the "plural parameter" that has the form {[#name]}
// this allows using the second parameter as plural: "Player {[name1]} has {[#value]} points"
int idx0 = text.IndexOf("{[#", StringComparison.Ordinal);
if (idx0 < 0)
{
if (forceTag) return null;
idx0 = text.IndexOf("{[", StringComparison.Ordinal); // fallback to the first paremeter if no one has the # tag
}
if (idx0 < 0)
return null;
int idx1 = text.IndexOf("]}", idx0+2, StringComparison.Ordinal);
if (idx1 < 0)
return null; // no closing parameter tag
return text.Substring(idx0, idx1 - idx0 + 2);
}
public static string GetPluralText( string text, string pluralType )
{
pluralType = "[i2p_" + pluralType + "]";
int idx0 = text.IndexOf(pluralType, StringComparison.Ordinal);
if (idx0>=0)
{
idx0 += pluralType.Length;
int idx1 = text.IndexOf("[i2p_",idx0, StringComparison.Ordinal);
if (idx1 < 0) idx1 = text.Length;
return text.Substring(idx0, idx1 - idx0);
}
// PluralType not found, fallback to the first one
idx0 = text.IndexOf("[i2p_", StringComparison.Ordinal);
if (idx0 < 0)
return text; // No plural tags: "my text"
if (idx0>0)
return text.Substring(0, idx0); // Case: "my text[i2p_zero]hello"
// Case: "[i2p_plural]my text[i2p_zero]hello"
idx0 = text.IndexOf("]", StringComparison.Ordinal);
if (idx0 < 0) return text; // starts like a plural, but has none
idx0 += 1;
int idx2 = text.IndexOf("[i2p_", idx0, StringComparison.Ordinal);
if (idx2 < 0) idx2 = text.Length;
return text.Substring(idx0, idx2 - idx0);
}
static int FindClosingTag(string tag, MatchCollection matches, int startIndex)
{
for (int i = startIndex, imax = matches.Count; i < imax; ++i)
{
var newTag = I2Utils.GetCaptureMatch(matches[i]);
if (newTag[0]=='/' && tag.StartsWith(newTag.Substring(1), StringComparison.Ordinal))
return i;
}
return -1;
}
static string GetGoogleNoTranslateTag(int tagNumber)
{
//return " I2NT" + tagNumber;
if (tagNumber < 70)
return "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++".Substring(0, tagNumber+1);
string s = "";
for (int i = -1; i < tagNumber; ++i)
s += "+";
return s;
}
static void ParseNonTranslatableElements( ref TranslationQuery query )
{
//\[i2nt].*\[\/i2nt]
var matches = Regex.Matches( query.Text, @"\{\[(.*?)]}|\[(.*?)]|\<(.*?)>");
if (matches == null || matches.Count == 0)
return;
string finalText = query.Text;
List<string> finalTags = new List<string>();
for (int i=0, imax=matches.Count; i<imax; ++i)
{
var tag = I2Utils.GetCaptureMatch( matches[i] );
int iClosingTag = FindClosingTag(tag, matches, i); // find [/tag] or </tag>
if (iClosingTag < 0)
{
// Its not a tag, its a parameter
var fulltag = matches[i].ToString();
if (fulltag.StartsWith("{[", StringComparison.Ordinal) && fulltag.EndsWith("]}", StringComparison.Ordinal))
{
finalText = finalText.Replace(fulltag, GetGoogleNoTranslateTag(finalTags.Count)+" "); // 0x2600 is the start of the UNICODE Miscellaneous Symbols table, so they are not going to be translated by google
//finalText = finalText.Replace(fulltag, /*"{[" + finalTags.Count + "]}"*/ ((char)(0x2600 + finalTags.Count)).ToString()); // 0x2600 is the start of the UNICODE Miscellaneous Symbols table, so they are not going to be translated by google
finalTags.Add(fulltag);
}
continue;
}
if (tag == "i2nt")
{
var tag1 = query.Text.Substring(matches[i].Index, matches[iClosingTag].Index-matches[i].Index + matches[iClosingTag].Length);
finalText = finalText.Replace(tag1, GetGoogleNoTranslateTag(finalTags.Count)+" ");
//finalText = finalText.Replace(tag1, /*"{[" + finalTags.Count + "]}"*/ ((char)(0x2600 + finalTags.Count)).ToString());
finalTags.Add(tag1);
}
else
{
var tag1 = matches[i].ToString();
finalText = finalText.Replace(tag1, GetGoogleNoTranslateTag(finalTags.Count)+" ");
//finalText = finalText.Replace(tag1, /*"{[" + finalTags.Count + "]}"*/ ((char)(0x2600 + finalTags.Count)).ToString());
finalTags.Add(tag1);
var tag2 = matches[iClosingTag].ToString();
finalText = finalText.Replace(tag2, GetGoogleNoTranslateTag(finalTags.Count)+" ");
//finalText = finalText.Replace(tag2, /*"{[" + finalTags.Count + "]}"*/ ((char)(0x2600 + finalTags.Count)).ToString());
finalTags.Add(tag2);
}
}
query.Text = finalText;
query.Tags = finalTags.ToArray();
}
public static string GetQueryResult(string text, string LanguageCodeTo, TranslationDictionary dict)
{
if (!dict.ContainsKey(text))
return null;
var query = dict[text];
if (query.Results == null || query.Results.Length < 0)
return null;
if (string.IsNullOrEmpty(LanguageCodeTo))
return query.Results[0];
int idx = Array.IndexOf(query.TargetLanguagesCode, LanguageCodeTo);
if (idx < 0)
return null;
return query.Results[idx];
}
public static string RebuildTranslation(string text, TranslationDictionary dict, string LanguageCodeTo)
{
if (!text.Contains("[i2s_"))
{
return RebuildTranslation_Plural(text, dict, LanguageCodeTo);
}
var variants = SpecializationManager.GetSpecializations(text);
var results = new Dictionary<string,string>(StringComparer.Ordinal);
foreach (var kvp in variants)
{
results[kvp.Key] = RebuildTranslation_Plural(kvp.Value, dict, LanguageCodeTo);
}
return SpecializationManager.SetSpecializedText(results);
}
static string RebuildTranslation_Plural( string text, TranslationDictionary dict, string LanguageCodeTo )
{
bool hasPluralParams = text.Contains("{[#");
bool hasPluralTypes = text.Contains("[i2p_");
if (!HasParameters(text) || !hasPluralParams && !hasPluralTypes)
{
return GetTranslation (text, LanguageCodeTo, dict);
}
var sb = new StringBuilder();
string pluralTranslation = null;
bool forcePluralParam = hasPluralParams;
for (var i = ePluralType.Plural; i >= 0; --i)
{
var pluralType = i.ToString();
if (!GoogleLanguages.LanguageHasPluralType(LanguageCodeTo, pluralType))
continue;
var newText = GetPluralText(text, pluralType);
int testNumber = GoogleLanguages.GetPluralTestNumber(LanguageCodeTo, i);
var parameter = GetPluralParameter(newText, forcePluralParam);
if (!string.IsNullOrEmpty(parameter))
newText = newText.Replace(parameter, testNumber.ToString());
var translation = GetTranslation(newText, LanguageCodeTo, dict);
//Debug.LogFormat("from: {0} -> {1}", newText, translation);
if (!string.IsNullOrEmpty(parameter))
translation = translation.Replace(testNumber.ToString(), parameter);
if (i==ePluralType.Plural)
{
pluralTranslation = translation;
}
else
{
if (translation == pluralTranslation)
continue;
sb.AppendFormat("[i2p_{0}]", pluralType);
}
sb.Append(translation);
}
return sb.ToString ();
}
public static string UppercaseFirst(string s)
{
if (string.IsNullOrEmpty(s))
{
return string.Empty;
}
char[] a = s.ToLower().ToCharArray();
a[0] = char.ToUpper(a[0]);
return new string(a);
}
public static string TitleCase(string s)
{
if (string.IsNullOrEmpty(s))
{
return string.Empty;
}
#if NETFX_CORE
var sb = new StringBuilder(s);
sb[0] = char.ToUpper(sb[0]);
for (int i = 1, imax=s.Length; i<imax; ++i)
{
if (char.IsWhiteSpace(sb[i - 1]))
sb[i] = char.ToUpper(sb[i]);
else
sb[i] = char.ToLower(sb[i]);
}
return sb.ToString();
#else
return CultureInfo.CurrentCulture.TextInfo.ToTitleCase(s);
#endif
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 206e4bf72a490864e9bcb59edbdddaed
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: c6bd173cd8524b04daa3dabce666b456
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using UnityEngine.Networking;
namespace I2.Loc
{
using TranslationDictionary = Dictionary<string, TranslationQuery>;
public class TranslationJob : IDisposable
{
public eJobState mJobState = eJobState.Running;
public enum eJobState { Running, Succeeded, Failed }
public virtual eJobState GetState() { return mJobState; }
public virtual void Dispose() { }
}
public class TranslationJob_WWW : TranslationJob
{
public UnityWebRequest www;
public override void Dispose()
{
if (www!=null)
www.Dispose();
www = null;
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 7dae211a5bb44db46a568fb70fca3296
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,79 @@
using System.Collections.Generic;
using System.Text;
using UnityEngine.Networking;
namespace I2.Loc
{
using TranslationDictionary = Dictionary<string, TranslationQuery>;
public class TranslationJob_GET : TranslationJob_WWW
{
TranslationDictionary _requests;
GoogleTranslation.fnOnTranslationReady _OnTranslationReady;
List<string> mQueries;
public string mErrorMessage;
public TranslationJob_GET(TranslationDictionary requests, GoogleTranslation.fnOnTranslationReady OnTranslationReady)
{
_requests = requests;
_OnTranslationReady = OnTranslationReady;
mQueries = GoogleTranslation.ConvertTranslationRequest(requests, true);
GetState();
}
void ExecuteNextQuery()
{
if (mQueries.Count == 0)
{
mJobState = eJobState.Succeeded;
return;
}
int lastQuery = mQueries.Count - 1;
var query = mQueries[lastQuery];
mQueries.RemoveAt(lastQuery);
string url = $"{LocalizationManager.GetWebServiceURL()}?action=Translate&list={query}";
www = UnityWebRequest.Get(url);
I2Utils.SendWebRequest(www);
}
public override eJobState GetState()
{
if (www != null && www.isDone)
{
ProcessResult(www.downloadHandler.data, www.error);
www.Dispose();
www = null;
}
if (www==null)
{
ExecuteNextQuery();
}
return mJobState;
}
public void ProcessResult(byte[] bytes, string errorMsg)
{
if (string.IsNullOrEmpty(errorMsg))
{
var wwwText = Encoding.UTF8.GetString(bytes, 0, bytes.Length); //www.text
errorMsg = GoogleTranslation.ParseTranslationResult(wwwText, _requests);
if (string.IsNullOrEmpty(errorMsg))
{
if (_OnTranslationReady!=null)
_OnTranslationReady(_requests, null);
return;
}
}
mJobState = eJobState.Failed;
mErrorMessage = errorMsg;
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 13df42f7287eccc4399bc757d577030e
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,102 @@
using System.Collections.Generic;
namespace I2.Loc
{
using TranslationDictionary = Dictionary<string, TranslationQuery>;
public class TranslationJob_Main : TranslationJob
{
TranslationJob_WEB mWeb;
TranslationJob_POST mPost;
TranslationJob_GET mGet;
TranslationDictionary _requests;
GoogleTranslation.fnOnTranslationReady _OnTranslationReady;
public string mErrorMessage;
public TranslationJob_Main(TranslationDictionary requests, GoogleTranslation.fnOnTranslationReady OnTranslationReady)
{
_requests = requests;
_OnTranslationReady = OnTranslationReady;
//mWeb = new TranslationJob_WEB(requests, OnTranslationReady);
mPost = new TranslationJob_POST(requests, OnTranslationReady);
}
public override eJobState GetState()
{
if (mWeb != null)
{
var state = mWeb.GetState();
switch (state)
{
case eJobState.Running: return eJobState.Running;
case eJobState.Succeeded:
{
mJobState = eJobState.Succeeded;
break;
}
case eJobState.Failed:
{
mWeb.Dispose();
mWeb = null;
mPost = new TranslationJob_POST(_requests, _OnTranslationReady);
break;
}
}
}
if (mPost != null)
{
var state = mPost.GetState();
switch (state)
{
case eJobState.Running: return eJobState.Running;
case eJobState.Succeeded:
{
mJobState = eJobState.Succeeded;
break;
}
case eJobState.Failed:
{
mPost.Dispose();
mPost = null;
mGet = new TranslationJob_GET(_requests, _OnTranslationReady);
break;
}
}
}
if (mGet != null)
{
var state = mGet.GetState();
switch (state)
{
case eJobState.Running: return eJobState.Running;
case eJobState.Succeeded:
{
mJobState = eJobState.Succeeded;
break;
}
case eJobState.Failed:
{
mErrorMessage = mGet.mErrorMessage;
if (_OnTranslationReady != null)
_OnTranslationReady(_requests, mErrorMessage);
mGet.Dispose();
mGet = null;
break;
}
}
}
return mJobState;
}
public override void Dispose()
{
if (mPost != null) mPost.Dispose();
if (mGet != null) mGet.Dispose();
mPost = null;
mGet = null;
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: b6aed7ae05f9c254596b3728c5811bdb
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,60 @@
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using UnityEngine.Networking;
namespace I2.Loc
{
using TranslationDictionary = Dictionary<string, TranslationQuery>;
public class TranslationJob_POST : TranslationJob_WWW
{
TranslationDictionary _requests;
GoogleTranslation.fnOnTranslationReady _OnTranslationReady;
public TranslationJob_POST(TranslationDictionary requests, GoogleTranslation.fnOnTranslationReady OnTranslationReady)
{
_requests = requests;
_OnTranslationReady = OnTranslationReady;
var data = GoogleTranslation.ConvertTranslationRequest(requests, false);
WWWForm form = new WWWForm();
form.AddField("action", "Translate");
form.AddField("list", data[0]);
www = UnityWebRequest.Post(LocalizationManager.GetWebServiceURL(), form);
I2Utils.SendWebRequest(www);
}
public override eJobState GetState()
{
if (www != null && www.isDone)
{
ProcessResult(www.downloadHandler.data, www.error);
www.Dispose();
www = null;
}
return mJobState;
}
public void ProcessResult(byte[] bytes, string errorMsg)
{
if (!string.IsNullOrEmpty(errorMsg))
{
// check for
//if (errorMsg.Contains("rewind")) // "necessary data rewind wasn't possible"
mJobState = eJobState.Failed;
}
else
{
var wwwText = Encoding.UTF8.GetString(bytes, 0, bytes.Length); //www.text
errorMsg = GoogleTranslation.ParseTranslationResult(wwwText, _requests);
if (_OnTranslationReady!=null)
_OnTranslationReady(_requests, errorMsg);
mJobState = eJobState.Succeeded;
}
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 3450e33294f339348ae4e52731974230
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,169 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.Text.RegularExpressions;
using UnityEngine;
using UnityEngine.Networking;
namespace I2.Loc
{
using TranslationDictionary = Dictionary<string, TranslationQuery>;
public class TranslationJob_WEB : TranslationJob_WWW
{
TranslationDictionary _requests;
GoogleTranslation.fnOnTranslationReady _OnTranslationReady;
public string mErrorMessage;
string mCurrentBatch_ToLanguageCode;
string mCurrentBatch_FromLanguageCode;
List<string> mCurrentBatch_Text;
List<KeyValuePair<string, string>> mQueries;
public TranslationJob_WEB(TranslationDictionary requests, GoogleTranslation.fnOnTranslationReady OnTranslationReady)
{
_requests = requests;
_OnTranslationReady = OnTranslationReady;
FindAllQueries();
ExecuteNextBatch();
}
void FindAllQueries()
{
mQueries = new List<KeyValuePair<string, string>>();
foreach (var kvp in _requests)
{
foreach (var langCode in kvp.Value.TargetLanguagesCode)
{
mQueries.Add(new KeyValuePair<string, string>(kvp.Value.OrigText, kvp.Value.LanguageCode+":"+langCode));
}
}
mQueries.Sort((a, b) => a.Value.CompareTo(b.Value));
}
void ExecuteNextBatch()
{
if (mQueries.Count==0)
{
mJobState = eJobState.Succeeded;
return;
}
mCurrentBatch_Text = new List<string>();
string lastLangCode = null;
int maxLength = 200;
var sb = new StringBuilder();
int i;
for (i=0; i<mQueries.Count; ++i)
{
var text = mQueries[i].Key;
var langCode = mQueries[i].Value;
if (lastLangCode==null || langCode==lastLangCode)
{
if (i != 0)
sb.Append("|||");
sb.Append(text);
mCurrentBatch_Text.Add(text);
lastLangCode = langCode;
}
if (sb.Length > maxLength)
break;
}
mQueries.RemoveRange(0, i);
var fromtoLang = lastLangCode.Split(':');
mCurrentBatch_FromLanguageCode = fromtoLang[0];
mCurrentBatch_ToLanguageCode = fromtoLang[1];
string url = string.Format ("http://www.google.com/translate_t?hl=en&vi=c&ie=UTF8&oe=UTF8&submit=Translate&langpair={0}|{1}&text={2}", mCurrentBatch_FromLanguageCode, mCurrentBatch_ToLanguageCode, Uri.EscapeUriString( sb.ToString() ));
Debug.Log(url);
www = UnityWebRequest.Get(url);
I2Utils.SendWebRequest(www);
}
public override eJobState GetState()
{
if (www != null && www.isDone)
{
ProcessResult(www.downloadHandler.data, www.error);
www.Dispose();
www = null;
}
if (www == null)
{
ExecuteNextBatch();
}
return mJobState;
}
public void ProcessResult(byte[] bytes, string errorMsg)
{
if (string.IsNullOrEmpty(errorMsg))
{
var wwwText = Encoding.UTF8.GetString(bytes, 0, bytes.Length); //www.text
var result = ParseTranslationResult(wwwText, "aab");
//errorMsg = GoogleTranslation.ParseTranslationResult(wwwText, _requests);
Debug.Log(result);
if (string.IsNullOrEmpty(errorMsg))
{
if (_OnTranslationReady != null)
_OnTranslationReady(_requests, null);
return;
}
}
mJobState = eJobState.Failed;
mErrorMessage = errorMsg;
}
string ParseTranslationResult( string html, string OriginalText )
{
try
{
// This is a Hack for reading Google Translation while Google doens't change their response format
int iStart = html.IndexOf("TRANSLATED_TEXT='", StringComparison.Ordinal) + "TRANSLATED_TEXT='".Length;
int iEnd = html.IndexOf("';var", iStart, StringComparison.Ordinal);
string Translation = html.Substring( iStart, iEnd-iStart);
// Convert to normalized HTML
Translation = Regex.Replace(Translation, @"\\x([a-fA-F0-9]{2})",
match => char.ConvertFromUtf32(int.Parse(match.Groups[1].Value, NumberStyles.HexNumber)));
// Convert ASCII Characters
Translation = Regex.Replace(Translation, @"&#(\d+);",
match => char.ConvertFromUtf32(int.Parse(match.Groups[1].Value)));
Translation = Translation.Replace("<br>", "\n");
if (OriginalText.ToUpper()==OriginalText)
Translation = Translation.ToUpper();
else
if (GoogleTranslation.UppercaseFirst(OriginalText)==OriginalText)
Translation = GoogleTranslation.UppercaseFirst(Translation);
else
if (GoogleTranslation.TitleCase(OriginalText)==OriginalText)
Translation = GoogleTranslation.TitleCase(Translation);
return Translation;
}
catch (Exception ex)
{
Debug.LogError(ex.Message);
return string.Empty;
}
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 3b72399bd2ff39042b1320bb943e0a20
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,876 @@
----------------------------------------------
I2 Localization
2.8.20 f2
http://www.inter-illusion.com
inter.illusion@gmail.com
----------------------------------------------
Thank you for buying I2 Localization!
Documentation can be found here: http://www.inter-illusion.com/assets/I2LocalizationManual/I2LocalizationManual.html
A few basic tutorials and more info: http://www.inter-illusion.com/tools/i2-localization
If you have any questions, suggestions, comments or feature requests, please
drop by the I2 forum: http://www.inter-illusion.com/forum/index
----------------------
Installation
----------------------
1- Import the plugin package into a Unity project.
2- Enable the support for third party plugins installed on the project
(Menu: Tools\I2 Localization\Enable Plugins)
3- Open any of the example scenes to see how to setup and localize Components
(Assets/I2/Localization/Examples)
4- To create your own localizations, open the prefab I2\Localization\Resources\I2Languages
5- Create the languages you will support.
6- The I2Languages source is a global source accessible by all scenes
The documentation provides further explanation on each of those steps and some tutorials.
Also its presented how to convert an existing NGUI localization into the I2 Localization system.
-----------------------
PLAYMAKER
-----------------------
If you use PlayMaker, please, install:
- http://www.inter-illusion.com/Downloads/I2Localization_PlayMaker.unitypackage
- PlayMaker Unity UI Addon (from the Playmaker website - only needed for the example scenes that use Unity UI)
That will install custom actions to access and modify the localization.
More details can be found in the example scene
Assets\I2\Localization PlayMaker\Playmaker Localization.unity
-----------------------
Ratings
-----------------------
If you find this plugin to be useful and want to recommend others to use it.
Please leave a review or rate it on the Asset Store.
That will help with the sales and allow me to invest more time improving the plugin!!
-----------------------
Extras
-----------------------
These are some of my plugins that may help you develop a better game:
I2 Parallax - Uses the mobile gyroscope to add depth to your UI (http://bit.ly/I2_Parallax)
I2 Text Animation - Take your texts to the next level (http://bit.ly/I2_TextAnimation)
I2 MiniGames - A better way to do Rewards and Energy Systems (http://bit.ly/I2_MiniGames)
AssetStore Deals - A bot that constantly checks the Store to find you the latest Sales (http://deals.inter-illusion.com)
-----------------------
Version History
-----------------------
2.8.20
NEW: Missing translations are now shown in the console log.
FIX: Null Exception when running in 2021.3
2.8.19
NEW: Baking terms now supports the use of Chinese/Japanese characters
FIX: Calling Import_Google with force=true, was not using the force parameter and skipping importing the data
FIX: Url to download the Playmaker actions was not right.
2.8.18
NEW: Translations fallbacks now working with multiple language sources
2.8.17
NEW: When generating ScriptLocalization.cs, if a term name is a C# keyword the variable now is set to start with @
NEW: There is now LocalizationManager.CustomApplyLocalizationParams to process ALL translations before ApplyLocalizationParams runs
FIX: Translations with RTL tags were failing (thanks @d xy for looking into this)
2.8.16
FIX: TextMesh Pro was not correctly displaying multi-line arabic texts
2.8.15
NEW: Performance improvement when switching levels by not calling Resources.UnloadUnusedAssets() unless the user requests it.
For most common scenarios, there is no need to unloadUnusedAssets
NEW: Lots of stability fixes by cleaning up all warnings detected by the Roslyn Analyzers
NEW: Fixed several issues/obsolete calls when on the latest versions of Unity
2.8.14
NEW: Added support for localizing Video Player
NEW: Allow skipping Google Synchronization from script by creating a RegisterCallback_AllowSyncFromGoogle class
(http://www.inter-illusion.com/forum/i2-localization/1679-turning-off-auto-update-via-script#4166)
FIX: UI changes to remove dark colors in the background
FIX: Disabling Localized Parameters now work as expected (i.e. Parameters still work, but they are not localized even if a term is found with that value)
FIX: Target TextMesh now correctly changes font and materials
2.8.13
NEW: Added UpdateFrequency EveryOtherDay to allow checking the spreadsheet every 48h
NEW: Added a function to retrieve an asset by using the term name (e.g. font, sprite) LocalizationManager.GetTranslatedObjectByTermName<t>(TermName)
FIX: Replaced all events using Action<..> by delegate function that clearly show what the parameters are for
FIX: Inspector was not showing correctly when in the latest alpha/beta of Unity 2019.2+
FIX: Bug where Languages coudn't be enabled at runtime (thanks to bschug for submitting a fix)
FIX: To reduce memory usage, Term descriptions are now only used in the editor (not in the final build) If needed, use a disabled language to store it
FIX: Inspector Width should now be detected more accurately
2.8.12
NEW: Now is possible to dynamically create a LanguageSourceData without a LanguageSource and use it at runtime.
NEW: LocalizationParamsManager now have a Manager Type (Local/Global) to define if it applies to ALL Localize or just the one in the same object.
FIX: Term's list is not longer fully expanded all the time.
FIX: Specialization bar in the Term's translations now shows the selected specialization as a tab-button
FIX: Adding new specializations now copies the translation from the current specialization, so the user can create several in sequence.
FIX: Terms can now have any letter, digit or any of the following symbols .-_$#@*()[]{}+:?!&'`,^=<>~
FIX: Removed invalid character from the StringObfucator that were causing build issues in XBox
FIX: RTL Fixer (Arabic, Persian, etc) was detecting tags like <xx>, only [xx]
2.8.11
NEW: Term's name can now have any of the following symbols ".-_$#@*)(][}{+:?!&'"
NEW: Now the plugin localizes MeshRenderer (Mesh + Material)
NEW: New parameter in the Google Spreadsheet tab to control when to apply the downloaded data (OnSceneLoaded, Manual, AsSoonAsDownloaded)
FIX: Inferring terms with '/' no longer generates a Category
FIX: Updated NGUI target to be compatible with the latest version
FIX: Localize inspector, the options in the dropdown for "ForceLocalize" and "Allow Localized Parameters" were in the wrong order
FIX: Inspector for the Google Spreadsheet tab in the LanguageSource was cutting when the Inspector was too narrow
FIX: Button "Open Source" in the Localize Inspector now works for both LanguageSources and LanguageSourceAssets
FIX: Terms name can now have Non latin letters (e.g. Chinese, Korean, etc), but no symbols, extra spaces, etc
2.8.10
NEW: LocalizationManager.GetCurrentDevice(true) will now force get the Device Language without using the startup language from the cache
FIX: Updated Playmaker actions to new Prefab system
FIX: Menu option: Tools/I2 Localization/Open I2Languages
FIX: When inferring terms, any tag (e.g. <color>) or invalid characters (e.g. ^/\`) are removed to form the term name
2.8.9
NEW: I2Languages.prefab is now an ScriptableObject instead of a prefab to avoid the locking issues of Unity 2018.3
FIX: Compatibility with Unity 2018.3
FIX: Plural rules for some Slavic languages were using the wrong settings.
FIX: Improved performance when using assets from Resources and in general only calling Resource.UnloadAll when loading scenes
2.8.8
NEW: Added a flag to disable Localized Parameters
(http://inter-illusion.com/forum/i2-localization/1163-localization-params-auto-translating-design-flaw#3195)
NEW: Merged all checkboxes in the Localize component into an "Options" popup to make the Localize's inspector use less space
NEW: Find all terms in the Scene/Scripts now also detects those in your code using [TermsPopup] and LocalizedString
FIX: Changing the Font or Material in a TextMeshPro now updates the linkedTextComponent
FIX: Startup language now ignores the disabled Languages if the "Default Language" is set to "Device Language"
FIX: Updated Playmaker example scene to show that it needs the Unity UI Addon.
FIX: Prevented a null reference on the GetSourcePlayerPrefName function when using Google Live Synchronization in Scene's sources
FIX: Google Live Synchronization was failing to load the downloaded data from the cache.
2.8.7
NEW: WebService now has a password to restrict other players from modifying the localization data
NEW: Importing a CSV file from script will now update the temporal files while playing
NEW: A warning is now displayed in top of the LanguageSource when Google Live Sync is enabled but the spreadsheet is not up-to-date
NEW: New option in the Languages tab to define if Runtime Unloading of Languages happens for the source, or if only in the device
NEW: By default, the Runtime Unloading of language will not happen in the Editor (to allow for editing while playing)
NEW: Missing terms are going to show hidden by default, given that they are only suggestions and are making the list to crowded
NEW: Added function LocalizationManager.GetTranslatedObject(termName) to return the translated Sprite/Material/Font/etc from a Term
FIX: Translating and editing terms now keep the [i2nt]...[/i2nt] sections correctly
FIX: Translating texts with rich text tags was removing the tags
FIX: Modified temporal language file format to recover from errors and avoid shifting the term's translations
FIX: When source is set to show a warning when the term is not found, the Localized Parameters was showing the warning
FIX: Corrected wrong layout in Terms list when in Retina displays (contributed by @TailoraSAS)
FIX: Languages will fallback were filling their translations when doing a build
2.8.6
NEW: Menu "Tools/I2 Localization/Toggle Highlight Localized" changes all localized text into "LOC:<TermName>" to easily spot errors
NEW: "Bake Terms" tool now generate another class (ScriptTerms) in ScriptLocalization.cs that class have variables for the Term Names
NEW: Parameters can now be localized if the parameter value is the name of an existing Term
NEW: Terms filtering in the LanguageSource list, now allow prefix 'f xxx' or 'c xx' to search in translations or category
FIX: Downloaded Spreadsheets will also save their key to avoid corrupting the cache when running different versions of the same app
FIX: Google Live Synchronization was not updating the temporal languages files used to save memory at runtime
FIX: GetCommonWordInLanguageNames now does a Case Insensitive comparison ("English (Canada)" can now match "english")
FIX: Latest unity beta was failing to detect TextMeshPro when installed using the PackageManager
FIX: Removed warning regarding Tizen
FIX: Clicking the Language names in the Term's description was not previewing the translations
FIX: Changing Fonts/Objects and Localize Targets when selecting multiple Localize components was only updating one of them
FIX: Charset tool was not removing the last ] from tags
FIX: ParameterManager activation was crashing IOS build in some Unity versions
2.8.5
NEW: Once a day (can be configured), the editor will check if the Spreadsheet is up-to-date to avoid issues when playing in device
NEW: Added Language code 'es-US' to support "Spanish (Latin Americas)"
NEW: Added Toggle "Separate Specializations into Rows" to Spreadsheet export inspector, to either merge or split the specializations
NEW: Startup language will now try to match an official language before trying a fallback to any custom language name or variant
FIX: Fallback languages now try finding a language of the same country, and then fallback to the first from the list
FIX: Removed harmless logs marked as error related to File not found or accessible
FIX: Disable language Loading/Unloading on the Switch console
FIX: Some character combinations where producing an error when using the CharSet tool and clicking "Copy to clipboard"
FIX: When the starting language had Fallbacks, those where not loaded correctly
FIX: If the Localize or LanguageSource inspector was open, changing the languages was not updating the inspector preview
FIX: Removed example script using OnMouseUp to avoid showing a warning when building the game (replaced with Unity UI)
2.8.4
NEW: Component CustomLocalizeCallback with a UnityEvent to set functions that should be called whenever the Language changes
NEW: Localize component now has the Callback as a UnityEvent which allows calling several function and even passing parameters
NEW: Customizable PlayerPrefs and FileAccess, allowing setting your own functions to handle settings and file IO
NEW: Term's list can now show and filter more than 31 categories (contributed by @71M THANKS!)
NEW: LocalizationManager.CurrentCulture to allow formating (e.g. string.Format(LocalizationManager.CurrentCulture, "{0:c}", 12))
FIX: Tool CharSet will no longer add Plural tag characters (e.g. [i2p_Zero])
FIX: Refactored BundlesManager to allow implementing a CustomBundlesManager
FIX: Translating a text with a plural parameter (e.g. {[#POINTS]} ) now generate all plural forms in the target language
FIX: Android devices were not auto-detecting some languages on startup
FIX: Translations that starts with characters (') or (=) can now be correctly exported and imported into Google Spreadsheets
FIX: Localize Target was not detected in Unity 2018+
FIX: Building XCode with Append failed unless set to Replace or manually deleting the Localization files
2.8.3
NEW: Runtime Memory optimization by loading/unloading languages depending on which ones is in use
NEW: Added Support for the following languages: (Although Google Translate doesn't support all of them)
Abkhazian, Afar, Akan, Amharic, Aragonese, Assamese, Avaric, Avestan, Aymara, Bambara, Bashkir, Bengali, Bihari,
Bislama, Breton, Burmese, Chamorro, Chechen, Chichewa, Chuvash, Cornish, Corsican, Cree, Divehi, Dzongkha, Ewe,
Fijian, Fulah, Guaraní, Haitian, Hausa, Herero, Hiri Motu, Interlingua, Interlingue, Igbo, Inupiaq, Ido, Inuktitut,
Javanese, Kalaallisut, Kanuri, Kashmiri, Central Khmer, Kikuyu, Kinyarwanda, Kirghiz, Komi, Kongo, Kuanyama,
Luxembourgish, Ganda, Limburgan, Lingala, Lao, Luba-Katanga, Manx, Malagasy, Marshallese, Nauru, Navajo, North Ndebele,
Nepali, Ndonga, Sichuan Yi, South Ndebele, Occitan, Ojibwa, Church Slavic, Oromo, Oriya, Ossetian, Panjabi, Pali, Rundi,
Sanskrit, Sardinian, Sindhi, Northern Sami, Samoan, Sango, Scottish Gaelic, Shona, Sinhala, Somali, Southern Sotho,
Sundanese, Swati, Tajik, Tigrinya, Tibetan, Turkmen, Tagalog, Tswana, Tonga, Tsonga, Twi, Tahitian, Uighur, Venda,
Volapük, Walloon, Wolof, Frisian, Yoruba, Zhuang
NEW: Exposed a variant of the LocalizationManager.ApplyLocalizationParams that can get the parameters from a function
NEW: Localization Target now use ScriptableObject to allow keeping extra parameters to setup the targets
NEW: Android devices now properly detect the Device Language Region (no longer using Unity's Application.SystemLanguage)
FIX: Two parameters in a single translation was failing if the length of the text was not the same
FIX: 'Missing' icon was not showing in the Term's list when in Unity 2017+
FIX: Compatibility with Window Store Apps and UWP
FIX: Support for multiple Localize component in the same GameObject
FIX: Increased the PostProcessBuild priority to avoid conflicting with other plugins
FIX: Assigning None to a Term translation's Object Field was ignored
FIX: LocalizationManager.OnLocalizeEvent now correctly releases all callbacks after finishing Play Mode in the Editor
FIX: Term list in language source was showing empty space for some seconds after unselecting a term
2.8.2
NEW: Improved the example scene: 'I2Localization features LocalizedString.unity'
NEW: Added a version of ForceTranslate to translate several texts at the same time
NEW: The translate/Translate All button will now skip terms that don't have type "Text" (avoid Materials, Fonts, etc)
NEW: Restored the translate button for each translation field, but this time it shows only "T" to still allow more space
NEW: Google Translate will now skip tags (e.g. [tag]..[/tag], <tag>..</tag>)
NEW: Google Translate skips any text inside [i2nt].ignored.text.[i2nt]. Those tags are also not used when rendering translations
NEW: Basic Hindi / Devanagari support
NEW: Optimized GC Allocations, removed runtime usage of Regex
NEW: By default, all scenes will be selected in the LanguageSource tools (Parsing, Renaming, Changing Category, etc)
FIX: Issue with some unity versions failing when Translate All/Export with an error related to 'Rewinding' the POST result
FIX: Issue where clicking the translate button was failing when terms source translation had & or similar symbols
FIX: Issue with some unity versions failing when Translate All/Export with an error related to 'Rewinding' the POST result
FIX: Issue where clicking the translate button was failing when terms source translation had & or similar symbols
FIX: Button "Translate All" will not longer override non-empty translations when input type is Touch instead of Normal
FIX: Play in Editor sometimes failed to localize when changing languages
FIX: Translating all terms to a language with a variant (e.g. en-CA) was failing
FIX: Example scenes had warning loading when the project was set to serialization: Force Text
FIX: Long Key names are now clamped to 100 characters in the terms list so that it doesn't get too wide
FIX: GoogleTranslate.ForceTranslate was not handling tags and parameters
FIX: LanguageSources in the scenes were not loaded inside the editor until they were clicked
FIX: Localize target AudioSource was not playing all the time
FIX: Selecting a different Target type in the Localize component was not updating correctly
FIX: Localization failed when there where empty slots in the Assets list (LangaugeSource) or References (localizeComponent)
2.8.1
NEW: Plural support with multiple Plural forms based on the target language
NEW: LocalizeDropdown now supports TMPro Dropdown
NEW: Adding a Term will automatically detect the Term type (e.g. Sprite, Font,...) (instead of always defaulting to "Text")
NEW: Google Translation will now generate translation for each plural form of the target language
NEW: New Term Type: Child (it enables the child GameObject with the name matching the translation to that language)
NEW: CharSet tool now has buttons to select all languages, clear or invert the selection
NEW: Right-To-Left and Modifiers sections in the Localize inspector will now only show if the term's type is 'Text'
NEW: Confirmation dialog before deleting a Language
NEW: Modified the WebService to support translation requests using POST. This increases the reliability of translating large data sets.
NEW: Added a close button to the Error message in the inspector.
NEW: When the Verify WebService fails, it will now display the error in the inspector
NEW: LocalizationManager.ApplyLocalizationParameters can now use Global, Local parameters or a dictionary of parameters
NEW: LocalizedString inspector now has a button that opens the LanguageSource to allow editing the term
NEW: The LanguageSource now has an option to decide if default Language will be Device Language or the first in the Languages list
NEW: LanguageSource's terms list now shows 3 dots (...) after the last term if some terms were hidden by the category filter
NEW: Sub Sprite Terms will now show the full path of the sprite (e.g. "Atlas.SpriteName")
DEL: Removed the "Translate" button next to each translation to allow for more space. Instead, use the "Translate All" in term/language
FIX: Term Type 'GameObject' now works as expected
FIX: IOS AppName Localization was not exporting languages with regions
FIX: Clicking the delete button ("x") of a disable button will now correctly delete it (no need to manually enable and then delete)
FIX: Google Translation will not longer fail silently when the target language is not supported by Google translate
FIX: Building Android Apps with a name including (') was failing
FIX: Sometimes when playing in editor, changing the language didn't localize all texts
FIX: Restored the GoogleTranslation.ForceTranslate (although its noted that it may fail in some unity versions having the www blocking bug)
2.8.0
NEW: Downloaded Spreadsheets at runtime are now saved into a file in the persitentData folder to avoid overflowing the PlayerPrefs
NEW: Example scene showing how to use LocalizedString
NEW: Localize component now has a checkbox (Separate Spaces) to add extra spaces to the languages that don't add them between words.
NEW: All saved translations are now encrypted by default, feel free to change the password in StringObfucator.cs for added security
NEW: ScriptLocalization is no longer built by default (to speed out compilation by avoiding checking all the time)
NEW: Instead of ScriptLocalization.Get(xx), it will be better to use LocalizationManager.GetTranslation(xx)
NEW: TermsPopup attribute now has an optional filter (e.g. [TermsPopup("Tutorials")] ). This change was contributed by @michael THANKS!
NEW: LocalizationManager.GetTranslation(Term, overrideLanguage="English") allows retrieving translations outside the current Language.
NEW: Tool PARSE now also detect script reference to LocalizationManager.TryGetTranslation("term")
NEW: Importing terms from Google will now remove invalid (Non-ASCII) characters from the Terms Name
NEW: Selecting the Language Code in the Languages Tab, now shows a more compact list with languages and variants as childs
NEW: When the localize component has a LanguageSource set as Source, it will only show the terms inside that source
NEW: Added a "Detect" button after the Source selection in the Localize component to find the LanguageSource containing the selected term
NEW: Added a confirmation dialog to the delete terms button
DEL: Deprecated old TextMeshPro_Pre53
DEL: Removed support for DFGUI (was removed from the AssetStore a while ago, if you still need support, please use I2Loc v2.7.0)
FIX: Localization targets are now AutoRegistering before the Awake function of the scene. This fixes issues with the LocalizeOnAwake flag
FIX: Export to Android was failing to create the correct Locale folders (i.e. values-en-rUS instead of values-en-US)
FIX: TextField used to filter the Terms List in the LanguageSource was not allowing Copy/Paste
FIX: Term's name can now include non-ASCII character as long as they are not controls (e.g. newline, tab, etc)
FIX: Android XML with the AppName will now properly escape the name if it contains XML-ilegal characters
FIX: Compatibility update for Unity 2017 when editor is set to .Net 4.6 (thanks to @nox_bello)
FIX: Tool PARSE was not detecting the correct term when ScriptLocalization.Get("xx", param1, param2) had 1 or more params
FIX: In some unity versions, compiling for UWP was throwing an exception when Google Live Sync was used.
FIX: Exporting Chinese Variants in ANDROID was failing because Android uses (zh-rXX instead of zh-XX) [thx to @fur contribution]
FIX: Disabling the last language in the LanguageSource list, was disabling some other UI controls outside that language
FIX: Realtime Translation example was failing when the I2Languages.prefab was not selected
FIX: TextField used to filter the Terms List in the LanguageSource will now not lose the focus when typing
FIX: When clicking Translate or Translate All int the editor, it was not showing the "Translating...." message
FIX: Translating texts with & was return wrong translations
FIX: Sometimes the inspector width was bigger than it had to be
2.7.0
NEW: To separate purposely empty translations from missing ones, the empty translations should be set to ---
NEW: Google Update Frequency can now be set to "OnlyOnce" to only download data from the Spreadsheet the first time the app is executed
FIX: OnMissingTranslation in the LanguageSource now is working as expected
FIX: Compatibility with Unity2017 was causing the editor to not find some EditorStyles and the Translate function was looping forever
FIX: Changing text alignment will not be reverted when switching languages
DEL: ForceTranslate is now removed, use the GoogleTranslation.Translate instead (because Unity 2017 doesn't run www in a separate thread)
2.6.12
NEW: When a term is not found, its translation will be null instead of "" to diferenciate that case from terms with empty translations
FIX: Terms with empty translations will change the label's text to empty.
FIX: Internal term "-" will not longer be shown in the LanguagesSources
FIX: Several errors when LanguageCode was invalid or only had 1 letter
FIX: Renaming terms in multiple scenes will now correctly save the scenes
FIX: Clicking the inspector to preview a language and then exiting the Localize inspector was only reverting the selected object
FIX: Corrected "RightToLeft Text Rendering" example scene (added names to the labels and made the buttons select the correct language)
FIX: RTL Line Wrap (when maxCharacters>0) will not longer add extra lines at the bottom
FIX: Language Source was downloading data from google when any delay was specified (even when the frequency was set to NEVER)
FIX: Building android on some MAC was failing to resolve the staging path
FIX: RTL languages will now be fixed correctly when surrounded by [] and other simbols
FIX: Compile error (about SceneManager) when running the game in 5.2 or older
FIX: Google Live Sync now will download the data, even if the scene is changed while the spreadsheet is been downloaded
FIX: New TextMeshPro not been detected because the DLL changed its signature
2.6.11
NEW: App Name can now be localized in both IOS and Android
NEW: Localize term now has two string fields to add a Prefix & Suffix to the translations (e.g. allows adding : at the end of the text)
NEW: Example of how to change the language using a Unity UI Dropdown (component SetLanguageDropdown) see the "uGUI Localization" Scene
FIX: IOS Store Integration now works automatically
FIX: Parsing terms was not updating the Term's Usage
FIX: Better support for arabic texts with tags
FIX: Previewing a language in the editor by clicking the Language name, will now respect the RTL or LTR direction depending on the language
FIX: Removed warnings in Unity 5.6
FIX: TextMeshPro not updating the font when using a material name in a subfolder of the Resources
FIX: TextMeshPro now wraps correctly texts from Right-To-Left Languages (e.g. Arabic)
FIX: CharSet tool will now correctly find what Arabic and other RTL characters are used (will apply RTLfix when adding the characters)
FIX: TextMeshPro (paid version, the one with the source code) was not been detected correctly
FIX: Translating a term inferring from Label's text, will no longer remove the non ASCII characters
FIX: Google Live Sync will now auto-update the scene texts without needing to change the current language
FIX: LocalizationManager.GetTermData will now call InitializeIfNeeded, which also now validates that there are sources available
FIX: Added validation for undefined BuildTargetGroup.Switch in 5.6
2.6.10
NEW: PlayMaker support (Actions: Get/SetCurrentLangauge, SetNextLanguage, Get/SetTerm, GetTranslation)
NEW: Button next to the plurals tab to show if the DisabledLanguages should show the translation or should be hidden
NEW: Massive inspector speed improvement when Parsing terms, selecting a LanguageSource, etc
NEW: LocalizationManager.ApplyLocalizationParams now accepts a general GameObject instead of forcing a LocalizeCmp. This allows using LOCAL parameters without localize component
NEW: added options for parameters when calling ScriptLocalization.Get(term, true, 0, false, applyParameters:true, localParamsRoot:gameObject)
NEW: Clicking a Translation in the Localize component will now Preview that language in the entire UI
NEW: Added a button at the top of the Term's List in the LanguageSource to refresh the translation shown in the Scene (calls LocalizeAll(true))
NEW: Menu option to also call the LocalizeAll (Menu/I2/Localization/Refresh Translations). This is useful if the translation is changed and should be updated in several UI elements
NEW: LocalizationManager.GetTermsList() now can have a parameter to only show the terms of that category (e.g. .GetTermsList("Tutorial"))
NEW: LocalizationManager.HasLanguage(..) and .GetAllLanguages(..) now has optional parameter SkipDisabled to skip disabled languages. Default=true
NEW: Build ScriptLocalization.cs tool now has a button to select the terms previously built
FIX: Disabling a language will skip it when selecting the startup language
FIX: Selecting a different LanguageSource will not longer set the categories to None, instead it will revert to Everything
FIX: Now the Scene can preview the translation of disabled languages. Just click in the language name next to the Terms's description (localize component OR language Source)
FIX: Compile errors when building for Windows Phone or WSA
FIX: Generating the files for the Store Integration (Android, IOS) was also exporting the disabled languages
FIX: Alignment option for TextMeshPro now works with the latest TextMeshPro version (v1.0.55.52 Beta 3)
FIX: LocalizationManager.LocalizeAll is now internally handled at the end of the frame (using a coroutine) to handle multiple localization in the same frame and timing issues when start Playing
FIX: A term will no longer show as missing translation (yellow + italics) if the missing translation belongs to a disabled language
FIX: ResourceManager.CleanResourceCache will now only be called when a level is loaded to avoid frame rate spikes in the middle of the game
FIX: Added support for the new TextMeshPro (free version)
2.6.9
NEW: AboutWindow will never open automatically, instead there will be an small warning next to the version number
NEW: LocalizedString (link to documentation)
NEW: Changing .NET CurrentCulture when the language changes is now optional. Its disabled by default and can be enabled by adding an AutoChangeCultureInfo component to your first scene
NEW: Terms can now be set to <none> to avoid localizing it (e.g. Don't localize Label's text, but do localize Label's font)
NEW: Languages can now be disabled (useful for having data columns in the spreadsheet) Just add a $ in front of the language name in the Spreadsheet or uncheck the toggle in the LanguageSource
NEW: Clicking the Language name next to the translations will preview the text in that language
FIX: Event_OnSourceUpdateFromGoogle is now called with ReceivedNewData==false whenever the languagesource is up-to-date
FIX: Auto-detection of plugins was not working correctly for IOS
FIX: Removed warning "Unsupported encoding: 'UTF-8,text/plain'" that was happening when translating a text
FIX: RTL fix was not been applied to Right-To-Left languages when EnableChangingCultureInfo was not called or false
FIX: Changing Category was not marking the scene Dirty
2.6.8
DEL: [i2auto] will not longer be used (if your spreadsheets have that, you should remove all [i2auto] texts and reimport to the LanguageSource)
DEL: Translations will not longer be marked as translated by google (this speed the import/export process)
NEW: When a term is not defined for some language, it can be set to display (Empty, Fallback or a Warning) The setting is in I2Languages.prefab Language Tab
NEW: Localize components will execute the Localization Callback even without a valid Translated Term.
NEW: When creating a term in the Localize component, the first language (e.g. English) will be auto-filled with the label's text
NEW: Added two more parameters to the callback when Import_Google finishes (Event_OnSourceUpdateFromGoogle(LanguageSource, bool ReceivedNewData, string errorMsg))
NEW: Selecting the checkbox next to the Term's list in the LanguageSource and then clicking the Term Usage button selects ALL objects using all the selected terms
NEW: Surrounding a text with the tag <ignoreRTL>, ignores converting it to RTL (e.g. "<ignoreRTL>2<ignoreRTL>. بدفع مبلغ")
NEW: New toggle (Ignore Numbers), next to the Max Line Length in the localize component, to automatically avoid converting numbers when parsing RTL texts
NEW: .NET CurrentCulture is changed based on the current language to make all culture-dependant operations to use the properties of the selected language
NEW: Detecting if the language is Right-To-Left will now be using the CurrentCulture settings as that maybe more precise
FIX: Right-To-Left languages will not adjust the alignment if the original alignment was CENTER
FIX: 2DToolkit now allows adjusting the alignment if the language is RTL
FIX: Add/Remove language was not marking the LanguageSource as dirty and the changes could have been getting lost
FIX: Copy/Paste a Localize component into a new GameObject will properly update the Target reference
FIX: If the WebService was set in a LanguageSource inside the scene and not in the I2Languages.prefab, Google Translate/Export/Import wasn't working.
FIX: Compile erors when using an old version of TextMeshPro (requiring TextMeshPro_Pre53)
FIX: Texts for Right-To-Left languages containing multiple lines was showing extra lines when using \r\n for new lines
FIX: LanguageSourceData.Import_Google was not executing when Auto-Update was set to NEVER (even if ForceUpdate was true)
FIX: Accessing www.text was returning an Encoding error in the latest patch releases (5.4.1p3 and 5.3.5p7)
2.6.7
NEW: SpriteRenderer can now be localized
NEW: Translations can have Parameters (e.g. "The winner is {[WINNER}]") and at runtime the tag is replaced by its value by using a local or global parameter
NEW: Local parameters can be set by adding a LocalizationParamsManager component to the gameObject, and it has a list of parameters (i.e. <Name, Value> pairs)
NEW: Global parameters can be set by adding a ILocalizationParamsManager class to the LocalizationManager.ParamsManager list
NEW: Example Scene named "Callbacks and Parameters" showing how to modify the translations using Callbacks, Local Parameters and Global Parameters
NEW: Unity UI Dropdowns can be localized by adding the LocalizeDropdown component
NEW: Localized objects (Textures, sprites) can now be loaded from a bundled by registering a ResourceManager_Bundles (see RegisterBundlesManager.cs example)
NEW: ScriptLocalization.Get(term) will now automatically fix it for RTL if the current language is Right-To-Left (use .Get(term, false) to avoid that)
NEW: Parse Terms in Scripts will now match terms in the form "LocalizationManager.GetTranslation" as well as "ScriptLocalization.Get"
NEW: ScriptLocalization.cs is now autogenerated to avoid overriding existing localizations. That file is also now moved into the Assets\I2 folder
NEW: Localize component now has a toogle "Force Localize" that should be true when the translation has parameters to force the localization when the object is enabled
NEW: Tool CharSet now has a button "Copy To Clipboard"
NEW: Local parameters SetParameterValue function now has an optional parameter to skip the localization (useful when setting several parameters in a frame)
NEW: LocalizationParamsManager.OnLocalize() executes the localization with the parameters previusly set.
FIX: Auto-Sync from Google Spreadsheet was not detecting the new versions correctly and wasn't loading from the cache.
FIX: Right-To-Left texts will now correctly handle ritch-text tags (e.g. <color=red>..</color> and [FF0000]..[-], etc)
FIX: Expanding/Collapsing the Terms, References or OnLocalize Callback in the Localize component is now remembered
FIX: Changing <none> in the terms selection list by <inferred from text> as thats more understandable
FIX: Selecting <inferred from text> from the list of term will use the Inferred one.
FIX: Selected Term is now drawn in a light Yellow when it is inferred (previously was dark yellow and wasn't as visible in the Editor Light Theme)
FIX: Renamed button at the bottom of the terms description to make it more understandable. From "Merge" to "Rename".
FIX: When clicking that Merge button, the current term is automatically selected as the term to rename
FIX: Exporting a csv file with auto-translated terms containing (,) was generating extra columns with "[i2auto]".
FIX: ParseTerms in scripts was not detecting the term when the function had spaces (e.g. ScriptLocalization.Get ( "term" ))
2.6.6
NEW: Allow multiple Localize component in the same object
NEW: TextMesh Pro localization when changing material (e.g. "ARIAL SDF - Outline") will now also find and use the corresponding font (e.g. "ARIAL SDF")
NEW: Added a Delay to the Auto-update from Google to wait some time before updating. To prevent a lag on startup
NEW: Exporting to a spreadsheet will sort the terms
NEW: Charset Tool allows adding upper and lower versions of characters even when one character variant is not found
FIX: Empty languages can not longer be added by clicking the "Add" button
FIX: Columns with empty language name in Google Spreadsheet or CSV files are now skipped
FIX: Sometimes when playing in the Devices, I2 Localization was using old localization data from PlayerPrefs
FIX: Google Live Synchronization was not detecting correctly the Spreadsheet changes
FIX: Removed a debug log that was printing the entire content of the downloaded spreadsheet, making the log file hard to read
FIX: Removing a Term from the LanguageSource was still displaying it in the Terms List even though they werent there anymore
FIX: Compile warning related missing BuildTargetGroups when detecting installed Plugins
FIX: Translation of UPPERCASE texts are now handled correctly
FIX: Categories/terms matching part of another category will export correctly (e.g. TUTORIAL and TUTORIAL1\Welcome)
FIX: I2 About Window will not longer shown when doing a build or when in batch-mode
FIX: Texts starting with a tag (e.g. [xxx]) are now accepted (useful for NGUI color tags)
2.6.5
(requires a new WebService: v4)
NEW: Localize.Term = xxx works now the same that executing Localize.SetTerm(xxx)
NEW: Importing a big Spreadsheet is 20-70 times faster than before
NEW: Added a Translate button next to each language to bulk Translate all missing terms for that language
NEW: Tool to find which characters are used in the languages (useful to create bitmap fonts)
NEW: Adding a term to a Language source without languages, will automatically create "English"
NEW: NGUI and TextMeshPro example scenes now also show changing Fonts based on the language
NEW: Viewing a big LanguageSource is now smoother even when seeing several thousands terms.
NEW: Added a dropdown menu to select the File Encoding (UTF8, ANSI, etc) of the local CSV file
NEW: Use of the WebService to get the Google Translations (previously it was a hack that parsed the google web but failed whenever google changed their look)
FIX: Translating Terms was skipping the first 2 letters
FIX: Translating text with Title Case (This Is An Example) was failing with google
FIX: Translation using Term Category (Tutorial/New Example)
FIX: Removed delay when selecting languageSources caused by the parsing of terms in scripts, now scripts are only parsed when using the Parse Scripts Tool
FIX: TextMeshPro labels will auto-size correctly when switching languages
FIX: 2D Toolkit example scene was corruptedLoca
FIX: localizeComponent: Button "Add term to Source" for a secondary Term will add the term to the source containing the primary term.
FIX: Selecting "None" as a referenced object will no longer produce a null reference exception
FIX: Errors reporting that DontDestroyOnLoad can only be called in Play mode
FIX: Errors when some referenced asset was destroyed and the plugin tried to release it
2.6.4
NEW: SVG Importer has been integrated (support for SVGImage and SVGRenderer: localizes VectorGraphic and Material)
NEW: Updated to support TextMeshPro 5.2 beta 3.1 (previous versions need to change TextMeshPro by TextMeshPro_Pre53 in the scripting define symbols)
NEW: I2Languages.prefab has been moved to I2/Resources to make update easier (just delete I2/Common and I2/Localization and import the new package)
NEW: The spreadsheet will not be auto-downloaded when running in the editor as the local language source its supposed to be the most up-to-date
NEW: Better compatibility with UnityScript (added method versions to avoid default parameters, still needs to move I2L to the Plugins folder)
NEW: Inferred terms will be changed to normal terms as soon as a matching term its found
NEW: Added variables LocalizeManager.CurrentRegion and .CurrentRegionCode to get the region part of the language (e.g. "en-US" -> "US")
FIX: When re-starting the game after downloading a modified spreadsheet, it was loading the old translations
FIX: Error shown in the console when playing the game in the editor while a Localize component its shown in the Inspector
FIX: Parsing scenes failed on Unity 5.3+ when scenes where not in Assets folder
FIX: Adding a localize term before adding a target (TMPro label, UI Text, etc) failed to get the inferred Term
FIX: Selecting a Term in the localize Secondary Terms Tab, was changing the label's text to the name of the font/atlas
FIX: TextMeshPro was producing warnings regarding materials when previewing different fonts in Editor and not in Playing mode
FIX: Marking scene dirty when Localize callback and other variables are changed
FIX: Button "Add Term To Source" in the localize inspector was sometime adding the term to the wrong LanguageSource
FIX: Selecting <inferred from text> from the term's list made that option disapear the next time the popup was openned
FIX: IOS integragion will now correctly generate Info.plist instead of info.plist
FIX: When copying a Localize component and pasting it in other object will no longer keep a reference to the previous object
2.6.3
NEW: IOS Store Integration (adds the languages to the Info.plist file)
NEW: If the localize component, can find its inferred term in a source, it will use that term and stop inferring it
NEW: When adding a term to a source, the scene is parsed and every object inferring that term will start using it
NEW: In LanguageSource inspector, button "Add Terms" and "Remove Term" will use the selected term even if it doesn't have the checkbox ticked
NEW: When auto-generating ScriptLocalization.cs, if the file was moved, the plugin finds it and regenerate it in the new location
NEW: Non printable/special characters in the Terms name are removed from inferred terms to increase legibility
NEW: On the Terms list, the buttons at the bottom (All, None, Used, Not Used, Missing) now select from the visible terms not the full list.
NEW: Button "Show" next to each Language in the LanguageSource to preview all LocalizeComponents in that language
NEW: Clicking on a translation previews how it looks, but selecting another object will now stop the preview and revert to the previus language
FIX: Compile error in TitleCase(s) when building for Windows Store
FIX: Android Store Integration was using a wrong path and now all generated files are in Plugins\Android\I2Localization
FIX: Textfield used to type the new category now allows typing \ and / to create subcategories
FIX: On the Terms list, the filters (Used, NotUsed, Missing) will now work correctly with categorized terms
FIX: Improved performance on the LanguageSource and Localize inspector. Now selecting a big languageSource its around 4 times faster
2.6.2
NEW: Plugin now supports Unity 5.3
NEW: Android Store Integration (adds strings.xml for each language so that the store detects the application is localized)
NEW: When editing a term, Translate and Translate All buttons will translate the Label's text instead of the Term name
NEW: Tool to find No Localized objects now saves the Include and Exclude filters
NEW: Added a Refresh button on top of the Terms list to quickly parse all localized objects in the scene
FIX: Alignment will not revert to "Left" when switching languages. RTL languages will still be adjusted correctly.
FIX: Parse terms was not detecting inferred terms used in Localize components that were not previously opened in the inspector
FIX: Importing spreadsheets with auto-translated terms having multiple lines was adding extra quotes.
FIX: Google translate Language code of all chinese variants was updated to the right code
FIX: Changing Term Categories or Renaming it will now update the language Source
FIX: Add button (+) after the Terms list is now always at the end of the terms, even when a term is expanded
FIX: When changing category in a term that its not in the source, it will display an error box showing why it fails
FIX: Sometimes the Resources folder failed to be created if it was previously created (when generating I2Languages.prefab)
FIX: TextField to edit the Term's description and translation has word wrap enabled to avoid expanding the inspector on long lines
FIX: Vertical scrollbar in the Terms list will now hide when all terms fit in the screen
DEL: Removed checking for installed plugins when scripts are compiled (will only happen at startup or if force from the menu)
2.6.1
NEW: Multiline texts can be fixed correctly for RTL languages by specifiying the maximum line length (Localize Inspector)
NEW: Added a checkbox to the Localize Inspector to allow changing alignment for RTL Languages (Right when RTL, Left otherwise)
NEW: Adding API for accessing translated objects: (LanguageSource and Localize).AddAsset, .HasAsset, .FindAsset
NEW: Localize.FinalTerm and .FinalSecondaryTerm are now public variables that can be used in the OnLocalizationCallback
FIX: Switched loc order of Main and SecondaryTerms to localice the text/sprite after the font/atlas was changed
FIX: Editor UI for the Terms translation was overflowing.
FIX: Automatically Importing from Google will not longer clear the localization data
FIX: Faster startup by avoding calling LanguageSourceData.UpdateDictionary multiple times
DEL: Projects using Unity new UI no longer have to add UGUI to their Scripting Define Symbols
DEL: Projects using TextMeshPro no longer have to add TMProBeta to their Scripting Define Symbols
DEL: Cleaned some variables in the Inspectors that were not longer needed
Thanks to 00christian00 and vicenterusso for their contributions!!
2.6.0
NEW: Localize component now has a "Translate ALL" button
NEW: Term can be flagged as "translated by human" or "translated by Google Translator"
NEW: The Callback in the Localize component now show all public methods of ALL monobehaviors in the Target object
NEW: Tool 'Parse Localized Terms" now allows searching for term usage in the SCENES and in the SCRIPTS
NEW: Localize was optimized to avoid localizing every time the component is enabled
NEW: Localize has now a setting for Pre-Localize on Awake or for waiting until the object is enabled.
NEW: Downloading from google uses now a custom format instead of JSON to avoid parsing errors
NEW: Method LocalizationManager.FixRTL_IfNeeded(string) does RTL fixing if the current language is RTL
NEW: TermsPopup attribute was added to display a string as a popup with the list of terms
FIX: The Plugin Manager window now allows op-out of automatic notification whenever there is a new version.
FIX: Tools tab now shows error messages and warnings
FIX: Corrected compile errors regarding ambiguous calls that happened on some projects/platforms
FIX: Fixed compile error when building for METRO about missing ToTitleCase method in the CultureInfo
FIX: NGUI LanguagePopup component now starts with the saved language instead of the first one in the list
FIX: Chinese Simplified/Traditional are now correctly detected when running on the device
FIX: SetTerm was failing when called on a disabled Object
Thanks to tacticsofttech for its contribution to the Parse terms in Scripts!!
2.5.0
- NEW: Terms can now have separated translations for Touch devices. This allows specifying "tap" instead of "click"
- NEW: Increased performance when browsing the terms list in the Language Source
- NEW: Add a new version to the required Google Service
- NEW: Localize can modify case not only to UPPER and lower but to UpperFirst("This is an example") and to Title ("This Is An Example")
- NEW: Scenes List in the Tools tab can now be collapsed
- FIX: Google Translation was failing for some strings with mixed or title casing e.g. ("Not Enough Rope" was not translating)
- FIX: SetLanguage component Inspector was not showing. Now it displays a dropdown to select the language
2.4.5
- NEW: Import/Export CSV files now supports changing the separator character (Comma, Semicolon, Tab)
- NEW: The Localization is now initialized when calling HasLanguage to allow changing the language before requesting any Translation
- NEW: The tool to bake the terms into ScriptLocalization.cs now replaces invalid characters by '_'
- NEW: Terms in ScriptLocalization.cs can now be clamped to a maximum length, Terms that clash are enumatated (Examp_1, Examp_2)
- NEW: When creating languages, those with a variant didn't list the base language, now the list includes the base (e.g English)
- NEW: All languages in the Add Language popup show the Language Code for easier identification
- NEW: Not all international language codes are supported by Google Translator. A fallback language is now provided for those.
- FIX: Translating to some languages by using the "Translate" button on the Localize component was failing for some languages
- FIX: When the Language Source had lot of languages, the Terms list was sometimes displayed empty when scrolling
2.4.4
- NEW: Menu: Tools\I2 Localization\About opens a window showing if there is a new version and has shortcuts to useful information
- NEW: Whenever there is a new version the editor automatically alert you. There are options to opt-out or skip a version
- NEW: Clicking the Translate button next to the Term translations will now use the Term name if no other translation is found
- NEW: Language Source Inspector has now better performance showing the list of terms, languages and scenes
- NEW: The list of languages in the Language Source inspector is now expanded to cover the available space
- NEW: LocalizationCallback can now access the static variables CallBackTerm, CallBackSecondaryTerm, MainTranslation, SecondaryTranslation
- FIX: No longer need to call LocalizationManager.UpdateSource and UpdateDictionary before using LocalizationManager.GetTermsList()
- FIX: NGUI example scene had missing references as the example NGUI atlas changed
- FIX: The UpgradeManager was failing on Unity 5 when accessing the BuildTargetGroup.Unknown
- FIX: Importing from CSV and Google Spreadsheets was ignoring the Language Codes and merging those with identical name
2.4.3
- NEW: Localizing UGUI sprites now supports sprites of type "Multiple"
- NEW: Menu Options to disable/enable auto plugins detection (menu: Tools/I2 Localization/Enable Plugins/...)
- FIX: Using Localize.SetTerm(term) on the Start or Awake functions will not get reverted to the default value
- FIX: Checks for when Localizing prefabs but the referenced objects are not found.
- FIX: Added support for Unity 5.0.0f3
2.4.2
- NEW: Added an optional bool to allow fixing for RTL when using translation = ScriptLocalization.Get(xxx, true)
- FIX: Realtime translation was failing on some mobile devices
- FIX: Fix error when localizing not empty or non existing terms(this caused Sprites and other Secondary Translations to fail)
- FIX: Terms are now saved after importing them from google
2.4.1 f2
- NEW: ScriptLocalization.cs and I2Language.prefab are now autogenerated so they will not override existing localizations
- NEW: The plugin now detects when using TextMeshPro or TextMeshPro beta, and adds a conditional TMProBeta if the beta is used
- NEW: Local Spreadsheets can now be saved as CSV or CSV renamed as TXT (this last avoids the Unity crash when on Mac)
- FIX: OnLocalize Callbacks were not called inside the IDE.
- FIX: Errors when compiling to WebPlayer
2.4.0
- NEW: Added support for multiple Global Sources. By default is only "I2Languages" but you can add any other in LocalizationManager.GlobalSources
- NEW: Dynamic Translation work now in the game by using Google Translator to translate chat messages and other dynamic texts.
- NEW: Localize component will detect automatically which sources contain the translation for its term
- NEW: Tool "Find No Localized Labels" can now filter which labels to include/exclude
- NEW: There is now a button to unlink the Google Spreadsheet Key
- NEW: Added quick links in the Source and Localize inspector to access the Forum, Tutorials and Documentation
- NEW: Google WebService now has a version number and the plugin will detect if that version is supported and ask you to upgrade
- FIX: Compile errors that prevented compiling for W8P and METRO
- FIX: Adding a Localize component at run time will now initialize its variables correctly
- FIX: Renamed some Example scripts to avoid conflicts. Also added them to the I2.Loc namespace
- FIX: When secondary translation is not set, it will take the value from the object (e.g. Font Name, Atlas, etc)
- FIX: Tool "Find No Localized Labels" now work with TextMesh, TextMeshPro, UI.Text, etc.
- FIX: Avoided creating multiple PlayerPrefs entries for the same language Source (LastGoogleUpdateXXXX)
- FIX: No longer is possible to rename/create a term if the new term already exists.
- DEL: The console message saying that no terms were found in the scene is now removed and only shown as part of the inspector
2.3.2
- NEW: import CSV fill autodetect if the Type or Desc columns are missing
- NEW: SpriteCollection shows now in the Type List in the editor for TK2D
- NEW: Added callback for when a language source is autodated from Google (Event_OnSourceUpdateFromGoogle)
- NEW: Increased translation lookup speed by using a fast string comparer in the dictionary
- NEW: Added a toggle in the Language Source to allow lookup the term with Case Insensitive comparison
- FIX: Terms list on the source will not longer cut off visible elements
- FIX: LoalizationManager.GetLanguageFromCode was returing the code instead of the language name
- FIX: Localization is now skipped if the Main and Secondary translations aren't changed
2.3.1
- NEW: Support for TextMeshPro UGUI objects
- NEW: Auto Update from google spreadsheets can now be set to ALWAYS, NEVER, DAILY, WEEKLY, MONTHLY
- NEW: Added functions to get/change the language based on the language code
- NEW: Added functions TryGetTranslation to both LocalizationManager and LanguageSource
- NEW: Language is now only remembered if the user changes it manually and ruled by the device language otherwise.
- FIX: The plugin is now Initialized automatically when requesting a translation or language code
- FIX: Changing the term category was not displaying correctly until the project was reopened
- FIX: Exporting to google as "Add New" was changing the order of languages
- FIX: Compile errors that prevented deploying to Windows Store
- FIX: The editor was not allowing to add language regions (e.g. English (US), English (CA))
- FIX: Auto Update Google dropdown box was not rendering correctly on all screen sizes
2.3.0
- NEW: Google Synchronization now uses a Web Service to avoid using the username/password
- NEW: When playing (even on a device) the game will download the latest changes to the spreadsheet
- NEW: Added support for both the "Classic" and new Google Spreadsheets
- NEW: Button to create a new spreadsheet
- NEW: Importing/Exporting to Google is now an Async operation that doesn't lock the editor and can be canceled
- NEW: Next to the Google Spreadsheet Key there is now a button to open it in the browser
- NEW: Google Import/Export tab will be the default (instead of local file) whenever a spreadsheet Key is set
- NEW: Import/Export can now be set to Replace all Terms, Merge or only add the New Terms
- NEW: A warning is now shown when using a LanguageSource other than the recommended I2Languages.prefab
- NEW: Menu option to open the Global Source I2Languages.prefab (Menu : Tools/I2/Localization/Open GLobal Source)
- NEW: Google Spreadsheet now has a new format, where the description and term type are defined as notes
- FIX: When switching terms or tabs the textfields will not longer keep the previous text
- DEL: Removed support for the old NGUI TextAssets as NGUI has moved into CSV files
- DEL: Removed Google API libraries dependencies
- DEL: The spreadsheet Key is no longer needed. The web service will get all the keys and allow you to select
2.2.1 b1
- NEW: Improved Language Recognition. It will now fallback to any region of the same Language
- NEW: Right To Left text rendering example scene
- NEW: DFGUI labels and buttons will be able to localize dynamic and bitmap fonts
- NEW: UI.RawImage Localization
- FIX: UI.Sprite Localization was not loading the Sprite from the Resource folder
- FIX: Up and Down arrows on the Languages list was not ordering the languages
- FIX: Detection of Unity UI (updated to 4.6)
- FIX: Unity UI example scene now uses the 4.6 UI classes
- FIX: Right To Left languages was not detected because the language code wasn't being applied
2.2.0
- NEW: Added support for TextMeshPro
- NEW: Terms can now have category and subcategories (e.g. Tutorials/Tutorial1/Startup/Title)
- FIX: NGUI is now detected by looking for the NGUIDebug class instead of UIPanel
2.1.0 f1
- NEW: After importing CSV or Google Spreadsheets, the category filter is set to show every term
- NEW: Terms list is now fully expanded on the Language Source
- NEW: Localize Component now has an Option to convert to (Upper, Lower, DontModify) the translations
- FIX: Validations for when importing Spreadsheets with empty columns/languages
2.1.0 b3
- NEW: The plugin is now compatible with Unity 5 (up to alpha 11)
- NEW: Register a function in the event LocalizationManager.OnLocalizeEvent to get called when the language changes
- FIX: Updated the example scenes to use the new Language Sources
- FIX: Terms are now saved correctly after importing a CSV or a Google Spreadsheet
- FIX: Allowed methods with one argument to be used as Localization CallBacks
- FIX: SelectNoLocalizedLabels was running every frame after executed
- DEL: Removed button to select CSV file. Now the Import and Export buttons display the open/save dialog
2.1.0 b2
- FIX: W8P and Metro compatibility
- FIX: Compiler warnings
2.1.0 b1
- NEW: Terms database is now saved within the LanguageSource and not a separated Language Files
- NEW: The selected language is now saved to the PlayerPrefs into "I2 Language"
- NEW: On the Localize Component, creating a key shows a list of terms as you type and their usage
- NEW: On the Localize Component, when changing the translation of a term shows a preview in the target (label/etc)
- NEW: When selecting a Term in the Localize Component, the list can be filtered with the Create Term string
- NEW: On the Localize Component, the Terms List is now sorted Case Insensitive
- NEW: The auto-enable Plugins will set the Script Define Symbols for ALL platforms (IOS,Android,Web,etc)
- NEW: In the Localize Component, the textField thats used for create a key now has a clear button to easy editing
- NEW: If a term is not found when localizing an object the object is left untouched (Previously labels got empty)
- NEW: There is now a button in the Localize Component to quickly rename a Term in the current scene
- DEL: Removing the Editor Databased used to cache the Language Files because all the info is now in the LanguageSource
- FIX: Selecting the CSV file to export will now allow you to create a new file
- FIX: Added a message to explain when exporting fails because the file is Read-Only or its open in other program
- FIX: When exporting to a file inside the project, the "Assets/" section was been skipped
- FIX: Import and Export CSV files now also works on when the editor is set to Web Player
- FIX: Exporting CSV now uses UTF8 encoding to keep special characters
- FIX: The "Open Source" button on the Localize Component now selects the Primary or Secondary term based on the selected tab
- FIX: Terms are now trimmed because spaces at the end/beggining can lead to confusions
- FIX: The list of terms was not showing correctly when selecting MISSING but unselecting USED
2.0.3 f1
- NEW: Support for localizing 2D-ToolKit (TextMeshes and Sprites)
2.0.3 b2
- NEW: When more than one localization type is available, the plugin allows you to select which component to localize
- FIX: When localizing secondary elements (Atlas, Fonts) the system checks that they still exist to avoid null exceptions
- FIX: Localization of Prefab now have the lowest priority to easy localizing labels/sprites with childs
2.0.3 b1
- NEW: The plugin will now check and enable by default all Plugins included in the project (NGUI,DFGUI,UGUI)
- NEW: Global Localization Source (I2Languages) its now empty by default to make it easy to start a new project
- FIX: Moved the Terms used in each example scene to a new Language Source inside each scene
- DEL: Removed Resources.UnloadAsset when changing the localization to avoid unloading referenced assets
2.0.2 f1
- NEW: UIFonts fonts can now be localized on NGUI
- FIX: Some example scenes were corrupted
- FIX: Modified the plugin to be compatible with Unity5
2.0.1 f1
- NEW: When an object is set as a translation, the object is also added automatically to the Reference array
- FIX: Importing from Google Spreadsheets will not longer generate 'Description' as a language
- FIX: The editor will show a message if exporting to Google fails
- FIX: The variable is IsLeft2Right was renamed as IsRight2Left to match its behavior
- FIX: Importing Google Spreadsheets no longer duplicate the languages
- FIX: Importing CSV was skipping some languages and not parsing terms after import
- FIX: Converted encoded translations into its ASCII characters ("Il s\x26#39;agit" -> "Il s'agit")
- FIX: Terms Section in the Localize custom editor can be collapsed
- FIX: Localize custom editor becomes more compact and easy to read when several sections are collapsed
- FIX: Expanded Terms in the Terms Tab of the LanguageSource will display an Arrow to make evident that they can be collapsed
- FIX: Terms description is now collapsed automatically when another term is selected
- FIX: The spreadsheet was been opened in the browser even if the Open Spreadsheet after Export flag was disabled
2.0.0 a2
- NEW: Support for languagges using Right To Left (RTL) with correct rendering for Arabic languages.
- NEW: Added a toggle on the Localize component to allow discarding RTL processing for selected objects.
- NEW: Languages can now have a Language code to allow for Language Regions (e.g. English Canada vs English United States)
- NEW: Automatic Translation using Google Services will use the language code instead of the Language Name
- NEW: CSV and Google Spreadsheets will save the language code if needed
- FIX: When adding a language to a source the editor will not switch to the Terms tab. That to allows adding several languages at once.
- FIX: Menu options was moved from "Menu > Assets > I2 Localization" to "Tools > I2 Localization"
- FIX: Localization Manager will not allow changing to a language that doesn't exist
2.0.0 a1
- NEW: Support for Daikon Forge GUI components
- NEW: Support for uGUI as of the Unity 4.6 beta 2 (this is only available for users in the beta test group)
- NEW: Terms can now have a type (Text, Object, Audio, Font, Sprite)
- NEW: Terms can be set to generate the ScriptLocalization.cs for Compile-Time-Checking of used Terms.
- FIX: Changed the Terms preview based on the Term Type
- FIX: Language Sources can now be in the Resources folder, the scene or bundled
- FIX: Component Localize allows to change the target for localizing more than one component in one GameObject
1.8.0
- NEW: Callbacks can be setup on the editor for correct concatenation according to the language
- NEW: Event system for callbacks with reflection
- NEW: Moved all localization calls into events for localizing more types of components without much code change
- FIX: Moved NGUI and UnityStandard localization code into separated files to minimize dependencies
1.7.0
- NEW: Localize component has now Primary and Secondary Terms
- NEW: Secondary term allows localizing Fonts on Labels
- NEW: Secondary term allows localizing Atlas on Sprites
- NEW: Support for localizing Prefabs
- NEW: Support for localizing GUITexture
1.6.0
- NEW: Added separated components to localize labels and sprites to remove the dependency with the NGUI localization
- NEW: Support for localizing Audio Clips
- NEW: Support for localizing GUIText
- NEW: Support for localizing TextMesh
1.4.0
- NEW: The filter on the Terms list can now have multiple values (e.g. "Tuto;Beg" will show only the terms containing "Tuto" or "Beg"
- NEW: Added References to the UILocalize component to be able of store not only text but also objects
- FIX: UILocalize will now show the Localization source it references
1.3.0
- NEW: Languages can now be moved up and down to organize them
- NEW: Allowed to filter by category on the Terms list
- FIX: First language in the list becomes now the starting/default language
1.2.0
- NEW: Merged Import and Export tabs to allow for external data sources that could be synchronized
- NEW: Ability to categorize Terms to improve organization (e.g. Tutorial, Main, Game Screen, etc)
- NEW: Each term category exports into a separated sheet when linking to Google Spreadsheets
- NEW: Parsing scenes for changing the category on selected terms
1.0.2
- FIX: Improved performance on the inspector by removing unneeded Layout functions
- FIX: General Code Cleanup
1.0.1
- NEW: Custom Editors now allow Undo the changes on the keys and startingLanguage
- FIX: Removed testing Log calls
1.0.0 f2
- FIX: Parsing scenes was executed several times in a row or not at all.
- FIX: Importing CSV will now parse the current scene to show Key Usages
- FIX: A message is shown when Selecting All No Localized labels in scene, if there are none
- FIX: Clicking on the usage number of unused keys will not try to select them
- FIX: Merging Keys will save scenes to avoid loosing changes
- FIX: Sometimes exporting without saving made changes to be lost. Now it automatically saves data if needed.
1.0.0 f1
- NEW: The language TextAsset will be shown in the Language list instead of just the name. That allows finding the asset, moving it to another folder, etc
- NEW: Languages can now be also added by dragging a TextAsset into the Add Language bars.
- NEW: Keys that are are missing the translation in any of the languages are highlighted in the Keys List by making them Italic and Darker
- DEL: Removed button Update NGUI in the Key list. All data will be saved automatically when the inspector view changes to another object or the editor is closed
- FIX: Filter for list of keys now is case insensitive.
- FIX: Auto opening google Spreadsheet after export was opening two web pages.
- FIX: Deleting a language will not only unlink the TextAsset from NGUI but will also delete the text file.
- FIX: If a TextAsset is manually deleted, but NGUI still keeps a reference in the language list, that language is now skipped
- FIX: Removed compile warnings when in WebPlayer platform
- FIX: Removed exception when adding keys before creating a language
- FIX: Adding multiple keys to NGUI was only adding the first one and returning an exception
1.0.0 b2
- NEW: Added a TextField to filter the list of keys.
- NEW: Option to auto open the Google Spreadsheet doc after exporting.
- NEW: Added a centralized Error reporting.
- NEW: Option to save or not the google password.
- NEW: Added a menu option to quickly access the help. (Help\I2 Localization For NGUI).
- NEW: Key list show a warning icon on the keys that are used in the scenes but are not in the NGUI files.
- FIX: An error will show when contacting Google Translation on the WebPlayer Platform as its not yet supported.
- FIX: Google public spreadsheet Key is now remembered when the editor opens.
1.0.0 b1
- NEW: First Version including core features.

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: b559e47b4c944104abfbfb9c64dc13bc
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,133 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &561847519761816000
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 561847519761816003}
- component: {fileID: 3465988004208473039}
- component: {fileID: 2606167641356688314}
- component: {fileID: 7815891630391582316}
m_Layer: 0
m_Name: I2LocalizationSourceManager
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &561847519761816003
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 561847519761816000}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &3465988004208473039
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 561847519761816000}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 488051eaa73ba421e8fe4868f2e0f364, type: 3}
m_Name:
m_EditorClassIdentifier:
mSource:
UserAgreesToHaveItOnTheScene: 0
UserAgreesToHaveItInsideThePluginsFolder: 0
GoogleLiveSyncIsUptoDate: 1
mTerms: []
CaseInsensitiveTerms: 0
OnMissingTranslation: 1
mTerm_AppName:
mLanguages: []
IgnoreDeviceLanguage: 1
_AllowUnloadingLanguages: 0
Google_WebServiceURL:
Google_SpreadsheetKey:
Google_SpreadsheetName:
Google_LastUpdatedVersion:
Google_Password: change_this
GoogleUpdateFrequency: 3
GoogleInEditorCheckFrequency: 2
GoogleUpdateSynchronization: 1
GoogleUpdateDelay: 0
Assets: []
Spreadsheet_LocalFileName:
Spreadsheet_LocalCSVSeparator: ','
Spreadsheet_LocalCSVEncoding: utf-8
Spreadsheet_SpecializationAsRows: 1
version: 1
NeverDestroy: 0
UserAgreesToHaveItOnTheScene: 0
UserAgreesToHaveItInsideThePluginsFolder: 0
GoogleLiveSyncIsUptoDate: 1
Assets: []
Google_WebServiceURL:
Google_SpreadsheetKey:
Google_SpreadsheetName:
Google_LastUpdatedVersion:
GoogleUpdateFrequency: 3
GoogleUpdateDelay: 5
mLanguages: []
IgnoreDeviceLanguage: 0
_AllowUnloadingLanguages: 0
mTerms: []
CaseInsensitiveTerms: 0
OnMissingTranslation: 1
mTerm_AppName:
Spreadsheet_LocalFileName:
Spreadsheet_LocalCSVSeparator: ','
Spreadsheet_LocalCSVEncoding: utf-8
Spreadsheet_SpecializationAsRows: 1
Google_Password: change_this
GoogleInEditorCheckFrequency: 2
--- !u!114 &2606167641356688314
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 561847519761816000}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 6cab7ade402b47a59bac4364f126f5e2, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!114 &7815891630391582316
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 561847519761816000}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 0753327e2b611cc42973dd09c0267034, type: 3}
m_Name:
m_EditorClassIdentifier:
serializationData:
SerializedFormat: 2
SerializedBytes:
ReferencedUnityObjects: []
SerializedBytesString:
Prefab: {fileID: 0}
PrefabModificationsReferencedUnityObjects: []
PrefabModifications: []
SerializationNodes: []
m_LanguageSource: {fileID: 3465988004208473039}
m_UseRuntimeModule: 0
m_DefaultLanguage: Chinese

Some files were not shown because too many files have changed in this diff Show More