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 always exchanges data in UTF-8 format, because these features are implemented through glyph mapping (similar to CSS sprites in frontend development) rather than actual text rendering. Some client mods (e.g., Chinese language patches) use UTF-8 rendering underneath, but it's impractical to map all UTF-8 glyphs into a single texture.

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.