Skip to main content

Add Translation (Advanced)

Monolith Gamemode Locale System Documentation

Overview

The Monolith gamemode features a robust localization system that allows for multi-language support. This system enables developers to register translations for different languages and dynamically access them throughout the codebase.

Core Components

1. Global Variables and Storage

  • Monolith.Phrases - Main storage table for all language phrases
  • Monolith.CurrentPhrasesTable - Cached table for current language phrases
  • CURRENT_LANGUAGE - Current active language (default: "en")
  • L - Global shorthand function for Monolith.GetPhrase

2. Main Functions

Monolith.RegisterPhrase(sLanguage, sPhraseID, sText)

Registers a single phrase for a specific language.

Parameters:

  • sLanguage (string): Language code (e.g., "en", "fr", "ru")
  • sPhraseID (string): Unique identifier for the phrase
  • sText (string): The translated text

Example:

Monolith.RegisterPhrase("en", "cfg.item.weapon_pistol", "Pistol")
Monolith.RegisterPhrase("fr", "cfg.item.weapon_pistol", "Pistolet")

Monolith.RegisterPhrases(sLanguage, tPhrases)

Registers multiple phrases at once for a specific language.

Parameters:

  • sLanguage (string): Language code
  • tPhrases (table): Table of phrase IDs and their translations

Example:

Monolith.RegisterPhrases("fr", {
["cfg.item.weapon_pistol"] = "Pistolet",
["cfg.item.weapon_rifle"] = "Fusil",
["cfg.item.ammo_pistol"] = "Munitions de pistolet"
})

Monolith.GetPhrase(sIdentifier, ...)

Retrieves a phrase for the current language with optional string formatting.

Parameters:

  • sIdentifier (string): Phrase ID to retrieve
  • ... (varargs): Optional arguments for string.format

Returns: Translated string or the identifier if not found

Example:

local weaponName = Monolith.GetPhrase("cfg.item.weapon_pistol")
local playerMessage = Monolith.GetPhrase("msg.player_killed", playerName, weaponName)

Monolith.LocaleBuilder(sLanguage, bSetFEnv)

Creates a builder object for easier locale registration.

Parameters:

  • sLanguage (string): Language code
  • bSetFEnv (boolean): Whether to set the function environment

Returns: Builder table with metamethods

How to Add New Locales

Step 1: Create Language Files

Create separate files for each language in the appropriate directory structure:

gamemode/config/locale/
├── en/
│ ├── sh_en_config.lua
│ ├── sh_en_entities.lua
│ └── sh_en_weapons.lua
├── fr/
│ ├── sh_fr_config.lua
│ ├── sh_fr_entities.lua
│ └── sh_fr_weapons.lua
└── ru/
├── sh_ru_config.lua
├── sh_ru_entities.lua
└── sh_ru_weapons.lua

Step 2: Using LocaleBuilder

The recommended approach is to use the LocaleBuilder system:

-- In sh_fr_config.lua
Monolith.LocaleBuilder("fr", true)

-- Now you can use the builder syntax
cfg.item.weapon_pistol = "Pistolet"
cfg.item.weapon_rifle = "Fusil"
cfg.item.weapon_shotgun = "Fusil à pompe"

-- Nested categories work automatically
cfg.item.desc.weapon_pistol = "Une arme de poing standard"
cfg.item.desc.weapon_rifle = "Un fusil d'assaut puissant"

-- Entity translations
entities.weapon_pistol.printName = "Pistolet"
entities.weapon_pistol.instructions = "Clic gauche pour tirer"

-- Messages and notifications
msg.player_joined = "%s a rejoint le serveur"
msg.player_left = "%s a quitté le serveur"

Step 3: Manual Registration (Alternative)

If you prefer manual registration:

-- English phrases
Monolith.RegisterPhrases("en", {
["cfg.item.weapon_pistol"] = "Pistol",
["cfg.item.desc.weapon_pistol"] = "A standard sidearm",
["msg.player_joined"] = "%s joined the server"
})

-- French phrases
Monolith.RegisterPhrases("fr", {
["cfg.item.weapon_pistol"] = "Pistolet",
["cfg.item.desc.weapon_pistol"] = "Une arme de poing standard",
["msg.player_joined"] = "%s a rejoint le serveur"
})

How to Use Translations in Code

Method 1: Using the L() Function

-- In item definitions
ITEM = Monolith.InventoryItem("weapon_pistol", L("cfg.item.weapon_pistol"), L("cfg.item.desc.weapon_pistol"))

-- In entity code
ENT.PrintName = L("entities.weapon_pistol.printName")

-- In notifications with formatting
Monolith.NotifyAll(L("msg.player_joined", player:Name()))

-- In UI elements
local weaponLabel = vgui.Create("DLabel")
weaponLabel:SetText(L("cfg.item.weapon_pistol"))

Method 2: Using Monolith.GetPhrase()

-- Same functionality as L()
local weaponName = Monolith.GetPhrase("cfg.item.weapon_pistol")
local description = Monolith.GetPhrase("cfg.item.desc.weapon_pistol")

-- With formatting
local message = Monolith.GetPhrase("msg.player_health", player:Health(), player:GetMaxHealth())

Naming Conventions

-- Items
cfg.item.[item_id] -- Item name
cfg.item.[item_id].desc -- Item description

-- Entities
entities.[entity_class].printName -- Entity display name
entities.[entity_class].desc -- Entity description
entities.[entity_class].useHint -- Usage hint

-- Weapons
sweps.[weapon_class].printName -- Weapon name
sweps.[weapon_class].instructions -- Weapon instructions
sweps.[weapon_class].purpose -- Weapon purpose

-- Messages
msg.[message_type] -- General messages
notif.[notification_type] -- Notifications
ui.[ui_element] -- UI text

Example Complete Item Translation

-- English
cfg.item.zgo2_battery = "Battery"
cfg.item.zgo2_battery.desc = "Rechargeable power module to keep your installations active."

-- French
cfg.item.zgo2_battery = "Batterie"
cfg.item.zgo2_battery.desc = "Module d'alimentation rechargeable pour maintenir vos installations actives."

-- Russian
cfg.item.zgo2_battery = "Батарея"
cfg.item.zgo2_battery.desc = "Перезаряжаемый силовой модуль для поддержания работы ваших установок."

Fallback System

The locale system includes an automatic fallback mechanism:

  1. If a phrase doesn't exist in the current language, it falls back to English ("en")
  2. If it doesn't exist in English either, it returns the phrase ID itself
  3. This ensures the game always displays something meaningful

Best Practices

1. Consistent Naming

Always use consistent naming patterns for similar types of content:

cfg.item.weapon_pistol
cfg.item.weapon_rifle
cfg.item.weapon_shotgun

2. Descriptive IDs

Use descriptive phrase IDs that indicate their purpose:

-- Good
cfg.item.desc.weapon_pistol
msg.error.insufficient_funds
ui.button.confirm

-- Avoid
item1
error5
btn_ok

3. String Formatting

Use string formatting for dynamic content:

-- French
msg.player_killed = "%s a été tué par %s avec %s"

-- Usage
L("msg.player_killed", victim:Name(), killer:Name(), weaponName)

4. Organization

Group related translations in the same files:

  • sh_[lang]_config.lua - Items, general configuration
  • sh_[lang]_entities.lua - Entities, weapons, tools
  • sh_[lang]_ui.lua - User interface elements
  • sh_[lang]_messages.lua - Messages, notifications, errors

Changing Language at Runtime

-- Set the current language
Monolith.SetLanguage("fr") -- Changes to French
Monolith.SetLanguage("en") -- Changes to English

File Loading Order

Make sure locale files are loaded in the correct order:

  1. Load English first (fallback language)
  2. Load other languages after English
  3. Set the desired language after all locales are loaded

Example Implementation

Here's a complete example of adding a new weapon with full localization:

-- gamemode/config/locale/en/sh_en_weapons.lua
Monolith.LocaleBuilder("en", true)

sweps.weapon_example.printName = "Example Weapon"
sweps.weapon_example.instructions = "Left click to fire, right click to aim"
sweps.weapon_example.purpose = "An example weapon for demonstration"

-- gamemode/config/locale/fr/sh_fr_weapons.lua
Monolith.LocaleBuilder("fr", true)

sweps.weapon_example.printName = "Arme d'exemple"
sweps.weapon_example.instructions = "Clic gauche pour tirer, clic droit pour viser"
sweps.weapon_example.purpose = "Une arme d'exemple pour démonstration"

-- gamemode/entities/weapons/weapon_example.lua
SWEP.PrintName = L("sweps.weapon_example.printName")
SWEP.Instructions = L("sweps.weapon_example.instructions")
SWEP.Purpose = L("sweps.weapon_example.purpose")

This documentation should provide everything needed to implement and use the Monolith locale system effectively.