Locales de script em FiveM: scripts traduzíveis com en.lua, ox_lib e ESX

Torne seu script FiveM traduzível: uma pasta locales com en.lua e es.lua, uma função locale simples, sistema de locale de ox_lib, ESX TranslateCap e uma configuração de idioma.

Seu script tem 'You have no money' codificado em quarenta lugares. Um dono de servidor em Madrid ou Berlin quer em seu idioma, e a única maneira é editar o código. A solução é uma camada locale: strings vivem em arquivos por idioma, o código pede por chaves. Este guia mostra uma versão simples em Lua simples, depois o sistema de ox_lib e ESX.

A ideia

Em vez de:

lua
ESX.ShowNotification('You have no money')

o código escreve:

lua
ESX.ShowNotification(L('no_money'))

e um arquivo de idioma fornece o texto para no_money. Tradutores então mudam arquivos, nunca código, e arquivos de locale abertos podem ser enviados sem criptografia (veja escrow_ignore).

Uma função locale simples em Lua

Layout de pasta:

text
my_script/
  fxmanifest.lua
  config.lua
  locales/
    en.lua
    es.lua
  shared/locale.lua

locales/en.lua:

lua
Locales = Locales or {}

Locales['en'] = {
    no_money = 'You have no money',
    bought   = 'You bought %s for $%s',
}

locales/es.lua:

lua
Locales = Locales or {}

Locales['es'] = {
    no_money = 'No tienes dinero',
    bought   = 'Compraste %s por $%s',
}

shared/locale.lua, a função que procura uma chave:

lua
function L(key, ...)
    local lang = Locales[Config.Locale] or Locales['en']
    local text = lang[key] or Locales['en'][key] or key
    if select('#', ...) > 0 then
        return text:format(...)
    end
    return text
end

Manifesto, com as locales primeiro e a configuração antes da função:

lua
fx_version 'cerulean'
game 'gta5'

shared_scripts {
    'config.lua',
    'locales/*.lua',
    'shared/locale.lua',
}
client_script 'client/main.lua'
server_script 'server/main.lua'

E em config.lua:

lua
Config = {}
Config.Locale = 'en'

Uso, com placeholders %s preenchidos por string.format:

lua
print(L('bought', 'bread', 5))   -- You bought bread for $5

Os fallbacks importam: uma chave faltando em es volta para en, e uma chave faltando em qualquer lugar retorna a chave em si, então você vê no_money na tela em vez de um erro. Um buraco em uma tradução então aparece como uma chave visível, não uma falha.

Dica: mantenha as mesmas chaves em cada arquivo de idioma. Um pequeno script que compara as chaves en com cada outro arquivo captura traduções faltando antes do lançamento.

Sistema de locale de ox_lib

Se seu script já depende de ox_lib, você pode usar seus locales integrados em vez de escrever L(). A forma é: carregue ox_lib no manifesto, coloque suas traduções em uma pasta locales/ (ox_lib usa arquivos .json nomeados por idioma, como locales/en.json), inclua-os com files, e chame lib.locale() uma vez:

lua
-- fxmanifest.lua
shared_script '@ox_lib/init.lua'
files { 'locales/*.json' }
json
{
  "no_money": "You have no money",
  "bought": "You bought %s for $%s"
}
lua
lib.locale()   -- load the language

lib.notify({ description = locale('no_money'), type = 'error' })
print(locale('bought', 'bread', 5))

Verifique os docs de ox_lib para o formato atual e para como o idioma é escolhido (uma convar do servidor), porque o layout de arquivo e nomes de opção mudaram entre versões. Se você vê ox_lib/init.lua não encontrado, corrija primeiro: ox_lib init.lua not found.

ESX e TranslateCap

Scripts ESX têm seu próprio padrão de locale. Arquivos de locale preenchem uma tabela Locales e o framework fornece uma função de tradução:

lua
-- fxmanifest.lua
shared_scripts {
    '@es_extended/imports.lua',
    '@es_extended/locale.lua',
    'locales/*.lua',
    'config.lua',
}
lua
-- locales/en.lua
Locales['en'] = {
    ['no_money'] = 'You have no money',
}
lua
TriggerEvent('esx:showNotification', TranslateCap('no_money'))

Scripts antigos usam _U('no_money') para a mesma coisa. TranslateCap é o nome atual em ESX Legacy recente, e o idioma é selecionado por Config.Locale ou configuração própria do framework. Como com ox_lib, verifique os docs da versão ESX que você executa para os nomes de arquivo exatos e qual das duas funções espera.

QBCore tem um módulo Lang similar (locales/en.lua usando Lang:t('key')) que funciona da mesma forma: uma tabela por idioma e uma função que resolve chaves.

Escolhendo o idioma

Ofereça uma linha de configuração, perto do topo de config.lua:

lua
Config.Locale = 'en'   -- 'en', 'es', 'fr'...

Se seu script é uma mistura de cliente, servidor e NUI, lembre-se de que texto NUI precisa de suas próprias traduções: envie as strings para a página uma vez quando ela abre, em vez de escrever inglês no HTML. Veja FiveM NUI with React and Vite para passar dados para a página.

Lista de verificação

Sintoma Solução
Texto inglês codificado em código Mova para locales/en.lua e chame L('key')
attempt to index a nil value em Locales[...] Carregue arquivos de locale antes do código que os lê
Chave bruta mostra na tela A chave está faltando no idioma escolhido e em en
Idioma errado usado Verifique Config.Locale e a convar de locale
ox_lib locale() retorna a chave Chame lib.locale() primeiro e inclua locales/*.json em files
NUI ainda em inglês Passe as strings traduzidas para a página

Respostas rápidas

Onde devo colocar traduções em um script FiveM?

Em uma pasta locales/ com um arquivo por idioma, como en.lua e es.lua, carregados antes do código que os usa. O script então pede por uma chave, nunca por uma string literal.

ox_lib tem um sistema de locale?

Sim. Ele lê arquivos de locale e oferece locale('key') após você chamar lib.locale(). Verifique os docs de ox_lib para o formato de arquivo atual e a configuração que escolhe o idioma.

Como escolho o idioma?

Com um valor Config.Locale em sua configuração, ou com uma convar que seu framework ou ox_lib lê. Volte para inglês quando uma chave ou um idioma estiver faltando.

Scripts sem esse problema

Mic PhoneUm celular dobrável que abre em tablet e chega ao celular de verdade do jogador.Ver script →Shop CreatorMonte uma loja em menos de um minuto — donos, funcionários, cofres e assaltos inclusos.Ver script →Item Creator V2Crie itens usáveis com animações, props, efeitos e muito mais — sem escrever código.Ver script →

Continue lendo