Zum Inhalt springen

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.


  1. Erstelle ein leeres GameObject und füge Add Component > FOS Essentials > Localization > Locale Manager hinzu.
  2. 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.
  3. Öffne FOS Essentials > FOS Localization > Translation Table und lege deine Schlüssel an.
  4. 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.
  5. Für die Sprachumschaltung: Füge jedem Button ein Language Button hinzu, eines je Sprache. Sein Inspektor verdrahtet das OnClick für dich.

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.


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.

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.


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.


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


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.


  • 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 FOSRegister an 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.