Localisation de tous les textes

La plupart des jeux utilisent la localisation basée sur les clés, c'est-à-dire qu'une clé est nécessaire pour décrire un texte spécifique, mais j'offre une meilleure option, bien que cette option ne convienne pas à ceux qui ont la voix dans les jeux, c'est plus facile grâce à une clé.

Qu'est-ce qu'une clé et pourquoi est-elle nécessaire


La clé, ou plutôt le mot-clé, est le mot par lequel il sera déterminé quel texte est nécessaire, puis la recherche de la langue sélectionnée est déjà en cours. Exemple de mot-clé: scene_Escape_from_jail_Ethan_dialog_with_Mary_3 , oui, la clé ressemblera à ceci si votre jeu a plusieurs scènes, une grande intrigue. Je suggère d'écrire immédiatement et immédiatement une phrase dans l'une des langues, le plus souvent l'anglais ou celle dans laquelle le programmeur parle couramment. Soit dit en passant, étant donné que toutes les phrases de la langue actuelle et de la langue principale se trouvent dans la RAM, cela sera plus productif que de les extraire du fichier à chaque fois, pour les grands jeux, vous pouvez légèrement modifier le fichier pour chaque scène.

Comment tout sera organisé


Dans les actions décrites ci-dessous, la classe Lang statique sera utilisée, dans laquelle toutes les recherches de mots / phrases auront lieu. Déclarons une classe en connectant les bibliothèques dont nous avons besoin:

using UnityEngine; using System.Collections.Generic; // list and dictionary #if UNITY_EDITOR using UnityEditor; using System.IO; // created file in editor #endif public class Lang { private const string Path = "/Resources/"; // path to resources folder private const string FileName = "Language"; // file name with phrases } 

Et donc, nous ne pouvons pas nous passer d'une bibliothèque standard, puisque nous obtiendrons le fichier des ressources, nous pouvons le télécharger de n'importe quelle manière pratique, mais c'est plus pratique et pratique. Les bibliothèques système sont nécessaires pour connecter la liste, le dictionnaire et travailler avec les fichiers de l'éditeur. La bibliothèque UnityEditor n'est nécessaire que pour mettre à jour le fichier lors du premier enregistrement de la phrase, car après un redémarrage rapide, toutes les phrases ne seront pas toujours chargées, mais avec cette bibliothèque, nous pouvons résoudre ce problème. La classe stocke deux champs statiques, que ce soit les noms du fichier, dans notre cas le chemin est un dossier avec des ressources, et il peut y avoir n'importe quel nom du fichier.

Vous devez maintenant ajouter des listes pour stocker tout ce qui est utilisé par la langue et le dictionnaire.

 private static int LangIndex; // variable to store the index of the current language private static List<SystemLanguage> languages = new List<SystemLanguage>(); // having languages in game private static Dictionary<string, string> Phrases = new Dictionary<string, string>(); // keys and values 

Le champ LangIndex contiendra l'index de la langue actuelle par rapport à l'enregistrement dans le fichier. Dans la liste des langues - toutes les langues utilisées dans le fichier seront enregistrées. Le dictionnaire stockera toutes les phrases dans la langue principale et dans la langue actuelle.

Il est nécessaire d'ajouter l'initialisation des champs décrits ci-dessus de la classe.

Code
 public static bool isStarting // bool for check starting { get; private set; } public static SystemLanguage language // return current language { get; private set; } #if UNITY_EDITOR public static void Starting(SystemLanguage _language, SystemLanguage default_language = SystemLanguage.English, params SystemLanguage[] _languages) // write languages without main language, it self added #else public static void Starting(SystemLanguage _language = SystemLanguage.English) // main language - only for compilation #endif { #if UNITY_EDITOR if (!File.Exists(Application.dataPath + Path + FileName + ".csv")) // if file wasn't created { File.Create(Application.dataPath + "/Resources/" + FileName + ".csv").Dispose(); // create and lose link File.WriteAllText(Application.dataPath + "/Resources/" + FileName + ".csv", SetLanguage(default_language, _languages)); // write default text with index } #endif string[] PhrasesArr = Resources.Load<TextAsset>(FileName).text.Split('\n'); // temp var for write in dicrionary string[] string_languages = PhrasesArr[0].Split(';'); // string with using languages int _length = string_languages.Length - 1; for (int i = 0; i < _length; i++) { languages.Add(SystemLanguageParse(string_languages[i])); // string language to SystemLanguage } LangIndex = FindIndexLanguage(_language); // index with current language for (int i = 0; i < PhrasesArr.Length; i++) // add keys and value { string[] temp_string = PhrasesArr[i].Split(';'); if (temp_string.Length > LangIndex) Phrases.Add(temp_string[0], temp_string[LangIndex]); else Phrases.Add(temp_string[0], temp_string[0]); } isStarting = true; } 

Il utilisera immédiatement la directive intégrée afin de ne pas effectuer d'actions inutiles après la compilation de l'application. L'appel à Lang.Starting (...) devrait ressembler à ceci:

 #if !UNITY_EDITOR Lang.Starting(LANGUAGE); #else Lang.Starting(LANGUAGE, SystemLanguage.English, SystemLanguage.Russian, SystemLanguage.Ukrainian); #endif private static int FindIndexLanguage(SystemLanguage _language) // finding index or current language { int _index = languages.IndexOf(_language); if (_index == -1) // if language not found return 0; // return main language return _index; } #if UNITY_EDITOR private static void Add(string AddString) // add phrases only form editor { File.AppendAllText(Application.dataPath + "/Resources/" + FileName +".csv", AddString + "\n"); // rewrite text to file Phrases.Add(AddString, AddString); // add phrase to dicrionary AssetDatabase.Refresh(); // refresh file } #endif #if UNITY_EDITOR private static string SetLanguage(SystemLanguage default_language, params SystemLanguage[] _languages) // set first string to file { string ret_string = ""; ret_string += default_language + ";"; foreach (SystemLanguage _language in _languages) { ret_string += _language + ";"; } return ret_string + "!@#$%\n"; // for last index } #endif 


L'appel lors de la lecture dans l'éditeur doit contenir deux paramètres principaux, c'est ce que les phrases de langue doivent être traduites maintenant, et quelle langue sera utilisée comme langue principale, tous les autres paramètres sont les paramètres de langue qui devraient être contenus dans le fichier, ces paramètres sont nécessaires uniquement lors du premier lancement, lorsque le fichier n'a pas encore été créé (et qu'il n'est pas nécessaire de le supprimer plus tard), sinon, si vous devez ajouter une langue, vous devez tout copier du fichier, supprimer le fichier et réexécuter le code dans l'éditeur ou l'ajouter vous-même au fichier.

Le code ci-dessus utilise la méthode SystemLanguageParse (...) , qui traduit simplement les noms de langue du type chaîne en SystemLanguage (cette méthode sera inférieure).

Arrêtons-nous sur la méthode add:

 #if UNITY_EDITOR private static void Add(string AddString) // add phrases only form editor { File.AppendAllText(Application.dataPath + "/Resources/" + FileName +".csv", AddString + "\n"); // rewrite text to file Phrases.Add(AddString, AddString); // add phrase to dicrionary AssetDatabase.Refresh(); // refresh file } #endif 

Étant donné que cette méthode ne sera utilisée qu'au démarrage à partir de l'éditeur, nous pouvons utiliser en toute sécurité l'utilitaire système pour écraser le fichier, ainsi que mettre à jour les fichiers modifiés dans l'éditeur à l'aide de la méthode Refresh (). Entre ces actions, une phrase est simplement ajoutée au dictionnaire, afin de vous protéger du réenregistrement dans la même session.

Au fait, j'ai oublié de dire que les phrases seront stockées dans un fichier .csv, ce qui nous permettra de traduire confortablement des phrases dans Excele. Maintenant, nous devons ajouter une méthode qui nous convient, qui nous permettra de changer la langue:

  public static void ChangeLanguage(SystemLanguage _language) // change language { string[] PhrasesArr = Resources.Load<TextAsset>(FileName).text.Split('\n'); // load all text from file LangIndex = FindIndexLanguage(_language); Phrases.Clear(); // clear dictionary with phrases for (int i = 1; i < PhrasesArr.Length; i++) { string[] temp_string = PhrasesArr[i].Split(';'); if (temp_string.Length > LangIndex) Phrases.Add(temp_string[0], temp_string[LangIndex]); else Phrases.Add(temp_string[0], temp_string[0]); } } 

Et donc, nous sommes arrivés à la méthode la plus importante, qui prendra la phrase dans la langue principale et la transmettra au bon utilisateur:

  public static string Phrase(string DefaultPhrase) // translate phrase, args use to formating string { #if UNITY_EDITOR if (!isStarting) // if not starting { throw new System.Exception("Forgot initialization.Use Lang.Starting(...)"); // throw exception } #endif string temp_EnglishPhrase = DefaultPhrase; // temp variable for try get value if (Phrases.TryGetValue(DefaultPhrase, out DefaultPhrase)) // if value has been found { return temp_EnglishPhrase; } #if UNITY_EDITOR Add(temp_EnglishPhrase); // add phrase if value hasn't been found #endif return temp_EnglishPhrase; } 

Cette méthode prend simplement une phrase dans la langue principale, puis itère sur tout ce qui est dans le dictionnaire, trouvant une telle phrase par clé, elle nous donne les valeurs de cette clé, qui est une phrase dans la langue dont nous avons besoin. Vous pouvez utiliser cette méthode avec une simple ligne de code:

 string str = Lang.Phrase("Hello world"); 

Maintenant, la phrase dans le langage dont nous avons besoin entrera dans la chaîne str, si soudain elle manque, alors la phrase spécifiée dans les paramètres, c'est-à-dire Hello world, tombera.

Cette méthode peut être un peu améliorée, afin que vous puissiez prendre des arguments à remplir:

  public static string Phrase(string DefaultPhrase, params string[] args) // translate phrase, args use to formating string { #if UNITY_EDITOR if (!isStarting) // if not starting { throw new System.Exception("Forgot initialization.Use Lang.Starting(...)"); // throw exception } #endif string temp_EnglishPhrase = DefaultPhrase; // temp variable for try get value if (Phrases.TryGetValue(DefaultPhrase, out DefaultPhrase)) // if value has been found { if (args.Length == 0) return DefaultPhrase; return string.Format(DefaultPhrase, args); } #if UNITY_EDITOR Add(temp_EnglishPhrase); // add phrase if value hasn't been found #endif if (args.Length == 0) return temp_EnglishPhrase; return string.Format(temp_EnglishPhrase, args); } 

Maintenant, cette méthode peut être appelée comme auparavant:

 string str = Lang.Phrase("Hello world"); 

Mais maintenant, notre méthode a formaté la sortie, indiquant les paramètres séparés par des virgules:

 string str = Lang.Phrase("Hello {0} from {1}", "world", "habr"); 

Traductions de phrases


Comme je l'ai écrit ci-dessus, le fichier utilise des extensions .csv qui vous permettront de tout faire dans Excel, mais pas si simple, le problème de C-sharpe et Excel est qu'ils comprennent l'alphabet cyrillique dans un encodage différent, Excel ne comprend que l'encodage UTF-8-BOM ou celui que notre YaP ne comprend pas, nous devons utiliser uniquement UTF-8, même si l'éditeur unitaire comprendra UTF-8-BOM, dans le code il y a deux mots identiques sur des encodages différents (UTF-8 et UTF-8- BOM) ne sera pas égal, ce qui entraînera l'ajout constant de mots identiques à notre fichier.

Nous pouvons encoder des fichiers en utilisant NotePad ++ gratuit en le téléchargeant depuis off. site. La modification d'un fichier ne vous posera aucun problème, pour ajouter un seul mot vous pouvez même utiliser un éditeur de texte, le même bloc-notes ou même notre environnement de programmation.

Code final
 using UnityEngine; using System.Collections.Generic; // list and dictionary #if UNITY_EDITOR using UnityEditor; using System.IO; // created file in editor #endif public class Lang { private const string Path = "/Resources/"; // path to resources folder private const string FileName = "Language"; // file name with phrases private static int NumberOfLanguage; // variable to store the index of the current language private static List<SystemLanguage> languages = new List<SystemLanguage>(); // having languages in game private static Dictionary<string, string> Phrases = new Dictionary<string, string>(); // keys and values private static SystemLanguage language; // current language #if UNITY_EDITOR public static void Starting(SystemLanguage _language, SystemLanguage default_language, params SystemLanguage[] _languages) // write languages without main language, it self added #else public static void Starting(SystemLanguage _language = SystemLanguage.English) // main language - only for compilation #endif { #if UNITY_EDITOR if (!File.Exists(Application.dataPath + Path + FileName + ".csv")) // if file wasn't created { File.Create(Application.dataPath + "/Resources/" + FileName + ".csv").Dispose(); // create and lose link File.WriteAllText(Application.dataPath + "/Resources/" + FileName + ".csv", SetLanguage(default_language, _languages)); // write default text with index } #endif string[] PhrasesArr = Resources.Load<TextAsset>(FileName).text.Split('\n'); // temp var for write in dicrionary string[] string_languages = PhrasesArr[0].Split(';'); // string with using languages int _length = string_languages.Length - 1; for (int i = 0; i < _length; i++) { languages.Add(SystemLanguageParse(string_languages[i])); // string language to SystemLanguage } NumberOfLanguage = FindIndexLanguage(_language); // index with current language for (int i = 0; i < PhrasesArr.Length; i++) // add keys and value { string[] temp_string = PhrasesArr[i].Split(';'); if (temp_string.Length > NumberOfLanguage) Phrases.Add(temp_string[0], temp_string[NumberOfLanguage]); else Phrases.Add(temp_string[0], temp_string[0]); } isStarting = true; } public static bool isStarting // bool for check starting { get; private set; } public static SystemLanguage Language // return current language { get { return language; } } public static string Phrase(string DefaultPhrase, params string[] args) // translate phrase, args use to formating string { #if UNITY_EDITOR if (!isStarting) // if not starting { throw new System.Exception("Forgot initialization.Use Lang.Starting(...)"); // throw exception } #endif string temp_EnglishPhrase = DefaultPhrase; // temp variable for try get value if (Phrases.TryGetValue(DefaultPhrase, out DefaultPhrase)) // if value has been found { if (args.Length == 0) return DefaultPhrase; return string.Format(DefaultPhrase, args); } #if UNITY_EDITOR Add(temp_EnglishPhrase); // add phrase if value hasn't been found #endif if (args.Length == 0) return temp_EnglishPhrase; return string.Format(temp_EnglishPhrase, args); } public static void ChangeLanguage(SystemLanguage _language) // change language { string[] PhrasesArr = Resources.Load<TextAsset>(FileName).text.Split('\n'); // load all text from file NumberOfLanguage = FindIndexLanguage(_language); Phrases.Clear(); // clear dictionary with phrases for (int i = 1; i < PhrasesArr.Length; i++) { string[] temp_string = PhrasesArr[i].Split(';'); if (temp_string.Length > NumberOfLanguage) Phrases.Add(temp_string[0], temp_string[NumberOfLanguage]); else Phrases.Add(temp_string[0], temp_string[0]); } } private static int FindIndexLanguage(SystemLanguage _language) // finding index or current language { int _index = languages.IndexOf(_language); if (_index == -1) // if language not found return 0; // return main language return _index; } #if UNITY_EDITOR private static void Add(string AddString) // add phrases only form editor { File.AppendAllText(Application.dataPath + "/Resources/" + FileName + ".csv", AddString + "\n"); // rewrite text to file Phrases.Add(AddString, AddString); // add phrase to dicrionary AssetDatabase.Refresh(); // refresh file } #endif #if UNITY_EDITOR private static string SetLanguage(SystemLanguage default_language, params SystemLanguage[] _languages) // set first string to file { string ret_string = ""; ret_string += default_language + ";"; foreach (SystemLanguage _language in _languages) { ret_string += _language + ";"; } return ret_string + "!@#$%\n"; // for last index } #endif private static SystemLanguage SystemLanguageParse(string _language) // just parse from string to SystemLanguage { switch (_language) { case "English": return SystemLanguage.English; case "Russian": return SystemLanguage.Russian; case "Ukrainian": return SystemLanguage.Ukrainian; case "Polish": return SystemLanguage.Polish; case "French": return SystemLanguage.French; case "Japanese": return SystemLanguage.Japanese; case "Chinese": return SystemLanguage.Chinese; case "Afrikaans": return SystemLanguage.Afrikaans; case "Arabic": return SystemLanguage.Arabic; case "Basque": return SystemLanguage.Basque; case "Belarusian": return SystemLanguage.Belarusian; case "Bulgarian": return SystemLanguage.Bulgarian; case "ChineseSimplified": return SystemLanguage.ChineseSimplified; case "ChineseTraditional": return SystemLanguage.ChineseTraditional; case "Czech": return SystemLanguage.Czech; case "Danish": return SystemLanguage.Danish; case "Dutch": return SystemLanguage.Dutch; case "Estonian": return SystemLanguage.Estonian; case "Faroese": return SystemLanguage.Faroese; case "Finnish": return SystemLanguage.Finnish; case "German": return SystemLanguage.German; case "Greek": return SystemLanguage.Greek; case "Hebrew": return SystemLanguage.Hebrew; case "Hungarian": return SystemLanguage.Hungarian; case "Icelandic": return SystemLanguage.Icelandic; case "Indonesian": return SystemLanguage.Indonesian; case "Italian": return SystemLanguage.Italian; case "Korean": return SystemLanguage.Korean; case "Latvian": return SystemLanguage.Latvian; case "Lithuanian": return SystemLanguage.Lithuanian; case "Norwegian": return SystemLanguage.Norwegian; case "Portuguese": return SystemLanguage.Portuguese; case "Romanian": return SystemLanguage.Romanian; case "SerboCroatian": return SystemLanguage.SerboCroatian; case "Slovak": return SystemLanguage.Slovak; case "Slovenian": return SystemLanguage.Slovenian; case "Spanish": return SystemLanguage.Spanish; case "Swedish": return SystemLanguage.Swedish; case "Thai": return SystemLanguage.Thai; case "Turkish": return SystemLanguage.Turkish; case "Vietnamese": return SystemLanguage.Vietnamese; } return SystemLanguage.Unknown; } } 

La principale chose à retenir: UTF-8-BOM - pour travailler dans Excel, UTF-8 pour travailler avec du code, n'oubliez pas.

Source: https://habr.com/ru/post/fr446844/


All Articles