feat: introduce i18n system and class invitation codes

Add complete i18n infrastructure using next-intl (cookie-driven, without i18n routing) with zh-CN/en dictionary files, locale switcher, and NextIntlClientProvider in root layout. Add class invitation code system with new class_invitation_codes table, data-access layer (generate/validate/consume/revoke), server actions with permission checks, rate limiting, and audit logging. Add class-invitation-manager UI component. Refactor onboarding stepper to use i18n translations and accept new invitation code format (6-char alphanumeric) with backward compatibility for legacy 6-digit codes.
This commit is contained in:
SpecialX
2026-06-22 14:04:55 +08:00
parent a4d096a6fc
commit c90748124d
25 changed files with 2911 additions and 30 deletions

43
src/shared/i18n/locale.ts Normal file
View File

@@ -0,0 +1,43 @@
/**
* 项目 i18n 配置without i18n routing 模式)。
*
* 设计决策v3 引入完整 i18n 体系):
* - 采用 next-intl 4.x官方推荐的 Next.js App Router 方案
* - 不使用 `[locale]` 路由段,避免破坏现有 (auth)/(dashboard)/(onboarding) 路由组结构
* - locale 通过 cookie 持久化SSR 时从 cookie 读取
* - 字典放在 shared/i18n/messages/,符合三层架构约束
*
* 支持的 locale
* - zh-CN默认简体中文
* - en英文
*/
export const LOCALES = ["zh-CN", "en"] as const;
export type Locale = (typeof LOCALES)[number];
export const DEFAULT_LOCALE: Locale = "zh-CN";
/** Cookie 名称,与 proxy.ts / request.ts 保持一致 */
export const LOCALE_COOKIE = "NEXT_LOCALE";
/** Cookie 属性1 年有效期,全站可读 */
export const LOCALE_COOKIE_OPTIONS = {
maxAge: 60 * 60 * 24 * 365,
path: "/",
sameSite: "lax" as const,
};
/**
* 校验字符串是否为受支持的 locale。
* 用于从 cookie/header 读取后的容错处理。
*/
export function isLocale(value: string | null | undefined): value is Locale {
return typeof value === "string" && (LOCALES as readonly string[]).includes(value);
}
/**
* 将任意字符串归一化为合法 locale非法值回退到默认。
*/
export function normalizeLocale(value: string | null | undefined): Locale {
return isLocale(value) ? value : DEFAULT_LOCALE;
}