国际化
国际化是 Infernus
很重要的核心功能。即使您在开发脚本过程中不考虑,您也至少需要了解玩家国际化部分,否则您可能遇到乱码等常见情况。
VSCode 插件
infernus-starter 中的 .vscode/extensions.json
提供了插件安装建议文件,十分建议您在打开 VSCode
的右下角的提示里点击安装,这样您可以方便的在开发时直观的查看国际化数据。
i18n-ally-custom-framework.yml
和settings.json
已经为您设置好了该插件相关的配置文件。
基本示例
语言包定义
语言包由.json
文件的数据组成,以树形结构作为语言包数据 key
。
定义的字符串数据可以含有%s
作为占位关键字,用于填充数据。
中文语言包
{
"server": {
"running": "成功运行由 node.js 强力驱动的 omp 服务器",
"connection": "连接信息: %s - %s : %s"
}
}
英文语言包
{
"server": {
"running": "Successfully running an omp server powered by node.js",
"connection": "connection information: %s - %s : %s"
}
}
实例
通过new I18n("默认区域key", "语言包")
得到一个国际化示例。
通常我们只需要用到内部的 $t
函数。
$t("语言包数据key", [占位数组], 区域key)
可以得到对应的语言包里的文字。
当字符串没有占位时可以不传入占位数组,以 null
或 undefined
或空数组代替。
不传入第三个参数意味着从默认区域取数据。
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
,分别对应字符集和区域。 默认值如下:
class Player {
charset = "ISO-8859-1";
locale = "en_US";
}
通常$t
会结合玩家的区域来得到对应的语言包数据。
// 假设您有一个player实例
console.log(
$t("server.incoming", ["127.0.0.1", "8080", "123456"], player.locale),
);
您要修改玩家的语言或是字符集,则应该修改玩家的 charset
和 locale
属性,请始终确保玩家的 charset
是正确的,您可以采用 ip
地址推测玩家区域,让玩家输入特定字符串然后比对字节来推算是什么字符集。
允许国际化用户名
TIP
默认情况下游戏服务器仅允许英文字母,数字和下划线的用户名连入游戏。
由于 omp
提供了一些新的 api
,可以禁用/启用某些字符(十进制字节 0-255)用户名连入服务器。
GameMode.supportAllNickname()
方法就利用了新的 api,让所有国际化的用户名包括中文字符等任意字符的玩家用户名连入游戏。
import { GameMode } from "@infernus/core";
GameMode.onInit(({ next }) => {
GameMode.supportAllNickname();
return next();
});
原理
WARNING
双向字符集数据交换都正常的前提是玩家的字符集是正确的。
如果设置了错误的字符集,对于服务端和客户端而言双方得到的都是乱码。
Infernus
底层采用 iconv-lite
对字符集进行转换,通过 polyfill.amx
拦截 gamemode
中的部分回调以十进制字节数组返回。
服务端向客户端侧SendClientMessage
,SendClientMessageToAll
,ShowPlayerDialog
,CreateDynamic3DTextLabel
等函数进行了字符集转换处理,即 utf8
数据转换为玩家的字符集数据,以确保玩家能正常显示数据。
又做了 OnText
,OnPlayerCommandText
,OnDialogResponse
等客户端到服务端侧的字符集转换处理,以保证服务端和客户端的数据交换是正确的。
TIP
虽然字符集转换了,但对于玩家的字符集中不含有的 utf8
字符,仍然会以乱码,比如?
的形式显示,这受限于早期的 sa
游戏底层代码。比如只有西方字体的字符集 ISO-8859-1
接收到 emoji
图标或中文汉字就会乱码。
对于 GameText/TextDraw
,Infernus
底层始终以 utf8
格式作为数据交换,因为这两个的实现方式基于已有的贴图文件的算法,它类似于前端中的精灵图的概念,而不是真正意义上的文字数据。一些客户端模组比如汉化补丁,底层使用了 utf8
,可以实现显示常用字,但不能把所有的 utf8
字库都列在一个贴图里,这样非常不合理,效果也肯定不如文本数据实现。
对于 sa
重制版而言,内部一定是采用 utf8
实现的,如果未来的某一天 omp
推出了重制版的联机则应当不需要额外处理。
终端乱码
如果您在使用 pino.js
等日志库时,终端打印乱码,可以尝试以下方式解决。
对于PowerShell
,请执行下面的命令(仅当前终端生效)。
如果你想永久生效,请将命令加入到 $PROFILE 中。
$OutputEncoding = [Console]::InputEncoding = [Console]::OutputEncoding = New-Object System.Text.UTF8Encoding
如果您使用的是 cmd
,请使用下方命令来运行 omp
服务器。
cmd /c "chcp 65001 > nul & omp-server"
上述命令会修改 PowerShell
或 cmd
的字符集为utf8
。
其他环境,请自行搜索解决方案。