mirror of
https://github.com/luckyyzh/pi-agent-integrated.git
synced 2026-10-03 02:59:35 +00:00
feat: integrate Pi backend and Pi Web
This commit is contained in:
@@ -0,0 +1,172 @@
|
||||
# Internationalization
|
||||
|
||||
Pi Web's interface uses a small internal i18n layer. It is intentionally kept
|
||||
inside the application instead of introducing another runtime dependency, so
|
||||
the UI can support more languages without coupling the server, API responses,
|
||||
or Pi's own output to a particular language.
|
||||
|
||||
## Current Languages
|
||||
|
||||
The built-in language packages are:
|
||||
|
||||
- `en` - English
|
||||
- `zh-CN` - Simplified Chinese
|
||||
|
||||
The initial locale is inferred from the browser. Users can change the locale
|
||||
from the language control in the top bar. The selected locale is persisted in
|
||||
`localStorage` under `pi-locale`.
|
||||
|
||||
## Using Translations In A Component
|
||||
|
||||
Client components should get the translation function from `useI18n`:
|
||||
|
||||
```tsx
|
||||
import { useI18n } from "@/hooks/useI18n";
|
||||
|
||||
export function ExampleButton() {
|
||||
const { t } = useI18n();
|
||||
|
||||
return <button aria-label={t("example.open")}>{t("example.open")}</button>;
|
||||
}
|
||||
```
|
||||
|
||||
The component must be rendered below `I18nProvider`. The application root
|
||||
already provides it in `app/page.tsx`.
|
||||
|
||||
Use parameters for values that change at runtime instead of concatenating
|
||||
translated fragments:
|
||||
|
||||
```tsx
|
||||
<span>{t("session.messageCount", { count: messageCount })}</span>
|
||||
```
|
||||
|
||||
The corresponding message can use `{count}`:
|
||||
|
||||
```ts
|
||||
"session.messageCount": "{count} messages"
|
||||
```
|
||||
|
||||
This keeps the sentence structure under the control of each language package.
|
||||
|
||||
## Adding A New Language
|
||||
|
||||
### 1. Create The Message File
|
||||
|
||||
Add a file under `lib/i18n/messages/`, using a BCP 47-style identifier. For
|
||||
example, a Japanese package would be `lib/i18n/messages/ja.ts`:
|
||||
|
||||
```ts
|
||||
import type { LocalePlugin } from "../types";
|
||||
|
||||
/** Pi Web Japanese language package. */
|
||||
export const jaLocale: LocalePlugin = {
|
||||
id: "ja",
|
||||
label: "日本語",
|
||||
messages: {
|
||||
"common.language": "言語",
|
||||
// Add the rest of the shared keys here.
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
The message keys must remain stable and language-neutral. Copy the complete
|
||||
key set from `lib/i18n/messages/en.ts` when starting a new package. Missing
|
||||
keys fall back to English, but a complete package is preferred for a user
|
||||
facing language.
|
||||
|
||||
### 2. Register The Package
|
||||
|
||||
Import and register the package in `lib/i18n/registry.ts`:
|
||||
|
||||
```ts
|
||||
import { jaLocale } from "./messages/ja";
|
||||
|
||||
registerLocale(jaLocale);
|
||||
```
|
||||
|
||||
`LocalePlugin.id` must be unique and non-empty. The label is displayed in the
|
||||
language selector. `getSupportedLocales()` automatically exposes registered
|
||||
packages to the UI.
|
||||
|
||||
### 3. Update Locale-Specific Types If Needed
|
||||
|
||||
The built-in `Locale` type currently lists `en` and `zh-CN` for compile-time
|
||||
safety. When adding a built-in language, update that union in
|
||||
`lib/i18n/types.ts` and update any locale validation that intentionally lists
|
||||
the built-in identifiers.
|
||||
|
||||
### 4. Add Tests
|
||||
|
||||
Extend `lib/i18n/registry.test.mjs` when browser-language detection or registry
|
||||
behavior changes. Extend `lib/i18n/format.test.mjs` when interpolation or
|
||||
locale-aware formatting changes. A new language should at minimum verify its
|
||||
registry id and a representative translation.
|
||||
|
||||
## Adding Or Changing UI Text
|
||||
|
||||
1. Add a stable key to both `lib/i18n/messages/en.ts` and
|
||||
`lib/i18n/messages/zh-CN.ts`.
|
||||
2. Put keys under a feature namespace such as `chat.*`, `files.*`,
|
||||
`settings.*`, or `common.*`.
|
||||
3. Use `t("namespace.key")` in visible text, `title`, `aria-label`, and
|
||||
`placeholder` values.
|
||||
4. Use interpolation for counts, names, paths, and other runtime values.
|
||||
5. Keep product names, model names, provider names, commands, file paths,
|
||||
user content, tool output, and server-provided error details unchanged.
|
||||
6. Do not translate an API error by matching its English text. Translate only
|
||||
the local UI fallback around it.
|
||||
|
||||
Keep established technical terms in English when translating them would make
|
||||
the interface harder to map back to commands, configuration fields, or Pi
|
||||
documentation. This includes terms such as `Agent`, `API Key`, `Provider`,
|
||||
`Token`, `worktree`, `Diff`, `CWD`, `Shell`, `Git`, `HEAD`, `OAuth`, and
|
||||
`Mermaid`; preserve their conventional casing. Translate the surrounding
|
||||
actions and status text. Common concepts with clear localized forms, such as
|
||||
model, plugin, skill, prompt, context, and cache, can remain localized.
|
||||
|
||||
For example:
|
||||
|
||||
```ts
|
||||
// en.ts
|
||||
"files.uploadedCount": "{count} uploaded"
|
||||
|
||||
// zh-CN.ts
|
||||
"files.uploadedCount": "已上传 {count} 个文件"
|
||||
```
|
||||
|
||||
```tsx
|
||||
<span>{t("files.uploadedCount", { count: uploadedCount })}</span>
|
||||
```
|
||||
|
||||
If a key is missing from the selected language, the formatter first tries the
|
||||
English package and finally returns the key itself. Missing keys also produce
|
||||
a development warning, which makes incomplete translations visible during
|
||||
development.
|
||||
|
||||
## Verification
|
||||
|
||||
Run the following commands from the repository root:
|
||||
|
||||
```bash
|
||||
node_modules/.bin/tsc --noEmit
|
||||
npm run lint
|
||||
node_modules/.bin/jiti lib/i18n/registry.test.mjs
|
||||
node_modules/.bin/jiti lib/i18n/format.test.mjs
|
||||
node --test lib/*.test.mjs
|
||||
```
|
||||
|
||||
Do not run `next build` during normal development. See the repository
|
||||
development notes for the reason.
|
||||
|
||||
## Design Principles
|
||||
|
||||
Pi Web is a user-facing web interface. Internationalization is therefore an
|
||||
accessibility and usability feature: people should be able to understand and
|
||||
operate the interface in a language they are comfortable with. Language
|
||||
support should lower the barrier to using Pi Web, not be treated as a measure
|
||||
of technical expertise or as a reason to exclude otherwise useful
|
||||
contributions.
|
||||
|
||||
The i18n layer is deliberately incremental. Contributors can add a language
|
||||
or improve a small group of UI messages without rewriting API contracts,
|
||||
changing Pi's output, or introducing a large translation framework.
|
||||
Reference in New Issue
Block a user