nSystemz / nemesus-world-server

RageMP GTA5 Roleplay Gamemode/Server von Nemesus World (Voice-RP/Text-RP)
https://nemesus-world.de
Other
26 stars 9 forks source link

Guide: Implementation of a Multilanguage Translation System #25

Open Retaview opened 8 months ago

Retaview commented 8 months ago

Guide: Implementation of a Multilanguage Translation System

Many people adore Nemesus World Server, however, not everyone speaks German or intends to create a server in German. That's why I want to explain step by step how to create a multilanguage translation system. First we will focus on the server interfaces (vuejsserver), then we will focus on the backend. To do this, we need to modify the main.js file inside the /vuejsserver/src folder by adding the following code:

import Vue from 'vue'
import App from './App.vue'

Vue.config.productionTip = false

global.gui = { 
  loading: null, 
  login: null, 
  register: null, 
  characterswitch: null, 
  charactercreator: null, 
  hud: null, 
  menu: null, 
  rpquiz: null, 
  inventory: null, 
  selectwheel: null, 
  lockpicking: null, 
  mdc: null 
}

function loadTranslations(lang) {
  switch (lang) {
    case 'de':
      return import('./locales/de.json');
    case 'en':
      return import('./locales/en.json');
    case 'es':
      return import('./locales/es.json');
    default:
      return {};
  }
}

function changeLanguage(lang) {
  loadTranslations(lang).then(translations => {
    Vue.prototype.$translations = translations.default;
  });
}

// Change language here
changeLanguage('en');

new Vue({
  render: h => h(App),
}).$mount('#app')

After updating the main.js file, we need to create a folder called "locales" inside /vuejsserver/src, we add the languages ​​we want to translate the interfaces to, in addition to the original language, German. In my case, I have created 3 languages: de.json, en.json, and es.json. Within each of those files, we add the keys along with the translations.

After that, we simply access the .vue components inside the /vuejsserver/src/components folder and change all the texts to keys.

For example, in the Login.vue file, we change this piece of code:

<div class="container-login100-form-btn p-t-10" v-if="!clicked">
    <button type="submit" class="login100-form-btn" @click="login()">
        Login
    </button>
</div>

To the following:

<div class="container-login100-form-btn p-t-10" v-if="!clicked">
    <button type="submit" class="login100-form-btn" @click="login()">
        {{ $translations.login.button1 }}
    </button>
</div>

And then we add the text that was in de.json:

{
  "login": {
    "button1": "Login"
  }
}

We also do the same with the rest of the .json files in /vuejsserver/src/locales. For example, for Spanish, we would put the following in es.json:

{
  "login": {
    "button1": "Acceder"
  }
}

As you can see, we are organizing everything by categories, which correspond to the file. For example, since we are modifying the Login.vue file, we add all those translations in the login category, and in the key, we put it in this way: {{ $translations.login.button1 }}. If we modify another file, we will change the name of the category to the name of the file. For example, for Register.vue, it would be {{ $translations.register.name }}, and the .json file would look like this:

{
  "login": {
    "button1": "Login"
  },
  "register": {
    "name": "Text"
  }
}

To translate placeholders, we need to make a small change, which will be according to the following structure :placeholder="$translations.login.password" instead of simply placeholder= "Text". In summary, we need to add ":" before placeholder and use quotes instead of {}, for the rest, we add the keys exactly the same to the .json files like the others. Functions with this.warning must be changed as follows: this.warning = this.$translations.login.shortWarning;. We must always change both the category (login) and the keys (password in the example of the previous placeholder or shortWarning in the case of the this.warning function). For example, our JSON file would still look like this:

{
  "login": {
    "button1": "Login",
    "password": "Password",
    "shortWarning": "Username or password too short!"
  },
  "register": {
    "name": "Text"
  }
}

To choose the language that will be displayed on the server, we must change the string of the changeLanguage('en'); option in main.js with the language we want to display. Once we have made changes, we must run npm run build within the /vuejsserver directory and then start the server as usual. If you followed the instructions, you should see the server with the language completely changed.

Creating a Multilanguage Translation System for the backend

We have already created a multilanguage translation system for the interfaces (vuejsserver), but we still need to create a translation system for the backend. To do this, we simply need to create a new file called Translator.cs inside the folder /backend/NemesusWorld/Utils and paste the following content:

using System;
using System.Collections.Generic;
using System.IO;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace NemesusWorld.Utils
{
    public static class Translator
    {
        private static Dictionary<string, JObject> translations = new Dictionary<string, JObject>();
        private static string defaultLang = "en"; // Change language
        private static bool translationsLoaded = false;

        public static string Translate(string category, string key)
        {
            LoadTranslationsIfNeeded();

            if (translations.ContainsKey(defaultLang) && translations[defaultLang].ContainsKey(category))
            {
                var categoryTranslations = translations[defaultLang][category];
                if (categoryTranslations != null && categoryTranslations[key] != null)
                {
                    return categoryTranslations[key].ToString();
                }
            }

            return key;
        }

        private static void LoadTranslationsIfNeeded()
        {
            if (!translationsLoaded)
            {
                LoadTranslations("de");
                LoadTranslations("en");
                LoadTranslations("es");
                translationsLoaded = true;
            }
        }

        private static void LoadTranslations(string lang)
        {
            string jsonFilePath = $"./vuejsserver/src/locales/{lang}.json";
            if (File.Exists(jsonFilePath))
            {
                string jsonContent = File.ReadAllText(jsonFilePath);
                try
                {
                    var translationsObj = JsonConvert.DeserializeObject<JObject>(jsonContent);
                    translations[lang] = translationsObj;
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"[Translator] Error loading translation file for language '{lang}': {ex.Message}");
                }
            }
            else
            {
                Console.WriteLine($"[Translator] Warning: Translation file for language not found '{lang}'.");
            }
        }
    }
}

Once the file is created, we will open each C# file that we want to translate and replace the strings with the following function Translator.Translate("backend", "name"));, then we will add the text in the same .json files that we use for the interface translations, that is de.json, en.json, and es.json. For example, we could change this:

Helper.ConsoleLog("info", $"Roleplay-Art: Voice-RP (SaltyChat)");

to this:

Helper.ConsoleLog("info", Translator.Translate("backend", "voiceSalty"));

and add the following in, for example, es.json:

{
  "backend": {
    "voiceSalty": "Sistema de voz activado correctamente (SaltyChat)"
  }
}

As you can see, we have added the category first and then the key name in the C# code. This way we have all the translations in the same files globally and easy to translate. To change the default language displayed, we must change private static string defaultLang = "en"; to the language we want to load. Finally, we will rebuild the entire solution and we can start the server with the changes applied.

alyansosa commented 7 months ago

Does anyone have a .json file already created to share? I don't mind the language. It's just that on such a complex server like this, it's very complicated to know every button or text that needs translation. If you have one made in another language that only needs to be changed to Spanish, I would appreciate it.