文档手册

Internalization Support

2024-07-18 14:45:58

Internalization support in Sciter's JSX...

Sciter 为 JSX 文本翻译提供了内置的、零运行时成本的机制。

Current state of affairs of i18n support in ReactJS.

请考虑以下使用 JSX 文本的函数:

render() {
return <caption>Settings</caption>;
}

这绝对是翻译成其他语言的主题。

理想情况下,在俄语版本的应用程序中,函数应如下所示:

render() {
return <caption>Настройки</caption>;
}

这里的“理想情况下”意味着应用程序的英语和俄语版本将以相同的速度和 CPU 负载运行。每次我们执行 render() 函数时,无论我们使用哪种语言,我们的 JavaScript VM 都将以完全相同的运行时成本加载和输出字符串文字。

但实际上翻译会增加运行时成本,例如,在 React-i18n 中,我们可能会看到这样的建议:

render() {
return <caption>{t('Settings')}</caption>;
}

请注意,每次调用 render() 它时,它都会 a) 调用全局 t() 函数,该函数将执行 b) 在某些转换表中查找“设置”键以替换字符串。

(a)和(b)显然都具有非零运行时成本。通常,同时执行两个步骤都不是问题,但是如果您有动态UI怎么办?在每次渲染时,它都会执行相同的查找步骤 - 不好,只是浪费 CPU 资源。

为了解决这个问题,Sciter 提供了 mechansim,其中查找只会发生一次 - 在 JS 编译阶段 - 稍后的 render() 调用将使用已经翻译的字符串文字。

Static translation markers

Literal strings to translate

为了在 JS 源代码中将字符串文字定义为可翻译的,在字符串文字前面加上 @ 符号:

const title = @"Meeting preferences";

在解析此类文字时,Sciter 运行时将调用 JSX_translateText(text) 翻译钩子函数,并将其 resuslt 作为字符串文本放入字节码中。

所谓的 translationID,即翻译表中文本的唯一标识符,将设置为文本内容 - "Meeting preferences" 在本例中。

Parametrized literal strings to translate

语言可能因短语中的单词顺序而异。一种可能的处理方法是使用参数化格式字符串,例如:

const greeting = @"Hello %1%, today is %2%".format(name,date.toLocaleDateString());

在这种情况下 JSX_translateText() ,将使用 "Hello %1%, today is %2%" 字符串调用。例如,对于俄语翻译,它可能会返回 "%1%, привет, сегодня %2%" 。使用的格式化字符串将是 "Вася, привет, сегодня 31.02.2021"

请注意,使用上面的非标准 format 字符串方法,您可以在源代码中定义为:

String.prototype.format = function(...values) {
return this.replace(/%([0-9]+)%/g, (match, index) => values[index - 1] ?? match );
};

JSX attribute to translate

为了定义作为翻译主题的 HTML 属性,在其名称前面加上 @ 符号并提供初始值:

<button @title="Meeting preferences">Show preferences</button>

在解析此类属性时,Sciter 运行时将调用 JSX_translateText(text) 翻译钩子函数,并将其 resuslt 作为字符串文本放入字节码中。最后,DOM 元素将转换 title 属性且不带 @ 标记。

所谓的 translationID,即翻译表中文本的唯一标识符,将设置为初始属性文本 - "Meeting preferences" 在本例中。

JSX text to translate

为了将 DOM 元素标记为可翻译的,请放置标准 @ 符号或 @name 其属性:

<button @>Show preferences</button>

在解析此类元素时,Sciter 运行时将调用 JSX_translateText(text) 翻译钩子函数,并将其 resuslt 作为字符串文字(文本)放入字节码中。该文本将出现在最终的 DOM 中。

在这种情况下,TranslationID 将是原始元素的文本,或者(如果 @name 使用标记)名称。

JSX text span to translate

有时我们只需要翻译文本的一部分。在这种情况下,我们可以使用“可翻译片段”标记:

render() {
return <caption><@>Hello</>, {userName}!</caption>;
}

<@>...</> 标志着文本片段是可翻译的。该片段将是其翻译 ID。

Dynamic translation markers

在某些情况下,我们需要更复杂的翻译处理,而不仅仅是静态大小写。考虑我们需要输出一些像瓶子计数器一样的东西:

render() {
return <span @>{n} bottles</span>;
}

理想情况下,我们应该有这样的输出:“没有瓶子”、“1 瓶”、“2 瓶”......在一般情况下,我们不能只用静态表来处理这样的结构——数字规则 a) 在不同的语言中是不同的,b) 可能非常复杂,c) 在不同的上下文中可能不同。

在这种情况下,唯一的选择是将此类逻辑实现为函数。在这种情况下,Sciter 运行时将调用 JSX_translateNode(node) 翻译钩子函数。

Sciter translation hooks

转换钩子是自定义函数,需要在应用程序端定义以支持转换。

JSX_translateText()

调用以转换静态文本 - 属性值或元素的文本:

JSX_translateText = function(text, context, type) {
...
}

 参数:

  • text - 字符串,要翻译的文本;

  • context - 字符串,对于属性,它是属性的名称,对于元素,它是标签名称;

  • type - int,0 - 它是一个属性,1 - 元素的文本,2 - 字符串文字

该函数应返回一个字符串 - 转换的结果。

JSX_translateNode()

用于翻译动态文本,例如将某些数值复数化:

JSX_translateNode = function(node, translationId) {
...
}

 参数:

  • node - 虚拟 DOM 节点,3 元素元组:[“tag”,{attributes},[children]];

  • translationId - 字符串,内容字符串如“{} bottles”或显式 ID,如 “nbottles” <span @nbottles>{n} bottles</span>

该函数应返回虚拟 DOM 节点 - 转换结果。用于 JSX(tag,{...},[...]) 返回转换后的虚拟 DOM 元素。

Translation environment variables

这些全局变量在钩子函数JSX_translateXXX可用:

JSX_translationFileName

string,源脚本文件的 URL。

JSX_translationlineNo

整数、字符串或 JSX 文本的行号。

JSX_translationContext

字符串,翻译上下文。翻译上下文在源代码中由第一个位置有 @ 符号的注释定义,例如:

/*@Host meeting*/
let text = @"Host";

在这种情况下 JSX_translateText() ,将调用为 JSX_translateText("Host") 函数 JSX_translationContext 变量,并且函数内部变量将具有 "Host meeting" 值。

注意:有些单词在不同的上下文中可能有不同的翻译,因此需要一些澄清才能正确翻译。例如,“主持人”可以是名词,例如“主机”,也可以是动词,如“主持会议”。

JSX_translateTags

这是默认情况下需要翻译的标签映射 - 没有翻译标记。

 例:

JSX_translateTags = {
 "caption": true,
 "label": true,
 "button": true,
 "span": true,
};

Declaring translation hooks

在加载构成应用程序其余部分的脚本之前,需要定义转换钩子。原因:钩子应存在于使用其服务的脚本的解析/编译时。

 可能的情况:

In different script sections:

 <head>
<script type="module" src="i18n/hooks.js" />
<script type="module" src="application/main.js" />
</head>

第一个脚本将安装钩子,第二个脚本是应用程序的主根脚本。

Framed application:

 <head>
<script type="module" src="i18n.js" />
</head>
<body>
<frame lang="en" src="application.htm" />
</body>

这种设置允许在运行时切换 UI 语言。若要更改 UI 语言i18n.js脚本应:

  1. 加载相应的转换表;

  2. frame 元素上的 set lang 属性(可选);

  3. 在框架中重新加载“application.htm” - 脚本将被重新加载,因此使用新翻译重新编译;

Instrumental hooks

应用程序可以定义钩子的工具版本,以生成所需格式的翻译表原型:JSON、PO(gettext 格式)等。