Skip to content

国际化

Infernus 的国际化核心在于字符集编码转换,而非多语言翻译。虽然 $t 可以用于翻译需求,但核心功能是确保服务端(UTF-8)与玩家客户端(旧式字符集如 ISO-8859-1GBK)之间的数据交换正确。大多数服务器仅服务于单一区域,因此您可能完全不需要多语言支持——但至少应了解玩家国际化部分,以避免乱码问题。

VSCode 插件

infernus-starter 中的 .vscode/extensions.json 提供了插件安装建议。强烈建议您在 VSCode 右下角弹出提示时点击安装,以便在开发时直观地查看国际化数据。

i18n-ally-custom-framework.ymlsettings.json 已为您配置好相关插件设置。

示例

定义语言包

语言包由 .json 文件组成,以树形结构作为语言包数据的 key

字符串中可以包含 %s 作为占位符,用于动态填充数据。

中文语言包

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

英文语言包

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

实例化

通过 new I18n("默认区域 key", 语言包对象) 创建国际化实例。

通常我们只需使用内部的 $t 函数。

$t("语言包数据 key", [占位数组], 区域 key) 可获取对应区域的语言包文本。

当字符串没有占位符时,可传入 nullundefined 或空数组。

不传入第三个参数则从默认区域获取数据。

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

// 国际化的 JSON 语言包
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"));

实用函数

I18n 类还提供了几个实用的静态方法,用于字符集之间的转换:

  • encodeToBuf
    • 将字符串转换为指定字符集的字节数组。
  • decodeFromBuf
    • 将字节数组转换为指定字符集的字符串。
  • getValidStr
    • 截取字节数组中的有效字符串,以第一个 0 字节作为字符串结尾标记。

玩家国际化

每个玩家实例上有两个属性控制国际化:charset(字符集)和 locale(区域)。默认值如下:

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

通常 $t 会结合玩家的区域来获取对应的语言包数据。

ts
// 假设您有一个 player 实例
console.log($t("server.incoming", ["127.0.0.1", "8080", "123456"], player.locale));

如需修改玩家的语言或字符集,请修改 charsetlocale 属性,并始终确保 charset 正确。您可以根据 IP 地址推测玩家区域,或让玩家输入特定字符串后比对字节来推断字符集。

允许国际化用户名

TIP

默认情况下,游戏服务器只允许英文字母、数字和下划线组成的用户名连接。

OMP 提供了新的 API,可启用或禁用用户名中的特定字节值(0–255)。

GameMode.supportAllNickname() 方法利用这些 API,允许所有国际化的用户名(包括中文等非 ASCII 字符)连接游戏。

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

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

原理

WARNING

双向字符集数据交换正常的前提是玩家的字符集设置正确。

如果设置了错误的字符集,服务端和客户端双方都将得到乱码。

Infernus 底层使用 iconv-lite 进行字符集转换,并通过 polyfill.amx 拦截 gamemode 中的部分回调,以十进制字节数组形式返回。

服务端向客户端的函数(如 SendClientMessageSendClientMessageToAllShowPlayerDialogCreateDynamic3DTextLabel)进行了字符集转换,将 UTF-8 数据转为玩家字符集数据,确保玩家能正常显示。

客户端到服务端的函数(如 OnTextOnPlayerCommandTextOnDialogResponse)同样经过了字符集转换,确保数据交换正确。

TIP

虽然字符集已转换,但玩家字符集中不包含的 UTF-8 字符仍会以乱码(如 ?)形式显示,这是早期 SA 客户端的底层限制。例如,使用 ISO-8859-1 字符集的客户端收到 emoji 或中文字符时就会显示为乱码。

对于 GameText/TextDrawInfernus 底层始终以 UTF-8 格式交换数据,因为这两个功能基于贴图映射实现(类似于前端中的精灵图),而非真正的文本渲染。部分客户端模组(如汉化补丁)底层使用了 UTF-8 渲染,但将所有 UTF-8 字库放入一张贴图中是不现实的,效果也无法与文本数据相比。

SA 重制版内部使用 UTF-8 实现,如果未来 OMP 推出重制版的联机功能,应无需额外处理。

终端乱码

如果使用 pino.js 等日志库时终端出现乱码,可尝试以下方法解决。

PowerShell 用户请执行以下命令(仅对当前会话有效)。

如需永久生效,请将该命令添加到 $PROFILE 中。

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

cmd 用户可使用以下命令启动 OMP 服务器:

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

上述命令会将终端的字符集切换为 UTF-8。

其他环境请自行搜索解决方案。