F5 StudioF5 Studio
Skip to main content

Localization

F5 Combat HUD ships twelve complete languages, each holding exactly 897 keys:

CodeLanguageCodeLanguage
enEnglishplPolish
deGermanesSpanish
frFrenchptPortuguese
nlDutchcsCzech
trTurkisharArabic
zhChinesethThai
config/main.lua
F5Cfg.Locale = 'en'

One language for the whole server — there is no per-player language picker.

What happens when a key is missing

Lookup goes: your language → English → the literal text Translation [key] does not exist. The fallback is per key, not per file, so a half-translated file quietly mixes languages rather than breaking.

Naming a language with no file in locales/ is only a warning; the server keeps running entirely in English:

[f5_combathud][config-validator] WARN: F5Cfg.Locale = "it" has no file in locales/ — every message falls back to English

An empty or non-string F5Cfg.Locale is a hard error and the resource does not start.

How the Files Are Built

locales/en.lua
Locales['en'] = {

['crosshair_enabled'] = 'Crosshair enabled',
['settings_saved'] = 'Settings saved successfully',
['ui_tab_crosshair'] = 'Crosshair',
-- …
}

Two kinds of key live in the same file:

PrefixCountWhere it is used
ui_…830The menu itself. These are the only keys sent to the browser
everything else67Notifications produced by Lua — saves, profile actions, marketplace errors, rate limits. Translated before they are sent

A key you invent for menu text must start with ui_, or it will never reach the menu.

Adding Your Own Language

  1. Copy locales/en.lua to locales/<code>.lua — say locales/it.lua.
  2. Change the first line to match: Locales['it'] = {.
  3. Translate the values. Leave every key exactly as it is.
  4. Set F5Cfg.Locale = 'it' in config/main.lua.
  5. Restart the resource.

No manifest edit is needed — locales/*.lua is loaded as a glob, so a new file is picked up automatically.

Rules that matter

  • Keep the keys. A renamed key is a missing key, and falls back to English.
  • Keep the placeholders. Substitution is positional: %s is replaced in order, so a value must carry the same number of %s as the English one, in the same order. There are 60 placeholders across the file.
  • One key uses %d. ui_killfeed_preview_scn_fmt ships as Scenario %d/%d: %s and must keep exactly two %d followed by one %s.
  • Never translate a value to an empty string. An empty translation is treated as "no translation", and the English text baked into the menu stays visible.
  • Keep single quotes and escape them properly. Every value in the shipped files is a single-quoted Lua string; an apostrophe inside one needs \'.
  • Never delete a key from en.lua. English is the floor: a key missing from your language falls back to English, but a key missing from English is absent from the menu payload altogether — and the menu writes it straight into the page, so the label renders as the literal word undefined.
  • Do not put a bare % in a non-ui_ value. Those go through Lua's string.format. A % that is not part of a valid placeholder makes the substitution fail, and the player sees the raw template — Maximum profiles reached (%s) — with nothing in any console. Write percent, or double the sign in a way you have tested.
  • Two families of keys look unused and are not. ui_kd_icon_* (74 keys, including the category tabs) and ui_ep_tag_* (6) are looked up by names the menu builds at runtime, so a text search finds no reference. Deleting one does not break the menu — the label falls back to English text built into the interface — but the translation is lost.
  • Keep the file encoding. The shipped files are UTF-8 without a BOM, with CRLF line endings. A BOM on the first line breaks the Lua chunk.
Check your work in game

There is no validation of translation files at startup — a missing key is silently English and a bad %s count silently prints the untranslated template. Open the menu after translating and walk through every tab.

What Is Not Translatable

A number of visible strings deliberately live in config/*.lua instead of locales/, because they are yours to rename rather than ours to translate. They reach the menu exactly as typed:

StringWhere it lives
Crosshair type labels — Cross, Dot, Circle…config/main.luaCrosshairTypes[].label
Hit particle labels — Money Burst, Clown…config/features.luaHitParticles.effects[].label
Killstreak tier names — DOUBLE KILL, GODLIKE…config/defaults.luaKillstreak.thresholds[].name
Marketplace tags — competitive, fun, sniper…config/features.luaMarketplace.tags.available
Weapon category labels — Pistols, Snipers…config/weapons.luacategories[].label
Crosshair preset names and their category tabsconfig/presets.lua
Effects preset names, descriptions and tabsconfig/presets.lua
Font names in the dropdownsconfig/limits.luaValidation.Fonts

Translating those means editing the config file — and remember that ids stay untouched: rename a label, never an id. See Configuration.

A few more strings are fixed in the interface files themselves:

StringWhere
NPC — the kill feed's name for a non-player killer or victim, plus Unknown and Player when a name cannot be readSet in Lua
KILL — the word next to the killmarkerhtml/index.html
BOB / ROB — labels on the crosshair preview figure. The kill feed preview has its own hardcoded sample nameshtml/index.html and the menu script

The share-code prefix chips shown in the menu follow config/main.lua: change crosshairPrefix and the chip changes with it.

See Also