> For the complete documentation index, see [llms.txt](https://docs.ipcheck.ing/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.ipcheck.ing/developer/zh-tw/contributing/translating.md).

# MyIP 翻譯

將 MyIP 帶入你的語言：一個指令即可建立語系套件，部分翻譯則是很受歡迎的第一個拉取請求。

MyIP 的介面以多種語言提供——應用程式內的語言選擇器是權威且永遠最新的清單。新增下一個語言只需要 **一個語系包加上一行登錄項目**。你不需要懂 Vue，不需要碰任何元件，也不需要在開啟 pull request 之前把所有內容都翻完。

{% hint style="success" %}
**快速解答：** fork，從以下分支建立分支： `dev`，執行 `pnpm i18n-new <code>`，填入你想填的任意多個字串，執行 `pnpm test`，開啟 pull request。你留白的部分都會回退為英文。
{% endhint %}

未翻譯的字串會保留在你的套件中，作為 `""` 而不是消失。這正是讓翻譯 pull request 保持可讀性的原因——差異中的每一行都會 `""` 逐步變成一句話——也正因如此，一個含有一百個字串的套件，才能在第一天就真正有用，並在多次 pull request 中逐步成長。

## 一個語言由什麼構成

有四個檔案承載使用者可見的文案。只有第一個是必需的。

| 資料集     | 檔案                                                | 大小                 | 必需？                      |
| ------- | ------------------------------------------------- | ------------------ | ------------------------ |
| **主套件** | `frontend/locales/<code>.json`                    | 約 1,150 個鍵         | **是** ——所有鍵都存在，值可以是 `""` |
| 隱私政策    | `frontend/locales/privacy/<code>.json`            | 約 50 個鍵            | 否——但要嘛整個完成，要嘛完全不做        |
| 資安檢查清單  | `frontend/locales/security-checklist/<code>.json` | 約 1,080 個鍵，258 個項目 | 否——但要嘛整個完成，要嘛完全不做        |
| 發行說明    | `frontend/data/changelog.json`                    | 163 筆條目            | 否——新增語言例外                |

`en.json` 是它們全部的參考依據。翻譯可以落後於英文；但絕不能與英文相矛盾。

{% hint style="warning" %}
**這兩個可選資料集要嘛整個出貨，要嘛完全不出貨。** 每個都會作為單一檔案載入，內部沒有逐鍵回退，所以半成品會顯示成半英文頁面。測試套件會拒絕 `""` 其中任何一個——要嘛一次把檔案完成，要嘛就不要加入。
{% endhint %}

## 流程

{% stepper %}
{% step %}

### 從以下 fork 並建立分支： `dev`

與其他貢獻相同的分支規範——請見 [如何貢獻](/developer/zh-tw/contributing/how-to-contribute.md).

```bash
git clone https://github.com/<you>/MyIP.git
cd MyIP
git checkout dev
git checkout -b i18n/es-mx
pnpm install
```

{% endstep %}

{% step %}

### 建立語言骨架

一個指令就能寫出語言所需的兩個檔案。

```bash
pnpm i18n-new es-MX
```

它會建立 `frontend/locales/es-MX.json` ，其中包含 **每一個鍵 `en.json` 所擁有的內容，以及每個值 `""`**，並在 `common/locale-registry.js` ，其中包含 `status: 'beta'`.

在你往下做之前，先把那行登錄項目仔細讀過一遍。這個腳本會猜 `nativeName`, `flag` 與 `apiTag`，而它也可能猜錯——請見 [那行登錄項目](#the-registry-line).
{% endstep %}

{% step %}

### 想翻多少就翻多少

打開你的套件並填入值。先從以下內容開始： `頁面` 與 `導覽` 區塊是一個很好的第一個 pull request。

**把你跳過的鍵保留在原處，並維持它們的 `""`.** 刪掉它們會使測試套件失敗，而保留它們正是重點：進度報告可以計算剩下多少，審查者也能一眼看出你實際寫了哪些字串。
{% endstep %}

{% step %}

### 檢查你的成果

```bash
pnpm test          # 硬性關卡——必須是綠燈
pnpm i18n-status   # 進度報告——永遠不會失敗，只會告訴你目前進度
pnpm dev           # 然後在偏好設定中選擇你的語言
```

`?hl=<code>` 也會選擇語言，但只有在你尚未於偏好設定中儲存語言之前才有效——已儲存的偏好會勝過查詢參數。
{% endstep %}

{% step %}

### 向以下目標開啟 pull request： `dev`

說明你涵蓋了哪些區塊，以及哪些留待之後處理。對於部分完成的套件，沒有什麼好道歉的。
{% endstep %}
{% endstepper %}

不需要後端變更、不需要建置設定、不需要編輯元件。語言選擇器、 `<html lang>` 屬性、回退鏈與你的套件延遲載入，全都來自這一行登錄項目。

## 命名你的語言代碼

這個代碼同時也是 UI 代碼和你的 JSON 檔名，所以一旦發佈後，實際上就是永久的。

* **語言的預設變體使用不帶區域的純代碼。** `zh` 是簡體中文； `pt` 則會是歐洲葡萄牙語。
* **後來才出現的變體使用完整的地區代碼：** `zh-TW`, `pt-BR`, `es-MX`.
* 如果基礎語言已註冊，請使用地區代碼——你的套件之後就會以基礎語言作為回退。

## 那行登錄項目

`pnpm i18n-new` 會為你寫出這段內容。這就是你要拿來檢查的依據。

{% code title="common/locale-registry.js" %}

```js
{ code: 'es-MX', nativeName: 'Español (México)', flag: 'mx', apiTag: 'es', htmlLang: 'es-MX', status: 'beta' },
```

{% endcode %}

| 欄位           | 該放什麼                                                                           |
| ------------ | ------------------------------------------------------------------------------ |
| `code`       | UI 代碼 **與** 你的 JSON 檔名。請參見上方的命名規則。                                             |
| `nativeName` | 該語言由其母語者寫出的名稱—— `Français`，不是 `法語`.                                            |
| `flag`       | 小寫的兩個字母 [circle-flags](https://github.com/HatScripts/circle-flags) 用於選擇器圖示的代碼。 |
| `apiTag`     | 傳送給上游資料來源的標籤。詳見下文。                                                             |
| `htmlLang`   | 寫入以下位置的 BCP-47 標籤： `<html lang>`。 `zh` 會指定 `zh-CN` 這樣漢字在日本系統上仍會保持簡體。           |
| `status`     | `'beta'` 用於新語言。維護者會將它切換為 `'full'` ——請見 [從 Beta 到正式版](#from-beta-to-full).      |

登錄項目的順序也是語言選擇器的顯示順序，所以請把你的項目放在最順眼的位置，而不是永遠放在最後。

### 挑選 `apiTag`

地名——城市、地區——來自上游 IP 資料來源，而這些來源會將它們本地化為固定的一組標籤： `en`, `de`, `es`, `fr`, `ja`, `pt-BR`, `ru`, `zh-CN`。請把其中最接近的一個填入 `apiTag`。如果沒有接近的，就直接重複你自己的代碼；地名會以英文顯示，這是預期行為，不是 bug。

國家名稱不受影響——它們來自瀏覽器本身的 `Intl` 資料，並會自動適用於任何語言。日期和時間也是如此。

## 你尚未翻譯的鍵會讓訪客看到什麼

未翻譯的字串——一個 `""`，或者不存在的鍵——會沿著以下鏈路查找： **你的語系 → 其基礎語言（如果已註冊）→ 英文**.

* `fr` → `en`
* `zh-TW` → `zh` → `en`

這條鏈路適用於主套件中的每一個鍵，以及發行說明中的每一筆條目。隱私政策和檢查清單也走同樣的鏈路，但一次處理整個檔案。

應用程式永遠不會顯示空白或原始鍵路徑，也不會記錄任何警告：不完整的 `beta` 套件是一種受支援的狀態，不是錯誤。在語言選擇器中，一個 `beta` 語言會帶有一個小型 **Beta** 徽章——刻意使用英文單字，而且在每種語言中都如此。

你留空的值會在建置時被剔除，因此在發佈的 bundle 中完全不佔成本。

## 這兩個可選資料集

當你準備一次坐下來完成其中一個時，也用同樣方式建立骨架：

```bash
pnpm i18n-new es-MX --privacy --checklist    # 任一旗標，或兩者皆可
```

這兩個都要求語言已先註冊，所以先執行普通的 `pnpm i18n-new <code>` 。

* **隱私政策** 很短。一次完成它，或把它留著不做。
* **檢查清單** 很長——258 個項目。顯示完整的英文檢查清單比顯示缺口更好，所以在完成之前先不要加入這個檔案。它的骨架會保留 `slug` 與 `priority` 填入：那些是資料——連結目標與徽章優先順序——不是文案，而翻譯它們會替你使關卡失敗。

在這個骨架化的可選檔案中，除非其他每個值都填完， `pnpm test` 仍會顯示紅燈。提交前先完成檔案，否則就把它刪掉。

## 什麼 `pnpm test` 強制執行

`tests/locale-packs.test.js` 是關卡。以英文為基準，你的套件必須：

* **鍵的數量必須與英文完全一致** ——不能更多（最常見原因是路徑拼錯），也不能更少（`pnpm i18n-sync` 會把你刪掉的任何鍵重新加回來）。未翻譯的項目會保留為 `""`.
* **不要使用英文未提供的占位符。** `{count}`, `{name}` 及其同類必須是英文字串所使用內容的子集。請完全照原樣拼寫，並依你的文法需要在句中調整它們的位置。空值會被略過。
* **保留 `slug` 與 `priority` 未翻譯** 在資安檢查清單中。
* **不得包含任何 `""` 在這兩個可選檔案中。**
* **如果該語言是 `full`.** 一個 `""` 留在一個 `full` 語系主套件會使建置失敗，而且三個檔案都必須存在。 `beta` 各語系可以保留任意多個 `""` 都可以——在主套件中。

`tests/locale-registry.test.js` 會檢查你的登錄項目格式，且 `tests/changelog.test.js` 只要求 `full` 語言的發行說明歷史。關於測試套件的更多內容請見 [測試](/developer/zh-tw/development/testing.md).

## 什麼 `pnpm i18n-status` 會顯示

以每個語言、每個資料集來看：已翻譯的百分比，以及下一批要處理的鍵。它也會計算與英文完全逐位元相同的值——有時是對的（`MTR`、產品名稱），有時則只是一直沒被翻譯的複製貼上。這只是一份報告，永遠不是關卡。

```bash
pnpm i18n-status --locale es-MX --limit 30
```

## 當英文在你手上變動時

新鍵總是不斷出現。 `en.json` 用一個指令讓每個套件重新對齊：

```bash
pnpm i18n-sync
```

它會把英文的新鍵加入你的主套件，並作為 `""`，刪除英文不再擁有的鍵，並把所有內容重新按英文順序排列。每當 `pnpm test` 回報缺少鍵，或在 rebase 之後執行它。 **它絕不會覆寫翻譯。**

對隱私政策和檢查清單而言，它只會 *回報* 哪些內容有變動——如果把 `""` 寫進去，會直接替你使關卡失敗。請翻譯新鍵，或者把檔案移除。

## 從 Beta 到正式版

一個 `full` 表示未來每一次文案變更都必須落在其中的語言，因此升級是一個由維護者決定的事項，只有在語言真正完整時才會進行：

* 主套件、隱私政策與資安檢查清單相對於英文都達到 100%—— `en` 完全沒有一個 `""` 空白留下，而這點 `pnpm i18n-status` 測試會驗證。
* 發行說明歷史已補齊——全部 163 筆條目都已補上 `frontend/data/changelog.json`.
* 已有足夠的歷史紀錄，讓文案變更持續落在該語言中。

一旦 `status` 切換為 `'full'`，語系與變更記錄規格就會在任何缺口上失敗，這正是設計目的。在那之前沒有壓力： `beta` 語言永遠不會讓建置失敗。

## 改善既有語言

修正與更好的措辭，對 MyIP 已經提供的語言一樣歡迎，和新增語言一樣——編輯 JSON 並開啟 pull request。有兩件事要記住：

* **優先採用自然說法，而不是逐字翻譯。** 這是一個網路工具，而大多數使用者熟悉的術語通常都是英文用詞。
* **留意輸入欄位中的占位文字。** 這些自由輸入欄位刻意避開了 "address / 地址 / adresse / adresi" 這幾個字——iOS QuickType 會抓住它們，並嘗試把郵寄地址自動填入 IP 欄位。翻譯占位文字時，也請選擇能避開你語言對應詞的措辭。

## 已知限制

不管你的套件多完整，看起來都會像「未翻譯」的東西。它們都不是 bug，也都不會阻擋 pull request。

| 什麼                                | 為什麼                                                                                                                                 |
| --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| 地名（城市、地區）                         | 它們來自上游 IP 資料來源，而這些來源只發布 `de`, `en`, `es`, `fr`, `ja`, `pt-BR`, `ru`, `zh-CN`。其他語言會在完整翻譯的介面旁看到英文地名。                                  |
| 應用程式出現前的載入畫面                      | 它在 `index.html` 中自帶一小組字串，並且會在應用程式 bundle 尚未存在前執行。 `beta` 語言在此處會回退為英文；維護者會在升級時處理。                                                    |
| Whois 記錄、DNS 回應、ASN 組織名稱、服務狀態事件文字 | 那是上游資料，不是介面文案。它會以來源發布的任何語言出現。                                                                                                       |
| 這些文件頁面                            | 你正在閱讀的網站是另一個獨立的儲存庫，以英文發布，並由 GitBook 自動翻譯。                                                                                           |
| README 翻譯                         | 這是另一項獨立工作。倉庫中維護著幾份 README 翻譯，並且也歡迎任何其他語言的社群翻譯；請見 [`CONTRIBUTING.md`](https://github.com/jason5ng32/MyIP/blob/main/CONTRIBUTING.md). |

新語言也不需要後端修改。它會把介面送出的任何標籤，對應到其資料來源實際擁有的最接近標籤，因此翻譯 pull request 永遠不會碰到後端程式碼。

## 在規劃大型內容嗎？

在開始前先開一個 issue 並說明。這可避免兩個人平行翻譯同樣的一千個鍵，而維護者也能告訴你是否還有其他人正在處理這個語言。請見 [回報問題](/developer/zh-tw/contributing/reporting-issues.md).

## 還是卡住了？

* [`TRANSLATING.md`](https://github.com/jason5ng32/MyIP/blob/main/TRANSLATING.md) ——與程式碼並列保存的權威參考。這一頁是引導路徑；那個檔案是規則手冊，凡是已經偏移的細節都以它為準。
* [i18n](/developer/zh-tw/development/i18n.md) ——翻譯系統內部如何運作： `t()`、延遲載入、子套件。
* [如何貢獻](/developer/zh-tw/contributing/how-to-contribute.md) ——fork、分支、pull request 與提交訊息規則。
* [開發環境](/developer/zh-tw/development/dev-environment.md) ——讓 `pnpm dev` 先成功執行。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.ipcheck.ing/developer/zh-tw/contributing/translating.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
