ब्लॉग पर वापस
Tutorial7 मिनट पढ़ें

FiveM लोकलाइजेशन और i18n: मल्टी-भाषा स्क्रिप्ट्स

FiveM स्क्रिप्ट्स को कई भाषाओं में भेजें। Locale फाइलें, fallback कीज, टूलिंग और पैटर्न जो ox_lib और अन्य प्रमुख ओपन-सोर्स रिसोर्सेज द्वारा उपयोग किए जाते हैं।

Agency Scripts

Agency Scripts के संस्थापक और प्रमुख डेवलपर

FiveM सर्वरों के लिए लोकलाइजेशन क्यों महत्वपूर्ण है

FiveM रोलप्ले समुदाय विश्वभर में फैले हुए हैं, जिनमें जर्मनी, फ्रांस, ब्राज़ील, तुर्की और दर्जनों अन्य देशों में विशाल खिलाड़ी आधार हैं। यदि आपकी स्क्रिप्ट केवल अंग्रेज़ी का समर्थन करती हैं, तो आप संभावित ग्राहकों का एक बड़ा हिस्सा काट रहे हैं और उन समुदायों को सीमित कर रहे हैं जो आपके संसाधनों का उपयोग कर सकते हैं। एक सही तरीके से स्थानीयकृत स्क्रिप्ट सभी उपयोगकर्ता-सामना करने वाले टेक्स्ट, सूचनाएं, मेनू, और त्रुटि संदेश खिलाड़ी की पसंदीदा भाषा में अनुकूलित करता है। यह केवल जीवन की गुणवत्ता की सुविधा नहीं बल्कि एक प्रतिस्पर्धात्मक लाभ है जो शौकिया स्क्रिप्ट को पेशेवरों से अलग करता है। अच्छी खबर यह है कि FiveM में अंतरराष्ट्रीयकरण (i18n) लागू करना पैटर्न समझने के बाद सरल है।

Locale सिस्टम सेट अप करना

किसी भी स्थानीयकरण प्रणाली की नींव अनुवादित स्ट्रिंग्स को संग्रहीत और पुनः प्राप्त करने का एक संरचित तरीका है। FiveM में सबसे सामान्य तरीका locale फ़ाइलों का उपयोग करना है, प्रत्येक भाषा के लिए एक, जो एक में संग्रहीत होती हैं। locales directory inside your resource. Each file exports a table of key-value pairs where the key is a unique identifier and the value is the translated string. Here is how to structure your locale module:

-- locales/en.lua
Locales = Locales or {}
Locales['en'] = {
    ['job_started']       = 'You have started your shift as %s.',
    ['job_ended']         = 'You have ended your shift. Earnings: $%d',
    ['not_enough_money']  = 'You do not have enough money. You need $%d.',
    ['inventory_full']    = 'Your inventory is full. Free up some space first.',
    ['vehicle_spawned']   = 'Your vehicle has been spawned nearby.',
    ['access_denied']     = 'You do not have permission to do that.',
    ['cooldown_active']   = 'Please wait %d seconds before doing that again.',
    ['item_received']     = 'You received %dx %s.',
}
-- locales/de.lua
Locales = Locales or {}
Locales['de'] = {
    ['job_started']       = 'Du hast deine Schicht als %s begonnen.',
    ['job_ended']         = 'Du hast deine Schicht beendet. Verdienst: $%d',
    ['not_enough_money']  = 'Du hast nicht genug Geld. Du brauchst $%d.',
    ['inventory_full']    = 'Dein Inventar ist voll. Schaffe zuerst Platz.',
    ['vehicle_spawned']   = 'Dein Fahrzeug wurde in der Naehe gespawnt.',
    ['access_denied']     = 'Du hast keine Berechtigung dafuer.',
    ['cooldown_active']   = 'Bitte warte %d Sekunden, bevor du das erneut tust.',
    ['item_received']     = 'Du hast %dx %s erhalten.',
}

ट्रांसलेशन फंक्शन बनाना

सिस्टम का मूल एक अनुवाद फ़ंक्शन है जो कुंजियों को खोजता है और चर तर्कों के साथ स्ट्रिंग स्वरूपण का समर्थन करता है। यह फ़ंक्शन सक्रिय स्थानीय भाषा में कुंजी गायब होने पर सहजता से डिफ़ॉल्ट भाषा पर वापस जाना चाहिए, और विकास के दौरान डेवलपर्स को गायब अनुवादों के बारे में चेतावनी देनी चाहिए बजाय इसके कि खिलाड़ियों को कच्ची कुंजियाँ दिखाए।

-- shared/locale.lua
local currentLocale = 'en'
local fallbackLocale = 'en'

function SetLocale(locale)
    if Locales[locale] then
        currentLocale = locale
    else
        print(('[^1LOCALE^0] Language "%s" not found, falling back to "%s"'):format(locale, fallbackLocale))
        currentLocale = fallbackLocale
    end
end

function L(key...)
    local str = nil

    if Locales[currentLocale] and Locales[currentLocale][key] then
        str = Locales[currentLocale][key]
    elseif Locales[fallbackLocale] and Locales[fallbackLocale][key] then
        print(('[^3LOCALE^0] Missing key "%s" for locale "%s", using fallback'):format(key, currentLocale))
        str = Locales[fallbackLocale][key]
    end

    if not str then
        print(('[^1LOCALE^0] Missing translation key: "%s"'):format(key))
        return key
    end

    if ... then
        return str:format(...)
    end

    return str
end

अपने स्क्रिप्ट्स में अनुवादों का उपयोग

एक बार locale मॉड्यूल लोड हो जाने के बाद, अपने स्क्रिप्ट में अनुवादों का उपयोग करना उतना ही सरल है जितना कि कॉल करना L() function को कुंजी और किसी भी फॉर्मेट तर्क के साथ कॉल करें। इससे आपका स्क्रिप्ट कोड साफ रहता है और सामग्री को पूरी तरह से लॉजिक से अलग करता है।

-- server/main.lua
RegisterNetEvent('myresource:startJob', function(jobName)
    local src = source
    local xPlayer = ESX.GetPlayerFromId(src) -- or your framework equivalent

    if not xPlayer then return end

    if not HasPermission(src, jobName) then
        TriggerClientEvent('ox_lib:notify', src, {
            title = L('access_denied'),
            type = 'error'
        })
        return
    end

    ActiveJobs[src] = { name = jobName, started = os.time() }

    TriggerClientEvent('ox_lib:notify', src, {
        title = L('job_started', jobName),
        type = 'success'
    })
end)

प्रति-खिलाड़ी भाषा पहचान

एक वास्तव में पेशेवर स्थानीयकरण प्रणाली प्रत्येक खिलाड़ी की भाषा को स्वचालित रूप से पहचानती है। आप इसे क्लाइंट के गेम भाषा सेटिंग को पढ़कर या खिलाड़ियों को कॉन्फ़िग या कमांड के माध्यम से अपनी भाषा चुनने की अनुमति देकर पूरा कर सकते हैं। क्लाइंट-साइड पहचान दृष्टिकोण उपयोग करता है GetCurrentLanguage native, जो खेल भाषा को दो-अक्षर कोड के रूप में लौटाता है। आप इसे सर्वर को भेज सकते हैं ताकि उस खिलाड़ी के लिए सभी नोटिफिकेशन उनकी पसंदीदा भाषा में हों।

-- client/locale_detect.lua
CreateThread(function()
    local gameLang = GetCurrentLanguage()

    -- Map GTA language codes to your locale codes
    local langMap = {
        ['en-us'] = 'en',
        ['de-de'] = 'de',
        ['fr-fr'] = 'fr',
        ['es-es'] = 'es',
        ['pt-br'] = 'pt',
        ['it-it'] = 'it',
        ['pl-pl'] = 'pl',
        ['tr-tr'] = 'tr',
        ['ru-ru'] = 'ru',
        ['zh-cn'] = 'zh',
        ['ja-jp'] = 'ja',
        ['ko-kr'] = 'ko',
    }

    local detected = langMap[gameLang] or 'en'
    SetLocale(detected)

    TriggerServerEvent('myresource:setPlayerLocale', detected)
end)

सर्वर-साइड प्रति-खिलाड़ी लोकल स्टोरेज

सर्वर साइड पर, प्रत्येक खिलाड़ी की लोकल पसंद को स्टोर करें ताकि आप संदेशों को सही भाषा में फॉर्मेट कर सकें इससे पहले कि उन्हें भेजा जाए। यह सर्वर-ट्रिगर किए गए नोटिफिकेशन और चैट संदेशों के लिए महत्वपूर्ण है जो सर्वर-साइड लॉजिक से उत्पन्न होते हैं जहाँ आपके पास क्लाइंट की लोकल सेटिंग तक सीधी पहुँच नहीं होती।

-- server/locale_manager.lua
local PlayerLocales = {}

RegisterNetEvent('myresource:setPlayerLocale', function(locale)
    local src = source
    if Locales[locale] then
        PlayerLocales[src] = locale
    else
        PlayerLocales[src] = 'en'
    end
end)

AddEventHandler('playerDropped', function()
    PlayerLocales[source] = nil
end)

function GetPlayerLocale(src)
    return PlayerLocales[src] or 'en'
end

function LForPlayer(src, key...)
    local locale = GetPlayerLocale(src)
    local str = nil

    if Locales[locale] and Locales[locale][key] then
        str = Locales[locale][key]
    elseif Locales['en'] and Locales['en'][key] then
        str = Locales['en'][key]
    end

    if not str then return key end
    if ... then return str:format(...) end
    return str
end

NUI और JavaScript इंटरफेस का स्थानीयकरण

कई FiveM स्क्रिप्ट्स अपने यूजर इंटरफेस के लिए NUI (HTML/JS) का उपयोग करते हैं, और इन्हें भी लोकलाइजेशन की आवश्यकता होती है। सबसे अच्छा तरीका है कि जब NUI फ्रेम इनिशियलाइज़ हो, तो पूरी लोकल टेबल भेजें, फिर एक जावास्क्रिप्ट ट्रांसलेशन फ़ंक्शन का उपयोग करें जो Lua वाले की नकल करता है। इससे हर स्ट्रिंग के लिए लगातार NUI कॉलबैक की आवश्यकता नहीं रहती।

// nui/js/locale.js
let currentLocale = {};
let fallbackLocale = {};

window.addEventListener('message', (event) => {
    if (event.data.action === 'setLocale') {
        currentLocale = event.data.locale || {};
        fallbackLocale = event.data.fallback || {};
        updateAllTranslations();
    }
});

function L(key...args) {
    let str = currentLocale[key] || fallbackLocale[key] || key;

    if (args.length > 0) {
        let i = 0;
        str = str.replace(/%[sd]/g, () => args[i++] ?? '');
    }

    return str;
}

function updateAllTranslations() {
    document.querySelectorAll('[data-locale]').forEach((el) => {
        const key = el.getAttribute('data-locale');
        el.textContent = L(key);
    });
}

संसाधन मैनिफेस्ट कॉन्फ़िगरेशन

आपका fxmanifest.lua सुनिश्चित करना आवश्यक है कि सभी लोकल फाइलें शामिल हों ताकि वे संसाधन शुरू होने पर लोड हों। एक ग्लोब पैटर्न का उपयोग करें ताकि आप जो भी नई लोकल फाइलें जोड़ें वे स्वचालित रूप से उठ जाएं बिना हर बार मैनिफेस्ट अपडेट किए। सुनिश्चित करें कि साझा लोकल मॉड्यूल लोकल डेटा फाइलों से पहले लोड हो।

-- fxmanifest.lua
fx_version 'cerulean'
game 'gta5'

shared_scripts {
    'shared/locale.lua',
    'locales/*.lua',
}

client_scripts {
    'client/locale_detect.lua',
    'client/main.lua',
}

server_scripts {
    'server/locale_manager.lua',
    'server/main.lua',
}

ui_page 'nui/index.html'

files {
    'nui/**/*',
}

FiveM स्थानीयकरण के लिए सर्वश्रेष्ठ प्रथाएँ

  • वर्णनात्मक कुंजियों का उपयोग करें संख्यात्मक IDs के बजाय। कुंजी जैसे inventory_full स्वयं-दस्तावेज़ीकरण करते हैं और रखरखाव को आसान बनाते हैं msg_042.
  • हमेशा फॉर्मेट प्लेसहोल्डर्स का उपयोग करें (%s, %d) स्ट्रिंग संयोजन के बजाय गतिशील मानों के लिए। विभिन्न भाषाओं में शब्द क्रम अलग होता है, इसलिए मानों को विभिन्न स्थानों पर डाला जाना चाहिए।
  • संदर्भ टिप्पणियाँ शामिल करें आपकी locale फ़ाइलों में ताकि अनुवादक समझ सकें कि प्रत्येक स्ट्रिंग कहाँ प्रदर्शित होती है और फॉर्मेट तर्क क्या दर्शाते हैं।
  • लंबी स्ट्रिंग्स के साथ परीक्षण करें। जर्मन पाठ आमतौर पर अंग्रेज़ी से 30% लंबा होता है। सुनिश्चित करें कि आपके UI तत्व लंबी अनुवादों को बिना लेआउट टूटे संभाल सकें।
  • यूजर-फेसिंग स्ट्रिंग्स को कभी हार्डकोड न करें। हर सूचना, मेनू लेबल, सहायता पाठ, और त्रुटि संदेश को L() function, भले ही आप प्रारंभ में केवल एक भाषा का समर्थन करें।
  • एक भाषा कमांड प्रदान करें पसंद करें /lang de ताकि खिलाड़ी कभी भी ऑटो-डिटेक्ट की गई भाषा को ओवरराइड कर सकें।

शुरू करने के लिए तैयार?

हमारी शॉप से स्क्रिप्ट लें, या सपोर्ट, अपडेट और आगे आने वाली चीज़ों की झलक के लिए Discord से जुड़ें।