Skip to content

Internationalization ​

Internationalization in Infernus is primarily about charset encoding conversion, not multi-language translation. While $t can serve translation needs, the core feature is ensuring correct data exchange between the server (UTF-8) and the player client (legacy charsets like ISO-8859-1 or GBK). Most servers only serve a single region, so you may not need multi-language at all — but you should at least understand player internationalization to avoid garbled text.

VSCode Extension ​

infernus-starter ships with a plugin recommendation file (.vscode/extensions.json). It is highly recommended to click install when prompted by VSCode, so you can view internationalization data easily during development.

i18n-ally-custom-framework.yml and settings.json are already configured for the plugin.

Example ​

Defining Language Packs ​

Language packs are .json files. Tree-structured keys are used to organize translation data.

Strings can contain %s placeholders for dynamic values.

Chinese Language Pack ​

json
{
  "server": {
    "running": "成功运行由 node.js 强力驱动的 omp 服务器",
    "connection": "连接信息: %s - %s : %s"
  }
}

English Language Pack ​

json
{
  "server": {
    "running": "Successfully running an omp server powered by node.js",
    "connection": "connection information: %s - %s : %s"
  }
}

Instance ​

Create an I18n instance with new I18n("default locale key", languagePack).

Typically you only need the $t function.

$t("translation key", [placeholder array], locale key) returns the translated text for the given locale.

When there are no placeholders, pass null, undefined, or an empty array.

Omitting the third parameter falls back to the default locale.

ts
import { I18n } from "@infernus/core";

// Internationalized JSON language packs
import zh_CN from "./locales/zh_CN.json";
import en_US from "./locales/en_US.json";

const locales = {
  zh_CN,
  en_US,
};

export const { $t } = new I18n("en_US", locales);

console.log($t("server.running"));
console.log($t("server.connection", ["127.0.0.1", "8080", "123456"]));
console.log($t("server.connection", ["127.0.0.1", "8080", "123456"], "zh_CN"));

Utility Functions ​

The I18n class also provides several useful static methods for character set conversions:

  • encodeToBuf
    • Converts a string to a byte array in the specified charset.
  • decodeFromBuf
    • Converts a byte array to a string in the specified charset.
  • getValidStr
    • Extracts a valid string from a byte array — the first 0 byte marks the end of the string.

Player Internationalization ​

Each player instance has two properties for internationalization: charset and locale, corresponding to the character set and region respectively. Default values:

ts
class Player {
  charset = "ISO-8859-1";
  locale = "en_US";
}

Usually $t combines the player's locale to retrieve the corresponding language pack data.

ts
// Assuming you have a player instance
console.log($t("server.incoming", ["127.0.0.1", "8080", "123456"], player.locale));

To change a player's language or charset, modify their charset and locale properties. Always ensure charset is correct. You can guess the player's region from their IP address, or ask them to input a specific string and compare bytes to determine the charset.

supportAllNickname ​

TIP

By default, the game server only allows alphanumeric characters and underscores in usernames.

OMP provides new APIs to enable or disable specific byte values (0–255) in usernames.

GameMode.supportAllNickname() leverages these APIs to allow all international usernames — including Chinese characters and other non-ASCII names — to connect.

ts
import { GameMode } from "@infernus/core";

GameMode.onInit(({ next }) => {
  GameMode.supportAllNickname();
  return next();
});

How It Works ​

WARNING

Bidirectional charset data exchange works correctly only if the player's charset is set properly.

If an incorrect charset is configured, both the server and client will receive garbled text.

Infernus uses iconv-lite for charset conversion and polyfill.amx to intercept gamemode callbacks, returning them as decimal byte arrays.

Server-to-client functions like SendClientMessage, SendClientMessageToAll, ShowPlayerDialog, and CreateDynamic3DTextLabel convert UTF-8 data into the player's charset, ensuring proper display.

Client-to-server functions like OnText, OnPlayerCommandText, and OnDialogResponse also undergo charset conversion, ensuring correct data exchange.

TIP

Despite charset conversion, UTF-8 characters not present in the player's charset will still appear garbled (e.g., as ?). This is a limitation of the original SA client's underlying code. For example, an ISO-8859-1 client receiving emoji or Chinese characters will display garbled text.

For GameText/TextDraw, Infernus does not apply the per-player charset conversion. These two APIs encode the text with the charset you pass to them — win1252 by default for GameText, ISO-8859-1 for TextDraw — and the client picks glyphs from its font texture by byte value (similar to CSS sprites in frontend development) instead of decoding the bytes as text. Some client mods (e.g., Chinese language patches) replace the font and expect UTF-8 bytes, in which case pass charset: "utf8".

Russian works the same way from the other side. A russifier is a Russian localization mod the player installs on their own client; it redraws the game's font, putting Cyrillic letters into the slots the original font reserves for accented Latin characters. @infernus/rustext supplies the server half, rewriting the outgoing GameText, TextDraw and Menu RPC text so that cp1251 bytes land on that mod's glyph slots. Pass charset: "cp1251" explicitly — the defaults above turn Cyrillic into ? before the package can convert anything — and set the RussifierType that matches the pack the player actually installed, since the packs lay the letters out differently (SanLtd is the default, alongside OneC, Rush, MG and others). The package ships no russifier assets. Text sent to all players (GameText.forAll) carries no player id and is not converted.

The SA Definitive Edition uses UTF-8 internally. If OMP adds online support for it in the future, no additional handling should be needed.

Terminal Garbled Characters ​

If you encounter garbled characters in the terminal when using logging libraries like pino.js, try one of the following solutions.

For PowerShell users, run the following command (effective for the current session only).

To make the change permanent, add the command to your $PROFILE.

powershell
$OutputEncoding = [Console]::InputEncoding = [Console]::OutputEncoding = New-Object System.Text.UTF8Encoding

For cmd users, use the following command to start your OMP server:

sh
cmd /c "chcp 65001 > nul & omp-server"

These commands change the terminal charset to UTF-8.

For other environments, please search for solutions on your own.