Skip to content

Multicharacter Selector Languages ​

VORP

Every word the selection screen draws comes from ConfigSelector.Locales in config_selector.lua. It is a plain Lua table of tables — nothing in this resource is escrowed, so you can read and edit all of it.

The resource has two separate translation systems, and this page is about the first one:

CoversLives inChosen by
Selector localesThe selection screen and its panelsConfigSelector.LocalesEach player, in Settings
VORP translationsThe character creator, clothing stores, outfitsshared/translation.luaLang in config.lua, server-wide

They do not share key names, language names or defaults. Translating one does nothing to the other. The second is covered in Two systems, not one further down.

What ships ​

ConfigSelector.Locales holds seven tables, and all seven are complete at 89 keys each. None of them is partial.

Table nameKeys
English89The reference table. Everything else falls back to it
Deutsch89Complete
Español89Complete
Français89Complete
Nederlands89Complete
Русский89Complete
日本語89Complete

Every table carries the same 89 key names as English, with nothing extra and nothing missing. A player switching language does not lose a label anywhere on the screen.

Italian and Romanian are not selection-screen languages

They exist in this resource, but in shared/translation.lua, which drives the character creator and clothing menus and is a different system with a different key structure. Setting Lang = "Italian" gives you Italian creator menus and an English selection screen, because there is no Italian table in ConfigSelector.Locales. See Two systems, not one.

What the 89 keys cover ​

Grouped by where they appear on screen:

AreaKeysExamples
Character cards and stats13character, newCharacter, emptySlot, welcomeTitle, playtime, job, unemployed, money, gold
Buttons and prompts12play, create, delete, settings, credits, accept, decline, navigate, enterKey
Delete panel4deleteTitle, deleteConfirm, deleteWrongName, deleteFailed
Pose and location pickers13pose, poseTitle, poseNone, poseDuoTitle, location, locationCount, pickNone
Settings panel32theme, menuStyle, buttonSkin, filter, framing, bgZoom, camOrbit, camHeight, weather, timeOfDay, resetSettings
Partner panel15partner, lover, friend, unpair, tabIncoming, searchHint, searchPlaceholder, withdraw

The Settings panel is the largest group by a wide margin, because every row label, every segment button and every dropdown placeholder in it is a key. If you are translating a table by hand, that is where most of the work is.

The language dropdown ​

The dropdown in Settings → Language is built from the table names themselves. config_selector.lua holds no separate list of display labels, so whatever you call a table is exactly what a player sees.

The list is sorted before it is sent to the interface, so the order is alphabetical by name — and because the sort is by byte, the two non-Latin names come last:

text
Deutsch  English  Español  Français  Nederlands  Русский  日本語

Rename Deutsch to German and the dropdown reads "German" and sorts between Français and Nederlands. Nothing else needs changing — the name is the identifier.

A player's choice is saved on their own PC, in the client KVP entry vorp_character_selector_settings_v1, alongthe rest of their Settings. It survives a restart and a reconnect, and it is per-player: one player reading the screen in Japanese does not change what anyone else sees. Reset settings in that same panel clears the entry and returns them to the server default.

The interface can only send back a name that is a key in ConfigSelector.Locales; anything else is refused and logged. If a language change appears to do nothing, turn on /selectordebug and watch for rejected unknown language in F8.

Which language a player starts in ​

A player who has never opened Settings gets the server default, and the default comes from Lang in config.lua.

ConfigSelector.UI.language does not take effect in 1.0.0

The setting exists in the ConfigSelector.UI block, commented nil = follow Lang from config.lua, and it is the one entry in that block the loader never reads. The defaults it merges UI over are built by walking a Lua table in which language is set to nil, and a key set to nil is simply absent — so language is never one of the keys considered. Set Lang in config.lua instead. It works, and it is the value the code actually resolves.

Lang is VORP's own setting and has to name a table in shared/translation.lua, not one in ConfigSelector.Locales. The two naming schemes are different, so the selector keeps an alias table to bridge them:

LangSelector table it resolves to
GermanDeutsch
SpanishEspañol
Francais or FrenchFrançais
DutchNederlands
RussianРусский
Japanese日本語

English is the only name that exists in both files, so it is the only one needing no alias. The resolution order, in full:

  1. The player's saved choice, if they have one.
  2. Otherwise Lang, if it names a table in ConfigSelector.Locales.
  3. Otherwise the alias above.
  4. Otherwise English.

Step 4 is what Lang = "Portugues_PT" and Lang = "Portuguese_BR" land on. Both are valid VORP translations, and the character creator comes out in Portuguese, but there is no Portuguese locale table and no alias for one, so the selection screen stays English until the player picks something in Settings.

The Language row can read "Deutsch" when the screen is English

Lang is stored as the player's language value even when it is not a table name. The dropdown cannot find it among its options, so it displays the first option instead, which sorts to Deutsch. The screen itself is still resolved correctly through the list above. Picking any entry replaces the unmatched value and the row starts telling the truth.

Missing keys fall back to English ​

Before the interface is handed a locale, the chosen table is merged over a copy of English. A key the chosen table does not define keeps the English value.

This happens in Lua, per key, every time the screen opens or Settings is saved, so:

  • A partial table like Italian is safe to ship. Its 15 gaps read as English rather than as blanks or key names.
  • A table you are halfway through translating is usable immediately. Translate the Settings panel first and the rest will catch up.
  • Deleting a key from a table is a valid way to say "use the English wording here".
  • Adding a key to one table only does nothing. The merge starts from English, and the interface only ever asks for keys English defines. A key that exists in Italian but not in English is unreachable — which is exactly what happened to those five leftovers.

Adding a language ​

  1. Open config_selector.lua and find ConfigSelector.Locales — it starts just after the partner settings. Copy the whole ["English"] block, from the opening brace to its closing },.

  2. Paste it inside ConfigSelector.Locales and rename the key to the name you want in the dropdown. Write it the way speakers of that language write it — ["Português"], not ["Portuguese"] — and wrap it in brackets and quotes if it is not a plain identifier. The file is UTF-8, so accented and non-Latin names are fine.

  3. Translate the values, leaving every key name untouched. A key name is what the interface looks up; only the string on the right of the = is read by a human.

  4. Keep %s in deleteConfirm. It is replaced by the character's first name, in bold, at the point where you leave it. The English string is "This cannot be undone. Type %s to confirm." — move %s to wherever your sentence needs the name.

  5. Restart the resource:

    cfg
    restart vorp_character

    Open Settings and the new name is in the dropdown. If you also edited anything under html/, raise the ?v= number on its tag in html/index.html — CEF caches by URL.

Do not drop %s from deleteConfirm

The interface splits the string on %s and inserts the name between the halves. With no %s there is only one half, so the name is appended to the end of your sentence instead of landing inside it — which reads as a mistake in a panel asking someone to confirm a permanent delete. With two %s, the first becomes the name and the second disappears.

Nothing else needs touching. ConfigSelector.Locales is read directly, there is no manifest entry per language, and config_selector.lua is already a shared script. Adding a table is one edit to one file.

Two systems, not one ​

The character creator, the clothing stores and the outfits menu are stock VORP. They read shared/translation.lua through T = Translation.Langs[Lang], and that file ships eight languages:

text
English  Italian  Portugues_PT  Portuguese_BR  Francais  German  Spanish  Romanian

Those names are VORP's, they are not the selector's, and the key structure inside them is completely different — nested tables like T.MainMenu, T.MenuClothes and T.PromptLabels rather than the flat list of 89. A translation you write for the selector cannot be reused here, and vice versa.

Lang must name a table in shared/translation.lua

Set Lang = "Deutsch" and Translation.Langs["Deutsch"] is nil, so the first creator menu that reads T throws an error and the character creator stops working. Use German — the alias table above maps it to the selector's Deutsch for you.

Nederlands, Русский and 日本語 have no counterpart in shared/translation.lua at all. They are selector-only: a player can pick them in Settings, and the creator menus stay in whatever Lang is set to.

So on a German server the correct pair is Lang = "German" in config.lua — creator menus in German, selection screen in Deutsch through the alias. On a Dutch server, set Lang to the closest language shared/translation.lua does carry, and expect the creator and the selection screen to differ until you add a Dutch table to shared/translation.lua yourself.

What stays in English ​

Why
The Scene Creator panelcreator.js has no translation layer and reads no locale key. The editor is an admin tool
Pose and emote labelsNames in animations.lua and config_emotes.lua, not locale keys. Edit the label fields to translate them
Location namesSet per location in config.lua and config_scenes.lua
Weather namesPassed through from weathersync, shown as the type name. Only scene is translated, through sceneDefault
Command names and console output/scenecreator, /selectordebug and every F8 line
Credits rowsPlain strings in ConfigSelector.UI.credits

The pose browser's own labels are listed on The Multicharacter Emote Library, and the shapes you edit to rename one are under Adding your own.

Where to go next ​

  • Configuration — the rest of config_selector.lua, including the ConfigSelector.UI block the language default lives in.
  • Player Guide — the Settings panel as a player sees it.
  • Troubleshooting — /selectordebug and reading its output.
  • VORP framework — how Lang and vorp_core fit together.

Stuck on a translation, or want a language added to a future build? Ask on Discord.

Documentation for RedMorrow. Scripts are licensed per server — redistribution is not permitted.