嗨咿,我是illumi,在使用 Next-intl 做多語系網站時,處理多行文字總是讓人糾結:
每行都要命名好麻煩,有沒有更快的方法?
到底哪種比較好?讓我們用實際案例來分析!
// messages/en.json
{
"Frontend": {
"title": "Frontend Engineer",
"me": "Sonia",
"about": {
"skill": "Good at interactive web pages.",
"hobby": "I enjoy coding and design.",
}
}
}
// 使用方式
const t = await getTranslations('Frontend');
const aboutItems = [
t('about.skill'), // ❌ 每一行都要寫一次
t('about.hobby'), // ❌ 維護麻煩
];
優點:
缺點:
// messages/en.json
{
"Frontend": {
"title": "Frontend Engineer",
"me": "Sonia",
"about": {
"0": "Good at interactive web pages.",
"1": "I enjoy coding and design.", ......
}
}
}
// 使用方式
const t = await getTranslations('Frontend.about');
// 重點:動態生成陣列
const aboutItems = Array.from({ length: 3 }, (_, i) => t(i.toString()));
// 或者更彈性的版本
const aboutItems = [];
let i = 0;
while (true) {
try {
const text = t(i.toString());
if (!text || text === i.toString()) break; // 沒有翻譯就停止
aboutItems.push(text);
i++;
} catch {
break;
}
}
使用範例:
export default function Introduction({ title, me }: Props) {
const t = useTranslations('Frontend.about');
// 一行解決!
const aboutItems = Array.from({ length: 3 }, (_, i) => t(i.toString()));
return (
<div>
<h2>{title}</h2>
<p>{me}</p>
<ul className="text-sm">
{aboutItems.map((item, i) => (
<li key={i}>{item}</li>
))}
</ul>
</div>
);
}
優點:
缺點:
// messages/en.json
{
"Frontend": {
"about": "Good at interactive web pages.\nI enjoy coding and design.\nThis is the third line of the introduction."
}
}
// 使用方式
const aboutText = t('Frontend.about');
const aboutItems = aboutText.split('\n');
優點:
缺點:
// hooks/useArrayTranslations.ts
'use client';
import { useTranslations } from 'next-intl';
export function useArrayTranslations(namespace: string, maxLength: number = 20) {
const t = useTranslations(namespace);
const items = [];
for (let i = 0; i < maxLength; i++) {
try {
const text = t(i.toString());
// 如果翻譯不存在,Next-intl 會返回 key 本身
if (text === i.toString()) break;
items.push(text);
} catch {
break;
}
}
return items;
}
// utils/getArrayTranslations.ts
import { getTranslations } from 'next-intl/server';
export async function getArrayTranslations(namespace: string, maxLength: number = 20) {
const t = await getTranslations(namespace);
const items = [];
for (let i = 0; i < maxLength; i++) {
try {
const text = t(i.toString());
if (text === i.toString()) break;
items.push(text);
} catch {
break;
}
}
return items;
}
// messages/en.json
{
"skills": {
"0": "React & Next.js",
"1": "TypeScript",
"2": "Tailwind CSS",
"premium_0": "Advanced Animation", // 付費用戶才看得到
"premium_1": "Performance Optimization"
}
}
// 進階使用
function SkillsList({ isPremium }: { isPremium: boolean }) {
const basicSkills = useArrayTranslations('skills');
const premiumSkills = isPremium ? useArrayTranslations('skills', 'premium_') : [];
const allSkills = [...basicSkills, ...premiumSkills];
return (
<ul>
{allSkills.map((skill, i) => (
<li key={i} className={i >= basicSkills.length ? 'text-gold' : ''}>
{skill}
</li>
))}
</ul>
);
}
方法 | 程式碼維護性 | 翻譯維護性 | 執行效能 | 推薦度 |
---|---|---|---|---|
語義化巢狀物件 | ⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐ |
編號物件 + 迴圈 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
換行字串 | ⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐ |
好的到這邊啦~我們明天再見~