├── ReadmeSource ├── preview.png ├── preview1.png ├── preview2.png ├── preview3.png ├── preview4.png ├── preview5.png ├── preview6.png ├── preview7.png ├── preview8.png ├── preview9.png ├── preview10.png ├── preview11.png ├── preview12.png ├── preview13.png ├── preview14.png ├── preview15.png ├── preview16.png ├── preview17.png ├── preview18.png └── preview19.png ├── Assets ├── LocalizeService │ ├── Demo │ │ ├── Demo.unity │ │ ├── Demo.unity.meta │ │ ├── LocolizeTest.cs.meta │ │ └── LocolizeTest.cs │ ├── Tutorial Localization Service.pdf │ ├── Scripts │ │ ├── Editor │ │ │ ├── libs │ │ │ │ ├── Newtonsoft.Json.dll │ │ │ │ ├── Google.GData.Client.dll │ │ │ │ ├── Google.GData.Documents.dll │ │ │ │ ├── Google.GData.Extensions.dll │ │ │ │ ├── Google.GData.Spreadsheets.dll │ │ │ │ ├── Google.GData.AccessControl.dll │ │ │ │ ├── Newtonsoft.Json.dll.meta │ │ │ │ ├── Google.GData.Client.dll.meta │ │ │ │ ├── Google.GData.Documents.dll.meta │ │ │ │ ├── Google.GData.Extensions.dll.meta │ │ │ │ ├── Google.GData.AccessControl.dll.meta │ │ │ │ └── Google.GData.Spreadsheets.dll.meta │ │ │ ├── LocalizationDownloader.cs.meta │ │ │ ├── libs.meta │ │ │ ├── DownloaderSettings.cs.meta │ │ │ ├── LocalizationAnalytics.cs.meta │ │ │ ├── UILocalizationEditor.cs.meta │ │ │ ├── UILocalizationKeyEditor.cs.meta │ │ │ ├── DownloaderSettings.cs │ │ │ ├── UILocalizationEditor.cs │ │ │ ├── UILocalizationKeyEditor.cs │ │ │ ├── LocalizationAnalytics.cs │ │ │ └── LocalizationDownloader.cs │ │ ├── Editor.meta │ │ ├── Extend.meta │ │ ├── CSVReader.cs.meta │ │ ├── CSVWriter.cs.meta │ │ ├── TextObject.cs.meta │ │ ├── UILocalization.cs.meta │ │ ├── UILocalizationKeys.cs.meta │ │ ├── Extend │ │ │ ├── StringExtension.cs.meta │ │ │ └── StringExtension.cs │ │ ├── LocalizationService.cs.meta │ │ ├── CSVWriter.cs │ │ ├── CSVReader.cs │ │ ├── UILocalizationKeys.cs │ │ ├── UILocalization.cs │ │ ├── TextObject.cs │ │ └── LocalizationService.cs │ ├── Tutorial Localization Service.pdf.meta │ ├── Demo.meta │ ├── Resources │ │ ├── Localization │ │ │ ├── English.csv.meta │ │ │ ├── French.csv.meta │ │ │ ├── Russian.csv.meta │ │ │ ├── Russian.csv │ │ │ ├── English.csv │ │ │ └── French.csv │ │ └── Localization.meta │ ├── Plugins.meta │ ├── Resources.meta │ ├── Scripts.meta │ └── Plugins │ │ ├── Core.meta │ │ └── Core │ │ ├── TypeHelper.cs.meta │ │ ├── MonoSingleton.cs.meta │ │ ├── SafetyAction.cs.meta │ │ ├── SafetyAction.cs │ │ ├── TypeHelper.cs │ │ └── MonoSingleton.cs └── LocalizeService.meta ├── .gitignore ├── .github └── FUNDING.yml └── README.md /ReadmeSource/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suncube/LocalizationService/HEAD/ReadmeSource/preview.png -------------------------------------------------------------------------------- /ReadmeSource/preview1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suncube/LocalizationService/HEAD/ReadmeSource/preview1.png -------------------------------------------------------------------------------- /ReadmeSource/preview2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suncube/LocalizationService/HEAD/ReadmeSource/preview2.png -------------------------------------------------------------------------------- /ReadmeSource/preview3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suncube/LocalizationService/HEAD/ReadmeSource/preview3.png -------------------------------------------------------------------------------- /ReadmeSource/preview4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suncube/LocalizationService/HEAD/ReadmeSource/preview4.png -------------------------------------------------------------------------------- /ReadmeSource/preview5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suncube/LocalizationService/HEAD/ReadmeSource/preview5.png -------------------------------------------------------------------------------- /ReadmeSource/preview6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suncube/LocalizationService/HEAD/ReadmeSource/preview6.png -------------------------------------------------------------------------------- /ReadmeSource/preview7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suncube/LocalizationService/HEAD/ReadmeSource/preview7.png -------------------------------------------------------------------------------- /ReadmeSource/preview8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suncube/LocalizationService/HEAD/ReadmeSource/preview8.png -------------------------------------------------------------------------------- /ReadmeSource/preview9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suncube/LocalizationService/HEAD/ReadmeSource/preview9.png -------------------------------------------------------------------------------- /ReadmeSource/preview10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suncube/LocalizationService/HEAD/ReadmeSource/preview10.png -------------------------------------------------------------------------------- /ReadmeSource/preview11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suncube/LocalizationService/HEAD/ReadmeSource/preview11.png -------------------------------------------------------------------------------- /ReadmeSource/preview12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suncube/LocalizationService/HEAD/ReadmeSource/preview12.png -------------------------------------------------------------------------------- /ReadmeSource/preview13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suncube/LocalizationService/HEAD/ReadmeSource/preview13.png -------------------------------------------------------------------------------- /ReadmeSource/preview14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suncube/LocalizationService/HEAD/ReadmeSource/preview14.png -------------------------------------------------------------------------------- /ReadmeSource/preview15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suncube/LocalizationService/HEAD/ReadmeSource/preview15.png -------------------------------------------------------------------------------- /ReadmeSource/preview16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suncube/LocalizationService/HEAD/ReadmeSource/preview16.png -------------------------------------------------------------------------------- /ReadmeSource/preview17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suncube/LocalizationService/HEAD/ReadmeSource/preview17.png -------------------------------------------------------------------------------- /ReadmeSource/preview18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suncube/LocalizationService/HEAD/ReadmeSource/preview18.png -------------------------------------------------------------------------------- /ReadmeSource/preview19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suncube/LocalizationService/HEAD/ReadmeSource/preview19.png -------------------------------------------------------------------------------- /Assets/LocalizeService/Demo/Demo.unity: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suncube/LocalizationService/HEAD/Assets/LocalizeService/Demo/Demo.unity -------------------------------------------------------------------------------- /Assets/LocalizeService/Tutorial Localization Service.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suncube/LocalizationService/HEAD/Assets/LocalizeService/Tutorial Localization Service.pdf -------------------------------------------------------------------------------- /Assets/LocalizeService/Scripts/Editor/libs/Newtonsoft.Json.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suncube/LocalizationService/HEAD/Assets/LocalizeService/Scripts/Editor/libs/Newtonsoft.Json.dll -------------------------------------------------------------------------------- /Assets/LocalizeService/Scripts/Editor/libs/Google.GData.Client.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suncube/LocalizationService/HEAD/Assets/LocalizeService/Scripts/Editor/libs/Google.GData.Client.dll -------------------------------------------------------------------------------- /Assets/LocalizeService/Scripts/Editor/libs/Google.GData.Documents.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suncube/LocalizationService/HEAD/Assets/LocalizeService/Scripts/Editor/libs/Google.GData.Documents.dll -------------------------------------------------------------------------------- /Assets/LocalizeService/Scripts/Editor/libs/Google.GData.Extensions.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suncube/LocalizationService/HEAD/Assets/LocalizeService/Scripts/Editor/libs/Google.GData.Extensions.dll -------------------------------------------------------------------------------- /Assets/LocalizeService/Scripts/Editor/libs/Google.GData.Spreadsheets.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suncube/LocalizationService/HEAD/Assets/LocalizeService/Scripts/Editor/libs/Google.GData.Spreadsheets.dll -------------------------------------------------------------------------------- /Assets/LocalizeService/Scripts/Editor/libs/Google.GData.AccessControl.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suncube/LocalizationService/HEAD/Assets/LocalizeService/Scripts/Editor/libs/Google.GData.AccessControl.dll -------------------------------------------------------------------------------- /Assets/LocalizeService/Tutorial Localization Service.pdf.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 26bef605caa26394587fe16ac88f44ae 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Assets/LocalizeService/Demo/Demo.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5ec92b6a89f24eb419087678de292e3b 3 | timeCreated: 1447923398 4 | licenseType: Store 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/LocalizeService.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 67d9d585f0b8db044a4149b3594bd22a 3 | folderAsset: yes 4 | timeCreated: 1551803808 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/LocalizeService/Demo.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fa4715c764fdcfb4d8f58330e51826ca 3 | folderAsset: yes 4 | timeCreated: 1448191521 5 | licenseType: Store 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/LocalizeService/Resources/Localization/English.csv.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: deb971baa5b2c1b44ae47c03b9302dbd 3 | timeCreated: 1496411621 4 | licenseType: Store 5 | TextScriptImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/LocalizeService/Resources/Localization/French.csv.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: aac2e3924c429434498930a5ad4d7dc0 3 | timeCreated: 1496411621 4 | licenseType: Store 5 | TextScriptImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/LocalizeService/Resources/Localization/Russian.csv.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5aa3642286b8d4b46b64c3a45b157588 3 | timeCreated: 1496411621 4 | licenseType: Store 5 | TextScriptImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/LocalizeService/Plugins.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c864f30370930cb4e95a330f13744635 3 | folderAsset: yes 4 | timeCreated: 1496405518 5 | licenseType: Store 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/LocalizeService/Resources.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6c9e7063756c2134fb1a5781570e1584 3 | folderAsset: yes 4 | timeCreated: 1448032301 5 | licenseType: Store 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/LocalizeService/Scripts.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f4b0173294942e74f835c1cb4451f92d 3 | folderAsset: yes 4 | timeCreated: 1448032271 5 | licenseType: Store 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/LocalizeService/Scripts/Editor/LocalizationDownloader.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 29b1d103cb0414ecf8e7fb09d569060c 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | userData: 9 | -------------------------------------------------------------------------------- /Assets/LocalizeService/Plugins/Core.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7c26efe9577e127439f596b77a98f1ac 3 | folderAsset: yes 4 | timeCreated: 1496405671 5 | licenseType: Store 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/LocalizeService/Scripts/Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c3c2f90e8d419b74b8bcc96733a461bf 3 | folderAsset: yes 4 | timeCreated: 1448037230 5 | licenseType: Store 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/LocalizeService/Scripts/Extend.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 98c6818a771564b4d9d171b5ae4da34c 3 | folderAsset: yes 4 | timeCreated: 1522322617 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/LocalizeService/Scripts/Editor/libs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 56b7d2615b9e47b49bb5bcdc128940b3 3 | folderAsset: yes 4 | timeCreated: 1506512814 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/LocalizeService/Resources/Localization.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f5d172dde4c8ada43ab55c52454b1bb6 3 | folderAsset: yes 4 | timeCreated: 1448026235 5 | licenseType: Store 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/LocalizeService/Demo/LocolizeTest.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e157314cbb765c24eb9b3f394089d66c 3 | timeCreated: 1447924015 4 | licenseType: Store 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/LocalizeService/Scripts/CSVReader.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: dcf90603dea710742b6389ed2b30b093 3 | timeCreated: 1447934971 4 | licenseType: Store 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/LocalizeService/Scripts/CSVWriter.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1a58c294e99135f4cbe918c6281faf85 3 | timeCreated: 1506515153 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/LocalizeService/Scripts/TextObject.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9747bfb79c69baf4fb7107e694e20905 3 | timeCreated: 1517590333 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/LocalizeService/Plugins/Core/TypeHelper.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 99979011e3cb5b74baae098011a44de2 3 | timeCreated: 1522322845 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/LocalizeService/Scripts/UILocalization.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1137a3dd71637cb4183ce720f58b1991 3 | timeCreated: 1447923371 4 | licenseType: Store 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/LocalizeService/Plugins/Core/MonoSingleton.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3f15c194df501274aba4af158f4ceda9 3 | timeCreated: 1496404859 4 | licenseType: Store 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/LocalizeService/Plugins/Core/SafetyAction.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 43e8889e01af4334482e6f3a4bdb8193 3 | timeCreated: 1496405557 4 | licenseType: Store 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/LocalizeService/Scripts/UILocalizationKeys.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8c91204010aba9542a384fd866457f20 3 | timeCreated: 1531234812 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/LocalizeService/Scripts/Editor/DownloaderSettings.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f61be20e71a4c5443a38c6dbff2ed797 3 | timeCreated: 1552475333 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/LocalizeService/Scripts/Extend/StringExtension.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1026835288be18243b97b586ef5e9cad 3 | timeCreated: 1523702893 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/LocalizeService/Scripts/LocalizationService.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8cbed725fb81db24099b02ba160be30a 3 | timeCreated: 1488218774 4 | licenseType: Store 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: -20 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/LocalizeService/Scripts/Editor/LocalizationAnalytics.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 23d34cd0a661c814b9805447f38292de 3 | timeCreated: 1521543179 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/LocalizeService/Scripts/Editor/UILocalizationEditor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e5abf9954d78f674094830f93a78afca 3 | timeCreated: 1448011825 4 | licenseType: Store 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/LocalizeService/Scripts/Editor/UILocalizationKeyEditor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4a137ec63a1743a418ca69e0a1aba440 3 | timeCreated: 1531315764 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/LocalizeService/Resources/Localization/Russian.csv: -------------------------------------------------------------------------------- 1 | Id,Russian 2 | title,Сервис Локолизации 3 | text,"Это пакет предназначен для отображения локализации текстов в ваших приложениях. Простой интерфейс. Локализация из файла .CSV формата. Работает с несколькими возможными видами вывода текста в Unity3d ( MeshText, UIText, TextMesh Pro), так же есть возможность получить текстовое значение из кода." 4 | autors,Sun Cube 5 | localization1,Английский 6 | localization2,Русский 7 | localization3,Французский 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /[Ll]ibrary/ 2 | /[Tt]emp/ 3 | /[Oo]bj/ 4 | /[Bb]uild/ 5 | /[Bb]uilds/ 6 | /Assets/AssetStoreTools* 7 | 8 | # Autogenerated VS/MD solution and project files 9 | ExportedObj/ 10 | *.csproj 11 | *.unityproj 12 | *.sln 13 | *.suo 14 | *.tmp 15 | *.user 16 | *.userprefs 17 | *.pidb 18 | *.booproj 19 | *.svd 20 | 21 | 22 | # Unity3D generated meta files 23 | *.pidb.meta 24 | 25 | # Unity3D Generated File On Crash Reports 26 | sysinfo.txt 27 | 28 | # Builds 29 | *.apk 30 | *.unitypackage 31 | -------------------------------------------------------------------------------- /Assets/LocalizeService/Resources/Localization/English.csv: -------------------------------------------------------------------------------- 1 | Id,English 2 | title,Localization Service 3 | text,"This package is designed to show the localization of text in your applications. Simple interface. Text of localization located in the .CSV file format. Works with several possible types of text output in Unity3d( MeshText, UIText, TextMesh Pro), there is also has the opportunity to get text value of the code." 4 | autors,Sun Cube 5 | localization1,English 6 | localization2,Russian 7 | localization3,French 8 | -------------------------------------------------------------------------------- /Assets/LocalizeService/Scripts/Extend/StringExtension.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Localization; 3 | 4 | public static class StringExtension 5 | { 6 | public static string Translate(this string _this) 7 | { 8 | return LocalizationService.Instance.GetTextByKey(_this); 9 | } 10 | 11 | public static string ParceNewLine(this string _this) 12 | { 13 | if (string.IsNullOrEmpty(_this)) 14 | return string.Empty; 15 | 16 | return _this.Replace("\\n", Environment.NewLine); 17 | } 18 | } -------------------------------------------------------------------------------- /Assets/LocalizeService/Resources/Localization/French.csv: -------------------------------------------------------------------------------- 1 | Id,French 2 | title,Service de Localisation 3 | text,"Ce forfait est conçu pour montrer la localisation de texte dans vos applications. Interface simple. Texte de localisation situé dans le format de fichier .csv. Fonctionne avec plusieurs types possibles de sortie de texte dans Unity3d ( MeshText, UIText, TextMesh Pro), on a aussi la possibilité d'obtenir la valeur de texte du code." 4 | autors,Sun Cube 5 | localization1,Anglaise 6 | localization2,Russe 7 | localization3,Français 8 | -------------------------------------------------------------------------------- /Assets/LocalizeService/Scripts/Editor/libs/Newtonsoft.Json.dll.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 814b2d8c36d2e4ddba8780f1658af56f 3 | PluginImporter: 4 | serializedVersion: 1 5 | iconMap: {} 6 | executionOrder: {} 7 | isPreloaded: 0 8 | platformData: 9 | Editor: 10 | enabled: 1 11 | settings: 12 | DefaultValueInitialized: true 13 | WindowsStoreApps: 14 | enabled: 0 15 | settings: 16 | CPU: AnyCPU 17 | data: 18 | enabled: 0 19 | settings: {} 20 | userData: 21 | assetBundleName: 22 | assetBundleVariant: 23 | -------------------------------------------------------------------------------- /Assets/LocalizeService/Scripts/Editor/libs/Google.GData.Client.dll.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b647d813be8c84b0f8514b48f7a9e840 3 | PluginImporter: 4 | serializedVersion: 1 5 | iconMap: {} 6 | executionOrder: {} 7 | isPreloaded: 0 8 | platformData: 9 | Editor: 10 | enabled: 1 11 | settings: 12 | DefaultValueInitialized: true 13 | WindowsStoreApps: 14 | enabled: 0 15 | settings: 16 | CPU: AnyCPU 17 | data: 18 | enabled: 0 19 | settings: {} 20 | userData: 21 | assetBundleName: 22 | assetBundleVariant: 23 | -------------------------------------------------------------------------------- /Assets/LocalizeService/Scripts/Editor/libs/Google.GData.Documents.dll.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d9b00c22cdbd649d5b8b8110f6a77bd5 3 | PluginImporter: 4 | serializedVersion: 1 5 | iconMap: {} 6 | executionOrder: {} 7 | isPreloaded: 0 8 | platformData: 9 | Editor: 10 | enabled: 1 11 | settings: 12 | DefaultValueInitialized: true 13 | WindowsStoreApps: 14 | enabled: 0 15 | settings: 16 | CPU: AnyCPU 17 | data: 18 | enabled: 0 19 | settings: {} 20 | userData: 21 | assetBundleName: 22 | assetBundleVariant: 23 | -------------------------------------------------------------------------------- /Assets/LocalizeService/Scripts/Editor/libs/Google.GData.Extensions.dll.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 958a0aeb094f24ed68d299a3f5e214ad 3 | PluginImporter: 4 | serializedVersion: 1 5 | iconMap: {} 6 | executionOrder: {} 7 | isPreloaded: 0 8 | platformData: 9 | Editor: 10 | enabled: 1 11 | settings: 12 | DefaultValueInitialized: true 13 | WindowsStoreApps: 14 | enabled: 0 15 | settings: 16 | CPU: AnyCPU 17 | data: 18 | enabled: 0 19 | settings: {} 20 | userData: 21 | assetBundleName: 22 | assetBundleVariant: 23 | -------------------------------------------------------------------------------- /Assets/LocalizeService/Scripts/Editor/libs/Google.GData.AccessControl.dll.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b72b50c73e1324ea383917171bd5e5a7 3 | PluginImporter: 4 | serializedVersion: 1 5 | iconMap: {} 6 | executionOrder: {} 7 | isPreloaded: 0 8 | platformData: 9 | Editor: 10 | enabled: 1 11 | settings: 12 | DefaultValueInitialized: true 13 | WindowsStoreApps: 14 | enabled: 0 15 | settings: 16 | CPU: AnyCPU 17 | data: 18 | enabled: 0 19 | settings: {} 20 | userData: 21 | assetBundleName: 22 | assetBundleVariant: 23 | -------------------------------------------------------------------------------- /Assets/LocalizeService/Scripts/Editor/libs/Google.GData.Spreadsheets.dll.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d1d7d7a204f964a6b990fb254729276c 3 | PluginImporter: 4 | serializedVersion: 1 5 | iconMap: {} 6 | executionOrder: {} 7 | isPreloaded: 0 8 | platformData: 9 | Editor: 10 | enabled: 1 11 | settings: 12 | DefaultValueInitialized: true 13 | WindowsStoreApps: 14 | enabled: 0 15 | settings: 16 | CPU: AnyCPU 17 | data: 18 | enabled: 0 19 | settings: {} 20 | userData: 21 | assetBundleName: 22 | assetBundleVariant: 23 | -------------------------------------------------------------------------------- /Assets/LocalizeService/Plugins/Core/SafetyAction.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | public static class SafetyAction 4 | { 5 | public static void SafeInvoke(this Action action) 6 | { 7 | if (action != null) 8 | { 9 | action.Invoke(); 10 | } 11 | } 12 | 13 | public static void SafeInvoke(this Action action, T arg1) 14 | { 15 | if (action != null) 16 | { 17 | action.Invoke(arg1); 18 | } 19 | } 20 | 21 | public static void SafeInvoke(this Action action, T1 arg1, T2 arg2) 22 | { 23 | if (action != null) 24 | { 25 | action.Invoke(arg1, arg2); 26 | } 27 | } 28 | 29 | } -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: https://www.donationalerts.com/r/suncube 13 | -------------------------------------------------------------------------------- /Assets/LocalizeService/Plugins/Core/TypeHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Reflection; 4 | 5 | public class TypeHelper 6 | { 7 | public static Dictionary _fastTypes = new Dictionary(); 8 | 9 | public static Type GetTypeByName(string name, string assemblyName) 10 | { 11 | if (_fastTypes.ContainsKey(name)) 12 | return _fastTypes[name]; 13 | 14 | foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) 15 | { 16 | if (!assembly.FullName.Contains(assemblyName)) 17 | continue; 18 | 19 | foreach (Type type in assembly.GetTypes()) 20 | { 21 | if (type.Name == name) 22 | { 23 | _fastTypes.Add(name, type); 24 | return type; 25 | } 26 | } 27 | } 28 | 29 | return null; 30 | } 31 | } -------------------------------------------------------------------------------- /Assets/LocalizeService/Plugins/Core/MonoSingleton.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | public class MonoSingleton : MonoBehaviour where T : MonoBehaviour 4 | { 5 | private static T s_Instance; 6 | private static bool s_IsDestroyed; 7 | 8 | public static T Instance 9 | { 10 | get 11 | { 12 | if (s_IsDestroyed) 13 | return null; 14 | 15 | if (s_Instance == null) 16 | { 17 | s_Instance = FindObjectOfType(typeof(T)) as T; 18 | 19 | if (s_Instance == null) 20 | { 21 | var gameObject = new GameObject(typeof(T).Name); 22 | DontDestroyOnLoad(gameObject); 23 | 24 | s_Instance = gameObject.AddComponent(typeof(T)) as T; 25 | } 26 | } 27 | 28 | return s_Instance; 29 | } 30 | } 31 | 32 | protected virtual void OnDestroy() 33 | { 34 | s_Instance = null; 35 | s_IsDestroyed = true; 36 | 37 | if (s_Instance) 38 | Destroy(s_Instance); 39 | } 40 | 41 | public static bool IsLive 42 | { 43 | get { return !s_IsDestroyed; } 44 | } 45 | } -------------------------------------------------------------------------------- /Assets/LocalizeService/Scripts/CSVWriter.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.IO; 3 | using System.Text; 4 | 5 | namespace Localization 6 | { 7 | public class CSVWriter : StreamWriter 8 | { 9 | public CSVWriter(string filename) 10 | : base(filename, false, System.Text.Encoding.UTF8) 11 | { 12 | } 13 | 14 | public void WriteRow(CSVRow row) 15 | { 16 | StringBuilder builder = new StringBuilder(); 17 | bool firstColumn = true; 18 | foreach (string value in row) 19 | { 20 | if (!firstColumn) 21 | builder.Append(','); 22 | 23 | if (value.IndexOfAny(new char[] {'"', ','}) != -1) 24 | builder.AppendFormat("\"{0}\"", value.Replace("\"", "\"\"")); 25 | else 26 | builder.Append(value); 27 | firstColumn = false; 28 | } 29 | row.LineText = builder.ToString(); 30 | WriteLine(row.LineText); 31 | } 32 | } 33 | 34 | 35 | public class CSVRow : List 36 | { 37 | public string LineText { get; set; } 38 | } 39 | } -------------------------------------------------------------------------------- /Assets/LocalizeService/Scripts/CSVReader.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Text.RegularExpressions; 3 | using UnityEngine; 4 | 5 | namespace Localization 6 | { 7 | public class CSVReader 8 | { 9 | public static string[,] SplitCsvGrid(string csvText) 10 | { 11 | var lines = Regex.Split(csvText, System.Environment.NewLine); 12 | int width = 0; 13 | for (int i = 0; i < lines.Length; i++) 14 | { 15 | string[] row = SplitCsvLine(lines[i]); 16 | width = Mathf.Max(width, row.Length); 17 | } 18 | 19 | string[,] outputGrid = new string[width, lines.Length + 1]; 20 | for (int y = 0; y < lines.Length; y++) 21 | { 22 | string[] row = SplitCsvLine(lines[y]); 23 | for (int x = 0; x < row.Length; x++) 24 | { 25 | outputGrid[x, y] = row[x]; 26 | outputGrid[x, y] = outputGrid[x, y].Replace("\"\"", "\""); 27 | } 28 | } 29 | 30 | return outputGrid; 31 | } 32 | 33 | public static string[] SplitCsvLine(string line) 34 | { 35 | return (from Match m in Regex.Matches(line, 36 | @"(((?(?=[,\r\n]+))|""(?([^""]|"""")+)""|(?[^,\r\n]+)),?)", 37 | System.Text.RegularExpressions.RegexOptions.ExplicitCapture) 38 | select m.Groups[1].Value).ToArray(); 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /Assets/LocalizeService/Scripts/Editor/DownloaderSettings.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using UnityEngine; 5 | 6 | [SerializeField] 7 | public class DownloaderSettings 8 | { 9 | public string spreadSheetKey = ""; 10 | public string loadingDir = "./Assets/LocalizeService/Resources/Localization"; 11 | public string accessCode = ""; 12 | 13 | private const string SettingName = "DownloaderSettings.json"; 14 | private const string SettingPath = "./Assets/LocalizeService/"; 15 | private static string Path { 16 | get { return string.Format(SettingPath+"{0}", SettingName); } 17 | } 18 | 19 | public static DownloaderSettings GetInstance() 20 | { 21 | return new DownloaderSettings(); 22 | } 23 | 24 | public static DownloaderSettings Load() 25 | { 26 | if (!File.Exists(Path)) 27 | return new DownloaderSettings(); 28 | 29 | using (StreamReader streamReader = File.OpenText(Path)) 30 | { 31 | string jsonString = streamReader.ReadToEnd(); 32 | return JsonUtility.FromJson(jsonString); 33 | } 34 | } 35 | 36 | public void Save() 37 | { 38 | string jsonString = JsonUtility.ToJson(this); 39 | if (!File.Exists(Path)) 40 | Directory.CreateDirectory(SettingPath); 41 | 42 | using (StreamWriter streamWriter = File.CreateText(Path)) 43 | { 44 | streamWriter.Write(jsonString); 45 | } 46 | } 47 | } 48 | 49 | -------------------------------------------------------------------------------- /Assets/LocalizeService/Demo/LocolizeTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Localization; 3 | using UnityEngine; 4 | using UnityEngine.UI; 5 | 6 | // For DEMO VIEW 7 | public class LocolizeTest : MonoBehaviour 8 | { 9 | public Toggle Localization1; 10 | public Toggle Localization2; 11 | public Toggle Localization3; 12 | 13 | private void Start() 14 | { 15 | Localization1.onValueChanged.AddListener(OnLocalization1Set); 16 | Localization2.onValueChanged.AddListener(OnLocalization2Set); 17 | Localization3.onValueChanged.AddListener(OnLocalization3Set); 18 | 19 | CheckLocalization(); 20 | } 21 | 22 | private void CheckLocalization() 23 | { 24 | if (LocalizationService.Instance == null) return; 25 | 26 | switch (LocalizationService.Instance.Localization) 27 | { 28 | case "Russian": 29 | Localization2.isOn = true; 30 | break; 31 | case "English": 32 | Localization1.isOn = true; 33 | break; 34 | case "French": 35 | Localization3.isOn = true; 36 | break; 37 | } 38 | } 39 | 40 | private void OnLocalization1Set(bool value) 41 | { 42 | if (!value) return; 43 | LocalizationService.Instance.Localization = "English"; 44 | } 45 | private void OnLocalization2Set(bool value) 46 | { 47 | if (!value) return; 48 | LocalizationService.Instance.Localization = "Russian"; 49 | } 50 | private void OnLocalization3Set(bool value) 51 | { 52 | if (!value) return; 53 | LocalizationService.Instance.Localization = "French"; 54 | } 55 | 56 | } -------------------------------------------------------------------------------- /Assets/LocalizeService/Scripts/UILocalizationKeys.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text.RegularExpressions; 5 | using UnityEngine; 6 | 7 | namespace Localization 8 | { 9 | public class UILocalizationKeys : UILocalization 10 | { 11 | public string[] Keys = new string[]{}; 12 | 13 | protected override void Initialize() 14 | { 15 | base.Initialize(); 16 | //Key = _textObject.Text; 17 | } 18 | 19 | public override void Localize() 20 | { 21 | if (!LocalizationService.IsLive || _textObject == null) 22 | return; 23 | 24 | string[] values = new string[Keys.Length]; 25 | 26 | for (var index = 0; index < values.Length; index++) 27 | { 28 | values[index] = LocalizationService.Instance.GetTextByKey(Keys[index]); 29 | } 30 | SetTextValue(string.Format(Key, values)); 31 | } 32 | 33 | #if UNITY_EDITOR 34 | public void SetEditorValue(string[] keyValues) 35 | { 36 | SetTextValue(string.Format(Key, keyValues)); 37 | } 38 | #endif 39 | #region Helpers 40 | 41 | public string[] GetParceKeys() 42 | { 43 | //if (_textObject == null) 44 | // _textObject = new TextObject(gameObject); 45 | 46 | //Key = _textObject.Text; 47 | if (string.IsNullOrEmpty(Key)) 48 | { 49 | return new string[]{}; 50 | } 51 | 52 | var matches = Regex.Matches(Key, "{\\d}"); 53 | return matches 54 | .OfType() 55 | .Select(m => m.Value) 56 | .Distinct().ToArray(); 57 | } 58 | 59 | public void CreateLocalKeys() 60 | { 61 | var matchCollection = GetParceKeys(); 62 | 63 | var newKeys = new string[matchCollection.Length]; 64 | for (var index = 0; index < matchCollection.Length; index++) 65 | { 66 | 67 | if (index < Keys.Length) 68 | { 69 | newKeys[index] = Keys[index]; 70 | } 71 | else 72 | { 73 | 74 | newKeys[index] = string.Empty; 75 | } 76 | } 77 | 78 | Keys = newKeys; 79 | } 80 | 81 | #endregion 82 | } 83 | } -------------------------------------------------------------------------------- /Assets/LocalizeService/Scripts/UILocalization.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | 4 | namespace Localization 5 | { 6 | public enum TextType 7 | { 8 | None, 9 | UiText, 10 | MeshText, 11 | TextMeshPro, 12 | } 13 | 14 | 15 | public class UILocalization : MonoBehaviour 16 | { 17 | protected TextObject _textObject; 18 | 19 | public string Key; 20 | 21 | #region Localize Logic 22 | 23 | #if UNITY_EDITOR 24 | public void SetEditorValue(string text) 25 | { 26 | text = ParceText(text); 27 | if (_textObject != null) 28 | { 29 | _textObject.Text = text; 30 | } 31 | } 32 | #endif 33 | private void Start() 34 | { 35 | Initialize(); 36 | OnChangeLocalization(); 37 | } 38 | 39 | protected virtual void Initialize() 40 | { 41 | LocalizationService.Instance.OnChangeLocalization += OnChangeLocalization; 42 | 43 | _textObject = new TextObject(gameObject); 44 | } 45 | 46 | private void OnChangeLocalization() 47 | { 48 | Localize(); 49 | } 50 | 51 | public virtual void Localize() 52 | { 53 | if(LocalizationService.IsLive && _textObject != null) 54 | SetTextValue(LocalizationService.Instance.GetTextByKey(Key)); 55 | } 56 | 57 | protected void SetTextValue(string text) 58 | { 59 | _textObject.Text = ParceText(text); 60 | } 61 | 62 | private string ParceText(string text) 63 | { 64 | return text.ParceNewLine(); 65 | } 66 | 67 | private void OnDestroy() 68 | { 69 | if(_textObject != null) 70 | _textObject.Delete(); 71 | 72 | _textObject = null; 73 | 74 | if (!LocalizationService.IsLive) return; 75 | 76 | LocalizationService.Instance.OnChangeLocalization -= OnChangeLocalization; 77 | } 78 | #endregion Localize Logic 79 | 80 | #region Helpers 81 | 82 | public TextType InitializeTextObject() 83 | { 84 | if(_textObject == null) 85 | _textObject = new TextObject(gameObject); 86 | 87 | return GetTextType(); 88 | } 89 | 90 | public TextType GetTextType() 91 | { 92 | return _textObject.TextType; 93 | } 94 | 95 | public bool IsHasTextObject() 96 | { 97 | return _textObject != null; 98 | } 99 | 100 | #endregion Helpers 101 | } 102 | } -------------------------------------------------------------------------------- /Assets/LocalizeService/Scripts/TextObject.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | using UnityEngine.UI; 4 | 5 | namespace Localization 6 | { 7 | 8 | public class TextObject 9 | { 10 | public string Text 11 | { 12 | set 13 | { 14 | switch (TextType) 15 | { 16 | case TextType.UiText: 17 | UiText.text = value; 18 | break; 19 | case TextType.MeshText: 20 | MeshText.text = value; 21 | break; 22 | case TextType.TextMeshPro: 23 | MeshProText.GetType().GetProperty("text").SetValue(MeshProText,value, null); 24 | break; 25 | } 26 | } 27 | 28 | get 29 | { 30 | switch (TextType) 31 | { 32 | case TextType.UiText: 33 | return UiText.text; 34 | 35 | case TextType.MeshText: 36 | return MeshText.text; 37 | case TextType.TextMeshPro: 38 | return (string) MeshProText.GetType().GetProperty("text").GetValue(MeshProText, null); 39 | } 40 | 41 | return String.Empty; 42 | } 43 | } 44 | public TextType TextType { get; private set; } 45 | 46 | private Component MeshProText = null; 47 | private Text UiText = null; 48 | private TextMesh MeshText = null; 49 | 50 | public TextObject(GameObject gameObject) 51 | { 52 | TextType = TextType.None; 53 | 54 | UiText = gameObject.GetComponent(); 55 | if (UiText) 56 | { 57 | TextType = TextType.UiText; 58 | return; 59 | } 60 | 61 | MeshText = gameObject.GetComponent(); 62 | if (MeshText) 63 | { 64 | TextType = TextType.MeshText; 65 | return; 66 | } 67 | 68 | var type = TypeHelper.GetTypeByName("TextMeshPro", "TextMeshPro"); 69 | if (type != null) 70 | { 71 | MeshProText = gameObject.GetComponent(type); 72 | if (MeshProText != null) 73 | { 74 | TextType = TextType.TextMeshPro; 75 | return; 76 | } 77 | } 78 | 79 | type = TypeHelper.GetTypeByName("TextMeshProUGUI", "TextMeshPro"); 80 | if (type != null) 81 | { 82 | MeshProText = gameObject.GetComponent(type); 83 | if (MeshProText != null) 84 | { 85 | TextType = TextType.TextMeshPro; 86 | return; 87 | } 88 | } 89 | 90 | 91 | 92 | } 93 | 94 | public void Delete() 95 | { 96 | MeshProText = null; 97 | UiText = null; 98 | MeshText = null; 99 | } 100 | } 101 | } -------------------------------------------------------------------------------- /Assets/LocalizeService/Scripts/LocalizationService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | 6 | namespace Localization 7 | { 8 | public class LocalizationService : MonoSingleton 9 | { 10 | private const string DefaultLocalizationName = "English"; 11 | public static string LocalizationPath = "Localization/"; 12 | 13 | public static string LocalizationFilePath 14 | { 15 | get { return LocalizationPath + _localization; } 16 | } 17 | 18 | public Action OnChangeLocalization; 19 | 20 | private static string _localization = "English"; 21 | private Dictionary localizationLibrary = new Dictionary(); 22 | 23 | public string Localization 24 | { 25 | get { return _localization; } 26 | set 27 | { 28 | _localization = value; 29 | localizationLibrary = LoadLocalizeFileHelper(); 30 | SetLocalization(value); 31 | 32 | OnChangeLocalization.SafeInvoke(); 33 | } 34 | } 35 | 36 | private void Awake() 37 | { 38 | Initialize(); 39 | } 40 | 41 | #region Localize Logic 42 | 43 | private void Initialize() 44 | { 45 | Localization = GetLocalization(); 46 | localizationLibrary = LoadLocalizeFileHelper(); 47 | } 48 | 49 | private static Dictionary ParseLocalizeFile(string[,] grid) 50 | { 51 | var result = new Dictionary(grid.GetUpperBound(0) + 1); 52 | 53 | for (int ln = 1; ln <= grid.GetUpperBound(1); ln++) 54 | for (int col = 1; col <= grid.GetUpperBound(0); col++) 55 | { 56 | if (string.IsNullOrEmpty(grid[0, ln]) 57 | || string.IsNullOrEmpty(grid[col, ln])) continue; 58 | 59 | if (!result.ContainsKey(grid[0, ln])) 60 | result.Add(grid[0, ln], grid[col, ln]); 61 | else 62 | { 63 | Debug.LogError(string.Format("Key {0} already exist", grid[0, ln])); 64 | } 65 | } 66 | return result; 67 | } 68 | 69 | public string GetTextByKey(string key) 70 | { 71 | if (string.IsNullOrEmpty(key)) return "[EMPTY]"; 72 | 73 | string keyValue; 74 | if (localizationLibrary.TryGetValue(key, out keyValue)) 75 | { 76 | return keyValue; 77 | } 78 | 79 | return string.Format("[ERROR KEY {0}]", key); 80 | } 81 | 82 | // todo Integrate this to your PlayerPref Manager 83 | private string GetLocalization() 84 | { 85 | SystemLanguage language = Application.systemLanguage; 86 | 87 | if (language == SystemLanguage.ChineseSimplified) 88 | { 89 | language = SystemLanguage.Chinese; 90 | } 91 | 92 | return PlayerPrefs.GetString("localization", language.ToString()); 93 | } 94 | 95 | private void SetLocalization(string localize) 96 | { 97 | PlayerPrefs.SetString("localization", localize); 98 | } 99 | 100 | #endregion Localize Logic 101 | 102 | #region Helpers 103 | 104 | public string[] GetLocalizations() 105 | { 106 | var result = new string[localizationLibrary.Count]; 107 | var i = 0; 108 | foreach (var loc in localizationLibrary) 109 | { 110 | result[i] = loc.Key; 111 | i++; 112 | } 113 | return result; 114 | } 115 | 116 | public Dictionary LoadLocalizeFileHelper() 117 | { 118 | var languages = Resources.Load(LocalizationFilePath, typeof (TextAsset)) as TextAsset; 119 | if (languages == null) 120 | { 121 | // todo load any available??? 122 | if (Localization != DefaultLocalizationName) 123 | LoadDefault(); 124 | 125 | return null; 126 | } 127 | var resultGrid = CSVReader.SplitCsvGrid(languages.text); 128 | return ParseLocalizeFile(resultGrid); 129 | } 130 | 131 | private void LoadDefault() 132 | { 133 | Localization = DefaultLocalizationName; 134 | } 135 | 136 | public static string[] GetLocalizationKeys() 137 | { 138 | var languages = Resources.Load(LocalizationFilePath, typeof (TextAsset)) as TextAsset; 139 | if (languages == null) return null; 140 | var resultGrid = CSVReader.SplitCsvGrid(languages.text); 141 | var localizeFile = ParseLocalizeFile(resultGrid); 142 | return localizeFile.Keys.ToArray(); 143 | } 144 | 145 | public static Dictionary GetLocalizationKeyValue() 146 | { 147 | var languages = Resources.Load(LocalizationFilePath, typeof(TextAsset)) as TextAsset; 148 | if (languages == null) return null; 149 | var resultGrid = CSVReader.SplitCsvGrid(languages.text); 150 | var localizeFile = ParseLocalizeFile(resultGrid); 151 | return localizeFile; 152 | } 153 | 154 | #endregion Helpers 155 | } 156 | 157 | } -------------------------------------------------------------------------------- /Assets/LocalizeService/Scripts/Editor/UILocalizationEditor.cs: -------------------------------------------------------------------------------- 1 | 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using UnityEditor; 5 | using UnityEngine; 6 | 7 | namespace Localization 8 | { 9 | [CustomEditor(typeof(UILocalization))] 10 | [CanEditMultipleObjects] 11 | public class UILocalizationEditor : Editor 12 | { 13 | protected string[] localizationKeys = null; 14 | protected static string[] searchKeys = null; 15 | protected static string[] localizationValues = null; 16 | 17 | protected SerializedProperty KeyValue; 18 | 19 | private void OnEnable() 20 | { 21 | Initialize(); 22 | } 23 | 24 | protected virtual void Initialize() 25 | { 26 | Dictionary localization = LocalizationService.GetLocalizationKeyValue(); 27 | localizationKeys = localization.Keys.ToArray(); 28 | searchKeys = localization.Keys.Select(t => t.ToLower()).ToArray(); 29 | localizationValues = localization.Values.ToArray(); 30 | 31 | KeyValue = serializedObject.FindProperty("Key"); 32 | } 33 | 34 | 35 | public override void OnInspectorGUI() 36 | { 37 | var myTarget = (UILocalization)target; 38 | 39 | if (!AddingTypeTest(myTarget)) 40 | return; 41 | 42 | EditorGUILayout.LabelField("KEY"); 43 | 44 | EditorGUI.BeginChangeCheck(); 45 | KeyValue.stringValue = EditorGUILayout.TextArea(KeyValue.stringValue); 46 | if (EditorGUI.EndChangeCheck()) 47 | { 48 | serializedObject.ApplyModifiedProperties(); 49 | } 50 | 51 | 52 | if(string.IsNullOrEmpty(myTarget.Key)) return; 53 | 54 | ShowLocalizeValues(myTarget); 55 | var check = KeyValidCheck(myTarget.Key); 56 | 57 | if (check && GUILayout.Button("Preview")) 58 | UpdateValue(myTarget); 59 | 60 | } 61 | 62 | 63 | private void ShowLocalizeValues(UILocalization myTarget) 64 | { 65 | string searchValue = myTarget.Key.ToLower(); 66 | 67 | const int maxCount = 5; 68 | Dictionary helpKeys = new Dictionary(maxCount); 69 | for (int i = 0; i < searchKeys.Length; i++) 70 | { 71 | string key = searchKeys[i]; 72 | if (key == searchValue) 73 | { 74 | return; 75 | } 76 | if (key.Contains(searchValue)) 77 | { 78 | helpKeys.Add(key, i); 79 | if (helpKeys.Count == maxCount) 80 | { 81 | break; 82 | } 83 | } 84 | } 85 | if (helpKeys.Count == 0) 86 | { 87 | return; 88 | } 89 | EditorGUILayout.Space(); 90 | 91 | var color = GUI.backgroundColor; 92 | GUI.backgroundColor = Color.green; 93 | 94 | foreach (KeyValuePair kvp in helpKeys) 95 | { 96 | if (GUILayout.Button(kvp.Key)) 97 | { 98 | myTarget.Key = localizationKeys[kvp.Value]; 99 | UpdateValue(myTarget); 100 | GUI.FocusControl(string.Empty); 101 | } 102 | } 103 | GUI.backgroundColor = color; 104 | } 105 | 106 | private void UpdateValue(UILocalization myTarget) 107 | { 108 | int keyIndex = GetIdByKey(myTarget.Key, searchKeys); 109 | if (keyIndex != -1) 110 | { 111 | myTarget.SetEditorValue(localizationValues[keyIndex]); 112 | // update lower case to real one 113 | myTarget.Key = localizationKeys[keyIndex]; 114 | } 115 | } 116 | 117 | protected bool KeyValidCheck(string key) 118 | { 119 | var idByKey = GetIdByKey(key, localizationKeys); 120 | if (idByKey == -1) 121 | { 122 | EditorGUILayout.HelpBox("KEY not found in localization file. ", MessageType.Error); 123 | return false; 124 | } 125 | return true; 126 | } 127 | 128 | protected bool AddingTypeTest(UILocalization myTarget) 129 | { 130 | if (myTarget.InitializeTextObject() == TextType.None) 131 | { 132 | EditorGUILayout.HelpBox("TEXT component not found \n\n[UIText|MeshText|TextMeshPro]", MessageType.Error); 133 | return false; 134 | } 135 | 136 | return true; 137 | } 138 | 139 | protected int GetIdByKey(string key, string[] keys) 140 | { 141 | for (int index = 0; index < keys.Length; index++) 142 | { 143 | if (keys[index] == key) 144 | return index; 145 | } 146 | return -1; 147 | } 148 | } 149 | 150 | } 151 | -------------------------------------------------------------------------------- /Assets/LocalizeService/Scripts/Editor/UILocalizationKeyEditor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using UnityEditor; 4 | using UnityEngine; 5 | 6 | namespace Localization 7 | { 8 | [CustomEditor(typeof(UILocalizationKeys))] 9 | [CanEditMultipleObjects] 10 | public class UILocalizationKeyEditor : UILocalizationEditor 11 | { 12 | protected override void Initialize() 13 | { 14 | base.Initialize(); 15 | 16 | } 17 | void ReadOnlyTextField(string label, string text) 18 | { 19 | EditorGUILayout.BeginHorizontal(); 20 | { 21 | EditorGUILayout.LabelField(label, GUILayout.Width(EditorGUIUtility.labelWidth - 4)); 22 | EditorGUILayout.SelectableLabel(text, EditorStyles.textField, GUILayout.Height(EditorGUIUtility.singleLineHeight)); 23 | } 24 | EditorGUILayout.EndHorizontal(); 25 | } 26 | 27 | Vector2 scroll; 28 | public override void OnInspectorGUI() 29 | { 30 | var myTarget = (UILocalizationKeys)target; 31 | if (!AddingTypeTest(myTarget)) 32 | return; 33 | 34 | if (localizationKeys == null) 35 | localizationKeys = LocalizationService.GetLocalizationKeys(); 36 | 37 | GUILayout.Label("KEY"); 38 | 39 | scroll = EditorGUILayout.BeginScrollView(scroll, GUILayout.MinHeight(50), GUILayout.ExpandHeight(true)); 40 | 41 | EditorGUI.BeginChangeCheck(); 42 | KeyValue.stringValue = EditorGUILayout.TextArea(KeyValue.stringValue, GUILayout.ExpandHeight(true)); 43 | if (EditorGUI.EndChangeCheck()) 44 | { 45 | serializedObject.ApplyModifiedProperties(); 46 | } 47 | EditorGUILayout.EndScrollView(); 48 | 49 | if (myTarget.GetParceKeys().Length != myTarget.Keys.Length) 50 | { 51 | if (GUILayout.Button("Refresh keys")) 52 | myTarget.CreateLocalKeys(); 53 | } 54 | 55 | var keys = myTarget.Keys; 56 | GUILayout.Space(15); 57 | 58 | if (keys.Length == 0) 59 | { 60 | EditorGUILayout.HelpBox("Key {1..n} in TEXT not found", MessageType.Error); 61 | } 62 | 63 | for (var index = 0; index < keys.Length; index++) 64 | { 65 | GUILayout.Label("{" + index + "}"); 66 | 67 | keys[index] = EditorGUILayout.TextField("", keys[index]); 68 | if (!string.IsNullOrEmpty(keys[index])) 69 | { 70 | ShowLocalizeValues(myTarget, index); 71 | KeyValidCheck(keys[index]); 72 | } 73 | 74 | GUILayout.Space(10); 75 | } 76 | 77 | if (GUILayout.Button("Preview")) 78 | { 79 | UpdateValue(myTarget); 80 | } 81 | } 82 | 83 | private void ShowLocalizeValues(UILocalizationKeys myTarget,int index) 84 | { 85 | string searchValue = myTarget.Keys[index].ToLower(); 86 | 87 | const int maxCount = 5; 88 | Dictionary helpKeys = new Dictionary(maxCount); 89 | for (int i = 0; i < searchKeys.Length; i++) 90 | { 91 | string key = searchKeys[i]; 92 | if (key == searchValue) 93 | { 94 | return; 95 | } 96 | if (key.Contains(searchValue)) 97 | { 98 | helpKeys.Add(key, i); 99 | if (helpKeys.Count == maxCount) 100 | { 101 | break; 102 | } 103 | } 104 | } 105 | if (helpKeys.Count == 0) 106 | { 107 | return; 108 | } 109 | 110 | EditorGUILayout.Space(); 111 | 112 | var color = GUI.backgroundColor; 113 | GUI.backgroundColor = Color.green; 114 | 115 | foreach (KeyValuePair kvp in helpKeys) 116 | { 117 | if (GUILayout.Button(kvp.Key)) 118 | { 119 | myTarget.Keys[index] = localizationKeys[kvp.Value]; 120 | UpdateValue(myTarget); 121 | GUI.FocusControl(string.Empty); 122 | } 123 | } 124 | GUI.backgroundColor = color; 125 | } 126 | 127 | private void UpdateValue(UILocalizationKeys myTarget) 128 | { 129 | var result = new string[myTarget.Keys.Length]; 130 | for (var index = 0; index < myTarget.Keys.Length; index++) 131 | { 132 | var myTargetKey = myTarget.Keys[index]; 133 | int keyIndex = GetIdByKey(myTargetKey, searchKeys); 134 | if (keyIndex != -1) 135 | { 136 | result[index] = localizationValues[keyIndex]; 137 | 138 | myTarget.Keys[index] = localizationKeys[keyIndex]; 139 | } 140 | else 141 | { 142 | result[index] = ""; 143 | } 144 | } 145 | 146 | myTarget.SetEditorValue(result); 147 | } 148 | } 149 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Localization Service ![GitHub release](https://img.shields.io/github/release/suncube/LocalizationService.svg) 4 | 5 | Plugin for localization keys. Works with **MeshText/UIText/TextMeshPro** 6 | 7 | Support [suncubestudio@gmail.com](mailto:suncubestudio@gmail.com) - subject of mail [Localization Sevice] 8 | 9 | # How to start 10 | 1) Import plugin from [Asset Store](http://u3d.as/miF) or copy from [GitHub](https://github.com/suncube/LocalizeService) 11 | 2) Create and Load .CSV 12 | 3) Add **UILocalization** component to **MeshText/UIText/TextMeshPro** 13 | #### [HOW TO USE ](#how-to-use) 14 | 15 | - Help tools: [Analytic of Keys ](#help-tools) 16 | 17 | 18 | # Create files of localization 19 | Plugin use .CSV files for localization key/value. Create a table of localization and export it to a .CSV file. You can use for this google sheets, because all your team can edit this with sync. 20 | 21 | ![](/ReadmeSource/preview1.png) 22 | 23 | 24 | 25 | Create for each language its own list. 26 | 27 | ![](/ReadmeSource/preview2.png) 28 | 29 | 30 | 31 | **Save and export** each localization to file **“Localization” .CSV** file or use [Download manager](#download-manager) 32 | 33 | > Copy/put the file to the resources (Resources\Localization). Rename 34 | > the file to language name. [!!! Names of languages you can see 35 | > here](https://docs.unity3d.com/ScriptReference/SystemLanguage.html*) 36 | 37 | 38 | 39 | ## Download Manager 40 | 41 | It is possible to download the latest localization changes from your Google sheet. Plugin uses the [Google Sheets API](https://developers.google.com/sheets/) . If you want to use your project for working with tables [create here](https://console.developers.google.com/project) . 42 | 43 | This tool can be opened by path **Window / Localization** 44 | 45 | 46 | 47 | ![](/ReadmeSource/preview3.png) 48 | 49 | 50 | 51 | 52 | 53 | Next - open your localization page and copy google sheet **IDKey** 54 | 55 | ![](/ReadmeSource/preview4.png) 56 | 57 | 58 | 59 | 60 | Copy and paste this to **SpreadSheetKey** : 61 | 62 | 63 | 64 | ![](/ReadmeSource/preview5.png) 65 | 66 | > Check the path to localization files will be downloaded. (! it must be 67 | > a folder **../Resources/Localization**) 68 | 69 | Press **SET** button 70 | 71 | 72 | 73 | ![](/ReadmeSource/preview6.png) 74 | 75 | 76 | 77 | 78 | Get session key (this case will be repeated if the key is expired or invalid) 79 | 80 | ![](/ReadmeSource/preview7.png) 81 | 82 | Copy and paste this to **AccessCode** field: 83 | 84 | ![](/ReadmeSource/preview8.png) 85 | 86 | Press **SET** button 87 | 88 | ![](/ReadmeSource/preview9.png) 89 | 90 | 91 | 92 | Now you need to get list of localization , press GET LIST 93 | 94 | 95 | 96 | ![](/ReadmeSource/preview10.png) 97 | 98 | 99 | 100 | A list of localizations will shown like: 101 | 102 | ![](/ReadmeSource/preview11.png) 103 | 104 | 105 | 1. List can be updated 106 | 107 | 2. Localization can be removed from the list of updated localizations 108 | 109 | 3. Download selected list 110 | 111 | 112 | 113 | 114 | ## How to use 115 | 116 | 1) Select your text component on the scene **MeshText/UIText/TextMeshPro** and add the component UILocalization. 117 | 118 | 119 | 120 | 2) Set localization’s key or write to the Key field 121 | 122 | 123 | 124 | ![](/ReadmeSource/preview12.png) 125 | 126 | 127 | If the entered key does not exist you will get an **error**. Check that the key in the localization! 128 | 129 | 130 | 131 | ![](/ReadmeSource/preview13.png) 132 | 133 | 134 | New version include ability to **localize multikey**. This is very useful when you using tags. 135 | 136 | 137 | 138 | ![](/ReadmeSource/preview14.png) 139 | 140 | 141 | You need enter the keys for each **id** {0...N} 142 | 143 | ![](/ReadmeSource/preview15.png) 144 | 145 | 146 | 147 | #### Change the location in the code 148 | 149 | LocalizationService is singleton, for call this use 150 | 151 | > LocalizationService.Instance 152 | 153 | 154 | - When it is first started, it get and set system language by [Application.systemLanguage](https://docs.unity3d.com/ScriptReference/Application-systemLanguage.html). You can change logic of first initialize localization value in **LocalizationService.GetLocalization().** 155 | 156 | 157 | 158 | for example, you can use this enum for languages values ​​in your project 159 | 160 | 161 | 162 | enum SystemLanguage 163 | 164 | LocalizationService.Instance.Localization = SystemLanguage.English.ToString(); 165 | 166 | 167 | 168 | 169 | Get the key in the code 170 | 171 | 172 | 173 | // for current set localization 174 | LocalizationService.Instance.GetTextByKey("localization1"); 175 | 176 | 177 | 178 | 179 | or 180 | 181 | 182 | 183 | "localization1".Translate(); 184 | 185 | 186 | 187 | 188 | You can encode the transition to a new line by adding the translation value "**\n**". UILocalization make this automaticly, but if you need made this from code use extension for string **ParceNewLine()**. 189 | 190 | // key="line" value = "first line \n secondline" 191 | UIText.text = "line".Translate().ParceNewLine(); 192 | 193 | 194 | 195 | ## Help Tools: 196 | 197 | ### Analytic Keys (in development) 198 | 199 | Path to open **Window / Localization / Analytic keys** 200 | This tool will allow you to analyze all keys that are used in the project (!Before starting you need save all changes in the current scene) 201 | 202 | Press **"Find Use"** 203 | 204 | ![](/ReadmeSource/preview16.png) 205 | 206 | ![](/ReadmeSource/preview17.png) 207 | 208 | 209 | 210 | 1. Update Analysis 211 | 212 | 2. Search prefabs and scenes 213 | 214 | 3. Places where there are errors when using 215 | 216 | ![](/ReadmeSource/preview18.png) 217 | 218 | 219 | >**Errors Types:** 220 | >*EmptyKey* - key not set 221 | >*KeyNotFound* - key not found 222 | *TextComponent_NotFound *- no supported component on GameObject - **MeshText / UIText / TextMeshPro** 223 | > 224 | 225 | 226 | 227 | 4. List of keys that are not used 228 | 229 | >! Does not check usage in the code of the project like LocalizationService.Instance.GetTextByKey("localization1") 230 | 231 | ![](/ReadmeSource/preview19.png) 232 | 233 | # 234 | 235 | [![Twitter](https://img.shields.io/badge/follow-Twitter-9cf.svg)](https://twitter.com/suncubestudio) 236 | [![Facebook](https://img.shields.io/badge/follow-Facebook-blue.svg)](https://www.facebook.com/suncubestudio/) 237 | [![YouTube](https://img.shields.io/badge/follow-YouTube-red.svg)](https://www.youtube.com/channel/UC4O9GHjx0ovyVYJgMg4aFMA?view_as=subscriber) 238 | [![AssetStore](https://img.shields.io/badge/-AssetStore-lightgrey.svg)](https://assetstore.unity.com/publishers/14506) 239 | 240 | [![Donate](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://www.donationalerts.com/r/suncube) 241 | -------------------------------------------------------------------------------- /Assets/LocalizeService/Scripts/Editor/LocalizationAnalytics.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Localization; 3 | using UnityEditor; 4 | using UnityEditor.SceneManagement; 5 | using UnityEngine; 6 | using UnityEngine.SceneManagement; 7 | 8 | namespace Localization 9 | { 10 | public enum KeyStatus 11 | { 12 | EmptyKey, 13 | KeyNotFound, 14 | TextComponent_NotFound, 15 | Actual 16 | } 17 | 18 | public class FindInfo 19 | { 20 | public KeyStatus KeyStatus { get; private set; } 21 | public string Name { get; private set; } 22 | public string Path { get; private set; } 23 | public string Key { get; private set; } 24 | 25 | public FindInfo(KeyStatus keyStatus, string name, string path, string key) 26 | { 27 | KeyStatus = keyStatus; 28 | Name = name; 29 | Path = path; 30 | Key = key; 31 | } 32 | } 33 | 34 | public class LocalizationAnalytics : EditorWindow 35 | { 36 | 37 | [MenuItem("Window/Localization/Analytic Keys")] 38 | private static void ShowWindow() 39 | { 40 | EditorWindow.GetWindow(typeof (LocalizationAnalytics)); 41 | } 42 | 43 | private string[] localizationKeys = null; 44 | private Dictionary useKeys = null; 45 | private List sceneInfo = null; 46 | private List prefabInfo = null; 47 | private Vector2 scrollPosTab1; 48 | private Vector2 scrollPosTab2; 49 | private Vector2 scrollPosTab3; 50 | private int tab; 51 | 52 | private void Analytics() 53 | { 54 | SetLocalizationList(); 55 | 56 | FindSceneUse(); 57 | FindPrefabUse(); 58 | //FindCodeUse(); 59 | } 60 | 61 | private void SetLocalizationList() 62 | { 63 | localizationKeys = LocalizationService.GetLocalizationKeys(); 64 | useKeys = new Dictionary(); 65 | 66 | foreach (var localizationKey in localizationKeys) 67 | { 68 | useKeys.Add(localizationKey, false); 69 | } 70 | } 71 | 72 | private void FindSceneUse() 73 | { 74 | sceneInfo = new List(); 75 | 76 | foreach (var settingsScene in EditorBuildSettings.scenes) 77 | { 78 | EditorSceneManager.OpenScene(settingsScene.path, OpenSceneMode.Single); 79 | Scene scene = SceneManager.GetActiveScene(); 80 | 81 | var rootGameObjects = scene.GetRootGameObjects(); 82 | foreach (var o in rootGameObjects) 83 | { 84 | var componentInChildren = o.gameObject.GetComponentsInChildren(); 85 | sceneInfo.AddRange(GetKeyInfo(componentInChildren,scene.name)); 86 | 87 | } 88 | } 89 | } 90 | 91 | private void FindPrefabUse() 92 | { 93 | prefabInfo = new List(); 94 | 95 | string[] allPrefabs = GetAllPrefabs(); 96 | foreach (string prefab in allPrefabs) 97 | { 98 | var load = AssetDatabase.LoadMainAssetAtPath(prefab); 99 | GameObject go; 100 | try 101 | { 102 | go = (GameObject) load; 103 | var componentInChildren = go.GetComponentsInChildren(); 104 | 105 | prefabInfo.AddRange(GetKeyInfo(componentInChildren, prefab)); 106 | } 107 | catch 108 | { 109 | Debug.Log("For some reason, prefab " + prefab + " won't cast to GameObject"); 110 | 111 | } 112 | } 113 | } 114 | 115 | private FindInfo[] GetKeyInfo(UILocalization[] componentList, string path) 116 | { 117 | List result = new List(); 118 | foreach (var component in componentList) 119 | { 120 | if (component.InitializeTextObject() == TextType.None) 121 | { 122 | result.Add(new FindInfo(KeyStatus.TextComponent_NotFound, component.gameObject.name, path, component.Key)); 123 | 124 | } 125 | 126 | var uiLocalizationKeys = component as UILocalizationKeys; 127 | if (uiLocalizationKeys != null) 128 | { 129 | foreach (var key in uiLocalizationKeys.Keys) 130 | result.Add(new FindInfo(GetKeyStatus(key), component.gameObject.name, path, key)); 131 | } 132 | else 133 | { 134 | result.Add(new FindInfo(GetKeyStatus(component.Key), component.gameObject.name, path, 135 | component.Key)); 136 | } 137 | } 138 | 139 | return result.ToArray(); 140 | } 141 | 142 | private KeyStatus GetKeyStatus(string key) 143 | { 144 | if (string.IsNullOrEmpty(key)) 145 | return KeyStatus.EmptyKey; 146 | else if (!useKeys.ContainsKey(key)) 147 | return KeyStatus.KeyNotFound; 148 | 149 | 150 | useKeys[key] = true; 151 | 152 | return KeyStatus.Actual; 153 | } 154 | 155 | private void FindCodeUse() 156 | { 157 | //string projectPath = Application.dataPath; 158 | //projectPath = projectPath.Substring(0, projectPath.IndexOf("Assets")); 159 | //string[] allAssets = AssetDatabase.GetAllAssetPaths(); 160 | 161 | // 162 | // Selection.activeObject = AssetDatabase.LoadMainAssetAtPath(s); 163 | // 164 | 165 | //foreach (string asset in allAssets) 166 | //{ 167 | // int indexCS = asset.IndexOf(".cs"); 168 | // int indexJS = asset.IndexOf(".js"); 169 | // if (indexCS != -1 || indexJS != -1) 170 | // { 171 | // try 172 | // { 173 | // System.IO.FileStream FS = new System.IO.FileStream(projectPath + asset, System.IO.FileMode.Open, 174 | // System.IO.FileAccess.Read, System.IO.FileShare.ReadWrite); 175 | // System.IO.StreamReader SR = new System.IO.StreamReader(FS); 176 | 177 | // string line; 178 | // int lineNum = 0; 179 | // while (!SR.EndOfStream) 180 | // { 181 | // lineNum++; 182 | // line = SR.ReadLine(); 183 | // int index = line.IndexOf("GetTextByKeyWithLocalize"); 184 | // if (index != -1) 185 | // { 186 | // Debug.Log(asset + " " + lineNum); 187 | // Debug.Log(line); 188 | // } 189 | // } 190 | // } 191 | // catch 192 | // { 193 | // } 194 | // } 195 | //} 196 | } 197 | 198 | private void DrawHead(string[] columns, GUIStyle style) 199 | { 200 | 201 | EditorGUILayout.BeginHorizontal(); 202 | 203 | GUI.backgroundColor = Color.gray; 204 | 205 | foreach (var column in columns) 206 | { 207 | EditorGUILayout.LabelField(column, style); 208 | } 209 | 210 | EditorGUILayout.EndHorizontal(); 211 | // 212 | } 213 | 214 | private void OnGUI() 215 | { 216 | titleContent.text = "Analytic Keys"; 217 | 218 | GUILayout.BeginVertical(); 219 | 220 | 221 | bool sceneUse = sceneInfo != null && sceneInfo.Count > 0; 222 | bool prefabUse = prefabInfo != null && prefabInfo.Count > 0; 223 | 224 | string buttonText = "Find Use"; 225 | if (sceneUse || prefabUse) 226 | { 227 | buttonText = "Refresh"; 228 | } 229 | 230 | if (GUILayout.Button(buttonText)) 231 | { 232 | Analytics(); 233 | } 234 | 235 | if (!sceneUse && !prefabUse) 236 | { 237 | EditorGUILayout.HelpBox("The search takes place in [Scenes in Build] and [Prefabs].\nSearch in code is not supported.", MessageType.Info); 238 | EditorGUILayout.Space(); 239 | EditorGUILayout.HelpBox("Save your changes for current scene! ", MessageType.Warning); 240 | 241 | GUILayout.EndVertical(); 242 | return; 243 | } 244 | 245 | 246 | tab = GUILayout.Toolbar(tab, new string[] {"Actual Use ", "Error Use", "Unused Keys"}); 247 | 248 | GUI.backgroundColor = Color.gray; 249 | GUIStyle styleList = new GUIStyle(EditorStyles.textField); 250 | styleList.normal.textColor = Color.white; 251 | GUIStyle styleCategory = new GUIStyle(EditorStyles.textField); 252 | styleCategory.normal.textColor = Color.black; 253 | 254 | 255 | if (tab == 0) 256 | { 257 | string category = string.Empty; 258 | scrollPosTab1 = EditorGUILayout.BeginScrollView(scrollPosTab1); 259 | 260 | GUILayout.Label("Scene", EditorStyles.boldLabel); 261 | DrawHead(new []{ "[ KEY ]" ,"OBJECT_NAME"},styleList); 262 | if (sceneInfo != null) 263 | { 264 | foreach (var findInfo in sceneInfo) 265 | { 266 | if (findInfo.KeyStatus != KeyStatus.Actual) 267 | continue; 268 | 269 | if (category != findInfo.Path) 270 | { 271 | category = findInfo.Path; 272 | GUI.backgroundColor = Color.cyan; 273 | EditorGUILayout.LabelField(findInfo.Path, styleCategory); 274 | GUI.backgroundColor = Color.gray; 275 | } 276 | 277 | EditorGUILayout.BeginHorizontal(); 278 | 279 | EditorGUILayout.LabelField(string.Format("[ {0} ]", findInfo.Key), styleList); 280 | EditorGUILayout.LabelField(findInfo.Name, styleList); 281 | 282 | EditorGUILayout.EndHorizontal(); 283 | } 284 | } 285 | GUILayout.Label("Prefabs", EditorStyles.boldLabel); 286 | DrawHead(new[] { "[ KEY ]", "OBJECT_NAME" }, styleList); 287 | if (prefabInfo != null) 288 | { 289 | foreach (var findInfo in prefabInfo) 290 | { 291 | if (findInfo.KeyStatus != KeyStatus.Actual) 292 | continue; 293 | if (category != findInfo.Path) 294 | { 295 | category = findInfo.Path; 296 | GUI.backgroundColor = Color.cyan; 297 | EditorGUILayout.LabelField(findInfo.Path, styleCategory); 298 | GUI.backgroundColor = Color.gray; 299 | } 300 | 301 | EditorGUILayout.BeginHorizontal(); 302 | 303 | EditorGUILayout.LabelField(string.Format("[ {0} ]", findInfo.Key), styleList); 304 | EditorGUILayout.LabelField(findInfo.Name, styleList); 305 | 306 | EditorGUILayout.EndHorizontal(); 307 | 308 | } 309 | } 310 | 311 | EditorGUILayout.EndScrollView(); 312 | } 313 | else if (tab == 1) 314 | { 315 | string category = string.Empty; 316 | scrollPosTab2 = EditorGUILayout.BeginScrollView(scrollPosTab2); 317 | 318 | GUILayout.Label("Scene", EditorStyles.boldLabel); 319 | DrawHead(new[] { "KEY_STATUS", "[ KEY ]", "OBJECT_NAME" }, styleList); 320 | if (sceneInfo != null) 321 | { 322 | 323 | foreach (var findInfo in sceneInfo) 324 | { 325 | if (findInfo.KeyStatus == KeyStatus.Actual) 326 | continue; 327 | 328 | if (category != findInfo.Path) 329 | { 330 | category = findInfo.Path; 331 | GUI.backgroundColor = Color.cyan; 332 | EditorGUILayout.LabelField(findInfo.Path, styleCategory); 333 | GUI.backgroundColor = Color.gray; 334 | } 335 | 336 | EditorGUILayout.BeginHorizontal(); 337 | 338 | GUI.backgroundColor = Color.red; 339 | EditorGUILayout.LabelField(string.Format("({0})", findInfo.KeyStatus), styleList); 340 | GUI.backgroundColor = Color.gray; 341 | 342 | EditorGUILayout.LabelField(string.Format("[ {0} ]", findInfo.Key), styleList); 343 | EditorGUILayout.LabelField(findInfo.Name, styleList); 344 | 345 | EditorGUILayout.EndHorizontal(); 346 | } 347 | } 348 | 349 | GUILayout.Label("Prefabs", EditorStyles.boldLabel); 350 | DrawHead(new[] { "KEY_STATUS", "[ KEY ]", "OBJECT_NAME" }, styleList); 351 | if (prefabInfo != null) 352 | { 353 | foreach (var findInfo in prefabInfo) 354 | { 355 | if (findInfo.KeyStatus == KeyStatus.Actual) 356 | continue; 357 | 358 | if (category != findInfo.Path) 359 | { 360 | category = findInfo.Path; 361 | GUI.backgroundColor = Color.cyan; 362 | EditorGUILayout.LabelField(findInfo.Path, styleCategory); 363 | GUI.backgroundColor = Color.gray; 364 | } 365 | 366 | EditorGUILayout.BeginHorizontal(); 367 | 368 | GUI.backgroundColor = Color.red; 369 | EditorGUILayout.LabelField(string.Format("({0})", findInfo.KeyStatus), styleList); 370 | GUI.backgroundColor = Color.gray; 371 | 372 | EditorGUILayout.LabelField(string.Format("[ {0} ]", findInfo.Key), styleList); 373 | EditorGUILayout.LabelField( findInfo.Name, styleList); 374 | 375 | EditorGUILayout.EndHorizontal(); 376 | } 377 | } 378 | 379 | EditorGUILayout.EndScrollView(); 380 | } 381 | else if (tab == 2) 382 | { 383 | scrollPosTab3 = EditorGUILayout.BeginScrollView(scrollPosTab3); 384 | 385 | foreach (var useKey in useKeys) 386 | { 387 | if (useKey.Value) 388 | continue; 389 | 390 | EditorGUILayout.SelectableLabel(useKey.Key, styleList, GUILayout.Height(20)); 391 | 392 | } 393 | 394 | EditorGUILayout.Space(); 395 | EditorGUILayout.HelpBox("This keys that are not used. ", MessageType.Info); 396 | EditorGUILayout.HelpBox("Search in the code is not supported.", MessageType.Warning); 397 | 398 | EditorGUILayout.EndScrollView(); 399 | } 400 | 401 | 402 | GUILayout.EndVertical(); 403 | } 404 | 405 | public static string[] GetAllPrefabs() 406 | { 407 | string[] temp = AssetDatabase.GetAllAssetPaths(); 408 | List result = new List(); 409 | foreach (string s in temp) 410 | { 411 | if (s.Contains(".prefab")) result.Add(s); 412 | } 413 | return result.ToArray(); 414 | } 415 | } 416 | } -------------------------------------------------------------------------------- /Assets/LocalizeService/Scripts/Editor/LocalizationDownloader.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEditor; 3 | using System.Collections.Generic; 4 | using Google.GData.Client; 5 | using Google.GData.Spreadsheets; 6 | using System.Security.Cryptography.X509Certificates; 7 | using System.Net.Security; 8 | using System; 9 | using System.Net; 10 | using System.IO; 11 | 12 | namespace Localization 13 | { 14 | public class LocalizationDownloader : EditorWindow 15 | { 16 | [MenuItem("Window/Localization/Downloader")] 17 | private static void ShowWindow() 18 | { 19 | LocalizationDownloader window = EditorWindow.GetWindow(typeof (LocalizationDownloader)) as LocalizationDownloader; 20 | window.Init(); 21 | } 22 | 23 | // Access Settings 24 | private const string PREF_ACCESS_CODE = "accessCode"; 25 | private const string PREF_SHEET_KEY = "spreadSheetKey"; 26 | private static string ACCESS_TOKEN = ""; 27 | private static string REFRESH_TOKEN = ""; 28 | 29 | // Google Application settings 30 | private static string CLIENT_ID = "35584708058-glpfem3u6unhf8d4k8gq20gtleo54m7a.apps.googleusercontent.com"; 31 | static string CLIENT_SECRET = "sh8wUKb9uoYv8Cchs0iLfRiH"; 32 | private static string SCOPE = "https://spreadsheets.google.com/feeds"; 33 | private static string REDIRECT_URI = "urn:ietf:wg:oauth:2.0:oob"; 34 | private static string TOKEN_TYPE = "refresh"; 35 | 36 | private static GOAuth2RequestFactory RefreshAuthenticate() 37 | { 38 | OAuth2Parameters parameters = new OAuth2Parameters() 39 | { 40 | RefreshToken = ACCESS_TOKEN, 41 | AccessToken = REFRESH_TOKEN, 42 | ClientId = CLIENT_ID, 43 | ClientSecret = CLIENT_SECRET, 44 | //Scope = "https://www.googleapis.com/auth/drive https://spreadsheets.google.com/feeds", 45 | Scope = "https://spreadsheets.google.com/feeds", 46 | AccessType = "offline", 47 | TokenType = "refresh" 48 | }; 49 | OAuthUtil.CreateOAuth2AuthorizationUrl(parameters); 50 | return new GOAuth2RequestFactory("spreadsheet", "MySpreadsheetIntegration-v1", parameters); 51 | } 52 | 53 | // 54 | private string appName = "UnityEditor"; 55 | private string urlRoot = "https://spreadsheets.google.com/feeds/spreadsheets/"; 56 | private Vector2 scrollPosition; 57 | private float progress = 100; 58 | private string progressMessage = ""; 59 | private bool isConnect = false; 60 | private SpreadsheetFeed spreadsheetFeed; 61 | private int localizationCount = 0; 62 | 63 | private DownloaderSettings settings; 64 | private List wantedSheetNames = new List(); 65 | 66 | private void OnGUI() 67 | { 68 | if (settings == null) 69 | { 70 | Close(); 71 | 72 | } 73 | 74 | titleContent.text = "Downloader"; 75 | scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition, GUI.skin.scrollView); 76 | 77 | GUILayout.BeginVertical(); 78 | { 79 | GUILayout.Label("Settings", EditorStyles.boldLabel); 80 | 81 | settings.spreadSheetKey = EditorGUILayout.TextField("Spread sheet key", settings.spreadSheetKey); 82 | settings.loadingDir = EditorGUILayout.TextField("Path to loacalization files", settings.loadingDir); 83 | 84 | if (IsTokkenEmpty) 85 | { 86 | GUILayout.BeginHorizontal(); 87 | settings.accessCode = EditorGUILayout.TextField("Access code", settings.accessCode); 88 | GUI.backgroundColor = Color.green; 89 | if (GUILayout.Button("SET", EditorStyles.toolbarButton, GUILayout.Width(50))) 90 | { 91 | GetAccessCode(false); 92 | 93 | if (settings != null) 94 | settings.Save(); 95 | } 96 | GUILayout.EndHorizontal(); 97 | 98 | GUILayout.EndVertical(); 99 | EditorGUILayout.EndScrollView(); 100 | return; 101 | } 102 | 103 | GUI.backgroundColor = Color.white; 104 | settings.accessCode = EditorGUILayout.TextField("Access code", settings.accessCode); 105 | GUILayout.Label(""); 106 | GUILayout.Label("Localizations:", EditorStyles.boldLabel); 107 | 108 | if (wantedSheetNames.Count == 0) 109 | { 110 | GUI.backgroundColor = Color.green; 111 | if (GUILayout.Button("Get List")) 112 | { 113 | wantedSheetNames.Clear(); 114 | GetLocalizationList(); 115 | } 116 | 117 | GUILayout.EndVertical(); 118 | EditorGUILayout.EndScrollView(); 119 | return; 120 | } 121 | 122 | if (GUILayout.Button("Refresh List")) 123 | { 124 | wantedSheetNames.Clear(); 125 | GetLocalizationList(); 126 | } 127 | 128 | int _removeId = -1; 129 | for (int i = 0; i < wantedSheetNames.Count; i++) 130 | { 131 | GUILayout.BeginHorizontal(); 132 | 133 | EditorGUILayout.LabelField(wantedSheetNames[i]); 134 | if (GUILayout.Button("X", EditorStyles.toolbarButton, GUILayout.Width(20))) 135 | { 136 | _removeId = i; 137 | } 138 | GUILayout.EndHorizontal(); 139 | } 140 | 141 | if (_removeId >= 0) 142 | wantedSheetNames.RemoveAt(_removeId); 143 | 144 | if (wantedSheetNames.Count == 0) 145 | { 146 | GUILayout.EndVertical(); 147 | EditorGUILayout.EndScrollView(); 148 | return; 149 | } 150 | 151 | string downloadText = ""; 152 | 153 | if (wantedSheetNames.Count == localizationCount) 154 | downloadText = "Download all sheets"; 155 | else 156 | downloadText = string.Format("Download {0} sheets", wantedSheetNames.Count); 157 | 158 | GUILayout.Label(""); 159 | 160 | GUI.backgroundColor = Color.green; 161 | 162 | if (GUILayout.Button(downloadText, GUILayout.Height(50))) 163 | { 164 | progress = 0; 165 | DownloadLocalizationToCsv(); 166 | } 167 | 168 | GUI.backgroundColor = Color.white; 169 | if ((progress < 100) && (progress > 0)) 170 | { 171 | if (EditorUtility.DisplayCancelableProgressBar("Processing", progressMessage, progress/100)) 172 | { 173 | progress = 100; 174 | EditorUtility.ClearProgressBar(); 175 | } 176 | } 177 | else 178 | { 179 | EditorUtility.ClearProgressBar(); 180 | } 181 | } 182 | GUILayout.EndVertical(); 183 | EditorGUILayout.EndScrollView(); 184 | } 185 | 186 | 187 | public void Init() 188 | { 189 | progress = 100; 190 | progressMessage = ""; 191 | 192 | LoadSettings(); 193 | 194 | ServicePointManager.ServerCertificateValidationCallback = MyRemoteCertificateValidationCallback; 195 | } 196 | 197 | private void LoadSettings() 198 | { 199 | settings = DownloaderSettings.Load(); 200 | } 201 | 202 | private void OnDestroy() 203 | { 204 | if (settings != null) 205 | settings.Save(); 206 | } 207 | 208 | private bool IsTokkenEmpty 209 | { 210 | get { return (ACCESS_TOKEN == "" && REFRESH_TOKEN == ""); } 211 | } 212 | 213 | private void GetLocalizationList() 214 | { 215 | 216 | if (string.IsNullOrEmpty(settings.spreadSheetKey)) 217 | { 218 | Debug.LogError("spreadSheetKey can not be null!"); 219 | return; 220 | } 221 | 222 | PlayerPrefs.SetString(PREF_SHEET_KEY, settings.spreadSheetKey); 223 | PlayerPrefs.Save(); 224 | 225 | if (IsTokkenEmpty) 226 | { 227 | EditorUtility.ClearProgressBar(); 228 | GetAccessCode(); 229 | return; 230 | } 231 | 232 | progressMessage = "Authenticating..."; 233 | GOAuth2RequestFactory requestFactory = RefreshAuthenticate(); 234 | SpreadsheetsService service = new SpreadsheetsService(appName); 235 | service.RequestFactory = requestFactory; 236 | 237 | SpreadsheetQuery query = new SpreadsheetQuery(); 238 | query.Uri = new System.Uri(urlRoot + settings.spreadSheetKey); 239 | progressMessage = "Get list of spreadsheets..."; 240 | 241 | spreadsheetFeed = service.Query(query); 242 | if ((spreadsheetFeed == null) || (spreadsheetFeed.Entries.Count <= 0)) 243 | { 244 | Debug.LogError("Not found any data!"); 245 | EditorUtility.ClearProgressBar(); 246 | return; 247 | } 248 | 249 | AtomEntry mySpreadSheet = spreadsheetFeed.Entries[0]; 250 | AtomLink link = mySpreadSheet.Links.FindService(GDataSpreadsheetsNameTable.WorksheetRel, null); 251 | WorksheetQuery sheetsQuery = new WorksheetQuery(link.HRef.ToString()); 252 | WorksheetFeed sheetsFeed = service.Query(sheetsQuery); 253 | 254 | foreach (WorksheetEntry sheet in sheetsFeed.Entries) 255 | { 256 | wantedSheetNames.Add(sheet.Title.Text); 257 | } 258 | localizationCount = wantedSheetNames.Count; 259 | } 260 | 261 | private void DownloadLocalizationToCsv() 262 | { 263 | if (string.IsNullOrEmpty(settings.spreadSheetKey)) 264 | { 265 | Debug.LogError("spreadSheetKey can not be null!"); 266 | return; 267 | } 268 | 269 | PlayerPrefs.SetString(PREF_SHEET_KEY, settings.spreadSheetKey); 270 | PlayerPrefs.Save(); 271 | 272 | if (IsTokkenEmpty) 273 | { 274 | EditorUtility.ClearProgressBar(); 275 | GetAccessCode(); 276 | return; 277 | } 278 | 279 | progressMessage = "Authenticating..."; 280 | GOAuth2RequestFactory requestFactory = RefreshAuthenticate(); 281 | SpreadsheetsService service = new SpreadsheetsService(appName); 282 | service.RequestFactory = requestFactory; 283 | 284 | progress = 5; 285 | EditorUtility.DisplayCancelableProgressBar("Processing", progressMessage, progress/100); 286 | 287 | SpreadsheetQuery query = new SpreadsheetQuery(); 288 | query.Uri = new System.Uri(urlRoot + settings.spreadSheetKey); 289 | progressMessage = "Get list of spreadsheets..."; 290 | 291 | EditorUtility.DisplayCancelableProgressBar("Processing", progressMessage, progress/100); 292 | SpreadsheetFeed feed = service.Query(query); 293 | if ((feed == null) || (feed.Entries.Count <= 0)) 294 | { 295 | Debug.LogError("Not found any data!"); 296 | progress = 100; 297 | EditorUtility.ClearProgressBar(); 298 | return; 299 | } 300 | progress = 10; 301 | AtomEntry mySpreadSheet = feed.Entries[0]; 302 | 303 | progressMessage = "Get entries from spreadsheets..."; 304 | EditorUtility.DisplayCancelableProgressBar("Processing", progressMessage, progress/100); 305 | AtomLink link = mySpreadSheet.Links.FindService(GDataSpreadsheetsNameTable.WorksheetRel, null); 306 | WorksheetQuery sheetsQuery = new WorksheetQuery(link.HRef.ToString()); 307 | WorksheetFeed sheetsFeed = service.Query(sheetsQuery); 308 | progress = 15; 309 | 310 | 311 | foreach (WorksheetEntry sheet in sheetsFeed.Entries) 312 | { 313 | if ((wantedSheetNames.Count <= 0) || (wantedSheetNames.Contains(sheet.Title.Text))) 314 | { 315 | progressMessage = string.Format("Processing {0}...", sheet.Title.Text); 316 | EditorUtility.DisplayCancelableProgressBar("Processing", progressMessage, progress/100); 317 | 318 | AtomLink cellsLink = sheet.Links.FindService(GDataSpreadsheetsNameTable.CellRel, null); 319 | CellQuery cellsQuery = new CellQuery(cellsLink.HRef.ToString()); 320 | CellFeed cellsFeed = service.Query(cellsQuery); 321 | 322 | CreateCSVFile(sheet.Title.Text, settings.loadingDir, cellsFeed.Entries); 323 | if (wantedSheetNames.Count <= 0) 324 | progress += 85/(sheetsFeed.Entries.Count); 325 | else 326 | progress += 85/wantedSheetNames.Count; 327 | } 328 | } 329 | progress = 100; 330 | AssetDatabase.Refresh(); 331 | } 332 | 333 | private void CreateCSVFile(string fileName, string outputDirectory, AtomEntryCollection cells) 334 | { 335 | if (!outputDirectory.EndsWith("/")) 336 | outputDirectory += "/"; 337 | Directory.CreateDirectory(outputDirectory); 338 | 339 | using (CSVWriter writer = new CSVWriter(outputDirectory + fileName + ".csv")) 340 | { 341 | CSVRow line = null; 342 | uint row = 0; 343 | foreach (CellEntry curCell in cells) 344 | { 345 | if (line == null) 346 | { 347 | line = new CSVRow(); 348 | line.Add(curCell.Cell.Value); 349 | row = curCell.Cell.Row; 350 | } 351 | else 352 | { 353 | if (row == curCell.Cell.Row) 354 | { 355 | line.Add(curCell.Cell.Value); 356 | } 357 | else 358 | { 359 | writer.WriteRow(line); 360 | line = new CSVRow(); 361 | line.Add(curCell.Cell.Value); 362 | row = curCell.Cell.Row; 363 | } 364 | } 365 | } 366 | 367 | if (line != null) 368 | { 369 | writer.WriteRow(line); 370 | } 371 | } 372 | } 373 | 374 | void GetAccessCode(bool withDownload = true) 375 | { 376 | // OAuth 2.0. 377 | OAuth2Parameters parameters = new OAuth2Parameters(); 378 | 379 | parameters.ClientId = CLIENT_ID; 380 | 381 | parameters.ClientSecret = CLIENT_SECRET; 382 | 383 | parameters.RedirectUri = REDIRECT_URI; 384 | 385 | parameters.Scope = SCOPE; 386 | 387 | parameters.AccessType = "offline"; 388 | 389 | parameters.TokenType = TOKEN_TYPE; 390 | 391 | string authorizationUrl = OAuthUtil.CreateOAuth2AuthorizationUrl(parameters); 392 | Debug.Log(authorizationUrl); 393 | Debug.Log("Please visit the URL above to authorize your OAuth " 394 | + "request token. Once that is complete, type in your access code to " 395 | + "continue..."); 396 | 397 | parameters.AccessCode = settings.accessCode; 398 | 399 | if (parameters.AccessCode == "") 400 | { 401 | Debug.LogWarning("Access code is blank!"); 402 | EditorUtility.ClearProgressBar(); 403 | Application.OpenURL(authorizationUrl); 404 | return; 405 | } 406 | 407 | Debug.Log("Get access token."); 408 | 409 | try 410 | { 411 | OAuthUtil.GetAccessToken(parameters); 412 | string accessToken = parameters.AccessToken; 413 | string refreshToken = parameters.RefreshToken; 414 | Debug.Log("OAuth Access Token: " + accessToken + "\n"); 415 | ACCESS_TOKEN = accessToken; 416 | Debug.Log("OAuth Refresh Token: " + refreshToken + "\n"); 417 | REFRESH_TOKEN = refreshToken; 418 | PlayerPrefs.SetString(PREF_ACCESS_CODE, settings.accessCode); 419 | PlayerPrefs.Save(); 420 | 421 | if (withDownload) 422 | DownloadLocalizationToCsv(); 423 | } 424 | catch (System.Exception e) 425 | { 426 | Debug.LogError(e.ToString()); 427 | EditorUtility.ClearProgressBar(); 428 | Application.OpenURL(authorizationUrl); 429 | return; 430 | } 431 | } 432 | 433 | public bool MyRemoteCertificateValidationCallback(System.Object sender, X509Certificate certificate, X509Chain chain, 434 | SslPolicyErrors sslPolicyErrors) 435 | { 436 | bool isOk = true; 437 | if (sslPolicyErrors != SslPolicyErrors.None) 438 | { 439 | for (int i = 0; i < chain.ChainStatus.Length; i++) 440 | { 441 | if (chain.ChainStatus[i].Status != X509ChainStatusFlags.RevocationStatusUnknown) 442 | { 443 | chain.ChainPolicy.RevocationFlag = X509RevocationFlag.EntireChain; 444 | chain.ChainPolicy.RevocationMode = X509RevocationMode.Online; 445 | chain.ChainPolicy.UrlRetrievalTimeout = new TimeSpan(0, 1, 0); 446 | chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllFlags; 447 | bool chainIsValid = chain.Build((X509Certificate2) certificate); 448 | if (!chainIsValid) 449 | { 450 | isOk = false; 451 | } 452 | } 453 | } 454 | } 455 | return isOk; 456 | } 457 | } 458 | } --------------------------------------------------------------------------------