Bilibili-Evolved/utils/i18n/i18n.md
2019-05-23 19:45:01 +08:00

255 lines
7.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 翻译指南
翻译程序能够将特定的文本替换成您的翻译, 作用范围为网页中所有文本节点(`nodeType === Node.TEXT_NODE`), 文本框的提示文字(`placeholder`), 以及鼠标停留时弹出的提示文字(`title`).
## 文件目录
- `i18n.css` 界面元素调整样式
- `i18n.js` 主程序
- `i18n.ts` 主程序(TypeScript)
- `i18n.ja-JP.js` 日语翻译
- `i18n.en-US.js` 英语翻译
- `i18n.de-DE.js` 德语翻译
- `i18n.md` 本说明文档
即翻译文本均存放在`i18n.[ISO语言代码].js`中.
## 添加翻译文本
1. 用代码编辑器打开相应的翻译文件, 以英语为例, 则打开`i18n.en-US.js`.
2. 文件结构大致为:
```js
export const map = new Map([
/* Your translation here */
[`*`, [
/* CSS translation here */
]],
]);
export const regex = new Map([
/* Regex translation here */
]);
export default {
export: { map, regex },
};
```
3. 在`/* Your translation here */`上方添加翻译, 或在`/* CSS translation here */`上方添加选择器翻译, 在`/* Regex translation here */`上方添加正则翻译, 详细语法见下一节.
## 翻译语法
有多种翻译方式可供选择.
### 直接翻译
格式为``[`原文本`,`翻译后文本`],``.
例如, 将`主站`翻译为`Home`, 则添加:
```js
[`主站`, `Home`],
```
添加后的文件大致如下:
```js
export const map = new Map([
/* 其他翻译... */
[`主站`, `Home`],
]);
export default {
export: { map },
};
```
### 特殊翻译
可以为特定元素的文本特别指定一种翻译, 通常用于特殊语境下词语的翻译, 但是需要翻译者对[CSS](https://developer.mozilla.org/zh-CN/docs/Glossary/CSS)的[选择器语法](https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_Selectors)有一定了解.
格式为:
```js
[`原文本`, {
selector: `CSS选择器`,
text: `翻译后文本`,
}],
```
例如:
```js
[`主站`, {
selector: `.xxx.yyy`,
text: `Home2`,
}],
```
将在文本所属节点匹配`.xxx.yyy`选择器时, 将`主站`翻译为`Home2`.
按照上面的例子, 以下的元素
```html
<a class="xxx yyy">主站</a>
<a class="zzz">主站</a>
```
将翻译为
```html
<a class="xxx yyy">Home2</a>
<a class="zzz">主站</a>
```
如果希望**不匹配**选择器的文本接受翻译, 只需添加一行`not,`:
```js
[`主站`, {
not,
selector: `.xxx.yyy`,
text: `Home2`,
}],
```
这样, 所有**不匹配**这个选择器的文本都将被翻译.
### 混合翻译
可以组合以上两种翻译方式, 为同一词语使用多种翻译.
格式为:
```js
[`原文本`, [
`直接翻译`,
{
selector: `CSS选择器1`,
text: `特殊翻译1`,
},
{
selector: `CSS选择器2`,
text: `特殊翻译2`,
},
]],
```
即存放翻译文本的地方改成一个数组`[]`, 其中存放多种翻译, 用逗号`,`隔开每一项.
- 直接翻译只能有一个, 而特殊翻译可以有多个.
- 越在后面的特殊翻译优先级越高, 如果一个元素同时满足两种翻译里的选择器, 程序会使用较后面出现的翻译.
- 程序其实不会检查直接翻译到底有几个, 要是真的有多个, 只有最后一个出现的直接翻译被采用.
例如以下混合翻译:
```js
[`主站`, [
`Home`,
{
text: `Home2`,
selector: `.xxx.yyy`
},
]]
```
能够将
```html
<a class="xxx yyy">主站</a>
<a class="zzz">主站</a>
```
翻译为
```html
<a class="xxx yyy">Home2</a>
<a class="zzz">Home</a>
```
### 使用选择器翻译
当原文本很长或很复杂时, 放在翻译文件里会影响易读性, 这时可以用CSS选择器选择该节点进行翻译. 这种翻译统一放在原文本为`*`的一节翻译中.
> ⚠ 这种翻译方式不管原文本是什么, 只要匹配了选择器就执行翻译.
格式为:
```js
[`*`, [
{
selector: `CSS选择器1`,
text: `翻译文本1`,
},
{
selector: `CSS选择器2`,
text: `翻译文本2`,
},
]],
```
例如以下选择器翻译:
```js
[`*`, [
{
selector: `.xxx.yyy`,
text: `Home3`,
},
]]
```
能够将
```html
<a class="xxx yyy">very very long text very very long text very very long text very very long text very very long text</a>
```
翻译为
```html
<a class="xxx yyy">Home3</a>
```
### 使用正则翻译
当原文本包含一段不确定内容时, 可以使用正则翻译来匹配, 需要翻译者对正则表达式有一定了解. 这种翻译放在这一区域: (`export const regex`)
```js
export const regex = new Map([
/* Regex translation here */
]);
```
例如, 要将`浏览23.3w`翻译为`Read: 23.3w`, 则添加:
```js
[/浏览:([0-9\.a-z])/, `Read: $1`],
```
第一个元素是正则表达式, 用一对斜杠(`/`)包围, 语法可在[MDN文档](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions)中学习. 第二个元素是替换文本. 在这个例子中, `$1`指代原文本中的浏览量数字, 利用了正则表达式的分组功能, 详见文档中的["使用括号的子字符串匹配"](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions#%E4%BD%BF%E7%94%A8%E6%8B%AC%E5%8F%B7%E7%9A%84%E5%AD%90%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%8C%B9%E9%85%8D_2)一节.
## 调整界面元素
一些界面元素的尺寸是固定大小, 如果添加翻译后, 无法适应翻译后的文本长度, 可以在`i18n.css`中添加CSS样式来调整.
## 示例翻译文件
此文件简单展示了一下每一种翻译方式. 其中所有的CSS选择器和翻译文本仅作示例使用, 并不代表实际情况.
```js
export const map = new Map([
[`主站`, `Home`], // 直接翻译
[`大会员`, { // 特殊翻译, 只有匹配.aaa的元素会被翻译
selector: `.aaa`,
text: `VIP`,
}],
[`关注`, [ // 混合翻译:
`Follow`, // 直接翻译, 适用于"关注"的动词形式
{ // 特殊翻译, 适用于"关注"的名词形式
selector: `.bbb`,
text: `Following`,
},
]],
/* Your translation here */
[`*`, [ // 选择器翻译
{ // 选择匹配.xxx的元素, 翻译为XXX
selector: `.xxx`,
text: `XXX`,
},
{ // 选择匹配.xxx的元素, 翻译为YYY
selector: `.yyy`,
text: `YYY`,
},
/* CSS translation here */
]],
]);
export const regex = new Map([
[/(\d+)次播放/, `Played $1 times`],
/* Regex translation here */
]);
export default {
export: { map, regex },
};
```
该文件能够将类似以下的网页内容
```html
<a class="home1">主站</a>
<a class="home2">主站</a>
<a class="aaa">大会员</a>
<a class="aaaa">大会员</a>
<a class="bbb">关注</a>
<a class="ccc">关注</a>
<a class="xxx">其他</a>
<a class="yyy">其他</a>
<a class="zzz">其他</a>
<a>233次播放</a>
```
翻译为
```html
<a class="home1">Home</a>
<a class="home2">Home</a>
<a class="aaa">VIP</a>
<a class="aaaa">大会员</a>
<a class="bbb">Following</a>
<a class="ccc">Follow</a>
<a class="xxx">XXX</a>
<a class="yyy">YYY</a>
<a>Played 233 times</a>
```