mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-16 21:33:46 +03:00
379 lines
10 KiB
Lua
379 lines
10 KiB
Lua
--[[
|
|
| This file was obtained through the combined efforts
|
|
| of Madbluntz & Plymouth Antiquarian Society.
|
|
|
|
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
|
| Maloy, DrPepper10 @ RIP, Atle!
|
|
|
|
|
| Visit for more: https://plymouth.thetwilightzone.ru/
|
|
--]]
|
|
|
|
---- Clientside language stuff
|
|
|
|
-- Need to build custom tables of strings. Can't use language.Add as there is no
|
|
-- way to access the translated string in Lua. Identifiers only get translated
|
|
-- when Source/gmod print them. By using our own table and our own lookup, we
|
|
-- have far more control. Maybe it's slower, but maybe not, we aren't scanning
|
|
-- strings for "#identifiers" after all.
|
|
|
|
LANG.Strings = {}
|
|
|
|
local ttt_language = CreateConVar("ttt_language", "auto", FCVAR_ARCHIVE)
|
|
|
|
LANG.DefaultLanguage = "english"
|
|
LANG.ActiveLanguage = LANG.DefaultLanguage
|
|
|
|
LANG.ServerLanguage = "english"
|
|
|
|
local cached_default, cached_active
|
|
|
|
function LANG.CreateLanguage(raw_lang_name)
|
|
if not raw_lang_name then return end
|
|
lang_name = string.lower(raw_lang_name)
|
|
|
|
if not LANG.IsLanguage(lang_name) then
|
|
LANG.Strings[lang_name] = {
|
|
-- Empty string is very convenient to have, so init with that.
|
|
[""] = "",
|
|
-- Presentational, not-lowercased language name
|
|
language_name = raw_lang_name
|
|
}
|
|
end
|
|
|
|
if lang_name == LANG.DefaultLanguage then
|
|
cached_default = LANG.Strings[lang_name]
|
|
|
|
-- when a string is not found in the active or the default language, an
|
|
-- error message is shown
|
|
setmetatable(LANG.Strings[lang_name],
|
|
{
|
|
__index = function(tbl, name)
|
|
return Format("[ERROR: Translation of %s not found]", name), false
|
|
end
|
|
})
|
|
end
|
|
|
|
return LANG.Strings[lang_name]
|
|
end
|
|
|
|
-- Add a string to a language. Should not be used in a language file, only for
|
|
-- adding strings elsewhere, such as a SWEP script.
|
|
function LANG.AddToLanguage(lang_name, string_name, string_text)
|
|
lang_name = lang_name and string.lower(lang_name)
|
|
|
|
if not LANG.IsLanguage(lang_name) then
|
|
ErrorNoHalt(Format("Failed to add '%s' to language '%s': language does not exist.\n", tostring(string_name), tostring(lang_name)))
|
|
return false
|
|
end
|
|
|
|
LANG.Strings[lang_name][string_name] = string_text
|
|
|
|
return string_name
|
|
end
|
|
|
|
-- Simple and fastest name->string lookup
|
|
function LANG.GetTranslation(name)
|
|
return cached_active[name]
|
|
end
|
|
|
|
-- Lookup with no error upon failback, just nil. Slightly slower, but best way
|
|
-- to handle lookup of strings that may legitimately fail to exist
|
|
-- (eg. SWEP-defined).
|
|
function LANG.GetRawTranslation(name)
|
|
return rawget(cached_active, name) or rawget(cached_default, name)
|
|
end
|
|
|
|
-- A common idiom
|
|
local GetRaw = LANG.GetRawTranslation
|
|
function LANG.TryTranslation(name)
|
|
return GetRaw(name) or name
|
|
end
|
|
|
|
local interp = string.Interp
|
|
|
|
-- Parameterised version, performs string interpolation. Slower than
|
|
-- GetTranslation.
|
|
function LANG.GetParamTranslation(name, params)
|
|
return interp(cached_active[name], params)
|
|
end
|
|
LANG.GetPTranslation = LANG.GetParamTranslation
|
|
|
|
function LANG.GetTranslationFromLanguage(name, lang_name)
|
|
return rawget(LANG.Strings[lang_name], name)
|
|
end
|
|
|
|
-- Ability to perform lookups in the current language table directly is of
|
|
-- interest to consumers in draw/think hooks. Grabbing a translation directly
|
|
-- from the table is very fast, and much simpler than a local caching solution.
|
|
-- Modifying it would typically be a bad idea.
|
|
function LANG.GetUnsafeLanguageTable() return cached_active end
|
|
|
|
function LANG.GetUnsafeNamed(name) return LANG.Strings[name] end
|
|
|
|
-- Safe and slow access, not sure if it's ever useful.
|
|
function LANG.GetLanguageTable(lang_name)
|
|
lang_name = lang_name or LANG.ActiveLanguage
|
|
|
|
local cpy = table.Copy(LANG.Strings[lang_name])
|
|
SetFallback(cpy)
|
|
|
|
return cpy
|
|
end
|
|
|
|
|
|
local function SetFallback(tbl)
|
|
-- languages may deal with this themselves, or may already have the fallback
|
|
local m = getmetatable(tbl)
|
|
if m and m.__index then return end
|
|
|
|
-- Set the __index of the metatable to use the default lang, which makes any
|
|
-- keys not found in the table to be looked up in the default. This is faster
|
|
-- than using branching ("return lang[x] or default[x] or errormsg") and
|
|
-- allows fallback to occur even when consumer code directly accesses the
|
|
-- lang table for speed (eg. in a rendering hook).
|
|
setmetatable(tbl,
|
|
{
|
|
__index = cached_default
|
|
})
|
|
|
|
end
|
|
|
|
function LANG.SetActiveLanguage(lang_name)
|
|
lang_name = lang_name and string.lower(lang_name)
|
|
|
|
if LANG.IsLanguage(lang_name) then
|
|
local old_name = LANG.ActiveLanguage
|
|
LANG.ActiveLanguage = lang_name
|
|
|
|
-- cache ref to table to avoid hopping through LANG and Strings every time
|
|
cached_active = LANG.Strings[lang_name]
|
|
|
|
-- set the default lang as fallback, if it hasn't yet
|
|
SetFallback(cached_active)
|
|
|
|
-- some interface elements will want to know so they can update themselves
|
|
if old_name != lang_name then
|
|
hook.Call("TTTLanguageChanged", GAMEMODE, old_name, lang_name)
|
|
end
|
|
else
|
|
MsgN(Format("The language '%s' does not exist on this server. Falling back to English...", lang_name))
|
|
|
|
-- fall back to default if possible
|
|
if lang_name != LANG.DefaultLanguage then
|
|
LANG.SetActiveLanguage(LANG.DefaultLanguage)
|
|
end
|
|
end
|
|
end
|
|
|
|
function LANG.Init()
|
|
local lang_name = ttt_language:GetString()
|
|
|
|
-- if we want to use the server language, we'll be switching to it as soon as
|
|
-- we hear from the server which one it is, for now use default
|
|
if LANG.IsServerDefault(lang_name) then
|
|
lang_name = LANG.ServerLanguage
|
|
end
|
|
|
|
LANG.SetActiveLanguage(lang_name)
|
|
end
|
|
|
|
function LANG.IsServerDefault(lang_name)
|
|
lang_name = string.lower(lang_name)
|
|
return lang_name == "server default" or lang_name == "auto"
|
|
end
|
|
|
|
function LANG.IsLanguage(lang_name)
|
|
lang_name = lang_name and string.lower(lang_name)
|
|
return LANG.Strings[lang_name]
|
|
end
|
|
|
|
local function LanguageChanged(cv, old, new)
|
|
if new and new != LANG.ActiveLanguage then
|
|
|
|
if LANG.IsServerDefault(new) then
|
|
new = LANG.ServerLanguage
|
|
end
|
|
|
|
LANG.SetActiveLanguage(new)
|
|
end
|
|
end
|
|
cvars.AddChangeCallback("ttt_language", LanguageChanged)
|
|
|
|
local function ForceReload()
|
|
LANG.SetActiveLanguage("english")
|
|
end
|
|
concommand.Add("ttt_reloadlang", ForceReload)
|
|
|
|
-- Get a copy of all available languages (keys in the Strings tbl)
|
|
function LANG.GetLanguages()
|
|
local langs = {}
|
|
for lang, strings in pairs(LANG.Strings) do
|
|
table.insert(langs, lang)
|
|
end
|
|
return langs
|
|
end
|
|
|
|
function LANG.GetLanguageNames()
|
|
-- Typically preferable to GetLanguages but separate to avoid API breakage.
|
|
local lang_names = {}
|
|
for lang, strings in pairs(LANG.Strings) do
|
|
lang_names[lang] = strings["language_name"] or string.Capitalize(lang)
|
|
end
|
|
return lang_names
|
|
end
|
|
|
|
---- Styling
|
|
|
|
local bgcolor = {
|
|
[ROLE_TRAITOR] = Color(150, 0, 0, 200),
|
|
[ROLE_DETECTIVE] = Color(0, 0, 150, 200),
|
|
[ROLE_INNOCENT] = Color(0, 50, 0, 200)
|
|
};
|
|
|
|
-- Table of styles that can take a string and display it in some position,
|
|
-- colour, etc.
|
|
LANG.Styles = {
|
|
default = function(text)
|
|
MSTACK:AddMessage(text)
|
|
print("TTT: " .. text)
|
|
end,
|
|
|
|
rolecolour = function(text)
|
|
MSTACK:AddColoredBgMessage(text,
|
|
bgcolor[ LocalPlayer():GetRole() ])
|
|
print("TTT: " .. text)
|
|
end,
|
|
|
|
chat_warn = function(text)
|
|
chat.AddText(COLOR_RED, text)
|
|
end,
|
|
|
|
|
|
chat_plain = chat.AddText
|
|
};
|
|
|
|
-- Table mapping message name => message style name. If no message style is
|
|
-- defined, the default style is used. This is the case for the vast majority of
|
|
-- messages at the time of writing.
|
|
LANG.MsgStyle = {}
|
|
|
|
-- Access of message styles
|
|
function LANG.GetStyle(name)
|
|
return LANG.MsgStyle[name] or LANG.Styles.default
|
|
end
|
|
|
|
-- Set a style by name or directly as style-function
|
|
function LANG.SetStyle(name, style)
|
|
if isstring(style) then
|
|
style = LANG.Styles[style]
|
|
end
|
|
|
|
LANG.MsgStyle[name] = style
|
|
end
|
|
|
|
function LANG.ShowStyledMsg(text, style)
|
|
style(text)
|
|
end
|
|
|
|
function LANG.ProcessMsg(name, params)
|
|
local raw = LANG.GetTranslation(name)
|
|
|
|
local text = raw
|
|
|
|
if params then
|
|
-- some of our params may be string names themselves
|
|
for k, v in pairs(params) do
|
|
if isstring(v) then
|
|
local name = LANG.GetNameParam(v)
|
|
if not name then continue end
|
|
|
|
params[k] = LANG.GetTranslation(name)
|
|
end
|
|
end
|
|
|
|
text = interp(raw, params)
|
|
end
|
|
|
|
LANG.ShowStyledMsg(text, LANG.GetStyle(name))
|
|
end
|
|
|
|
|
|
|
|
--- Message style declarations
|
|
|
|
-- Rather than having a big list of LANG.SetStyle calls, we specify it the other
|
|
-- way around here and churn through it in code. This is convenient because
|
|
-- we're doing it en-masse for some random interface things spread out over the
|
|
-- place.
|
|
--
|
|
-- Styles of custom SWEP messages and such should use LANG.SetStyle in their
|
|
-- script. The SWEP stuff here might be moved out to the SWEPS too.
|
|
|
|
local styledmessages = {
|
|
rolecolour = {
|
|
"round_traitors_one",
|
|
"round_traitors_more",
|
|
|
|
"buy_no_stock",
|
|
"buy_pending",
|
|
"buy_received",
|
|
|
|
"xfer_no_recip",
|
|
"xfer_no_credits",
|
|
"xfer_success",
|
|
"xfer_received",
|
|
|
|
"c4_no_disarm",
|
|
|
|
"tele_failed",
|
|
"tele_no_mark",
|
|
"tele_marked",
|
|
|
|
"dna_identify",
|
|
"dna_notfound",
|
|
"dna_limit",
|
|
"dna_decayed",
|
|
"dna_killer",
|
|
"dna_no_killer",
|
|
"dna_armed",
|
|
"dna_object",
|
|
"dna_gone",
|
|
|
|
"credit_det_all",
|
|
"credit_tr_all",
|
|
"credit_kill"
|
|
},
|
|
|
|
chat_plain = {
|
|
"body_call",
|
|
"disg_turned_on",
|
|
"disg_turned_off",
|
|
"mute_all",
|
|
"mute_off",
|
|
"mute_specs",
|
|
"mute_living"
|
|
},
|
|
|
|
chat_warn = {
|
|
"spec_mode_warning",
|
|
"radar_not_owned",
|
|
"radar_charging",
|
|
"drop_no_room",
|
|
"body_burning",
|
|
|
|
"tele_no_ground",
|
|
"tele_no_crouch",
|
|
"tele_no_mark_ground",
|
|
"tele_no_mark_crouch",
|
|
|
|
"drop_no_ammo"
|
|
}
|
|
};
|
|
|
|
local set_style = LANG.SetStyle
|
|
for style, msgs in pairs(styledmessages) do
|
|
for _, name in ipairs(msgs) do
|
|
set_style(name, style)
|
|
end
|
|
end
|