Monat: Juli 2017

Unity 3D – Ein Spiel in mehrere Sprachen Übersetzen / lokalisieren

Unity 3D – Ein Spiel in mehrere Sprachen Übersetzen / lokalisieren

Unity – Unterstützung mehrerer Sprachen

Um was geht es hier genau?

Ich zeige euch hier wie man in Unity 3D verschiedene Übersetzungstexte einfügt und genau den Text einblendet der zu den aktuellen Spracheinstellungen des Nutzers passt. Wird das Spiel auf einem Gerät mit deutscher Spracheinstellung gestartet wird ein Text in Deutsch angezeigt, auf einem amerikanischen Gerät auf Englisch – mehrere Sprachen in einer App also.

Wo speichert man die Übersetzungsdaten?

Eine vernünftige Datenstruktur zum speichern der Übersetzungstexte muss her! XML eignet sich hierfür gut. Unity stellt hierfür direkt zwei Klassen TextAsset und XmlDocument zur Verfügung um die Daten möglichst einfach in einem Spiel zu verarbeiten.

Erstellen einer Beispieldatei

Als erstes muss man eine leere XML-Datei erzeugen (Das geht zum Beispiel über einen Texteditor). Das einzig wichtige ist, dass die Datei die Dateiendung .xml hat. Der Code meiner Datei sieht wie folgt aus:

<!--?xml version="1.0" encoding="utf-8"?-->
<?xml version="1.0" encoding="utf-8"?>
<languages>
 
	<English>
		<string name="Test">This is a test</string>
	</English>
 
	<German>
		<string name="Test">Das ist ein Text</string>
	</German>
 
</languages>
<!--?xml version="1.0" encoding="utf-8"?-->

definiert eine XML Datei mit UTF-8 Formatierung.
XML weißt eine Baumstruktur auf. In dieser Datei habe ich das Element language definiert. Das Element weißt wiederum ein Element für jede Sprache auf, die ihr übersetzen wollt. Ich hab aus Platzgründen einfach nur Deutsch und Englisch genommen. Das Element string beinhaltet schließlich den Text mit dem Namen Test in der jeweiligen Sprache. Das wars auch schon. Jede beliebige weitere Sprache kann später einfach hinzugefügt werden. Für jeden neuen Übersetzungstext erstellt ihr ein neues string Element mit einem eindeutigem Namen.

Handling der XML-Datei in Unity

Exemplarisch habe ich ein Textfeld in Unity erzeugt, welches später unseren Übersetzungstext beinhalten wird.

Hierarchie mit Textfeld
Unity mit dem erstelltem Textfeld

Nun erstellt ihr einen neuen Script, ich habe ihr SprachManager genannt. Außerdem müsst ihr die XML-Datei in einen Ordner mit dem Namen „Resources“ in euer Projekt im Unity importieren (einfaches Drag and Drop in den Projekt-Tab von Unity genügt). Den Ordner Resources müsst ihr jedoch manuell erstellen. Dieser dient in Unity üblicherweise dazu, um Datein während des Spieles zu laden.

Die Struktur der Daten in Unity
Die Struktur der Daten in Unity

Librarys einbinden

Da der Übersetzungstext in einem Textfeld erscheinen soll und mit XML-Dateien gearbeitet wird, müssen die folgenden Import-Anweisungen hinzufügt werden:

using System.Xml;
using UnityEngine.UI;

Variablen deklarieren

Weiterhin müsst ihr für jeden Übersetzungstext ein Text-Variable erzeugen. Ich benutze exemplarisch nur eine.
public Text beispielText;

Auch benötigt ihr eine Variable zum speichern der aktuellen Sprache und des aktuellen XML-Nodes (darauf wird später genauer eingegangen)
string language;
XmlNode nodes;

Die Awake Methode – Welche Sprache sprechen Sie?

Die Awake-Methode in Unity wird automatisch von Unity aufgerufen. Sie verhält sich genau wie die Start-Methode, wird jedoch vorher aufgerufen.
Hier bauen wir die Erkennung der Sprache ein. Application.systemLanguage liefert uns die aktuelle Sprache zurück die auf dem System läuft. Weiterhin wird hier die XML-Datei geladen und in der Variablen node wird der Inhalt des Elementes mit der aktuellen Sprache geladen. Dies passiert in der For-Schleife. Hier wird durch alle Sprachen iteriert, bis man auf das Element mit der oben ermittelten Sprache stößt.

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

Text Suche in XML-Dokument

Weiterhin braucht man eine Methode die aus dem geladenen XML-Element das Element heraussucht, das man gerade in das Textfeld laden will. Identifiziert wird es durch den zuvor in XML festgelegten Namen.

Es muss sich also jedes Element angeschaut werden und mit der in die Methode übergebenen String-Variablen elemName verglichen werden. Ist das aktuelle Attribut name des Elementes gleich elemName, dann wird der entsprechende lokalisierte Inhalt zurückgegeben. Wurde kein Ergebnis gefunden wird ein leerer Srtring zurück gegeben.

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

Den Text anzeigen

In der Start-Methode kann nun das entsprechende Element gesucht und dem jeweiligem Text zugewiesen werden. Das ganze ist dann ein Einzeiler und kann für beliebig viele Textfelder erweitert werden.

void Start () {
		beispielText.text = sucheElement ("Test"); 
	}

Der komplette SprachManager-Skript

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Xml;
using UnityEngine.UI;
 
public class SprachManager : MonoBehaviour {
	string language;
	XmlNode nodes; 
 
	//Beispiel Übersetzungstext
	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 ""; 
	}
}

Die Variable beispielText zuweisen

Mit dem Programmieren seit ihr fertig! Jetzt muss man nur noch das Skript einem GameObject zuweisen (in habe das Canvas GameObject genommen weil hier alle Textfelder enthalten sein werden). Anschließend zieht ihr den Text aus der Hierarchie in das leere Feld Beispiel Text des Skriptes.

TextFeld Variablen zuweisen
Das TextFeld wird der Variablen im Skript zugewiesen
TopBlogs.de das Original - Blogverzeichnis | Blog Top Liste