GT JSX 数据格式

General Translation 精简版 JSX 数据格式参考

GT JSX 数据格式是 General Translation 库用于在 React 应用中表示已翻译 UI 的精简数据格式。

介绍:JSX 树

React 将 JSX 树表示为具有以下结构的对象:

type Element = {
    type: string;
    props: {
        children: JSXTree[] | JSXTree;
        // …其他 props
    };
    // …其他属性
};
type JSXTree = Element | string;

GT JSX 是该 JSX 树结构的压缩表示形式,供 General Translation 库在你的 React 应用中用来呈现已翻译的 UI。

参考资料

type Element = {
    t?: string; // 标签名
    c?: (Element | Variable | string)[]; // children(子内容)
    i?: number; // 元素的 GT ID
    d?: {
        b?: Record<string, Element | Variable | string>; // 分支
        t?: "p" | "b"; // 分支转换类型(复数或分支)
        pl?: string; // 占位符
        ti?: string; // 标题
        alt?: string; // alt 文本
        arl?: string; // aria-label
        arb?: string; // aria-labelledby
        ard?: string; // aria-describedby
        s?: Record<string, string>; // 样式
    };
}
type Variable = {
    k: string; // 键
    v?: "v" | "n" | "c" | "d"; // 类型
    i?: number; // GT ID
}
type GTJSXTree = Element | Variable | string | (Element | Variable | string)[];

GT JSX:字符串

GT JSX 的最简单形式是字符串,用于表示一段静态文本。

例如:

<T>你好,世界!</T>

在 GT 的 JSX 中表示为:

“你好,世界!”

字符串数组也可作为有效的 GT JSX:

["你好,", "世界!"]

GT JSX:元素

GT 以两种方式表示 JSX 的 Element 类型。

变量

首先是变量,它是一个包含键和可选类型的简单对象,用于表示在运行时可能变化的值。

type Variable = {
    k: string; // `k` 表示键,即变量的名称
    v?: ( // 表示变量的类型;若省略,则默认为 `v`
        "v" | // `v`,通用变量
        "n" | // `n`,数值变量
        "c" | // `c`,货币变量
        "d" // `d`,日期时间变量
    );
    i?: number; // 变量的 GT ID
}

示例 1:Var

<T>您好,<Var>{name}</Var>!</T>

在 GT 的 JSX 中表示为:

["你好,", { k: "_gt_var_1", i: 1 }, "!"]

未包含 name 属性的变量会基于其 GT ID 被分配唯一的内部名称

示例 2:Num

<T>计数是 <Num>{count}</Num></T>

在 GT 的 JSX 中表示为:

["当前计数为 ", { k: "count", v: "n", i: 1 }]

示例 3:使用 name 属性

<T>该产品售价为<Currency name="cost">{amount}</Currency></T>

在 GT 的 JSX 中表示为:

["该产品售价为", { k: "cost", v: "c", i: 1 }]

元素

非变量元素使用以下数据结构表示:

请注意,这些属性均为可选。 一个空对象表示在与其原始对应元素相同位置的已翻译元素,其后代中不包含任何可翻译内容。 在实际使用中,始终会包含 i

type Element = {
    t?: string; // 标签名
    c?: GTJSXTree | GTJSXTree[]; // children(子内容)
    i?: number; // 元素的 GT ID
    d?: { // data-_gt 属性
        b?: Record<string, GTJSXTree | GTJSXTree[]>; // 分支
        t?: "p" | "b"; // 分支转换类型(复数或分支)
        pl?: string; // 占位符
        ti?: string; // 标题
        alt?: string; // alt 文本
        arl?: string; // aria-label
        arb?: string; // aria-labelledby
        ard?: string; // aria-describedby
        s?: Record<string, string>; // 样式
    }
}

示例 1:简单标记

<T>你好,<b>世界</b>!</T>

在 GT 的 JSX 中表示为:

["你好,", { c: "世界", i: 1 }, "!"]

示例 2:嵌套与变量

<T><b>你好</b>,我的名字是<i><Var>{name}</Var></i></T>

在 GT 的 JSX 中表示为:

[
    { t: "b", c: "你好", i: 1 },
    ",我叫",
    { 
        t: "i",
        c: { k: "_gt_var_3", i: 3 }, 
        i: 2 
    }
]

示例 3:带复数

<T>
    <Plural 
        n={count} 
        one={<>我有 <Num>{count}</Num> 个物品</>} 
        other={<>我有 <Num>{count}</Num> 个物品</>}
    />
</T>

在 GT 的 JSX 中表示为:

{ 
    i: 1,
    d: {
        t: "p",
        b: {
            one: {
                c: ["我有", { k: "_gt_num_4", v: "n", i: 3 }, "个条目"],
                i: 2 
            },
            other: {
                c: ["我有", { k: "_gt_num_4", v: "n", i: 3 }, "个条目"],
                i: 2 // 注意:并行分支使用相同的ID
            }
        }
    }
}

GTJSX 类型

type GTJSXTree = Element | Variable | string | (Element | Variable | string)[];

GT ID

GT ID 会按深度优先的顺序依次分配给 JSX 树中的元素和变量,起始编号为 1。

当存在诸如 <Branch><Plural> 等分支组件时,并行分支会被赋予相同的 GT ID。这样即使某种语言的分支数量多于另一种(例如某些语言有更多复数形式),也仍然可以创建具有正确 props 和逻辑的元素。

GT JSX JSON 文件

每棵 JSX 树表示一个 <T> 组件的 children。 这些组件会统一存放在用于翻译的 JSON 文件中。 这些文件中存放的 JSON 对象类型对应如下:

type GTJSXFile = {
    [key: string]: GTJSXTree;
}

其中,key 可以是用户自定义的,或是原始语言 GTJSXTree 的哈希;而 GTJSXTree 指的是上文所述的 GT JSX 树类型。

完整示例

编写的 JSX:

<T>
    <b>Alice 的</b> 开心的 <i>顾客</i>
</T>

将表示为下述 JSX 树:

[
    {
        type: "b",
        "props": {
            "children": "Alice 的"
        }
    },
    " 开心的 "
    {
        type: "i",
        "props": {
            "children": "顾客"
        }
    }
]

这将被压缩为 GT 的 JSX:

[{ t: "b", c: "Alice 的", i: 1 }, " 满意的 ", { t: "i", c: "顾客", i: 2 }]

将其翻译成西班牙语后,GT JSX 将为:

[{ c: "客户", i: 2 }, " 很高兴地 ", { c: "Alice 的", i: 1 }]

它将被存储在如下所示的文件中:

{ "abc123": [{ "c": "这位客户", "i": 2 }, " 很开心 ", { "c": "Alice 的", "i": 1 }] }
abc123 是原始英文 GT JSX 树的哈希,而非西班牙语译文的哈希。

当西班牙语译文与原始 JSX 树对齐后,将得到如下结果:

[
    {
        type: "i",
        "props": {
            "children": "客户"
        }
    },
    " 开心的 "
    {
        type: "b",
        "props": {
            "children": "Alice的"
        }
    }
]

随后即可按预期的界面呈现:

<><i>客户</i><b>Alice 的</b>很满意</>

哈希

哈希算法与哈希长度:待定

避免在运行时计算哈希

为避免在运行时计算哈希,这些库提供了一种可选的fallback机制,用户可以指定一个id。

<T id="example">
    你好,世界
</T>

如果翻译 JSON 文件中存在该 id,则会优先使用它而非哈希值。

{ "example": "你好,世界" }

这份指南怎么样?

GT JSX 数据格式