Spare 20 % mit WELCOMEAngebote ansehen
Wie man Scripts mit KI übersetzt (FiveM-Anleitung)

Wie man FiveM Scripts mit KI übersetzt

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)

  1. 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).
  1. Erstellen/Erweitern eines Glossars
  • CSV- oder JSON-Zuordnung von kanonischen Begriffen → Zielbegriffen. Beispiel:
Quelle,Ziel EMS,Rettungsdienst PD,Polizeimechaniker,Mechaniker

  1. Platzhalter und Markup schützen
  • Platzhalter: %{name}, %s, %d, {0}
  • FiveM-Farbcodes: ~r~, ~g~, ~s~; Chat-Codes: ^1, ^2
  • NUI/HTML-Tags: <b>, <span>
  1. Übersetzen über API (Charge)
  • Senden Werte nur, behalten Schlüssel unverändert.
  • Liefern Glossar Und Stil (Ton) zum Modell/Motor.
  1. 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).
  1. Menschliche Stichprobenkontrolle (5–10 Minuten)
  • Überprüfe Befehle, Fehlermeldungen und lange UI-Strings.
  1. 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.lua mit einem _U Helfer.
  • 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.json als Quelle der Wahrheit; erstelle einen CI-Job, der die Unterschiede vergleicht en.json und aktualisiert nur geänderte Schlüssel in Zielen.
  • Behalte eine CHANGELOG.i18n.md fü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


Interne Ressourcen (weiterführende Literatur)


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