Jump to content
Unity Insider Forum
  • Announcements

    • Lars

      Allgemeine Forenregeln   03/13/2017

      Forenregeln Nimm dir bitte einen Moment um die nachfolgenden Regeln durchzulesen. Wenn du diese Regeln akzeptierst und die Registration fortsetzen willst, klick einfach auf den "Mit der Registrierung fortfahren"-Button. Um diese Registration abzubrechen, klick bitte einfach auf den "Zurück" Button deines Browsers. Wir garantieren nicht für die Richtigkeit, Vollständigkeit und Brauchbarkeit der Nachrichten und sind auch nicht dafür verantwortlich. Die Beiträge drücken die Meinung des Autors des Beitrags aus, nicht zwangsläufig das, wofür die Forensoftware steht. Jeder Nutzer, der denkt, dass ein veröffentlichter Beitrag unzulässig bzw. störend ist, ist aufgefordert uns unverzüglich per E-Mail zu kontaktieren. Wir haben das Recht störende Beiträge zu löschen und bemühen uns, das in einem realistischem Zeitraum zu erledigen (sofern wir beschlossen haben, dass die Löschung notwendig ist). Du akzeptierst, durchgehend während der Nutzung dieses Services, dass du dieses Forum nicht dazu missbrauchen wirst, Inhalte zu veröffentlichen, welche bewusst falsch und/oder verleumderisch, ungenau, beleidigend, vulgär, hasserfüllt, belästigend, obszön, sexuell belästigend, bedrohlich, die Privatsphäre einer Person verletzend oder in irgend einer Art und Weise das Gesetz verletzen. Des Weiteren akzeptierst du, dass du keine urheberrechtlich geschützte Inhalte ohne Erlaubnis des Besitzers in diesem Forum veröffentlichst. Mit dem Klick auf den "Mit der Registrierung fortfahren"-Button, akzeptierst du zudem unsere Datenschutzerklärung und stimmst der Speicherung deiner IP-Adresse und personenbezogenen Daten zu, die dafür benötigt werden, um dich im Falle einer rechtswidrigen Tat zurückverfolgen zu können bzw. permanent oder temporär aus dem Forum ausschließen zu können. Es besteht keine Pflicht zur Abgabe der Einwilligung, dies erfolgt alles auf freiwilliger Basis.   Zusatzinformationen Der Forenbetreiber hat das Recht, Nutzer ohne Angabe von Gründen permanent aus dem Forum auszuschließen. Des Weiteren hat er das Recht, Beiträge, Dateianhänge, Umfrage, Blogeinträge, Galleriebilder oder Signaturen ohne Angabe von Gründen zu entfernen. Mit der Registrierung verzichtest du auf alle Rechte an den von dir erstellten Inhalten, bzw. treten diese an das Unity-Insider.de und Unity-Community.de ab. Dies bedeutet im Klartext, dass das Unity-Insider.de und Unity-Community.de frei über deine Texte verfügen kann, sofern diese nicht wiederum die Rechte anderer verletzen. Es besteht weiterhin kein Anspruch von registrierten Nutzern bzw. ehemaligen registrierten Nutzern darauf, dass erstellte Inhalte und/oder die Mitgliedschaft (User) wieder gelöscht werden (Erhaltung der Konsistenz dieses Forums).   Einwilligungserklärung Wenn du mit der Speicherung deiner personenbezogenen Daten sowie den vorstehenden Regeln und Bestimmungen einverstanden bist, kannst du mit einem Klick auf den Mit der Registrierung fortfahren-Button unten fortfahren. Ansonsten drücke bitte Zurück. Stand: 07.03.2011
Mark

Mehrere Sprachen verwalten (StringTable)

Recommended Posts

Mark    867

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;
}

  • Like 6

Share this post


Link to post
Share on other sites
Rokks    5

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

Share this post


Link to post
Share on other sites
Mark    867

Die StringTable lädt schon alle Sprachen und alle dazugehörigen Dateien welche in der Hauptdatei verfügbar sind.

Share this post


Link to post
Share on other sites
Kojote    5

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. :huh:

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)) {

 

Edited by Kojote

Share this post


Link to post
Share on other sites
Kojote    5

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! :)

Edited by Kojote
Alles geklärt!

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now


×