Created
October 20, 2022 20:55
-
-
Save Draknek/a1b8b9dcfd056ba345740532aabc83fd to your computer and use it in GitHub Desktop.
Unity localisation scripts - pulling data from Google Sheets
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
StringsInspector.cs is the UI code (goes in an Assets/Editor folder so it only gets loaded in the editor) | |
Strings.Import is the function that takes the spreadsheet data and puts it into the ScriptableObject | |
Language.cs/Languages.cs might not be relevant but I see they're referenced here so I'm sharing them too |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Linq; | |
using UnityEngine; | |
namespace Localization | |
{ | |
[System.Serializable] | |
public class Language | |
{ | |
[SerializeField] string _id; | |
public string id => _id; | |
[SerializeField] SystemLanguage _systemLanguage; | |
public SystemLanguage systemLanguage => _systemLanguage; | |
[SerializeField] string _cultureid; | |
/// <summary> | |
/// Returns the culture string stored in the language. Unless English is selected in which case it checks for AU/US/GB and builds it's own string. | |
/// </summary> | |
public string cultureid | |
{ | |
get | |
{ | |
/*if (_systemLanguage == SystemLanguage.English) | |
{ | |
string[] allowedRegions = {"AU","US","GB"}; | |
string regionString = System.Globalization.RegionInfo.CurrentRegion?.ToString().ToUpper(); | |
if ( string.IsNullOrEmpty(regionString) == false && allowedRegions.Contains(regionString) ) | |
{ | |
return "en-" + regionString; | |
} | |
}*/ | |
return _cultureid; | |
} | |
} | |
[SerializeField] LanguageStyles _styleSheet; | |
public LanguageStyles styleSheet => _styleSheet; | |
[SerializeField] private bool _useImageToDisplayInDropdown = true; | |
public bool useImageToDisplayInDropdown => _useImageToDisplayInDropdown; | |
[SerializeField] private string _specificDateFormatString = null; | |
public string specificDateFormatString => _specificDateFormatString; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using UnityEngine; | |
namespace Localization | |
{ | |
//[CreateAssetMenu] | |
public class Languages : ScriptableObject | |
{ | |
[SerializeField] List<Language> languages = null; | |
[SerializeField] int defaultLanguageIndex = 0; | |
public Language defaultLanguage => languages[defaultLanguageIndex]; | |
public List<Language> All() | |
{ | |
return languages; | |
} | |
public string Auto() | |
{ | |
//Force through different English regions | |
if (Application.systemLanguage == SystemLanguage.English) | |
{ | |
string regionString = System.Globalization.RegionInfo.CurrentRegion?.ToString().ToUpper(); | |
if (regionString == "GB") | |
{ | |
return "en-GB"; | |
} | |
if (regionString == "AU") | |
{ | |
return "en-AU"; | |
} | |
//US | |
return "en"; | |
} | |
#if UNITY_SWITCH | |
//System language is not as accurate with Application.systemLanguage so lets do a custom string check first | |
string switchLanguageID = GetSwitchSystemLanguage(); | |
if (String.IsNullOrEmpty(switchLanguageID) == false) | |
{ | |
foreach (var language in languages) | |
{ | |
if (language.id == switchLanguageID) | |
{ | |
return language.id; | |
} | |
} | |
} | |
#endif | |
foreach (var language in languages) | |
{ | |
if (language.systemLanguage == Application.systemLanguage) | |
{ | |
return language.id; | |
} | |
} | |
return defaultLanguage.id; | |
} | |
public Language AutoLanguage() | |
{ | |
foreach (var language in languages) | |
{ | |
if (language.systemLanguage == Application.systemLanguage) | |
{ | |
return language; | |
} | |
} | |
return defaultLanguage; | |
} | |
public Language GetByName(string _language) | |
{ | |
if(_language == "auto") | |
{ | |
_language = Auto(); | |
} | |
foreach (var language in languages) | |
{ | |
if (language.id == _language) | |
{ | |
return language; | |
} | |
} | |
return defaultLanguage; | |
} | |
#if UNITY_EDITOR | |
/// <summary> | |
/// This just makes sure the number of styles is correct and they have the right name | |
/// </summary> | |
void OnValidate() | |
{ | |
if (Application.isPlaying) | |
return; | |
foreach (var language in languages) | |
{ | |
if (language.styleSheet.styleTags.Length < (int) StyleType.Count) | |
{ | |
Array.Resize(ref language.styleSheet.styleTags, (int) StyleType.Count); | |
} | |
for (int i = 0; i < language.styleSheet.styleTags.Length; i++) | |
{ | |
language.styleSheet.styleTags[i].setNameByStyle((StyleType)i); | |
} | |
} | |
} | |
#endif | |
#if UNITY_SWITCH | |
public static string GetSwitchSystemLanguage() | |
{ | |
string systemLanguage = nn.oe.Language.GetDesired(); | |
if (string.IsNullOrEmpty(systemLanguage)) return "en"; | |
systemLanguage = systemLanguage.Trim(); | |
// Do some extra careful trimming here because the Switch SDK might be doing some extra padding. | |
// This was read about here: https://developer.nintendo.com/group/development/g1kr9vj6/forums/english/-/gts_message_boards/thread/274502428 | |
if (systemLanguage.Contains("\0")) | |
systemLanguage = systemLanguage.Substring(0, systemLanguage.IndexOf('\0')); | |
// Languages supported by the Switch can be found here: https://developer.nintendo.com/html/online-docs/nx-en/g1kr9vj6-en/Packages/SDK/NintendoSDK/Documents/Package/contents/Pages/Page_100911958.html | |
/*if (systemLanguage == "en-US") CachedSystemLanguageString = "en"; // United States English | |
if (systemLanguage == "es-419") CachedSystemLanguageString = "es";// Latin American Spanish | |
if (systemLanguage == "pt") CachedSystemLanguageString = "pt-BR"; // Portuguese | |
if (systemLanguage == "zh-CN") CachedSystemLanguageString = "zh-Hans"; // Chinese | |
if (systemLanguage == "zh-TW") CachedSystemLanguageString = "zh-Hant"; // Taiwanese | |
*/ | |
return systemLanguage; | |
} | |
#endif | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using UnityEngine; | |
namespace Localization | |
{ | |
//[CreateAssetMenu] | |
public class Strings : ScriptableObject | |
{ | |
public string uiSheetURI; | |
[SerializeField] Languages languages = null; | |
[SerializeField] List<StringsByLanguageWithId> strings = null; | |
public string Get(string id, string language = null) | |
{ | |
if (language == null || language == "auto") | |
{ | |
//language can equal "auto", but languageData always contains the current in use | |
language = Config.languageData.id; | |
} | |
#if PRERELEASE | |
if (language == "debug") | |
{ | |
return id; | |
} | |
#endif | |
var stringByLanguageWithId = strings.Find(x => x.id == id); | |
if (stringByLanguageWithId == null) | |
{ | |
return id; | |
} | |
var stringWithLanguage = stringByLanguageWithId.languages.Find(x => x.language == language); | |
if (stringWithLanguage == null) | |
{ | |
return id; | |
} | |
if (string.IsNullOrWhiteSpace(stringWithLanguage.value)) | |
{ | |
Debug.LogWarning($"String '{id}' is blank in {language}, defaulting to en-GB"); | |
stringWithLanguage = stringByLanguageWithId.languages.Find(x => x.language == "en-GB"); | |
if (stringWithLanguage == null) | |
{ | |
return id; | |
} | |
} | |
#if LANGUAGE_TEST | |
return "{"+stringWithLanguage.value+"}"; | |
#endif | |
return stringWithLanguage.value; | |
} | |
public void Set(string id, List<(string language, string value)> stringsByLanguage) | |
{ | |
strings.RemoveAll(x => x.id == id); | |
var languages = new List<StringWithLanguage>(); | |
foreach (var (language, value) in stringsByLanguage) | |
{ | |
if (language == "ar") | |
{ | |
var lines = value.Split('\n'); | |
Array.Reverse( lines ); | |
string newArabicString = ArabicSupport.ArabicFixer.Fix(string.Join("\n", lines)); | |
//string newArabicString = value; | |
char[] reversedStringArray = newArabicString.ToCharArray(); | |
Array.Reverse(reversedStringArray); | |
languages.Add(new StringWithLanguage | |
{ | |
language = language, | |
value = new string(reversedStringArray) | |
}); | |
} | |
else | |
{ | |
languages.Add(new StringWithLanguage | |
{ | |
language = language, | |
value = value | |
}); | |
} | |
} | |
strings.Add(new StringsByLanguageWithId | |
{ | |
id = id, | |
languages = languages | |
}); | |
} | |
public void Import(string tsv) | |
{ | |
var values = tsv.Split('\n'); | |
if (values.Length < 2) | |
return; | |
string[] languageHeaders = values[0].Split('\t'); | |
for (int i = 0; i < languageHeaders.Length; i++) | |
{ | |
languageHeaders[i] = languageHeaders[i].Trim('\r', '\n'); | |
} | |
List<(string language, string value)> stringsByLanguage = new List<(string language, string value)>(); | |
for (var valueIndex = 0; valueIndex < values.Length; valueIndex++) | |
{ | |
stringsByLanguage.Clear(); | |
var value = values[valueIndex].Split('\t'); | |
// If headers have been copied, skip first line | |
if (valueIndex == 0 && value[0] == "Line ID") | |
{ | |
continue; | |
} | |
// If line too short, skip | |
if (value.Length < 3) | |
{ | |
continue; | |
} | |
var lineId = value[0]; | |
for (int i = 2; i < value.Length; i++) | |
{ | |
stringsByLanguage.Add( ( languageHeaders[i], | |
value[i].Trim('\r', '\n').Replace('¬','\n') ) ); | |
} | |
Set(lineId, stringsByLanguage); | |
} | |
} | |
/// <summary> | |
/// Looks for platform strings and swaps them for the original | |
/// </summary> | |
public void InitializeForPlatform() | |
{ | |
List<int> stringsToRemove = new List<int>(); | |
#if UNITY_SWITCH | |
for (int i = strings.Count; --i >= 0;) | |
{ | |
if (strings[i].id.EndsWith("_Switch")) | |
{ | |
string newID = strings[i].id.Substring(0, strings[i].id.Length - 7); | |
int indexToRemove = strings.FindIndex(0, x => x.id == newID); | |
#if !UNITY_EDITOR | |
if(indexToRemove>=0) | |
stringsToRemove.Add(indexToRemove); | |
strings[i].id = newID; | |
#else | |
Debug.Log("strings Found on device I would take" + strings[i].id + " and copy over " + newID + " at index " + indexToRemove); | |
#endif | |
} | |
} | |
#endif | |
if (stringsToRemove.Count > 0) | |
{ | |
stringsToRemove.Sort(); | |
} | |
for (int i = stringsToRemove.Count; --i >= 0;) | |
{ | |
strings.RemoveAt(stringsToRemove[i]); | |
} | |
} | |
[System.Serializable] | |
class StringsByLanguageWithId | |
{ | |
public string id; | |
public List<StringWithLanguage> languages; | |
} | |
[System.Serializable] | |
class StringWithLanguage | |
{ | |
public string language; | |
public string value; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using UnityEditor; | |
using System.IO; | |
using System.Net; | |
[CustomEditor(typeof(Localization.Strings), true)] | |
public class StringsInspector : Editor | |
{ | |
public override void OnInspectorGUI() | |
{ | |
DrawDefaultInspector(); | |
if (GUILayout.Button("Import UI Strings")) | |
{ | |
var strings = target as Localization.Strings; | |
var tsv = HTTPGet(strings.uiSheetURI); | |
if (!string.IsNullOrEmpty(tsv)) | |
{ | |
strings.Import(tsv); | |
EditorUtility.SetDirty(strings); | |
} | |
} | |
} | |
static string HTTPGet(string uri) | |
{ | |
var request = (HttpWebRequest)WebRequest.Create(uri); | |
request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; | |
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) | |
using (Stream stream = response.GetResponseStream()) | |
using (StreamReader reader = new StreamReader(stream)) | |
{ | |
return reader.ReadToEnd(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment