Last Update: 2023-07-06
Managing String Tables for Localization
This guide covers best practices for organizing, maintaining, and scaling string tables in your Don't Starve Together mods to support multiple languages efficiently.
String Table Structure
A well-organized string table structure is essential for maintainable localization. Here's a recommended structure:
STRINGS.MY_MOD = {
-- Categorize by content type
ITEMS = {
ITEM_1 = { NAME = "Item Name", DESCRIPTION = "Item description." },
ITEM_2 = { NAME = "Another Item", DESCRIPTION = "Another description." },
},
CHARACTERS = {
CHARACTER_1 = {
DESCRIBE = {
ITEM_1 = "Character's comment about item 1",
ITEM_2 = "Character's comment about item 2",
},
ACTIONFAIL = {
ITEM_1 = "Failed action comment",
},
},
},
UI = {
BUTTONS = {
CRAFT = "Craft",
CANCEL = "Cancel",
},
TOOLTIPS = {
ITEM_1 = "Tooltip for item 1",
},
},
-- Add more categories as needed
}
Naming Conventions
Consistent naming conventions make string tables easier to manage:
- Use
UPPERCASE
for keys - Use descriptive, hierarchical names
- Group related strings together
- Use consistent patterns for similar items
-- Good naming convention
STRINGS.MY_MOD.ITEMS.MAGIC_SWORD = { NAME = "Magic Sword" }
STRINGS.MY_MOD.ITEMS.MAGIC_STAFF = { NAME = "Magic Staff" }
-- Avoid inconsistent naming
STRINGS.MY_MOD.SWORD_NAME = "Magic Sword" -- Inconsistent structure
STRINGS.MY_MOD.staff = { name = "Magic Staff" } -- Inconsistent casing
String Table Management for Large Mods
For mods with extensive content, consider breaking down string tables into multiple files:
modroot/
├── scripts/
│ └── languages/
│ ├── en/
│ │ ├── items.lua
│ │ ├── characters.lua
│ │ ├── ui.lua
│ │ └── misc.lua
│ ├── zh/
│ │ ├── items.lua
│ │ ├── characters.lua
│ │ ├── ui.lua
│ │ └── misc.lua
│ └── strings_loader.lua
└── modmain.lua
Then use a loader script to combine them:
-- strings_loader.lua
local function LoadLanguageFiles(language)
local path = "scripts/languages/" .. language .. "/"
-- Load each category file if it exists
local categories = {"items", "characters", "ui", "misc"}
for _, category in ipairs(categories) do
local file_path = path .. category .. ".lua"
if GLOBAL.kleifileexists(file_path) then
modimport(file_path)
end
end
end
-- Load English as default
LoadLanguageFiles("en")
-- Load user's language if available
local language = GLOBAL.LanguageTranslator.defaultlanguage
if language ~= "en" and GLOBAL.kleifileexists("scripts/languages/" .. language) then
LoadLanguageFiles(language)
end
String Interpolation
For strings that require dynamic values, use a consistent pattern:
-- In string table
STRINGS.MY_MOD.UI.TOOLTIPS.DAMAGE = "Deals {damage} damage"
STRINGS.MY_MOD.UI.TOOLTIPS.HEALING = "Restores {amount} health over {duration} seconds"
-- In code
function FormatString(str, variables)
local result = str
for key, value in pairs(variables) do
result = string.gsub(result, "{" .. key .. "}", tostring(value))
end
return result
end
local tooltip = FormatString(STRINGS.MY_MOD.UI.TOOLTIPS.DAMAGE, {damage = 25})
-- Result: "Deals 25 damage"
local healing_tooltip = FormatString(STRINGS.MY_MOD.UI.TOOLTIPS.HEALING, {amount = 50, duration = 10})
-- Result: "Restores 50 health over 10 seconds"
Translation Management Tools
For larger mods with many strings, consider using external tools to manage translations:
Spreadsheet Method
- Create a spreadsheet with columns for key, English text, and each supported language
- Export to CSV
- Use a script to convert the CSV to Lua string tables
Example spreadsheet:
Key | English | Chinese | Russian
-----------------------|----------------|-------------|-------------
ITEMS.SWORD.NAME | Magic Sword | 魔法剑 | Магический меч
ITEMS.SWORD.DESCRIPTION | A magical sword| 一把魔法剑 | Магический меч
JSON Intermediate Format
Store translations in JSON for easier collaboration:
{
"ITEMS": {
"SWORD": {
"NAME": {
"en": "Magic Sword",
"zh": "魔法剑",
"ru": "Магический меч"
},
"DESCRIPTION": {
"en": "A magical sword",
"zh": "一把魔法剑",
"ru": "Магический меч"
}
}
}
}
Then convert to Lua string tables with a script.
Version Control for Translations
When working with multiple translators, use these practices:
- Keep each language in separate files
- Use clear comments to provide context for translators
- Mark untranslated strings clearly
- Track translation progress
Example with comments for translators:
-- strings_zh.lua
-- CONTEXT: This is the name of a magical sword item
STRINGS.MY_MOD.ITEMS.MAGIC_SWORD.NAME = "魔法剑"
-- CONTEXT: This describes a sword that glows with magical energy
STRINGS.MY_MOD.ITEMS.MAGIC_SWORD.DESCRIPTION = "一把闪烁着魔法能量的剑。"
-- TODO: Translation needed
-- STRINGS.MY_MOD.ITEMS.MAGIC_STAFF.NAME = "Magic Staff"
Handling Missing Translations
Always implement a robust system for handling missing translations:
function GetLocalizedString(stringTable, key, subKey, fallback)
if stringTable and stringTable[key] then
if subKey then
if stringTable[key][subKey] then
return stringTable[key][subKey]
end
else
return stringTable[key]
end
end
return fallback or (subKey and key .. "." .. subKey or key)
end
-- Usage for nested tables
local itemName = GetLocalizedString(STRINGS.MY_MOD.ITEMS, "MAGIC_SWORD", "NAME", "Magic Sword")
Updating String Tables
When updating your mod, follow these practices for string table updates:
- Never remove existing string keys (could break translations)
- Add new strings at the end of each category
- Comment deprecated strings rather than removing them
- Use version numbers in comments for tracking changes
-- strings_en.lua
-- Version 1.0
STRINGS.MY_MOD.ITEMS.MAGIC_SWORD.NAME = "Magic Sword"
STRINGS.MY_MOD.ITEMS.MAGIC_SWORD.DESCRIPTION = "A magical sword."
-- Version 1.1
STRINGS.MY_MOD.ITEMS.MAGIC_STAFF.NAME = "Magic Staff"
STRINGS.MY_MOD.ITEMS.MAGIC_STAFF.DESCRIPTION = "A magical staff."
-- Deprecated in version 1.1, kept for backwards compatibility
-- STRINGS.MY_MOD.ITEMS.OLD_ITEM.NAME = "Old Item"
Automated String Extraction
For large mods, consider automating string extraction:
- Use consistent string access patterns in your code
- Create a script that scans your code for these patterns
- Generate a template string table with all required keys
- Compare against existing translations to find missing strings
Example pattern for automated extraction:
-- In your code, use a consistent pattern
local itemName = STRINGS.MY_MOD.ITEMS.MAGIC_SWORD.NAME
-- A script can scan for patterns like:
-- STRINGS%.MY_MOD%.([%w_]+)%.([%w_]+)%.?([%w_]*)
-- to extract string keys
Next Steps
After mastering string table management, explore:
- Font Handling - For languages with special character requirements
- Localization Best Practices - For effective translations
- Testing Localized Content - For quality assurance
Effective string table management is the foundation of a well-localized mod, making it easier to add new languages and maintain existing translations as your mod evolves.