Publikum: FiveM-Serverbesitzer, Skriptersteller und -Betreuer, die qualitativ hochwertige Übersetzungen wünschen, ohne Platzhalter oder die Benutzeroberfläche zu beschädigen.
Kurz zusammengefasst
- Zentrale alle Texte in Locale-Dateien (JSON oder Lua-Tabellen). Kodiere niemals Zeichenfolgen in der Spiel-Logik.
- Platzhalter schützen (zB
%s,%d,%{name},{0},~r~,^1) während der Übersetzung. - Verwende AI für erste Übersetzungsdurchgänge + Glossar + automatisierte Prüfungen → schnelle menschliche Überprüfung → versende.
- Behalte eine einzige Wahrheit (meistens Englisch), vergleiche Änderungen und generiere nur geänderte Schlüssel.
Warum übersetzt du deine FiveM-Skripte
- Zugänglichkeit und Wachstum: Lokalisierte Server ziehen mehr Spieler an und halten sie bei der Stange.
- Professionalität: Einheitliche Terminologie für alle Befehle, Benutzeroberflächen und Fehlermeldungen.
- Beitragsfreundlich: Eine klare lokale Struktur lädt zu Community-PRs ein.
Wenn du eine grundlegende Auffrischung zur Struktur und zu den besten Praktiken benötigst, siehe: Wie man FiveM Scripts (auf die richtige Weise) übersetzt.
Architektur: der richtige Weg zur Lokalisierung
Ziel: Keine benutzersichtbaren Zeichenketten im Spielcode. Leite alles über eine Locale-Schicht weiter.
Empfohlenes Ressourcenlayout
my_resource/ ├─ fxmanifest.lua ├─ locales/ │ ├─ en.json # Quellsprache (einzige Wahrheit) │ ├─ de.json # übersetzt (generiert/bearbeitet) │ ├─ es.json # übersetzt (generiert/bearbeitet) │ └─ qa.rules.json # optional: Platzhalter-Whitelist & Checks ├─ client/ │ └─ main.lua ├─ server/ │ └─ main.lua └─ shared/ └─ i18n.lua # Übersetzungs-Helfer
fxmanifest.lua (Minimalbeispiel)
fx_version 'cerulean'
game 'gta5'
lua54 'yes'
shared_scripts {
'shared/i18n.lua',
}
files {
'locales/*.json'
}
shared/i18n.lua (leichtgewichtiger Loader + Platzhalterersetzung)
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 file = ('locales/%s.json'):format(lang)
local dict = loadJSON(file)
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)) -- %{name}
end
return str
end
function _U(key, vars)
local dict = readLocale(LOCALE)
local src = dict[key]
if not src then
-- fallback to English if missing
src = readLocale('en')[key] or key
end
return interpolate(src, vars)
end
exports('Translate', _U)
Verwendung im 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 (Quelle)
{
"notify_title": "Server-Nachricht",
"welcome_player": "Willkommen, %{name}!",
"server_started": "Server-Modul ist bereit.",
"no_permission": "Du hast keine Berechtigung.",
"items_remaining": "%{count} Artikel verbleiben"
}
KI-Übersetzungsworkflow (schnell und sicher)
- Quelle extrahieren und einfrieren
- Halten Englisch (oder deine Quelle) als
locales/en.json. - Schlüsselbenennung durchsetzen:
Domäne.Aktion.Betreff(z.B,Bestandsaufnahme.Ablegen.Bestätigen).
- Erstellen/Erweitern eines Glossars
- CSV- oder JSON-Zuordnung von kanonischen Begriffen → Zielbegriffen. Beispiel:
Quelle,Ziel EMS,Rettungsdienst PD,Polizeimechaniker,Mechaniker
- Platzhalter und Markup schützen
- Platzhalter:
%{name},%s,%d,{0} - FiveM-Farbcodes:
~r~,~g~,~s~; Chat-Codes:^1,^2 - NUI/HTML-Tags:
<b>,<span>…
- Übersetzen über API (Charge)
- Senden Werte nur, behalten Schlüssel unverändert.
- Liefern Glossar Und Stil (Ton) zum Modell/Motor.
- Automatisierte Qualitätssicherung
- JSON validieren.
- Verifizieren Platzhalterparität (jeder Platzhalter in der Quelle ist im Ziel vorhanden).
- Markiere verbotene Änderungen (z. B. geänderte Farbcodes oder hinzugefügte Interpunktion, wenn nicht erlaubt).
- Menschliche Stichprobenkontrolle (5–10 Minuten)
- Überprüfe Befehle, Fehlermeldungen und lange UI-Strings.
- Ausliefern und iterieren
- Behalte eine Übersetzungsspeicher (vorherige Ausgaben), um eine erneute Übersetzung unveränderter Schlüssel zu vermeiden.
Leitplanken: Hinweise und Regeln, die wirklich funktionieren
LLM-Eingabeaufforderung für JSON-Batch-Konvertierung
Aufgabe: Übersetze JSON-Werte von Englisch in für einen FiveM/GTA RP-Kontext.
Regeln:
- BEHALTEN DIE SCHLÜSSEL UNVERÄNDERT.
- BEHALT ALLE Platzhalter genau so: %{var}, %s, %d, {0}, ~r~, ~g~, ^1, ^2, usw.
- Behalte die Großschreibung und Code-Stil-Token (Befehle, /Schrägstrich-Befehle) unverändert.
- Füge keine Anführungszeichen, zusätzliche Satzzeichen hinzu oder ändere die Bedeutung.
- Gib NUR gültiges JSON mit derselben Struktur zurück.
JSON zum Übersetzen:
Regex, das du in einem QA-Skript verwenden kannst
- Platzhalter:
%%{[A-Za-z0-9_]+} - C printf:
%(?:d+$)?[sdif] - Chat-Codes:
^d - Tilde-Farbcodes:
~[rgbso]~
Beispiel: Übersetzen mit DeepL (Node.js)
Funktioniert hervorragend für einmalige Aufträge oder CI.
package.json (Skripte)
{
"type": "module",
"scripts": {
"i18n:translate:de": "node tools/translate-deepl.js en de",
"i18n:check": "node tools/i18n-check.js"
}
}
tools/translate-deepl.js
import fs from 'fs';
import path from 'path';
import assert from 'assert';
import fetch from 'node-fetch';
const [,, srcLang, dstLang] = process.argv;
const apiKey = process.env.DEEPL_API_KEY; // set in CI/ENV
assert(apiKey, 'DEEPL_API_KEY is required');
const src = JSON.parse(fs.readFileSync('locales/en.json', 'utf8'));
const out = {};
const GLOSSARY = {
'EMS': 'Rettungsdienst',
'PD': 'Polizei',
};
function protect(str){
// Replace placeholders with tokens DeepL won't alter
return str
.replace(/%{([^}]+)}/g, '⟦$1⟧')
.replace(/%s/g, '⟪S⟫')
.replace(/%d/g, '⟪D⟫');
}
function restore(str){
return str
.replace(/⟦([^⟧]+)⟧/g, '%{$1}')
.replace(/⟪S⟫/g, '%s')
.replace(/⟪D⟫/g, '%d');
}
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: 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;
}
for (const [k, v] of Object.entries(src)) {
const protectedText = protect(v);
// Glossary pre-pass (simple):
let glossed = protectedText;
for (const [from, to] of Object.entries(GLOSSARY)) {
glossed = glossed.replace(new RegExp(`b${from}b`, 'g'), to);
}
// Translate
// eslint-disable-next-line no-await-in-loop
const tr = await translate(glossed);
out[k] = restore(tr);
}
fs.writeFileSync(`locales/${dstLang}.json`, JSON.stringify(out, null, 2));
console.log(`Wrote locales/${dstLang}.json`);
tools/i18n-check.js (Platzhalterparität)
import fs from 'fs';
const src = JSON.parse(fs.readFileSync('locales\/en.json', 'utf8'));
const dst = JSON.parse(fs.readFileSync('locales\/de.json', 'utf8'));
const reVar = \/%{[^}]+}\/g;
const reS = \/%s\/g;
const reD = \/%d\/g;
let ok = true;
for (const k of Object.keys(src)) {
const a = (src[k].match(reVar)||[]).length === (dst[k]?.match(reVar)||[]).length;
const b = (src[k].match(reS)||[]).length === (dst[k]?.match(reS)||[]).length;
const c = (src[k].match(reD)||[]).length === (dst[k]?.match(reD)||[]).length;
if (!(a && b && c)) {
console.error('Placeholder mismatch for key:', k);
ok = false;
}
}
process.exit(ok ? 0 : 1);
LLMs (OpenAI/andere) effektiv nutzen
- Chunk nach Thema/Domäne für einen besseren Kontext (z. B. Inventar, Polizei, Jobs).
- Bieten Kurzbeschreibungen pro Gruppe (zwei Zeilen), um Ton und Publikum zu definieren.
- Beispiele mit wenigen Aufnahmen: 2–3 korrekt übersetzte Paare mit Platzhaltern verbessern die Konsistenz.
- Wiederholungsrichtlinie: führe nur die fehlgeschlagenen Schlüssel aus, die von
i18n-Prüfung.
Few‑Shot-Vorlage (System + Benutzer)
System: Du übersetzt FiveM-Spiel-UI-Zeichenfolgen für .
- Behalte die Schlüssel unverändert, bewahre Platzhalter, halte den Ton knapp.
Benutzerexemplare:
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."
Jetzt übersetze die folgenden JSON-Werte von Englisch zu . Gib nur gültiges JSON zurück:
NUI (HTML/JS)-Übersetzungen
Für Browser-Benutzeroberflächen ist eine clientseitige Bibliothek praktisch.
Empfohlene Vorgehensweise
- Verwende ein JSON-Bundle pro Sprache in
web/locales/ .json. - Lade mit deinem UI Framework und stelle eine
t(Schlüssel, Variablen)Helfer. - Behalte die gleiche Schlüssel als Server-Gebietsschemas, um die kognitive Belastung zu reduzieren.
Minimaler JS-Helfer
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;
}
ESX/QBCore-Besonderheiten
- Viele ESX-Skripte werden mitgeliefert
locales/en.lua,locales/de.luamit einem_UHelfer. - Wenn du Lua-Tabellen für Lokales verwendest, behalte ein Stil deinem Repo. Das Mischen von JSON und Lua für dieselbe Ressource erhöht die Wartungskosten.
- QBCore verwendet oft konfigurationsgesteuerte Nachrichten. Migriere wiederholte Zeichenfolgen in Locale-Dateien, um Divergenz zu vermeiden.
Lua-Tabelle für die Lokalisierung bereit (falls du Lua JSON vorziehst)
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}!'
}
Qualitätskontrollen vor dem Versand
- JSON/Lua-Analyseprüfung im CI.
- Platzhalterparität (Regex-Prüfungen wie gezeigt).
- Verbotene Änderungen: Änderungen an nicht zulassen
/Befehle, Tastenbelegungsbuchstaben, Farb-/Chatcodes. - Längendeltas: Flag +40%-Wachstum für UI-Schaltflächen; kann das Layout beschädigen.
- Rauchtest: starte deinen Server und überprüfe kritische Abläufe.
Bist du neu im Einrichten eines Servers zum Testen? Folge diesem Starter: So erstellst du einen FiveM-Server.
Wartungsstrategie
- Behandeln
en.jsonals Quelle der Wahrheit; erstelle einen CI-Job, der die Unterschiede vergleichten.jsonund aktualisiert nur geänderte Schlüssel in Zielen. - Behalte eine
CHANGELOG.i18n.mdfür Übersetzer. - Ermutige die Community, über PRs beizutragen; dokumentiere deine Stilhandbuch Und Glossar In
/docs/i18n.md.
Häufige Fallstricke (und Lösungen)
- Defekte Platzhalter → Nutze automatisierte Checks und Schutz-Tokens.
- Inkonsistente Terminologie → Pflege ein Glossar und setze es in Prompts und Vorverarbeitung durch.
- Gemischte Gebietsschemas im Code → CI fehlschlagen, wenn Zeichenfolgen außerhalb erkannt werden
Gebietsschemas/. - RTL-Sprachen → Stelle sicher, dass dein NUI CSS setzt
Regie: rtl;und verwendet Schriftarten mit RTL-Unterstützung. - Abweichungen bei Groß- und Kleinschreibung und Zeichensetzung → Weise die KI explizit an und führe einen Linter aus, um die Interpunktion zu normalisieren.
Externe Ressourcen
- DeepL-API — Entwicklerdokumente: https://www.deepl.com/docs-api
- Google Cloud-Übersetzung — Dokumente und bewährte Methoden: https://cloud.google.com/translate/docs
- FiveM-Ressourcenmanifest (fxmanifest.lua) - Referenz: https://docs.fivem.net/docs/scripting-reference/resource-manifest/resource-manifest/
Interne Ressourcen (weiterführende Literatur)
- Wie man FiveM Scripts (auf die richtige Weise) übersetzt — Arbeitsablauf und Muster: https://fivemx.com/fivem-scripts-translation/
- So erstellst du einen FiveM-Server — richte ein Testbett für die Qualitätssicherung ein: https://fivemx.com/how-to-create-a-fivem-server/
Checklisten kopieren und einfügen
Vorübersetzung
- Alle Saiten zentralisiert in
locales/en.json(oder Lua-Tabelle) - Schlüssel folgen einer Namenskonvention
- Glossar erstellt
- Platzhalter geprüft
Laufen
- Stapelübersetzung mit Glossar
- Ausgabe speichern unter
Gebietsschemas/ .json
Qualitätssicherung
- JSON/Lua gültig
- Platzhalterparität OK
- Verbotene Token unverändert
- Längendeltas akzeptabel
- Menschliche Stichprobenkontrolle durchgeführt
Schiff
- CI grün
- Änderungsprotokoll aktualisiert
- Community-Feedback einholen
KI für die nächsten Schritte mit FiveM
- Wie man KI mit FiveM verwendet
- Schreibe FiveM-Skripte mit KI
- ChatGPT-Eingabeaufforderungen für FiveM
- Übersetze FiveM-Skripte mit KI
- FiveM-Entwicklungstools
- FiveM-Skripte, ESX-Skripte, QBCore-Skripte, Und QBOX-Skripte