chore: establish learning module baseline
This commit is contained in:
commit
2d04197f3f
2409 files changed
+533050
No files matched your search
@@ -0,0 +1,31 @@
|
||||
# Translation Guide
|
||||
|
||||
## Adding a new language
|
||||
|
||||
1. Copy `locales/en-US.json` to `locales/<code>.json` (e.g. `ja-JP.json`)
|
||||
2. Append an entry to the end of the `supportedLocales` array in `locales.ts` — do not reorder existing entries, as the first locale for each language prefix (e.g. `zh-CN` for `zh`) is used as the default when the browser sends a bare language code:
|
||||
```ts
|
||||
{ code: 'ja-JP', label: '日本語', shortLabel: 'JA' },
|
||||
```
|
||||
3. Translate all values in the new JSON file. Keys must remain identical.
|
||||
|
||||
## Interpolation
|
||||
|
||||
This project uses i18next with the default double-brace syntax: `{{variable}}`.
|
||||
|
||||
Example: `"Hi, {{name}}"` will render as `"Hi, Alice"` when called with `t('key', { name: 'Alice' })`.
|
||||
|
||||
Do NOT remove or rename interpolation variables — they are referenced in code.
|
||||
|
||||
## Keys with design intent
|
||||
|
||||
Not every key needs explanation, but the following have non-obvious UX context that affects how they should be translated.
|
||||
|
||||
| Key | Where it appears | Translation notes |
|
||||
|-----|-----------------|-------------------|
|
||||
| `home.greetingWithName` | Top-left of homepage, clickable pill that opens nickname editor | This is a **call-to-action** — the greeting doubles as an entry point for users to set their nickname. The translation must include `{{name}}` and read naturally with the default nickname (see `profile.defaultNickname`). Avoid generic greetings that hide the name (e.g. don't translate as just "Welcome"). |
|
||||
| `profile.defaultNickname` | Pre-filled in the greeting and the nickname input field | Shown before the user sets a real name. Pick a warm, gender-neutral word that: (1) feels natural in the greeting, (2) clearly signals "this is a placeholder you should replace". Avoid cold terms like "User" or formal terms like "Student". Examples: EN "Learner", ZH "同学". |
|
||||
| `profile.bioPlaceholder` | Textarea placeholder in the profile editor | The bio is fed to the AI teacher to personalize lessons. The placeholder should hint at this — tell users *why* filling it in helps. |
|
||||
| `generation.textTruncated` / `generation.imageTruncated` | Toast warnings during PDF-based course generation | These are technical warnings shown briefly. Keep them short and factual. `textTruncated` has `{{n}}` (character count), `imageTruncated` has `{{total}}` and `{{max}}`. |
|
||||
| `agentBar.readyToLearn` | Classroom page, above the agent role list | Conversational prompt to set the mood before class starts. Should feel inviting, not instructional. |
|
||||
| `settings.agentsCollaboratingCount` | Settings panel, multi-agent mode description | Contains `{{count}}`. This is a status label, not a button — keep it descriptive. |
|
||||
@@ -0,0 +1,19 @@
|
||||
import i18n from 'i18next';
|
||||
import { initReactI18next } from 'react-i18next';
|
||||
import resourcesToBackend from 'i18next-resources-to-backend';
|
||||
import { supportedLocales } from './locales';
|
||||
import { defaultLocale } from './types';
|
||||
|
||||
i18n
|
||||
.use(initReactI18next)
|
||||
.use(resourcesToBackend((language: string) => import(`./locales/${language}.json`)))
|
||||
.init({
|
||||
lng: defaultLocale,
|
||||
fallbackLng: defaultLocale,
|
||||
supportedLngs: supportedLocales.map((l) => l.code),
|
||||
interpolation: {
|
||||
escapeValue: false,
|
||||
},
|
||||
});
|
||||
|
||||
export default i18n;
|
||||
@@ -0,0 +1,13 @@
|
||||
import i18n from './config';
|
||||
|
||||
export { type Locale, defaultLocale } from './types';
|
||||
export { type LocaleEntry, supportedLocales } from './locales';
|
||||
export type TranslationKey = string;
|
||||
|
||||
export function translate(locale: string, key: string): string {
|
||||
return i18n.t(key, { lng: locale });
|
||||
}
|
||||
|
||||
export function getClientTranslation(key: string): string {
|
||||
return i18n.t(key);
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
export type LocaleEntry = {
|
||||
code: string;
|
||||
/** Native name shown in dropdown, e.g. '简体中文' */
|
||||
label: string;
|
||||
/** Short label shown on the toggle button, e.g. 'CN' */
|
||||
shortLabel: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Supported locales registry.
|
||||
*
|
||||
* To add a new language:
|
||||
* 1. Create `lib/i18n/locales/<code>.json` (copy an existing file as template)
|
||||
* 2. Add an entry here
|
||||
*/
|
||||
export const supportedLocales = [
|
||||
{ code: 'zh-CN', label: '简体中文', shortLabel: 'CN' },
|
||||
{ code: 'zh-TW', label: '繁體中文', shortLabel: 'TW' },
|
||||
{ code: 'en-US', label: 'English', shortLabel: 'EN' },
|
||||
{ code: 'ja-JP', label: '日本語', shortLabel: 'JA' },
|
||||
{ code: 'ru-RU', label: 'Русский', shortLabel: 'RU' },
|
||||
{ code: 'ar-SA', label: 'العربية', shortLabel: 'AR' },
|
||||
{ code: 'pt-BR', label: 'Português (Brasil)', shortLabel: 'BR' },
|
||||
{ code: 'ko-KR', label: '한국어', shortLabel: 'KO' },
|
||||
{ code: 'es-MX', label: 'Español (México)', shortLabel: 'ES' },
|
||||
{ code: 'fr-FR', label: 'Français', shortLabel: 'FR' },
|
||||
{ code: 'vi-VN', label: 'Tiếng Việt', shortLabel: 'VI' },
|
||||
] as const satisfies readonly LocaleEntry[];
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,5 @@
|
||||
import { supportedLocales } from './locales';
|
||||
|
||||
export type Locale = (typeof supportedLocales)[number]['code'];
|
||||
|
||||
export const defaultLocale: Locale = 'zh-CN';
|
||||
Reference in new issue
Block a user