Search docs
Search guides, modules and symbols
Translations

Translations

Phrase files are the only copy of a plugin’s user-facing strings. Operators reword or recolour a message by editing JSON — no rebuild, no fork. Keys are checked at build against the files that plugin actually loads.

Load, then reply#

Nothing is loaded automatically, including the shared common set. s2s build reads translations.load(...) to work out which keys cmd.replyT and Translations.translate accept; a key from a file you did not load is a compile error.

import { command, ADMFLAG, Chat, Translations, translations, HookResult } from '@s2script/sdk';

export function OnPluginStart(): void {
	translations.load('basecomm', 'common');

	command.admin('sm_gag', ADMFLAG.CHAT, (cmd) => {
		cmd.replyT('Usage Gag');
		Chat.toSlot(cmd.callerSlot, Translations.translate(cmd.callerSlot, 'Gagged Player', 1));
		return HookResult.Handled;
	});
}

translations.load is load-window only — it throws after settle. Order is significant: translate takes the first hit within each of its two passes (the client’s language, then English). List your own set before any shared one if you want to override a shared phrase.

A plugin that loads nothing widens PhraseKey to string and compiles unchecked.

Phrase files#

One file per set, at translations/<set>.phrases.json in the addon (for example addons/s2script/translations/basecomm.phrases.json). Flat key → English template. {1}, {2}, … are positional slots; {green}, {default}, … are colour tags expanded on output.

{
	"Usage Gag": "Usage: sm_gag <target>",
	"Gagged Player": "{green}[SM]{default} Gagged {1} player."
}

Keys are human-readable English on purpose: an unresolved key renders as the key itself.

A translator adds translations/<code>/<set>.phrases.json — no code change, no rebuild. English (the root file) is the fallback when a language file omits a key.

A missing phrase file renders raw keys. Translations.load warns, naming the set, when a seedless load finds no file.

Colour tags#

On CS2, tags match ChatColors names in lowercase ({green}, {default}, {lightred}, …). Expansion happens at output: chat keeps the control byte; console expands then strips, so tags never leak as literal {green}. Unknown tags are deleted (players never see stray braces) and warned once each to the server console.

{1} arguments cannot inject tags — braces are stripped from substituted values.

Chat.toAll is not per-client localized; it uses the operator-settable server default (Translations.setDefaultLanguage). cmd.replyT and Translations.translate(slot, …) resolve for that caller’s language.

Lower-level load#

Prefer translations.load(...) — that is what the build reads. Translations.load(name, seed?) is the lower-level form, for a name computed at runtime or a set with an in-code default. A seed is starting content; the file overrides it.

See the translations module and commands.