FOS Localization
Version 1.0.1 · benötigt FOS Essentials Core 1.0.0 oder neuer
Übersetzt die Texte und Bilder einer VRChat-Welt in beliebig viele Sprachen, bearbeitet in einer echten Tabelle statt in zwei zusammenhanglosen Arrays, mit CSV-Hin-und-Rückweg für Übersetzende und gemerkter Sprachwahl über Besuche hinweg. Benötigt FOS Essentials Core 1.0.0.
Einrichtung
Abschnitt betitelt „Einrichtung“- Erstelle ein leeres GameObject und füge Add Component > FOS Essentials > Localization > Locale Manager hinzu.
- Fülle Language codes (
en,fr,es,de) und Language names (English,Français,Español,Deutsch). Die erste ist die Pivotsprache, auf die alle anderen zurückfallen — setze also die Sprache nach vorn, in der du die Welt schreibst. - Öffne FOS Essentials > FOS Localization > Translation Table und lege deine Schlüssel an.
- Füge an jedem Text deiner Oberfläche Add Component > FOS Essentials > Localization > Localized Text hinzu, richte es auf den Manager aus und gib ihm seinen Schlüssel.
- Für die Sprachumschaltung: Füge jedem Button ein Language Button hinzu, eines je
Sprache. Sein Inspektor verdrahtet das
OnClickfür dich.
Komponenten
Abschnitt betitelt „Komponenten“| Komponente | Aufgabe |
|---|---|
FOSLocaleManager |
Einer je Welt. Hält die Sprachen, die Tabelle und die aktuelle Sprache. |
FOSLocalizedText |
Bindet einen Schlüssel an ein TMP_Text oder ein altes Text. |
FOSLocalizedImage |
Tauscht ein Sprite je Sprache. |
FOSLanguageButton |
Schaltet die Welt in eine Sprache, mit optionaler Auswahlhervorhebung. |
Alles hier ist lokal. Keine synchronisierte Variable, kein Netzwerkverkehr, kein Ownership. Zwei Personen nebeneinander haben keinen Grund, dieselbe Sprache zu lesen, und die Wahl zu synchronisieren hieße, dass eine sie jedes Mal verliert, wenn die andere klickt.
Die Übersetzungstabelle
Abschnitt betitelt „Die Übersetzungstabelle“FOS Essentials > FOS Localization > Translation Table, oder die Schaltfläche im
Inspektor des Managers. Eine Zeile je Schlüssel, eine Spalte je Sprache, und leere Zellen
sind eingefärbt, damit eine Lücke sichtbar ist, statt gesucht werden zu müssen.
| Farbe | Bedeutung |
|---|---|
| Rot | Die erste Sprache ist leer. Nichts zum Zurückfallen: Die Welt zeigt #schlüssel. |
| Bernstein | Eine andere Sprache ist leer. Die Welt fällt auf die erste Sprache zurück. |
Die zuerst deklarierte Sprache ist der Pivot: Auf sie fallen alle anderen zurück. Setze die Sprache nach vorn, in der du die Welt tatsächlich schreibst.
Die Werkzeugleiste filtert nach Text — die Suche schaut auch in die Übersetzungen, ein im Spiel gesehener Satz genügt also, um seinen Schlüssel zu finden — und Untranslated only engt die Tabelle auf die Zeilen ein, die noch Arbeit brauchen.
Warum die Tabelle nicht im Inspektor steht
Abschnitt betitelt „Warum die Tabelle nicht im Inspektor steht“Schlüssel und Übersetzungen liegen in zwei Arrays, die absichtlich vor dem Inspektor
verborgen sind. Das Gitter ist flach: Übersetzung j von Schlüssel i liegt bei
i × Sprachen + j. Ein von Hand ins Array eingefügter Schlüssel ohne seine Zellenzeile
verschiebt jeden folgenden Text um eins — ohne Fehler, ohne etwas Sichtbares am Bildschirm
und ohne Möglichkeit, das Original wiederherzustellen. Das Fenster ist deshalb der einzige
Schreibweg, und es hält beide Arrays im Gleichschritt.
Eine Sprache im Inspektor hinzuzufügen oder zu entfernen ist dagegen unproblematisch: Der Manager meldet die Abweichung und repariert das Gitter, indem er jede Übersetzung an ihre neue Stelle rückt.
Export CSV schreibt die gesamte Tabelle, eine Zeile je Schlüssel, eine Spalte je Sprache, mit den Sprachcodes als Kopfzeile. Import CSV liest sie zurück.
Der Import ist eine Zusammenführung, nie ein Ersetzen:
- Ein Schlüssel, der in der Datei steht, aber nicht in der Tabelle, wird hinzugefügt.
- Ein Schlüssel der Tabelle, der in der Datei fehlt, bleibt unangetastet.
- Eine Spalte, deren Kopf zu keiner deklarierten Sprache passt, wird ignoriert — eine Kommentarspalte kostet nichts.
- Eine leere Zelle überschreibt nie eine vorhandene Übersetzung.
So kann eine einzelne Sprache zur Durchsicht hinausgehen und zurückkommen, ohne die anderen zu gefährden, und wer eine halb fertige Spalte zurückgibt, zerstört nichts.
Die Datei wird als UTF-8 mit BOM geschrieben. Ohne ihn öffnet Excel die Datei in der lokalen Codepage und zerlegt jeden Akzent — der mit Abstand häufigste Weg, einen Übersetzungsdurchlauf zu ruinieren.
Die Schlüssel
Abschnitt betitelt „Die Schlüssel“Ein Schlüssel ist eine Kennung, kein Satz: menu.title, rules.adult.warning,
teleport.button.spawn. Setze Präfixe nach Bereich, damit eine Familie beim Sortieren
beisammenbleibt — die Schaltfläche Sort ordnet die Schlüssel alphabetisch und nimmt
ihre Übersetzungen mit, und genau das macht das fehlende Mitglied einer Familie sichtbar.
Ein fehlender Schlüssel erscheint im Spiel als #der.schlüssel. Das ist Absicht: Eine
Übersetzungslücke muss auffallen, und eine leere Beschriftung tut das nie.
Zeilenumbrüche schreibt man \n in der Tabelle. Ein Inspektor-Feld nimmt keinen echten
Zeilenumbruch auf, und ein CSV-Durchlauf würde ihn nicht überstehen.
Die Sprache der Spielenden
Abschnitt betitelt „Die Sprache der Spielenden“VRChat verrät einer Welt nicht, in welcher Sprache der Client einer Person läuft. Es gibt dafür keine API, also kann kein Werkzeug sie erkennen — dieses eingeschlossen. Man kommt in der Standardsprache an und schaltet von Hand um.
Was möglich ist: sich die Wahl zu merken. Mit Remember the choice wird die Sprache in
die PlayerData von VRChat geschrieben und beim nächsten Besuch dieser Welt
wiederhergestellt.
- Nichts verlässt die Welt, und nichts wird mit anderen geteilt.
- Die Wahl wird unter dem Sprach-Code gespeichert, nie unter ihrem Index; Umsortieren oder Einfügen einer Sprache verschiebt also niemanden klammheimlich.
- Eine seit dem letzten Besuch entfernte Sprache lässt die Person in der Standardsprache landen statt im Nichts.
PlayerData sind im Start noch nicht lesbar. Die Standardsprache wird sofort angewandt
und die gespeicherte ersetzt sie bei OnPlayerRestored — deshalb sieht eine
wiederkehrende Person unter Umständen einen Frame lang die Standardsprache.
Die Kosten
Abschnitt betitelt „Die Kosten“Die Suche wird einmalig im Start aufgelöst: Jedes FOSLocalizedText merkt sich den
Index seines Schlüssels und sucht nie wieder. Ein Sprachwechsel ist dann ein indizierter
Lesezugriff je Text.
Bei jedem Wechsel nach Namen zu suchen — die naheliegende Schreibweise — kostet Texte × Schlüssel Zeichenkettenvergleiche, jedes Mal, wenn jemand auf eine Flagge klickt. Bei einer Tablet-Oberfläche mit hundert Beschriftungen und zweihundert Schlüsseln sind das zwanzigtausend Vergleiche pro Klick, in Udon.
Die Komponenten melden sich selbst beim Manager an; es gibt also keine Liste von Hand zu füllen und nichts nachzuziehen, wenn eine Seite eine Beschriftung dazubekommt.
Scripting
Abschnitt betitelt „Scripting“| Aufruf | An | Wirkung |
|---|---|---|
FOSSetLanguage(int) |
FOSLocaleManager |
Wechselt die Sprache und speichert die Wahl |
FOSCurrentLanguage() |
FOSLocaleManager |
Index der angezeigten Sprache |
FOSIndexOfLanguage(string) |
FOSLocaleManager |
Index eines Sprachcodes, -1 wenn unbekannt |
FOSIndexOfKey(string) |
FOSLocaleManager |
Index eines Schlüssels, -1 wenn unbekannt. Einmal aufrufen |
FOSTextAt(int) |
FOSLocaleManager |
Übersetzung eines bereits aufgelösten Schlüssels |
FOSText(string) |
FOSLocaleManager |
Übersetzung eines Schlüssels, Suche inklusive |
FOSRegister(UdonSharpBehaviour) |
FOSLocaleManager |
Sprachwechseln folgen |
SelectLanguage() |
FOSLanguageButton |
Die Aktion des Bedienelements |
Jedes UdonSharpBehaviour kann FOSRegister(this) aufrufen und ein öffentliches
FOSApplyLanguage() bereitstellen — es wird dann bei jedem Wechsel benachrichtigt, genau
wie die hier mitgelieferten Komponenten. Das ist der Erweiterungspunkt für alles, was
dieses Pack nicht abdeckt: eine Audioquelle je Sprache, ein Videoplayer, die Textur eines
Schilds.
Hinweise und Grenzen
Abschnitt betitelt „Hinweise und Grenzen“- Ein Manager je Welt ist der vorgesehene Aufbau. Mehrere funktionieren, aber jeder hat seine eigene Tabelle und seine eigene aktuelle Sprache, und wer den einen umschaltet, schaltet den anderen nicht mit.
- Zur Laufzeit erzeugte Texte werden nicht erfasst. Rufe selbst
FOSRegisteran ihnen auf. - Die Sprache wird nicht synchronisiert, bewusst. Siehe oben.
- Quest und PC verhalten sich identisch: Es gibt keinen plattformspezifischen Code, und es könnte ihn nicht geben — Udon wird einmal für beide kompiliert.
