Como traduzir scripts usando IA (Guia FiveM)
Público: Proprietários, criadores de scripts e mantenedores de servidores FiveM que desejam traduções de alta qualidade sem quebrar espaços reservados ou interface do usuário.
Resumo
- Centralize todo o texto em arquivos de localidade (tabelas JSON ou Lua). Nunca codifique strings na lógica do jogo.
- Proteja os espaços reservados (por exemplo,
%s,%d,%{nome},{0},~r~,^1) durante a tradução. - Use IA para tradução de primeira passagem + glossário + verificações automatizadas → revisão humana rápida → envio.
- Mantenha uma única fonte de verdade (geralmente inglês), compare as alterações e gere novamente apenas as chaves alteradas.
Por que traduzir seus scripts FiveM
- Acessibilidade e crescimento: Servidores localizados atraem mais jogadores e os mantêm engajados.
- Profissionalismo: Terminologia consistente em comandos, interfaces de usuário e mensagens de erro.
- Amigável para colaboradores: Uma estrutura local clara convida a relações públicas da comunidade.
Se você precisar de uma atualização básica sobre estrutura e melhores práticas, consulte: Como traduzir scripts FiveM (da maneira certa).
Arquitetura: a maneira certa de localizar
Meta: Nenhuma string visível ao usuário dentro do código do jogo. Roteie tudo por meio de uma camada de localidade.
Layout de recursos recomendado
my_resource/ ├─ fxmanifest.lua ├─ locales/ │ ├─ en.json # idioma de origem (única fonte de verdade) │ ├─ de.json # traduzido (gerado/editado) │ ├─ es.json # traduzido (gerado/editado) │ └─ qa.rules.json # opcional: lista de permissões e verificações de espaço reservado ├─ client/ │ └─ main.lua ├─ server/ │ └─ main.lua └─ shared/ └─ i18n.lua # auxiliar de tradução
fxmanifest.lua (exemplo mínimo)
fx_version 'cerúleo' jogo 'gta5' lua54 'sim' scripts_compartilhados { 'compartilhado/i18n.lua', } arquivos { 'locales/*.json' }
compartilhado/i18n.lua (carregador leve + substituição de espaço reservado)
local LOCALE = GetConvar('my_locale', 'en') local CACHE = {} função local loadJSON(caminho) arquivo local = io.open(caminho, 'r') se não for arquivo, então retorne {} fim conteúdo local = arquivo:ler('*a') arquivo:fechar() local ok, dados = pcall(função() return json.decode(conteúdo) fim) retorne ok e dados ou {} fim função local readLocale(idioma) se CACHE[idioma] então retorne CACHE[idioma] fim arquivo local = ('locales/%s.json'):formato(idioma) dicionário local = loadJSON(arquivo) CACHE[idioma] = dicionário retorne dicionário fim função local interpolate(str, vars) se não for vars, então retorne str fim para k, v em pares(vars) faça str = str:gsub('%%{'..k..'}', tostring(v)) -- %{nome} fim return str fim function _U(chave, vars) local dict = readLocale(LOCALE) local src = dict[chave] se não src então -- retornar para inglês se estiver faltando src = readLocale('en')[chave] ou chave fim return interpolate(src, vars) fim exports('Translate', _U)
Uso em código cliente/servidor
-- Cliente lib.notify({ title = _U('notify_title'), description = _U('welcome_player', { name = GetPlayerName(PlayerId()) }), }) -- Servidor print(('[MyRes] %s'):format(_U('server_started')))
locales/en.json (fonte)
{ "notify_title": "Mensagem do servidor", "welcome_player": "Bem-vindo, %{name}!", "server_started": "O módulo do servidor está pronto.", "no_permission": "Você não tem permissão.", "items_remaining": "%{count} itens restantes" }
Fluxo de trabalho de tradução de IA (rápido e seguro)
- Extrair e congelar fonte
- Manter Inglês (ou sua fonte) como
locais/en.json. - Aplicar nomenclatura de chaves:
domínio.ação.assunto(por exemplo,inventário.queda.confirmar).
- Criar/ampliar um glossário
- Mapa CSV ou JSON de termos canônicos → termos-alvo. Exemplo:
fonte, alvo EMS, Rettungsdienst PD, Mecânico Polizei, Mechaniker
- Proteja marcadores de posição e marcação
- Espaços reservados:
%{nome},%s,%d,{0} - Códigos de cores FiveM:
~r~,~g~,~s~; códigos de bate-papo:^1,^2 - Etiquetas NUI/HTML:
<b>,<span>…
- Traduzir via API (lote)
- Enviar valores apenas, mantenha chaves inalterado.
- Fornecer glossário e estilo (tom) para o modelo/motor.
- QA automatizado
- Validar JSON.
- Verificar paridade de espaço reservado (todo espaço reservado na origem existe no destino).
- Sinalize alterações proibidas (por exemplo, códigos de cores alterados ou pontuação adicionada quando não permitidos).
- Verificação pontual humana (5–10 minutos)
- Revise comandos, mensagens de erro e longas sequências de caracteres da interface do usuário.
- Enviar e iterar
- Mantenha um memória de tradução (saídas anteriores) para evitar a retradução de chaves inalteradas.
Guardrails: dicas e regras que realmente funcionam
Prompt LLM para tradução em lote JSON
Tarefa: Traduzir valores JSON do inglês para para um contexto FiveM/GTA RP. Regras: - MANTENHA AS CHAVES INALTERADAS. - PRESERVE todos os espaços reservados exatamente: %{var}, %s, %d, {0}, ~r~, ~g~, ^1, ^2, etc. - Mantenha a capitalização e os tokens de estilo de código (comandos, comandos com barra) inalterados. - Não adicione aspas, pontuação extra ou altere o significado. - Retorne SOMENTE JSON válido com a mesma estrutura. JSON para traduzir:
Regex que você pode usar em um script de controle de qualidade
- Espaços reservados:
%%\{[A-Za-z0-9_]+\} - C printf:
%(?:\d+\$)?[sdif] - Códigos de bate-papo:
\^\d - Códigos de cores til:
~[rgbso]~
Exemplo: traduzir com DeepL (Node.js)
Funciona muito bem para trabalhos únicos ou IC.
pacote.json (scripts)
{ "type": "module", "scripts": { "i18n:translate:de": "ferramentas node/translate-deepl.js em de", "i18n:check": "ferramentas node/i18n-check.js" } }
ferramentas/translate-deepl.js
importar fs de 'fs'; importar caminho de 'caminho'; importar assert de 'assert'; importar buscar de 'node-fetch'; const [,, srcLang, dstLang] = process.argv; const apiKey = process.env.DEEPL_API_KEY; // definido em CI/ENV assert(apiKey, 'DEEPL_API_KEY é necessário'); const src = JSON.parse(fs.readFileSync('locales/en.json', 'utf8')); const out = {}; const GLOSSARY = { 'EMS': 'Serviço de Retorno', 'PD': 'Polícia', }; função protect(str){ // Substituir espaços reservados por tokens que o DeepL não alterará return str .replace(/%\{([^}]+)\}/g, '⟦$1⟧') .replace(/%s/g, '⟪S⟫') .replace(/%d/g, '⟪D⟫'); } função restore(str){ return str .replace(/⟦([^⟧]+)⟧/g, '%{$1}') .replace(/⟪S⟫/g, '%s') .replace(/⟪D⟫/g, '%d'); } função assíncrona translate(texto){ const res = await fetch('https://api.deepl.com/v2/translate', { método: 'POST', cabeçalhos: { 'Content-Type': 'application/x-www-form-urlencoded' }, corpo: novo URLSearchParams({ auth_key: apiKey, texto: texto, idioma_de_origem: srcLang.toUpperCase(), idioma_de_destino: dstLang.toUpperCase(), formalidade: 'prefer_more' }) }); const json = await res.json(); se (!json.translations) lançar novo erro(JSON.stringify(json)); retornar json.translations[0].text; } para (const [k, v] de Object.entries(src)) { const protectedText = protect(v); // Pré-passe do glossário (simples): deixe glossed = protectedText; para (const [de, para] de Object.entries(GLOSSÁRIO)) { glossed = glossed.replace(new RegExp(`\\b${de}\\b`, 'g'), para); } // Traduzir // eslint-desativa-a-próxima-linha-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(`Escreveu locales/${dstLang}.json`);
ferramentas/i18n-check.js (paridade de espaço reservado)
importar fs de '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; deixe ok = true; para (const k de 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('Incompatibilidade de espaço reservado para chave:', k); ok = false; } } process.exit(ok ? 0 : 1);
Usando LLMs (OpenAI/outros) de forma eficaz
- Fragmento por tópico/domínio para melhor contexto (por exemplo, inventário, polícia, empregos).
- Fornecer descrições curtas por grupo (duas linhas) para definir tom e público.
- Exemplos de poucos disparos: 2–3 pares traduzidos corretamente com marcadores de posição melhoram a consistência.
- Política de repetição: execute novamente apenas as chaves com falha sinalizadas por
i18n-check.
Modelo de poucos disparos (sistema + usuário)
Sistema: Você traduz as strings da interface do usuário do jogo FiveM para . - Mantenha as chaves inalteradas, preserve os espaços reservados e mantenha o tom conciso. Exemplos de usuários: EN: "Você tem %{count} multas." DE: "Você tem %{count} multas." EN: "~r~Error:~s~ Você não tem permissão." DE: "~r~Fehler:~s~ Dir sentiu a permissão." Agora traduza os seguintes valores JSON do inglês para . Retorna somente JSON válido:
Traduções NUI (HTML/JS)
Para interfaces de usuário de navegador, uma biblioteca do lado do cliente é prática.
Abordagem recomendada
- Use um pacote JSON por idioma em
web/locais/ .json. - Carregue com sua estrutura de IU e exponha um
t(chave, variáveis)ajudante. - Mantenha o mesmas chaves como localidades de servidor para reduzir a carga cognitiva.
Auxiliar JS mínimo
const dict = await (await fetch(`/locales/${lang}.json`)).json(); exportar função t(chave, vars){ deixe s = dict[chave] || chave; para (const [k,v] de Object.entries(vars||{})) s = s.replace(`%{${k}}`, v); retornar s; }
Especificações do ESX/QBCore
- Muitos scripts ESX são enviados
locais/en.lua,locais/de.luacom um_Uajudante. - Se você usar tabelas Lua para localidades, mantenha um estilo em todo o seu repositório. Misturar JSON e Lua para o mesmo recurso aumenta o custo de manutenção.
- O QBCore frequentemente usa mensagens orientadas por configuração. Migre strings repetidas para arquivos de localidade para evitar divergências.
Localidade da tabela Lua (se você preferir Lua em vez de JSON)
Locales = Locales ou {} Locales['en'] = { no_permission = 'Você não tem permissão.', Welcome_player = 'Bem-vindo, %{name}!' } Locales['de'] = { no_permission = 'Você não tem nenhuma permissão.', Welcome_player = 'Willkommen, %{nome}!' }
Portões de qualidade antes do envio
- Verificação de análise JSON/Lua em CI.
- Paridade de espaço reservado (verificações de regex conforme mostrado).
- Mudanças proibidas: não permitir edições em
/comandos, letras de atalho, códigos de cores/bate-papo. - Deltas de comprimento: sinalizador +40% crescimento para botões da interface do usuário; pode quebrar o layout.
- Teste de fumaça: ative seu servidor e verifique fluxos críticos.
É novo na configuração de um servidor para testes? Siga este guia: Como criar um servidor FiveM.
Estratégia de manutenção
- Tratar
en.jsoncomo fonte da verdade; crie um trabalho de CI que difereen.jsone as atualizações apenas alteraram as chaves nos alvos. - Mantenha um
CHANGELOG.i18n.mdpara tradutores. - Incentive a comunidade a contribuir por meio de RP; documente seu guia de estilo e glossário em
/docs/i18n.md.
Armadilhas comuns (e soluções)
- Espaços reservados quebrados → Use verificações automatizadas e tokens de proteção.
- Terminologia inconsistente → Mantenha um glossário e aplique-o em prompts e pré-processamento.
- Localidades mistas no código → Falha no CI se strings forem detectadas fora
locais/. - Idiomas RTL → Certifique-se de que seus conjuntos NUI CSS
direção: rtl;e usa fontes com suporte RTL. - Desvio de maiúsculas e minúsculas e pontuação → Instrua a IA explicitamente e execute um linter para normalizar a pontuação.
Recursos externos
- API DeepL — documentação do desenvolvedor: https://www.deepl.com/docs-api
- Tradução do Google Cloud — documentos e melhores práticas: https://cloud.google.com/translate/docs
- Manifesto de Recursos FiveM (fxmanifest.lua) — referência: https://docs.fivem.net/docs/scripting-reference/resource-manifest/resource-manifest/
Recursos internos (leitura relacionada)
- Como traduzir scripts FiveM (da maneira certa) — fluxo de trabalho e padrões: https://fivemx.com/fivem-scripts-translation/
- Como criar um servidor FiveM — criar um ambiente de testes para controle de qualidade: https://fivemx.com/how-to-create-a-fivem-server/
Listas de verificação de copiar e colar
Pré-tradução
- Todas as strings centralizadas em
locais/en.json(ou tabela Lua) - As chaves seguem uma convenção de nomenclatura
- Glossário preparado
- Espaços reservados auditados
Correr
- Tradução em lote com glossário
- Salvar saída para
locais/ .json
Controle de qualidade
- JSON/Lua válido
- Paridade de espaço reservado OK
- Fichas proibidas inalteradas
- Deltas de comprimento aceitáveis
- Verificação humana pontual realizada
Enviar
- CI verde
- Log de alterações atualizado
- Convidar a comunidade a dar feedback






