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 phrasesMonolith.CurrentPhrasesTable- Cached table for current language phrasesCURRENT_LANGUAGE- Current active language (default: "en")L- Global shorthand function forMonolith.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 phrasesText(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 codetPhrases(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 codebSetFEnv(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
Recommended Phrase ID Structure
-- 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:
- If a phrase doesn't exist in the current language, it falls back to English ("en")
- If it doesn't exist in English either, it returns the phrase ID itself
- 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 configurationsh_[lang]_entities.lua- Entities, weapons, toolssh_[lang]_ui.lua- User interface elementssh_[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:
- Load English first (fallback language)
- Load other languages after English
- 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.