Files
frontend_v2/src/i18n/dictionary.ts
toom1996 3c7c5d8855 update
2026-08-29 15:47:58 +08:00

137 lines
4.3 KiB
TypeScript
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.

import { DEFAULT_LOCALE, type Locale } from '@/i18n/config';
/**
* 单文件翻译字典。
*
* 设计(按你的要求):
* - key 就是「英文原文」,直接当文案用,无需额外维护英文副本;
* - value 只存「非默认语言」的翻译(本项目默认语言是 en,所以只存 cn 等);
* - 英文环境调用 t(key) 直接返回 key 本身;
* - 其它语言从 value 里取对应翻译,取不到就回退英文(开发环境会告警,方便发现漏翻)。
*
* 新增一条:直接加一行 `'英文原文': { cn: '中文' }` 即可;
* 当前是英文时根本不需要在字典里登记,写了 t('Nice day!') 就能渲染 "Nice day!"。
*/
// 除默认语言外的所有语言(如 'cn')。加新语言(ja 等)时这里会自动包含。
type OtherLocale = Exclude<Locale, typeof DEFAULT_LOCALE>;
type TranslationEntry = Partial<Record<OtherLocale, string>>;
export const dict: Record<string, TranslationEntry> = {
// ── 导航 / Navigation ──
'about': { cn: '关于' },
'全部的 runway': { cn: '全部的 runway' },
'contact': { cn: '联系' },
'contact us': { cn: '联系我们' },
'home': { cn: '首页' },
'latest projects': { cn: '最新项目' },
'login': { cn: '登录' },
'portfolio': { cn: '作品集' },
'runway archive': { cn: '走秀档案' },
'signup': { cn: '注册' },
// ── 控件 / Controls ──
'back to index': { cn: '返回首页' },
'back to top': { cn: '回到顶部' },
'close': { cn: '关闭' },
'previous image': { cn: '上一张' },
'next image': { cn: '下一张' },
'previous': { cn: '上一组' },
'next': { cn: '下一组' },
// ── 错误 / Errors ──
'no article id specified': { cn: '未指定文章 ID' },
'failed to load article. please refresh or try later.': { cn: '加载文章失败,请刷新或稍后再试' },
'click image to zoom · scroll to view · esc to close': { cn: '点击图片放大 · 上下滚动查看 · Esc 关闭' },
// ── 页脚 / Footer ──
'© 2026 portfolio studio. all rights reserved.': { cn: '© 2026 PORTFOLIO STUDIO. 保留所有权利。' },
// ── 页脚工具 / Footer tools ──
'color studio tools': { cn: '色彩工作室工具' },
'ai color trend generator': { cn: 'AI 色彩趋势生成器' },
'photo swatch extractor': { cn: '图片色板提取器' },
'upload': { cn: '上传' },
'reset b&w theme': { cn: '重置黑白主题' },
'default': { cn: '默认' },
// ── 页脚简介 / Manifesto ──
'minimalist editorial portfolio documenting haute couture shows, backstage fittings, and street culture. integrated with 2026 color forecast intelligence and ai palette generator.':
{ cn: '极简编辑风格作品集,记录高级定制秀场、后台试装与街头文化。集成 2026 色彩预测情报与 AI 调色板生成器。' },
// ── 登录态 / Auth ──
'hi': { cn: '你好' },
'logout': { cn: '退出' },
'language': { cn: '语言' },
'runway looks': { cn: '秀场造型' },
// ── 街拍 / Street Snaps ──
'street style': { cn: '街拍' },
'street snaps': { cn: '街拍' },
'all street snaps': { cn: '全部街拍' },
'no street snap id specified': { cn: '未指定街拍 ID' },
'failed to load street snap. please refresh or try later.': { cn: '加载街拍失败,请刷新或稍后再试' }
};
/** 把 {name} 形式的占位符替换成参数值。 */
function interpolate(text: string, params?: Record<string, string | number>): string {
if (!params) return text;
return text.replace(/\{(\w+)\}/g, (_, k) => (k in params ? String(params[k]) : `{${k}}`));
}
/**
* 取翻译:
* - 当前是默认语言(en)→ 直接返回 key(英文原文);
* - 其它语言 → 优先取字典里的翻译,缺失则回退英文并返回 key(不会白屏)。
*/
export function translate(key: string, locale: Locale, params?: Record<string, string | number>): string {
if (locale === DEFAULT_LOCALE) return interpolate(key, params);
const localized = dict[key.toLowerCase()]?.[locale as OtherLocale];
if (localized) return interpolate(localized, params);
if (import.meta.env.DEV) {
console.warn(`[i18n] 缺少 "${locale}" 翻译:"${key}",已回退英文`);
}
return interpolate(key, params);
}