Mark Geschrieben 20. November 2013 Melden Share Geschrieben 20. November 2013 Ich habe für ein Spielchen für mich eine StringTable geschrieben die ich gerne öffentlich mache: Verwenden ist ganz einfach: var yesText = StringTable.Default.GetString("Dialogs.Yes"); Die StringTable wird dabei automatisch die Strings laden und entsprechend der aktuellen Systemsprache die passenden Strings wählen. Man kann die aktuelle Sprache ganz einfach ändern indem man den 2 Buchstaben ISO Sprachnamen wählt: StringTable.Default.CurrentLanguage = "fr"; // Französisch Wenn es den gesuchten String nicht für die gewünschte Sprache gibt, so wird zu der Standardsprache zurückgegriffen (englisch), auch diese kann man ändern: StringTable.Default.DefaultLanguage= "de"; // Deutsch Man erstellt dafür XML Dateien welche die Strings enthalten, so eine Reihe von XML Dateien sieht zB so aus: default.xml: <?xml version="1.0" encoding="utf-8"?> <StringTable xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <Locale Language="en" Path="strings/en-base" /> <Locale Language="de" Path="strings/de-base" /> </StringTable> Alternative default.xml: <?xml version="1.0" encoding="utf-8"?> <StringTable xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <Locale Language="en"> <String Name="Dialogs.Yes">Yes</String> <String Name="Dialogs.No">No</String> </Locale> <Locale Language="de"> <String Name="Dialogs.Yes">Ja</String> <String Name="Dialogs.No">Nein</String> </Locale> </StringTable> en-base.xml <?xml version="1.0" encoding="utf-8"?> <Locale Language="en" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <String Name="Dialogs.Yes">Yes</String> <String Name="Dialogs.No">No</String> </Locale> de-base.xml <?xml version="1.0" encoding="utf-8"?> <Locale Language="de" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <String Name="Dialogs.Yes">Ja</String> <String Name="Dialogs.No">Nein</String> </Locale> Die StringTable sucht im Resources Verzeichniss nach den Dateien, die Default StringTable versucht dabei von "strings/default" zu laden, erstellt dazu einfach die StringTable in einem Resources Verzeichniss mit dem Unterordner "strings". Hier die 3 notwendigen C# Dateien (namespaces habe ich entfernt und durch keine sinnvollen ersetzt): StringTable.cs using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; using System.Xml.Serialization; using System.Globalization; using UnityEngine; public class StringTable { private static StringTable defaultStringTable; public static StringTable Default { get { return defaultStringTable ?? (defaultStringTable = Load("strings/default")); } } public string CurrentLanguage = CultureInfo.CurrentCulture.TwoLetterISOLanguageName; public string DefaultLanguage = "en"; [XmlElement("Locale")] public Locale[] Locales; private Dictionary<string, Locale> localeMap = new Dictionary<string, Locale>(); public static StringTable Load(string path) { var textAsset = (TextAsset) Resources.Load(path, typeof(TextAsset)); using (var stream = new MemoryStream(textAsset.bytes)) { var serializer = new XmlSerializer(typeof(StringTable)); var stringTable = (StringTable)serializer.Deserialize(stream); foreach (var locale in stringTable.Locales) { locale.Load(path); Locale baseLocale; if (!stringTable.localeMap.TryGetValue(locale.Language, out baseLocale)) stringTable.localeMap.Add(locale.Language, locale); else baseLocale.Translations = locale.Translations.Concat(baseLocale.Translations).ToArray(); } foreach (var locale in stringTable.localeMap.Values) locale.Initialize(); return stringTable; } } public string GetString(string name) { var text = GetString(name, CurrentLanguage); if (text == null) text = GetString(name, DefaultLanguage); return text ?? "Missing String '" + name + "'"; } private string GetString(string name, string language) { Locale locale; if (!localeMap.TryGetValue(language, out locale)) return null; return locale.GetText(name); } } Locale.cs using System.Collections.Generic; using System.Linq; using System.Text; using System.Xml.Serialization; using System.IO; using UnityEngine; public class Locale { [XmlAttribute] public string Language; [XmlAttribute] public string Path; [XmlElement("String")] public Translation[] Translations; private Dictionary<string, string> translationMap = new Dictionary<string, string>(); internal void Initialize() { foreach (var translation in Translations) { translationMap.Add(translation.Name, translation.Text); } } internal void Load(string instigatorPath) { if (!string.IsNullOrEmpty(Path)) { var textAsset = (TextAsset) Resources.Load(path, typeof(TextAsset)); using (var stream = new MemoryStream(textAsset.bytes)) { var serializer = new XmlSerializer(typeof(Locale)); var locale = (Locale)serializer.Deserialize(stream); Translations = locale.Translations; Language = !string.IsNullOrEmpty(Language) ? Language : locale.Language; } } } public string GetText(string name) { string text; translationMap.TryGetValue(name, out text); return text; } } Translation.cs using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Xml.Serialization; public class Translation { [XmlAttribute] public string Name; [XmlText] public string Text; } 6 Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
LightYarn Geschrieben 20. November 2013 Melden Share Geschrieben 20. November 2013 Sehr, sehr cool! Danke Mark! Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Rokks Geschrieben 9. Juli 2016 Melden Share Geschrieben 9. Juli 2016 Altes Thema jedoch sehr Gut Eines Frage habe ich jedoch hierzu ... Wenn ich "runtime" die Sprache von "en" auf "de" umstelle, muss die StringTable ja angewiesen werden die richtige Datei neu zu laden. Gibt es dazu auch eine Lösung? LG Rokks Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Mark Geschrieben 18. Juli 2016 Autor Melden Share Geschrieben 18. Juli 2016 Die StringTable lädt schon alle Sprachen und alle dazugehörigen Dateien welche in der Hauptdatei verfügbar sind. Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Kojote Geschrieben 5. September 2017 Melden Share Geschrieben 5. September 2017 (bearbeitet) Vielen Dank, genau danach hatte ich gerade gesucht! Edit: So ganz funktionierts noch nicht, habe nun alle Scripte übernommen und wolle nun gern mal einen Text festlegen, bei mir siehts jetzt so aus: public class StringLaden : MonoBehaviour { public StringTabele stringTabelle; public Text neuesSpiel; void Start () { neuesSpiel.text = stringTabelle.Default.GetString("Dialogs.Yes"); } } Jedoch bekomme ich "stringTabelle.Default" rot unterstrichen. Er meint: "Auf den Member kann nicht mit einem Instanzverweis zugegriffen werden. Qualifizieren sie ihn stattdessen mit einem Typen." Also so richtig versteh ich nicht, was er meint, habe doch alles nach Anleitung gemacht. EDIT 2: OK, Fehler gefunden, ich habe nicht über die Klasse sondern über einen Member zugegriffe. Edit 3: Problem erkannt, Gefahr gebannt, funktioniert leider immer noch nicht. Habe nun die "StringTable.cs" und die "Translation.cs" in den Inspector gezogen. "Current Languaga" und "Default Language" sind auf "en" gestellt. In Locale ist "Language" und "Path" leer. Ich habe zudem eine "default.xml" im selben Ordner wie die Scripts, in einem Unterordner namens "strings" noch einmal eine "defautl.xml" und die anderen Sprachdateien. Fehlermeldung gibt es eine, wenn ich das Spiel beende, Strings in den XMLs sind vorhanden, jedoch wird der neue, englische String nicht geladen. Fehlermeldung: NullReferenceException: Object reference not set to an instance of an object Zeile: using (var stream = new MemoryStream(textAsset.bytes)) { bearbeitet 5. September 2017 von Kojote Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Kojote Geschrieben 5. September 2017 Melden Share Geschrieben 5. September 2017 (bearbeitet) Habe nun noch einmal ein anderes Script versucht, selbes Problem, beim Laden der XML Datei. xmldoc.LoadXml(textAsset.text); Hier mal der Code: string language; XmlNode nodes; // Übersetzungstexte public Text beispielText; void Awake() { if (SystemLanguage.German == Application.systemLanguage) { language = "German"; } else { language = "English"; } TextAsset textAsset = (TextAsset)Resources.Load("lang"); XmlDocument xmldoc = new XmlDocument(); xmldoc.LoadXml(textAsset.text); for (int i = 0; i < xmldoc.ChildNodes[1].ChildNodes.Count; i++) { if (xmldoc.ChildNodes[1].ChildNodes[i].Name == language) { nodes = xmldoc.ChildNodes[1].ChildNodes[i]; } } } // Use this for initialization void Start() { beispielText.text = sucheElement("Test"); } public string sucheElement(string elemName) { for (int i = 0; i < nodes.ChildNodes.Count; i++) { if (nodes.ChildNodes[i].Attributes["name"].Value == elemName) { return nodes.ChildNodes[i].InnerText; } } return ""; } Edit: Das ist der Knackpunkt: TextAsset textAsset = (TextAsset)Resources.Load("lang"); Lade Datei "lang" ist richtig, "Resources" bezieht sich auf eine Klasse, diese Klasse erwartet den Ordner "Resources" im Ordner "Asset". Schiebt man da die "lang" Datei hinein, ist alles in Butter und funktioniert! bearbeitet 5. September 2017 von Kojote Alles geklärt! Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Kojote Geschrieben 6. Oktober 2017 Melden Share Geschrieben 6. Oktober 2017 Fast vergessen das Thema, ich hab das Script etwas umgebaut, da ich mit dem Script von Mark nicht richtig zurecht kam. Hoffe ist OK, wenn ich hier eine alternative Version als Hilfe anfüge. using System.Xml; using UnityEngine; using UnityEngine.UI; public class Sprachenmanager : MonoBehaviour { string language; XmlNode nodes; // Hier kommen alle Verbindungen zu den Texten hinein // Variable erstellen und Text im Inspector der Variable zuweißen public Text hauptmenueButtonStart; public void SpracheAendern(string language) { TextAsset textAsset = (TextAsset)Resources.Load("lang"); XmlDocument xmldoc = new XmlDocument(); xmldoc.LoadXml(textAsset.text); for (int i = 0; i < xmldoc.ChildNodes[1].ChildNodes.Count; i++) { if (xmldoc.ChildNodes[1].ChildNodes[i].Name == language) { nodes = xmldoc.ChildNodes[1].ChildNodes[i]; } } SpracheTexteAendern(); } private void SpracheTexteAendern() { hauptmenueButtonStart.text = sucheElement("HauptmenueButtonStart"); } public string sucheElement(string elemName) { for (int i = 0; i < nodes.ChildNodes.Count; i++) { if (nodes.ChildNodes[i].Attributes["name"].Value == elemName) { return nodes.ChildNodes[i].InnerText; } } return "Text nicht gefunden!"; } } Hier müsst ihr den Text, den ihr ändern wollt im Inspector schieben, z.B. für den Buttontext Start: public Text hauptmenueButtonStart; Damit wird der Text je nach Sprache geändert, hier für den Buttontext Start: hauptmenueButtonStart.text = sucheElement("HauptmenueButtonStart"); Die XML, lang.xml: <?xml version="1.0" encoding="utf-8"?> <languages> <Englisch> <string name="HauptmenueButtonStart">START</string> </Englisch> <Deutsch> <string name="HauptmenueButtonStart">START</string> </Deutsch> <Franzoesisch> <string name="HauptmenueButtonStart">DÉBUT</string> </Franzoesisch> </languages> Sprache ändern funktioniert so: Sprachenmanager.SpracheAendern("Englisch"); // ODER Sprachenmanager.SpracheAendern("Deutsch"); // ODER Sprachenmanager.SpracheAendern("Franzoesisch"); Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.