PKU harness

多语言(i18n)

内置插件怎样同时提供中文和英文。清单里的文字在 `i18n.en` 里写英文版,页面和小组件的文字放进 `defineStrings` 表,日期交给 SDK 的格式化函数,给模型看的文字不翻译。

App 支持简体中文(zh-Hans)和英文(en)。中文是源语言:每个字符串先用中文写,再补上英文版。用户在设置里选择「跟随系统」「简体中文」或「English」。

每个内置插件(bundled plugin)都必须把两种语言写全。插件仓库里的测试 plugins/i18n.test.ts 会逐个检查插件,缺少英文字符串就会失败。本页讲的是内置插件。插件文档的英文文字全部写在清单的 i18n.en 部分(见声明式插件)。

哪些要翻译

给人看的文字要翻译。只给模型看的文字,比如工具描述和插件说明,只写一份,不翻译。

文字位置是否翻译
插件 name、descriptiondefinePlugin(中文)+ i18n.en是
工具 titletools.<name>.title + i18n.en.tools.<name>.title是
工具 summary(仅插件文档)工具文件里的 summary + i18n.en.tools.<name>.summary是
小组件标题和描述contributes.widgets + i18n.en.widgets是
页面标题contributes.screens + i18n.en.screens是
设置项contributes.settings + i18n.en.settings.<screen>是
快捷指令contributes.commands + i18n.en.commands.<name>(description、argHint、aliases、prompt)是
数据源标题dataSources + i18n.en.dataSources是
模型服务商名称、提示、模型名providers + i18n.en.providers是
页面和小组件里的文字src/strings.ts(defineStrings)是
工具 description、instructions、context、工具结果给模型看否

清单的英文版本

中文字符串照常写在 definePlugin 里,英文版写在 i18n.en 里。下面的例子来自 shuttle 插件:

definePlugin({
  id: 'shuttle',
  name: '校车',
  description: '燕园—新燕园(昌平)通勤班车和新燕园—地铁北安河快速公交时刻表,算出下一班车。',
  i18n: {
    en: {
      name: 'Shuttle bus',
      description: 'Timetables for the Yanyuan–Xinyanyuan (Changping) commuter shuttle and the Xinyanyuan–Bei’anhe metro express bus, with the next departure worked out for you.',
      tools: { next: { title: 'Next shuttle' }, timetable: { title: 'Shuttle timetable' } },
      widgets: { next: { title: 'Next shuttle', description: '…' } },
      commands: { shuttle: { description: 'Next shuttle (works offline)', argHint: 'e.g. Yanyuan to Xinyanyuan', aliases: ['bus'] } },
      dataSources: { next: { title: 'Next shuttle' } },
    },
  },
  // …
});

运行时,en 里缺少的字段会回退到中文。但覆盖测试仍会失败,所以请全部填上。

字符串表

页面和小组件里的文字放在字符串表里,每个插件一张,位于 src/strings.ts。先用类型定义一次所有的键,再为每种语言分别给出值:

src/strings.ts
import { defineStrings } from '@pku-harness/sdk';

type Strings = {
  none: string;
  later: (list: string) => string;
};

export const strings = defineStrings<Strings>({
  'zh-Hans': { none: '今明两天没有班次', later: (list) => `之后 ${list}` },
  en: { none: 'No buses today or tomorrow', later: (list) => `Then ${list}` },
});
const s = strings[host.useLocale()];
<Text>{s.none}</Text>

在组件里,用 host.useLocale() 选出用户所用语言的那张表。

defineStrings 会拿 en 和 zh-Hans 做类型检查:两者的键必须相同,值的类型也必须相同。带参数的字符串写成函数。不要把翻译好的片段拼接成句子,因为两种语言的语序不同。

日期和数字

App 运行在 JavaScript 引擎 Hermes 上,而 Hermes 会忽略 Intl 的语言设置,toLocaleDateString 之类的函数因此会给出错误的格式。请改用 SDK 提供的格式化函数,其中大多数接收来自 host.useLocale() 的语言参数 l:

函数zh-Hansen
formatClock(d)21:0421:04
formatWeekday(d, l)周一Mon
formatLocalDate(d, l)10月18日Oct 18
formatLocalDateTime(d, l)10月18日 21:04Oct 18, 21:04
formatRelative(ms, l)刚刚, 3 分钟前, 昨天 21:04Just now, 3 min ago, Yesterday 21:04
formatDay(d, l)今天, 明天, 周三Today, Tomorrow, Wed
formatCountdown(ms, l)2小时10分2h 10m
plural(n, one)—1 book, 3 books

详见 SDK → format。

英文文案规范

覆盖测试还会检查英文字符串的写法:

  • 除了括号里的注释和引号内的内容,不能出现中文。Treehole (树洞) 是可以的。
  • 用弯撇号(’),不用直撇号(')。
  • 不用感叹号。
  • 简短,并使用句首大写(sentence case),即只有第一个单词和专有名词首字母大写。校园专有名词用官方英文名或拼音:Peking University、Treehole (树洞)、Course (教学网 / Blackboard)、Campus Card。

中文文字也一样:写得简短,不用感叹号。

本页目录