Aller au contenu

FOS Localization

Version 1.0.1 · exige FOS Essentials Core 1.0.0 ou plus récent

Traduit les textes et les images d’un monde VRChat dans autant de langues que voulu, édités dans une vraie table plutôt que dans deux tableaux sans lien, avec un aller-retour CSV pour les traducteurs et la mémorisation du choix du joueur d’une visite à l’autre. Exige FOS Essentials Core 1.0.0.


  1. Créez un GameObject vide et ajoutez Add Component > FOS Essentials > Localization > Locale Manager.
  2. Remplissez Language codes (en, fr, es, de) et Language names (English, Français, Español, Deutsch). La première est la langue pivot vers laquelle toutes les autres retombent : mettez donc en premier celle dans laquelle vous écrivez le monde.
  3. Ouvrez FOS Essentials > FOS Localization > Translation Table et ajoutez vos clés.
  4. Sur chaque texte de votre interface, ajoutez Add Component > FOS Essentials > Localization > Localized Text, pointez-le vers le manager et donnez-lui sa clé.
  5. Pour le sélecteur de langue, ajoutez Language Button à chaque bouton, un par langue. Son inspecteur câble le OnClick pour vous.

Composant Rôle
FOSLocaleManager Un par monde. Porte les langues, la table et la langue courante.
FOSLocalizedText Relie une clé à un TMP_Text ou à un Text hérité.
FOSLocalizedImage Remplace un sprite selon la langue.
FOSLanguageButton Bascule le monde dans une langue, avec un état sélectionné optionnel.

Tout ici est local. Aucune variable synchronisée, aucun trafic réseau, aucun ownership. Deux joueurs côte à côte n’ont aucune raison de lire la même langue, et synchroniser le choix reviendrait à ce que l’un le perde chaque fois que l’autre clique.


FOS Essentials > FOS Localization > Translation Table, ou le bouton dans l’inspecteur du manager. Une ligne par clé, une colonne par langue, et les cellules vides sont colorées pour qu’un trou se voie au lieu d’être cherché.

Couleur Signification
Rouge La première langue est vide. Rien vers quoi retomber : le monde affichera #cle.
Ambre Une autre langue est vide. Le monde retombe sur la première langue.

La première langue déclarée est le pivot : c’est vers elle que retombent toutes les autres. Mettez en premier celle dans laquelle vous écrivez réellement le monde.

La barre d’outils filtre par texte — la recherche regarde aussi dans les traductions, donc une phrase repérée en jeu suffit à retrouver sa clé — et Untranslated only réduit la table aux lignes qui demandent encore du travail.

Les clés et les traductions sont stockées dans deux tableaux, volontairement masqués de l’inspecteur. La grille est à plat : la traduction j de la clé i se trouve en i × langues + j. Une clé ajoutée à la main dans le tableau, sans sa ligne de cellules, décale d’un cran tous les textes suivants — sans erreur, sans rien de visible à l’écran, et sans moyen de reconstituer l’original. La fenêtre est donc le seul chemin d’écriture, et elle maintient les deux tableaux en phase.

Ajouter ou retirer une langue dans l’inspecteur ne pose en revanche aucun problème : le manager signale l’écart et répare la grille, en déplaçant chaque traduction à sa nouvelle position.


Export CSV écrit toute la table, une ligne par clé, une colonne par langue, avec les codes de langue en en-tête. Import CSV la relit.

L’import est une fusion, jamais un remplacement :

  • Une clé présente dans le fichier mais absente de la table est ajoutée.
  • Une clé de la table absente du fichier est laissée telle quelle.
  • Une colonne dont l’en-tête ne correspond à aucune langue déclarée est ignorée — une colonne de commentaires ne coûte rien.
  • Une cellule vide n’écrase jamais une traduction existante.

Une seule langue peut donc partir en relecture et revenir sans le moindre risque pour les autres, et un traducteur qui rend une colonne à moitié faite ne détruit rien.

Le fichier est écrit en UTF-8 avec BOM. Sans lui, Excel ouvre le fichier dans la page de codes locale et massacre tous les accents, ce qui est de loin la façon la plus courante de rater un aller-retour de traduction.


Une clé est un identifiant, pas une phrase : menu.title, rules.adult.warning, teleport.button.spawn. Préfixez par domaine pour qu’une famille reste groupée une fois la table triée — le bouton Sort classe les clés par ordre alphabétique en emportant leurs traductions, et c’est ce qui rend visible le membre manquant d’une famille.

Une clé absente s’affiche #la.cle en jeu. C’est délibéré : un trou de traduction doit se remarquer, ce qu’une étiquette vide ne fait jamais.

Les retours à la ligne s’écrivent \n dans la table. Un champ d’inspecteur ne peut pas recevoir un vrai retour à la ligne, et un aller-retour CSV n’y survivrait pas.


VRChat ne dit pas à un monde dans quelle langue est le client d’un joueur. Il n’existe aucune API pour cela, donc aucun outil ne peut la détecter — celui-ci compris. Un joueur arrive dans la langue par défaut et change à la main.

Ce qu’on peut faire, c’est mémoriser son choix. Avec Remember the choice activé, la langue est écrite dans les PlayerData de VRChat et restaurée à la visite suivante de ce monde.

  • Rien ne quitte le monde, et rien n’est partagé avec les autres joueurs.
  • Le choix est enregistré sous le code de la langue, jamais sous son indice : réordonner ou insérer une langue ne déplace donc pas silencieusement tout le monde.
  • Une langue retirée du monde depuis la dernière visite d’un joueur le laisse sur la langue par défaut plutôt que sur rien.

Les PlayerData ne sont pas lisibles au Start. La langue par défaut est appliquée immédiatement et la langue enregistrée la remplace à OnPlayerRestored : c’est pourquoi un joueur qui revient peut voir une image de la langue par défaut.


La recherche est résolue une seule fois, au Start : chaque FOSLocalizedText retient l’indice de sa clé et ne cherche plus jamais. Un changement de langue devient alors une lecture indexée par texte.

Chercher par nom à chaque changement — la façon évidente d’écrire cela — coûte textes × clés comparaisons de chaînes chaque fois que quelqu’un clique sur un drapeau. Sur une interface de tablette avec cent étiquettes et deux cents clés, cela fait vingt mille comparaisons de chaînes par clic, en Udon.

Les composants s’enregistrent eux-mêmes auprès du manager : il n’y a donc aucune liste à remplir à la main, ni rien à mettre à jour quand une page gagne une étiquette.


Appel Sur Effet
FOSSetLanguage(int) FOSLocaleManager Change de langue et enregistre le choix
FOSCurrentLanguage() FOSLocaleManager Indice de la langue affichée
FOSIndexOfLanguage(string) FOSLocaleManager Indice d’un code de langue, -1 si inconnu
FOSIndexOfKey(string) FOSLocaleManager Indice d’une clé, -1 si inconnue. À appeler une fois
FOSTextAt(int) FOSLocaleManager Traduction d’une clé déjà résolue
FOSText(string) FOSLocaleManager Traduction d’une clé, recherche comprise
FOSRegister(UdonSharpBehaviour) FOSLocaleManager Suivre les changements de langue
SelectLanguage() FOSLanguageButton L’action du contrôle

N’importe quel UdonSharpBehaviour peut appeler FOSRegister(this) et exposer un FOSApplyLanguage() public — il sera alors prévenu à chaque changement, exactement comme les composants livrés ici. C’est le point d’extension pour tout ce que ce pack ne couvre pas : une source audio par langue, un lecteur vidéo, la texture d’un panneau.


  • Un manager par monde est le montage prévu. Plusieurs fonctionnent, mais chacun a sa table et sa langue courante, et un joueur qui change l’un ne change pas l’autre.
  • Les textes créés à l’exécution ne sont pas pris en compte. Appelez FOSRegister dessus vous-même.
  • La langue n’est pas synchronisée, par choix. Voir plus haut.
  • Quest et PC se comportent à l’identique : il n’y a pas de code spécifique à une plateforme, et il ne pourrait pas y en avoir — Udon est compilé une seule fois pour les deux.