Ir para o conteúdo principal
FiveMX
Loja
Scripts
MLOs
Servidores Completos
Mods Grátis
Ferramentas
Guias
Todos os Produtos
FiveMX

Comece a construir seu servidor hoje.

Recursos FiveM selecionados, entrega instantânea, mods grátis para começar e guias práticos em um marketplace tranquilo.

Navegar na lojasupport@fivemx.com

Loja

  • Loja
  • Todos os produtos
  • Mods grátis
  • Melhores scripts & mods
  • Scripts FiveM

Frameworks

  • Scripts QBCore
  • Scripts ESX
  • QBox
  • Standalone

Comunidade

  • Blog
  • Suporte
  • Criadores
  • Afiliados

Jurídico

  • Política de privacidade
  • Termos de serviço
  • Política de reembolso
  • Entrega digital
  • Política de cookies
  • Conformidade LGPD/GDPR
  • DMCA
  • Informações legais
  • Política editorial
© 2026 FiveMX. Todos os direitos reservados.·FiveMX não é afiliado à Rockstar Games, Take-Two Interactive ou CFX.re. Todas as marcas são propriedade de seus respectivos donos.
GitHubDiscordDocs
Table of Contents
TL;DRWhy translate your scripts at allArchitecture: structure your resource for translationRecommended resource layoutfxmanifest.luashared/i18n.lua (lightweight loader + interpolation)Usage in client/server codelocales/en.json (source of truth)The AI translation workflowStep 1: Extract and freeze the sourceStep 2: Build a glossaryStep 3: Protect placeholdersStep 4: Translate in batchesStep 5: Automated QAStep 6: Human spot-checkStep 7: Ship and iterateTranslate with DeepL (Node.js)package.jsontools/translate-deepl.jstools/i18n-check.js (parity check)Translate with OpenAI (for edge cases)System promptFew-shot examplesNUI (HTML/JS) translationsESX and QBCore specificsLua table locale (if you prefer Lua)Quality gates before you shipMaintenance strategyCommon pitfalls and fixesExternal resourcesRelated guides on FiveMXRelated FiveM resources

Move from research to a production-ready server stack

Once you know the direction, jump into the highest-leverage commercial hubs for verified scripts, curated bundles, and framework-specific buying paths.

Framework hub

Move into the QBCore landing page to compare verified scripts, framework fit, and install-ready products built for modern FiveM servers.

Open QBCore hub

Premium catalog

Move from research into the main shop to compare real products, framework labels, screenshots, and production-ready quality signals.

Open premium shop

Launch faster

Bundles shorten the path from planning to launch by grouping the highest-leverage scripts into a cleaner commercial starting point.

View bundles

Disclosure: Some links below are affiliate links to FiveMX products. We may earn a commission at no extra cost to you.

Premium Scripts You Might Like

Free Scripts You Might Like

Related Articles

The best FiveM job scripts in 2026 are wasabi-police and qb-policejob for law enforcement, qs-ambulancejob and qb-ambulancejob for EMS, qb-mechanicjob and wasabi_mechanic for…

February 24, 2026

Learn how to optimize FiveM server loading times by managing resources, using efficient mods, and choosing the right server host to eliminate annoying delays.

September 3, 2024

If you're a FiveM server owner or developer, you know the importance of optimizing your server scripts to ensure smooth and efficient gameplay. In this...

August 14, 2024

How to Translate FiveM Scripts with AI: The Complete 2026 Workflow

Published on August 17, 2025·by Lars Miller(Founder & Lead Editor)·Credentials·6 min read·Updated on May 18, 2026
Scripts & Resourcestranslate fivem scripts

Translate FiveM scripts to any language using AI — without breaking placeholders, color codes, or UI layout. Complete workflow covering locale architecture, DeepL and OpenAI pipelines, automated QA checks, and ESX/QBCore integration.

How to Translate FiveM Scripts with AI: The Complete 2026 Workflow
How to Translate FiveM Scripts with AI: The Complete 2026 Workflow

Translating FiveM scripts to a new language used to mean hiring a translator, waiting two weeks, and dealing with broken placeholders when the file came back. With modern AI — DeepL, GPT-4, Claude — a 500-string locale file can be translated, QA-checked, and shipped in under an hour, at production quality.

This guide covers the full workflow: locale file architecture that scales, placeholder protection that actually works, a working Node.js pipeline for both DeepL and OpenAI, automated QA checks, and framework-specific notes for ESX, QBCore, and QBox.

TL;DR

Translating FiveM Scripts Using AI Tools

  • Centralize every user-visible string in locale files (locales/en.json, locales/de.json, etc.). No hardcoded strings in gameplay code.
  • Protect placeholders (%s, %d, %{name}, ~r~, ^1) with unique tokens before translating.
  • Use DeepL for major European languages, GPT-4 for edge cases or nuanced context.
  • Run a glossary pre-pass, translate, restore placeholders, then a regex parity check in CI.
  • Keep en.json as single source of truth; diff and translate only changed keys.

Why translate your scripts at all

  • Player retention — localized servers keep non-English speakers engaged past the first session.
  • Professional polish — consistent terminology across commands, UI, and error messages separates serious servers from hobby ones.
  • Community contribution friendly — clean locale files invite PRs for languages you don't speak.
  • SEO and discovery — servers that advertise multi-language support rank better on server lists for non-English queries.

Architecture: structure your resource for translation

The cardinal rule is zero user-visible strings inside gameplay code. Everything routes through a locale layer.

Recommended resource layout

my_resource/
├─ fxmanifest.lua
├─ locales/
│  ├─ en.json        # source language (single source of truth)
│  ├─ de.json        # generated + human-reviewed
│  ├─ es.json        # generated + human-reviewed
│  ├─ fr.json        # generated + human-reviewed
│  └─ qa.rules.json  # optional: placeholder whitelist
├─ client/
│  └─ main.lua
├─ server/
│  └─ main.lua
└─ shared/
   └─ i18n.lua       # translation helper

fxmanifest.lua

fx_version 'cerulean'
game 'gta5'
lua54 'yes'

shared_scripts {
    'shared/i18n.lua',
}

files {
    'locales/*.json',
}

shared/i18n.lua (lightweight loader + interpolation)

local LOCALE = GetConvar('my_locale', 'en')
local CACHE = {}

local function loadJSON(path)
    local file = io.open(path, 'r')
    if not file then return {} end
    local content = file:read('*a')
    file:close()
    local ok, data = pcall(function() return json.decode(content) end)
    return ok and data or {}
end

local function readLocale(lang)
    if CACHE[lang] then return CACHE[lang] end
    local dict = loadJSON(('locales/%s.json'):format(lang))
    CACHE[lang] = dict
    return dict
end

local function interpolate(str, vars)
    if not vars then return str end
    for k, v in pairs(vars) do
        str = str:gsub('%%{' .. k .. '}', tostring(v))
    end
    return str
end

function _U(key, vars)
    local dict = readLocale(LOCALE)
    local src = dict[key] or readLocale('en')[key] or key
    return interpolate(src, vars)
end

exports('Translate', _U)

Usage in client/server code

-- Client
lib.notify({
    title = _U('notify_title'),
    description = _U('welcome_player', { name = GetPlayerName(PlayerId()) })
})

-- Server
print(('[MyRes] %s'):format(_U('server_started')))

locales/en.json (source of truth)

{
    "notify_title": "Server Message",
    "welcome_player": "Welcome, %{name}!",
    "server_started": "Server module is ready.",
    "no_permission": "You do not have permission.",
    "items_remaining": "%{count} items remaining"
}

Everything in your gameplay code now routes through _U(key) — no hardcoded strings means no translation drift when you add or change features.

The AI translation workflow

Step 1: Extract and freeze the source

Lock locales/en.json before touching any translation tooling. Enforce a key naming convention like domain.action.subject (inventory.drop.confirm, police.arrest.success) so keys stay stable across refactors.

Step 2: Build a glossary

A glossary maps framework-specific or brand-specific terms to canonical translations. CSV is fine:

source,de,fr,es
EMS,Rettungsdienst,Urgences,Emergencias
PD,Polizei,Police,Policía
Mechanic,Mechaniker,Mécanicien,Mecánico
Citizenid,Citizenid,Citizenid,Citizenid

Glossary discipline matters — this is what separates professional localization from machine-translated slop.

Step 3: Protect placeholders

Before the text hits the translator, substitute every placeholder and color code with a unique token the model won't modify:

OriginalToken
%{name}⟦name⟧
%s⟪S⟫
%d⟪D⟫
~r~ / ~g~ / ~s~⟪COLOR_R⟫ / ⟪COLOR_G⟫ / ⟪COLOR_S⟫
^1 – ^9⟪CHAT_1⟫ – ⟪CHAT_9⟫
<b>, </b>⟪HTML_B⟫, ⟪HTML_B_END⟫

These tokens look like foreign words to the model and pass through unchanged. After translation, reverse the substitution.

Step 4: Translate in batches

Send values (not keys) to the translator, one batch per language. Supply the glossary and a style note (tone, formality) to the model.

Step 5: Automated QA

Four checks, all automated:

  1. JSON parses valid.
  2. Every placeholder present in source is present in target.
  3. Forbidden tokens (commands, keybinds, color codes) unchanged.
  4. Length deltas within budget (UI strings not more than 40% longer).

Step 6: Human spot-check

Five to ten minutes on a random 20 strings per locale. Focus on commands and long UI strings where nuance matters.

Step 7: Ship and iterate

Commit the translated locale. On the next source edit, diff en.json and re-translate only changed keys using a translation memory to skip unchanged ones.

Translate with DeepL (Node.js)

DeepL is the best default for German, French, Spanish, Portuguese, Italian, Dutch, Polish, and about 25 other languages. Cheap, fast, near-native quality.

package.json

{
    "type": "module",
    "scripts": {
        "i18n:translate:de": "node tools/translate-deepl.js en de",
        "i18n:translate:fr": "node tools/translate-deepl.js en fr",
        "i18n:check": "node tools/i18n-check.js"
    }
}

tools/translate-deepl.js

import fs from 'node:fs';
import assert from 'node:assert';

const [, , srcLang, dstLang] = process.argv;
const apiKey = process.env.DEEPL_API_KEY;
assert(apiKey, 'DEEPL_API_KEY required');

const GLOSSARY = {
    EMS: 'Rettungsdienst',
    PD: 'Polizei',
};

function protect(str) {
    return str
        .replace(/%\{([^}]+)\}/g, '⟦$1⟧')
        .replace(/%s/g, '⟪S⟫')
        .replace(/%d/g, '⟪D⟫')
        .replace(/~([rgbso])~/g, '⟪COLOR_$1⟫')
        .replace(/\^(\d)/g, '⟪CHAT_$1⟫');
}

function restore(str) {
    return str
        .replace(/⟦([^⟧]+)⟧/g, '%{$1}')
        .replace(/⟪S⟫/g, '%s')
        .replace(/⟪D⟫/g, '%d')
        .replace(/⟪COLOR_([RGBSO])⟫/gi, (_, c) => `~${c.toLowerCase()}~`)
        .replace(/⟪CHAT_(\d)⟫/g, '^$1');
}

async function translate(text) {
    const res = await fetch('https://api.deepl.com/v2/translate', {
        method: 'POST',
        headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
        body: new URLSearchParams({
            auth_key: apiKey,
            text,
            source_lang: srcLang.toUpperCase(),
            target_lang: dstLang.toUpperCase(),
            formality: 'prefer_more',
        }),
    });
    const json = await res.json();
    if (!json.translations) throw new Error(JSON.stringify(json));
    return json.translations[0].text;
}

const src = JSON.parse(fs.readFileSync('locales/en.json', 'utf8'));
const out = {};

for (const [k, v] of Object.entries(src)) {
    let input = protect(v);
    for (const [from, to] of Object.entries(GLOSSARY)) {
        input = input.replace(new RegExp(`\\b${from}\\b`, 'g'), to);
    }
    out[k] = restore(await translate(input));
}

fs.writeFileSync(`locales/${dstLang}.json`, JSON.stringify(out, null, 2));
console.log(`Wrote locales/${dstLang}.json (${Object.keys(out).length} keys)`);

tools/i18n-check.js (parity check)

import fs from 'node:fs';

const src = JSON.parse(fs.readFileSync('locales/en.json', 'utf8'));
const dst = JSON.parse(fs.readFileSync(`locales/${process.argv[2]}.json`, 'utf8'));

const patterns = [
    { name: 'var', re: /%\{[^}]+\}/g },
    { name: 'printf-s', re: /%s/g },
    { name: 'printf-d', re: /%d/g },
    { name: 'color', re: /~[rgbso]~/g },
    { name: 'chat-code', re: /\^\d/g },
];

let ok = true;
for (const key of Object.keys(src)) {
    for (const p of patterns) {
        const a = (src[key].match(p.re) || []).length;
        const b = (dst[key]?.match(p.re) || []).length;
        if (a !== b) {
            console.error(`[${key}] ${p.name} mismatch: en=${a} ${process.argv[2]}=${b}`);
            ok = false;
        }
    }
}
process.exit(ok ? 0 : 1);

Run pnpm i18n:translate:de && pnpm i18n:check de and you have a translated, parity-checked German locale ready for human review.

Translate with OpenAI (for edge cases)

When DeepL doesn't cover a language or you need context-aware translation, GPT-4 class models work well.

System prompt

You translate FiveM game UI strings from English to <TARGET_LANGUAGE>.

Rules:
- Preserve every placeholder exactly as-is: %{var}, %s, %d, ~r~, ~g~, ~s~, ^1, ^2.
- Keep slash-commands unchanged: /report, /me, /do.
- Keep citizenid, license, steam identifiers unchanged.
- Do not add quotes, extra punctuation, or change meaning.
- Return only a valid JSON object with the same keys as input.

Glossary (these terms must translate this way):
EMS → Rettungsdienst
PD → Polizei
Mechanic → Mechaniker

Few-shot examples

Include 2–3 correctly translated pairs with placeholders:

EN: "You have %{count} fines."
DE: "Du hast %{count} Strafzettel."

EN: "~r~Error:~s~ You lack permission."
DE: "~r~Fehler:~s~ Dir fehlt die Berechtigung."

Then paste the JSON to translate. Models do better with 50 strings at a time than with 500.

NUI (HTML/JS) translations

For browser-based UIs in your scripts, mirror the Lua approach.

const dict = await (await fetch(`/locales/${lang}.json`)).json();

export function t(key, vars) {
    let s = dict[key] ?? key;
    for (const [k, v] of Object.entries(vars || {})) {
        s = s.replace(`%{${k}}`, v);
    }
    return s;
}

Keep the same keys as your server locales. Mixing key schemas between NUI and server side is a guaranteed source of bugs.

ESX and QBCore specifics

  • Many legacy ship locales/en.lua and locales/de.lua with a _U helper. The JSON approach above is cleaner, but if you have to stay on Lua tables, keep one style across the repo — mixing JSON and Lua for the same resource doubles maintenance cost.
  • QBCore often uses config-driven messages scattered across config.lua. Migrate them to locale files when you touch them.
  • QBox uses ox_lib notify, which integrates cleanly with JSON locales.

Lua table locale (if you prefer Lua)

Locales = Locales or {}

Locales['en'] = {
    no_permission = 'You do not have permission.',
    welcome_player = 'Welcome, %{name}!',
}

Locales['de'] = {
    no_permission = 'Du hast keine Berechtigung.',
    welcome_player = 'Willkommen, %{name}!',
}

Quality gates before you ship

GateToolBlocks release?
JSON parses validjq . locales/*.jsonYes
Lua syntax validluac -p locales/*.luaYes
Placeholder paritytools/i18n-check.jsYes
Forbidden tokens unchanged (commands, keybinds, color codes)Regex checkYes
Length budget (+40% max)Custom scriptWarn
Human spot-check 20 stringsManualYes

Automate gates 1–4 in CI. Gate 5 is the only one that needs a human.

Maintenance strategy

  • en.json is the single source of truth. Never edit target locales directly (except for spot-fixes after human review).
  • On every English edit, run a diff script that: translates new keys, re-translates changed values, deletes orphaned keys in targets.
  • Store previous outputs as a translation memory (just a SQLite file or JSON map en_value -> target_value) to skip unchanged keys. This cuts API costs to near zero for routine maintenance.
  • Document your glossary and style guide in /docs/i18n.md so community contributors stay consistent.

Common pitfalls and fixes

  • Broken placeholders after translation — always use protection tokens plus the parity check.
  • Inconsistent terminology — glossary discipline, enforced in both the pre-pass and the LLM prompt.
  • Mixed locales in gameplay code — CI grep for hardcoded strings outside locales/; fail the build on matches.
  • RTL languages (Arabic, Hebrew) — ensure NUI CSS sets direction: rtl; and uses fonts with RTL support. Some layouts need conditional styles.
  • Casing or punctuation drift — instruct the AI explicitly and run a punctuation linter as part of QA.
  • Re-translation explosion — without a translation memory, every edit re-translates everything. Always cache previous outputs.

External resources

  • DeepL API developer docs — pricing, rate limits, supported languages.
  • Google Cloud Translation — alternative when DeepL doesn't cover your target.
  • OpenAI API docs — GPT-4 class models for context-aware translation.
  • FiveM fxmanifest reference — canonical manifest documentation.

Related guides on FiveMX

  • — spin up a test bed for QA on translated locales
  • — translation files hit load time if done wrong
  • — curated scripts with clean locale files
  • — ready-to-install scripts to practice on

Related FiveM resources

Use these internal resources to connect How to Translate FiveM Scripts with AI: The Complete 2026 Workflow with setup, framework, marketplace resources, and server operations.

Frequently Asked Questions

Why translate FiveM scripts with AI instead of by hand?

AI handles the 90% of routine strings (notifications, UI labels, error messages) in seconds, letting you focus human review on the 10% that actually needs it — commands, nuanced UI, and branding. DeepL and modern LLMs produce near-native quality for German, French, Spanish, and Portuguese out of the box. Hand-translating 500 strings takes a full day; an AI pipeline plus human review takes an hour.

What's the biggest risk when translating scripts with AI?

Broken placeholders. If the AI translates '%{playerName}' as '%{spielername}' or drops a '~r~' color code, the script will either crash or display malformed text in-game. The fix is placeholder protection: substitute placeholders with tokens the AI won't touch (like ⟦playerName⟧), translate, then restore. Combine with a regex-based parity check in CI to catch any mismatches before shipping.

DeepL or OpenAI for FiveM script translation?

DeepL for German, French, Spanish, Portuguese — it's faster, cheaper, and produces more natural phrasing for European languages. OpenAI (GPT-4 class models) for any language DeepL doesn't support, or when you need context-aware translation (e.g., distinguishing 'arrest' the command from 'arrest' the player status). Use DeepL as the default, fall back to GPT-4 for edge cases.

How do I protect placeholders during translation?

Replace every placeholder with a unique token the translator won't modify: '%{name}' becomes '⟦name⟧', '%s' becomes '⟪S⟫', '~r~' becomes '⟪COLOR_R⟫'. Translate the text, then restore the original placeholders by reversing the substitution. This works reliably across DeepL, GPT, Gemini, and any other translator because the tokens look like foreign words to the model and pass through unchanged.

Table of Contents

TL;DRWhy translate your scripts at allArchitecture: structure your resource for translationRecommended resource layoutfxmanifest.luashared/i18n.lua (lightweight loader + interpolation)Usage in client/server codelocales/en.json (source of truth)The AI translation workflowStep 1: Extract and freeze the sourceStep 2: Build a glossaryStep 3: Protect placeholdersStep 4: Translate in batchesStep 5: Automated QAStep 6: Human spot-checkStep 7: Ship and iterateTranslate with DeepL (Node.js)package.jsontools/translate-deepl.jstools/i18n-check.js (parity check)Translate with OpenAI (for edge cases)System promptFew-shot examplesNUI (HTML/JS) translationsESX and QBCore specificsLua table locale (if you prefer Lua)Quality gates before you shipMaintenance strategyCommon pitfalls and fixesExternal resourcesRelated guides on FiveMXRelated FiveM resources
Home
Blog
Scripts & Resources
Browse QBCore-ready scripts
Browse premium FiveM scripts
Compare curated bundles
FiveM Marketplace Script (Player-Owned)

FiveM Marketplace Script (Player-Owned)

$23.99
FiveM Fuel Pump Script

FiveM Fuel Pump Script

$14.49
FiveM Bike Hire / Rental Script

FiveM Bike Hire / Rental Script

$16.99
FiveM Housing / House Script

FiveM Housing / House Script

$17.99
Highway Police Patrol MLO

Highway Police Patrol MLO

304 downloads
Bunker shadow complex ( MAP + SCRIPT )

Bunker shadow complex ( MAP + SCRIPT )

259 downloads
The Most Advanced Appearance

The Most Advanced Appearance

251 downloads
Italian Pizzeria - Vespucci Pizza [FiveM MLO]

Italian Pizzeria - Vespucci Pizza [FiveM MLO]

247 downloads
Best FiveM Job Scripts 2026: Essential Roleplay Careers
Best FiveM Job Scripts 2026: Essential Roleplay Careers
Eliminate Annoying Delays: Optimize FiveM Server Loading ...
Eliminate Annoying Delays: Optimize FiveM Server Loading ...
Boosting Performance: FiveM Optimize Scripts
Boosting Performance: FiveM Optimize Scripts
How do I handle ESX/QBCore-specific terminology?

Build a glossary (CSV or JSON) of framework-specific terms with canonical translations: 'EMS' → 'Rettungsdienst' in German, 'citizenid' stays as 'citizenid', '/report' stays as '/report'. Apply the glossary as a pre-pass before sending to the translator, and enforce it in your prompt ('Keep these terms unchanged: …'). Glossary discipline is what separates a professional server localization from a machine-translated mess.

What should I check before shipping translated locales?

Five gates: (1) valid JSON/Lua parse, (2) placeholder parity (every %{var} in source present in target), (3) forbidden-change list (commands, color codes, keybinds untouched), (4) length budget (UI strings not more than 40% longer than source), (5) human spot-check on 20 random strings. Automate gates 1-4 in CI; only gate 5 requires a human.

How do I keep translations in sync when I change source strings?

Treat en.json as the single source of truth and diff it against target locales on every commit. A small CI script can identify new keys (translate them), changed English values (re-translate), and orphaned keys in targets (delete them). Store previous outputs as a translation memory so unchanged keys are never re-translated — this saves money on API calls and keeps community-reviewed translations stable.

More on This Topic

Best FiveM Phone Scripts 2026: Complete Comparison GuideBest FiveM Police Scripts 2026: Complete LEO Resource GuideTop 10 FiveM Medic and EMS Scripts for 2026Best FiveM Drug and Crime Scripts 2026: Complete GuideBest FiveM Garage and Vehicle Scripts 2026: Complete Guide
ESX scripts
How to set up a FiveM server
Optimize loading times
Best QBox scripts 2026
Best free FiveM scripts 2026
best FiveM scripts
install FiveM scripts
ESX vs QBCore vs QBox
inventory scripts
FiveMX shop
Jobs Creator
Previous Article

How to Connect txAdmin to Discord (2026 Guide)

Next Article

Inventory & Weight Tuning: From items.lua to Metadata