Lokalizacje skryptów FiveM: tłumaczalne skrypty z en.lua, ox_lib i ESX

Uczyń swój skrypt FiveM tłumaczalnym: folder locales z en.lua i es.lua, prosta funkcja locale, system locale ox_lib, ESX TranslateCap i konfiguracja języka.

Twój skrypt ma 'You have no money' na stałe zakodowany w czterdzieści miejscach. Właściciel serwera w Madrycie lub Berlinie chce tego w jego języku, a jedynym sposobem jest edycja kodu. Rozwiązaniem jest warstwa locale: stringi żyją w plikach dla każdego języka, kod prosi o klucze. Ten przewodnik pokazuje prostą wersję czystego Lua, potem system ox_lib i ESX.

Pomysł

Zamiast:

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

kod pisze:

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

i plik języka dostarcza tekst dla no_money. Tłumacze potem zmieniają pliki, nigdy kod, i otwórz pliki locale mogą być wysyłane nieszyfrowane (zobacz escrow_ignore).

Prosta funkcja locale Lua

Układ foldera:

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, funkcja, która wygląda klucz:

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

Manifest, z locales najpierw i konfigu przed funkcją:

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'

I w config.lua:

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

Użycie, z %s placeholders wypełnionymi przez string.format:

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

Fallbacky ma znaczenie: brakujący klucz w es wraca do en, i brakujący klucz wszędzie zwraca klucz sam, więc widzisz no_money na ekranie zamiast błędu. Dziura w tłumaczeniu potem pokazuje się jako widoczny klucz, nie crash.

Wskazówka: utrzymuj te same klucze w każdym pliku języka. Mały skrypt, który porównuje klucze en z każdym innym plikiem, łapie brakujące tłumaczenia przed wydaniem.

System locale ox_lib

Jeśli Twój skrypt już zależy od ox_lib, możesz użyć jego wbudowanej locales zamiast pisania L(). Kształt to: załaduj ox_lib w manifestcie, umieść swoje tłumaczenia w folderze locales/ (ox_lib używa plików .json nazwanych według języka, jak locales/en.json), dołącz je z files i wywołaj lib.locale() raz:

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

Sprawdzaj dokumenty ox_lib dla bieżącego formatu i dla tego, jak język jest wybierany (convar serwera), ponieważ układ pliku i nazwy opcji zmieniły się między wersjami. Jeśli widzisz ox_lib/init.lua nie znaleziony, napraw to najpierw: ox_lib init.lua not found.

ESX i TranslateCap

Skrypty ESX mają swój własny wzór locale. Pliki locale wypełniają tabelę Locales i framework dostarcza funkcję tłumaczenia:

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'))

Starsze skrypty używają _U('no_money') dla tej samej rzeczy. TranslateCap to bieżąca nazwa w ostatnim ESX Legacy, a język jest wybrany przez Config.Locale lub własne ustawienie frameworku. Jak w ox_lib, sprawdzaj dokumenty wersji ESX, którą uruchamiasz dla dokładnych nazw plików i który z dwóch funkcji to oczekuje.

QBCore ma podobny moduł Lang (locales/en.lua używając Lang:t('key')), który działa w ten sam sposób: tabela na język i funkcja, która rozwiązuje klucze.

Wybieranie języka

Oferuj jedną linię konfigu, blisko szczytu config.lua:

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

Jeśli Twój skrypt jest mieszanką klienta, serwera i NUI, pamiętaj, że tekst NUI potrzebuje swoich własnych tłumaczeń: wyślij stringi na stronę raz, gdy się otwiera, zamiast pisać angielski w HTML. Zobacz FiveM NUI with React and Vite dla przekazywania danych do strony.

Checklist

Objaw Rozwiązanie
Tekst angielski na stałe zakodowany w kodzie Przenieś go do locales/en.lua i wezwij L('key')
attempt to index a nil value na Locales[...] Załaduj pliki locale zanim kod, który je czyta
Raw klucz pokazany na ekranie Klucz brakuje w wybranym języku i w en
Użyty zły język Sprawdzaj Config.Locale i convar locale
ox_lib locale() zwraca klucz Najpierw wezwij lib.locale() i dołącz locales/*.json w files
NUI wciąż angielski Przekaż przetłumaczone stringi do strony

Szybkie odpowiedzi

Gdzie powinienem umieścić tłumaczenia w skrypcie FiveM?

W folderze locales/ z jednym plikiem na język, takim jak en.lua i es.lua, załadowanym zanim kod, który go używa. Skrypt potem prosi o klucz, nigdy o dosłowny string.

Czy ox_lib ma system locale?

Tak. Czyta pliki locale i daje Ci locale('key') po tym, jak wywołasz lib.locale(). Sprawdzaj dokumenty ox_lib dla bieżącego formatu pliku i ustawienia, które wybiera język.

Jak wybrać język?

Za pomocą wartości Config.Locale w Twoim konfigu, lub za pomocą convara, którą Twój framework lub ox_lib czyta. Wróć do angielskiego, gdy klucz lub język brakuje.

Skrypty bez tego problemu

Mic PhoneSkładany telefon, który rozkłada się w tablet i działa też na prawdziwym telefonie gracza.Zobacz skrypt →Shop CreatorZbuduj sklep w niecałą minutę — właściciele, pracownicy, sejfy i napady w zestawie.Zobacz skrypt →Item Creator V2Twórz używalne przedmioty z animacjami, propami, efektami i nie tylko — bez pisania kodu.Zobacz skrypt →

Czytaj dalej