Economize 20% hoje mesmo Use o código WELCOME ao finalizar a compra. BEM-VINDO

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)

  1. 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).
  1. 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

  1. 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>
  1. Traduzir via API (lote)
  • Enviar valores apenas, mantenha chaves inalterado.
  • Fornecer glossário e estilo (tom) para o modelo/motor.
  1. 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).
  1. Verificação pontual humana (5–10 minutos)
  • Revise comandos, mensagens de erro e longas sequências de caracteres da interface do usuário.
  1. 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.lua com um _U ajudante.
  • 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.json como fonte da verdade; crie um trabalho de CI que difere en.json e as atualizações apenas alteraram as chaves nos alvos.
  • Mantenha um CHANGELOG.i18n.md para 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


Recursos internos (leitura relacionada)


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
Lucas
Lucas

Eu sou Luke, sou um gamer e adoro escrever sobre FiveM, GTA e roleplay. Eu administro uma comunidade de roleplay e tenho cerca de 10 anos de experiência em administração de servidores.

Artigos: 570