Internationalization¶
The site supports three locales with full content and UI translations.
Supported Locales¶
Code |
Label |
Role |
|---|---|---|
|
English |
Default locale |
|
简体中文 |
Simplified Chinese |
|
日本語 |
Japanese |
Configuration lives in src/lib/i18n.ts:
export const locales = ["en", "zh-CN", "ja"] as const;
export type Locale = (typeof locales)[number];
export const defaultLocale: Locale = "en";
Locale Routing¶
All routes are prefixed with a locale segment (e.g., /en/blog,
/zh-CN/blog). The middleware in src/middleware.ts enforces this:
Pass-through — requests to
/_next,/api,/fonts, and static files (paths containing.) are not processedValid locale — if the first path segment is
en,zh-CN, orja, the request passes through unchangedDetection — the
Accept-Languageheader is parsed; the first matching locale is selected, falling back toenRedirect — the user is redirected to
/{detectedLocale}{path}
The middleware matcher excludes _next, api, fonts,
favicon.ico, robots.txt, and sitemap.xml.
Translation System¶
The t() function provides UI translations with placeholder support:
t(key: string, locale: Locale, params?: Record<string, string | number>): string
Behaviour:
Returns the translated string for the given locale
Falls back to
enif the key is missing in the requested localeReturns the raw key if no translation exists at all
Supports
{placeholder}interpolation:t("pageOf", "zh-CN", { page: 1, total: 5 })→"第 1 页,共 5 页"
Translation Keys¶
Approximately 80 keys are defined, organized by feature area:
Navbar: brand, blog, gallery, solutions, pricing,
developer, login, adminLogin
Blog: readMore, featuredArticles, allArticles,
noArticles, noArticlesTitle, noArticlesDesc, publishedOn,
by, filterByCategory, filterByTag (with {tag}),
allCategories, searchPlaceholder, categories, tags,
share, copyLink, linkCopied, seeMore, home,
lastUpdated (with {date})
Gallery: mediaGallery, noGalleries, viewGallery, photos
Pagination: previous, next, pageOf (with {page} and
{total})
Footer: Section headings (products, platform, services,
company), link labels, legal links (termsOfService, disclaimer,
privacyPolicy, manageCookies), copyright (with {year}),
icp
Cookie consent: Bar text and buttons, settings dialog headings and toggle descriptions (Essential, Performance, Advertising)
Theme: lightMode, darkMode
Errors: backToHome, httpErrorCode, errorSuggest,
tryAgain, plus title and description pairs for HTTP status codes
400, 401, 403, 404, 405, 408, 429, 500, 502, 503, 504, and a default
SEO: siteTitle, siteDescription
CMS Content Localization¶
Strapi articles and categories are localized server-side. The seed scripts
create English content first, then add zh-CN and ja localizations via
Strapi’s /actions/localize endpoint.
The fetchPublicArticles and fetchCategories functions pass the
locale query parameter to Strapi, which returns the appropriate
translation.
Adding a New Language¶
Add the locale code to the
localesarray insrc/lib/i18n.tsAdd a label to
localeLabels(e.g.,"ko": "한국어")Add translations for all keys in the translations object
Add CMS localizations in Strapi for existing articles and categories
Test the middleware detects the new locale from
Accept-Language
The LocaleSwitcher component automatically renders all entries from
localeLabels, so no component changes are needed.