Add languages, manage translations, and localize content
Internationalization (i18n)
DocsBlog supports multiple languages out of the box with English (en) and Simplified Chinese (zh-hans).
URL Structure
- Default language (en): no prefix —
/blog,/docs - Other languages: with prefix —
/zh-hans/blog,/zh-hans/docs
This is controlled by hideLocale: "default-locale" in src/lib/i18n.ts.
Adding a New Language
Step 1: Register the Language
Add an entry to src/config/languages/registry/languages.json:
[
{ "code": "en", "label": "English", "native": "English" },
{ "code": "zh-hans", "label": "Simplified Chinese", "native": "中文简体" },
{ "code": "ja", "label": "Japanese", "native": "日本語" }
]Step 2: Create Translation File
Copy src/locales/en.ts to src/locales/ja.ts and translate all strings:
export const ja = {
common: {
search: "検索",
loading: "読み込み中…",
noResults: "結果なし",
// ... translate all keys
},
nav: {
home: "ホーム",
blog: "ブログ",
docs: "ドキュメント",
// ...
},
// ... all other sections
};Step 3: Register in Locales Index
Update src/locales/index.ts to import and register the new locale:
import { ja } from "./ja";
const dictionaries: Record<string, Translations> = {
en,
"zh-hans": zhHans,
ja, // Add this line
};Step 4: Create Content Directories
mkdir -p content/blog/ja
mkdir -p content/docs/ja/adminStep 5: Create Docs Navigation
Create content/docs/ja/meta.json:
{
"title": "ドキュメント",
"pages": ["index", "project-structure", "configuration", "..."]
}Then create the corresponding .mdx files in content/docs/ja/.
Translation File Structure
The main translation files follow this structure:
export const en = {
duration: { second: "{count}s", minute: "{count}m", hour: "{count}h" },
common: { search: "Search", loading: "Loading…", noResults: "No results", ... },
nav: { home: "Home", blog: "Blog", docs: "Docs", ... },
hero: { badge: "...", title: "...", description: "...", cta: "..." },
twitter: { title: "Twitter", description: "...", ... },
youtube: { title: "YouTube", ... },
features: { heading: "...", ... },
faq: { heading: "...", items: [...] },
footer: { copyright: "...", twitter: "Twitter" },
// ... more sections
};Using Translations in Code
import { getTranslations, interpolate } from "@/locales";
// Get all translations for a locale
const t = getTranslations("zh-hans");
console.log(t.common.search); // "搜索"
// Variable interpolation
interpolate("{count} items found", { count: "42" });
// → "42 items found"Admin Panel Translations
Admin UI has separate translation files:
src/locales/admin/en.ts— English admin labelssrc/locales/admin/zh-hans.ts— Chinese admin labels
When adding a language, also create src/locales/admin/ja.ts for admin panel localization.
Content Organization
content/
├── blog/
│ ├── en/ # English blog posts
│ └── zh-hans/ # Chinese blog posts
├── docs/
│ ├── en/ # English documentation
│ │ └── admin/
│ └── zh-hans/ # Chinese documentation
│ └── admin/Each locale has its own content directory. Blog posts and docs are independent per language — you don't need to have the same posts in every language.
Language Switcher
A language switcher is automatically displayed in the top-right corner of the header. It shows all registered languages and switches between them while preserving the current page path.
AI Translation
For bulk translation of content, use the built-in Translation System in the admin panel, powered by DeepSeek AI.