Engineering
Translating FiveM scripts into other languages
Add translations to FiveM scripts: ox_lib’s locale system with locales/*.json and the ox:locale convar, ESX Legacy Translate/TranslateCap, QBCore’s Locale and Lang:t, placeholders, NUI translations, fallbacks, and a workflow for community translations.
Overview
FiveM servers run in dozens of languages, and a script that ships only English text loses most of its possible buyers. Moving text into locale files is a small change that makes your resource translatable by the community — and easier to maintain.
ox_lib locales
shared_script '@ox_lib/init.lua'
ox_lib 'locale'
files { 'locales/*.json' }{
"stored": "Vehicle %s stored",
"no_money": "You need $%d"
}lib.notify({ description = locale('stored', plate) })Owners pick the language with setr ox:locale de in server.cfg; missing languages fall back to English. More on ox_lib: the ox_lib guide.
ESX and QBCore
| Framework | Files | Usage |
|---|---|---|
| ESX Legacy | locales/en.lua with Locales['en'] = { ... } | TranslateCap('key') / Translate('key') |
| QBCore | locales/en.lua with Locale:new({ phrases = ... }) | Lang:t('key', { value = x }) |
For multi-framework scripts, ox_lib’s system is the simplest single choice — see framework bridges.
Translating the UI
SendNUIMessage({ action = 'locale', data = lib.getLocales() })Send the whole table once when the UI starts and look strings up in JavaScript, instead of sending text with every message. NUI patterns: NUI to Lua communication.
A translation workflow
- Keys that describe meaning (
impound_fee), not English text. - Placeholders for numbers and names — word order differs between languages.
- Accept community pull requests for new locale files; credit translators.
- Keep all locale files in
escrow_ignore.
Frequently asked questions
How do I add translations with ox_lib?
Add ox_lib 'locale' to the fxmanifest, create locales/<lang>.json, and call locale('key'). Owners choose the language with setr ox:locale <code>.
How do ESX scripts translate text?
With locale tables and TranslateCap('key') / Translate('key').
How do QBCore scripts translate text?
With Locale:new({ phrases = ... }) and Lang:t('key').
How do I translate my NUI?
Send the locale table to the UI once and look strings up in JavaScript.
Need this built, not just explained?
Ten years of FiveM work, from Lua to NUI
Custom resources, React NUI, ESX / QBCore / Qbox integration, OneSync performance audits and security reviews — plus the websites and SEO around your server brand.
Related guides
- FrameworksGetting started with ox_libStart ox_lib before your resource, add shared_script '@ox_lib/init.lua' and lua54 'yes' to your fxmanifest, and the global lib becomes available. Use cache.ped/cache.vehicle instead of calling natives in loops, lib.callback for client↔server requests, lib.notify, lib.progressBar, lib.registerContext/lib.showContext, lib.inputDialog, lib.points and lib.zones for interaction, and lib.addCommand for commands with ACE restrictions.
- EngineeringDesigning a config.lua people can actually usePut values owners change (locations, prices, jobs, feature toggles) in config.lua, keep logic out of it, and split server-only values (webhooks, tokens, reward amounts) into a server-side config that is never sent to clients. Group settings, name them clearly, ship working defaults, validate the config at startup with readable errors, and leave config files editable under escrow with escrow_ignore.
- FrameworksSupporting several frameworks with a bridgeDetect the running framework with GetResourceState('qbx_core'), ('qb-core') and ('es_extended'), load a matching bridge file, and have every bridge expose the same functions — get player identifier, job, money add/remove, notify, item add/remove. Keep framework calls out of your main logic, allow a config override, and test on each framework you claim to support.