Multi-language Support
Add support for multiple languages to reach a global audience.
Overview
The i18n system provides:
- Multiple languages - Support any number of languages
- URL prefixes -
/en/posts,/zh-CN/posts - Per-language config - Different menus, titles, etc.
- Language switcher - Built-in UI component
- SEO - Proper hreflang tags
Basic Setup
1. Configure Languages
In astro.config.mjs:
import { astroBlog, defineI18nConfig } from '@jet-w/astro-blog';
import { enConfig } from './src/config/locales/en';
import { zhCNConfig } from './src/config/locales/zh-CN';
const i18nConfig = defineI18nConfig({
defaultLocale: 'en',
locales: [
{ code: 'en', name: 'English', htmlLang: 'en', dateLocale: 'en-US' },
{ code: 'zh-CN', name: '中文', htmlLang: 'zh-CN', dateLocale: 'zh-CN' },
],
routing: {
prefixDefaultLocale: false,
},
localeConfigs: {
'en': enConfig,
'zh-CN': zhCNConfig,
},
});
export default defineConfig({
integrations: [astroBlog({ i18n: i18nConfig })],
});
2. Create Locale Configs
Create folders for each language:
src/config/locales/
├── en/
│ ├── index.ts
│ ├── site.ts
│ ├── menu.ts
│ ├── footer.ts
│ ├── sidebar.ts
│ └── ui.ts # UI translations
└── zh-CN/
├── index.ts
├── site.ts
├── menu.ts
├── footer.ts
├── sidebar.ts
└── ui.ts # UI translations
3. Configure Each Language
English (en/index.ts):
import { site } from './site';
import { menu } from './menu';
import { footer } from './footer';
import { sidebar } from './sidebar';
import { ui } from './ui';
export const enConfig = {
site,
menu,
footer,
sidebar,
ui,
};
English site (en/site.ts):
export const site = {
title: 'My Blog',
description: 'A blog about technology',
};
English menu (en/menu.ts):
export const menu = [
{ name: 'Home', href: '/', icon: 'home' },
{ name: 'Posts', href: '/posts', icon: 'posts' },
{ name: 'About', href: '/about', icon: 'about' },
];
URL Structure
With prefixDefaultLocale: false:
| Language | URL |
|---|---|
| English (default) | /posts |
| Chinese | /zh-CN/posts |
With prefixDefaultLocale: true:
| Language | URL |
|---|---|
| English | /en/posts |
| Chinese | /zh-CN/posts |
Content Organization
Option 1: Separate Folders
Create separate content folders per language:
content/posts/
├── blog_docs_en/ # English docs
│ └── ...
└── blog_docs/ # Chinese docs
└── ...
Option 2: Same Content
Use the same content with language-aware frontmatter:
---
title: Hello World
lang: en
---
Language Switcher
The language switcher appears in the header automatically when multiple languages are configured.
It shows:
- Current language flag/name
- Dropdown with all languages
- Links to the same page in other languages
Locale Configuration Options
Locale Definition
{
code: 'en', // URL prefix
name: 'English', // Display name
htmlLang: 'en', // HTML lang attribute
dateLocale: 'en-US', // Date formatting
direction: 'ltr', // Text direction (ltr/rtl)
}
Per-Locale Config
Each locale can override:
| Config | Purpose |
|---|---|
site | Title, description, author |
menu | Navigation links |
footer | Footer links and text |
sidebar | Document tree groups |
ui | UI translation strings |
UI Translations
The blog includes built-in translations for 50+ UI strings in English and Chinese. You can override any string in your locale’s ui.ts file.
Creating UI Translations
English (en/ui.ts):
import type { UITranslations } from '@jet-w/astro-blog';
export const ui: Partial<UITranslations> = {
// Override any UI strings here
browsePosts: 'Browse Posts',
aboutMe: 'About Me',
searchPlaceholder: 'Search articles...',
readMore: 'Continue reading',
};
Available UI Keys
| Category | Keys |
|---|---|
| Navigation | home, blog, about, search |
| Posts | posts, postList, noPostsFound, readMore, readingTime, minuteRead |
| Tags & Categories | tags, categories, allTags, allCategories, taggedWith, inCategory |
| Archives | archives, postsInArchive |
| Sidebar | recentPosts, popularTags, friendLinks, documentTree |
| Footer | quickLinks, contact |
| Search | searchPlaceholder, searchResults, noResults, searching, searchArticles, searchTips, etc. |
| Hero | browsePosts, aboutMe |
| Pagination | previousPage, nextPage, page, of |
| Article | publishedOn, updatedOn, author, tableOfContents, relatedPosts, sharePost |
| Misc | backToTop, copyCode, copied, expand, collapse, viewMode, sortBy, draft |
| Slides | slides, slidesList |
| RSS | rssFeed |
You only need to override strings you want to customize. The library provides sensible defaults for all strings.
Adding a New Language
- Add to
localesarray:
locales: [
{ code: 'en', name: 'English', htmlLang: 'en', dateLocale: 'en-US' },
{ code: 'zh-CN', name: '中文', htmlLang: 'zh-CN', dateLocale: 'zh-CN' },
{ code: 'ja', name: '日本語', htmlLang: 'ja', dateLocale: 'ja-JP' }, // New
],
- Create config folder:
src/config/locales/ja/
├── index.ts
├── site.ts
├── menu.ts
├── footer.ts
├── sidebar.ts
└── ui.ts # UI translations
- Create
ui.tswith translations:
import type { UITranslations } from '@jet-w/astro-blog';
export const ui: Partial<UITranslations> = {
// Navigation
home: 'ホーム',
posts: '記事',
tags: 'タグ',
categories: 'カテゴリー',
search: '検索',
// Hero section
browsePosts: '記事を見る',
aboutMe: '私について',
// Search
searchPlaceholder: '記事を検索...',
noResults: '結果が見つかりません',
// Add more translations as needed...
};
- Create
index.ts:
import { site } from './site';
import { menu } from './menu';
import { footer } from './footer';
import { sidebar } from './sidebar';
import { ui } from './ui';
export const jaConfig = {
site,
menu,
footer,
sidebar,
ui,
contentPathPrefix: 'blog_docs_ja',
};
- Add to
localeConfigsinastro.config.mjs:
import { jaConfig } from './src/config/locales/ja';
localeConfigs: {
'en': enConfig,
'zh-CN': zhCNConfig,
'ja': jaConfig, // New
},
RTL Languages
For right-to-left languages (Arabic, Hebrew):
{
code: 'ar',
name: 'العربية',
htmlLang: 'ar',
dateLocale: 'ar-SA',
direction: 'rtl', // Enable RTL
}
Best Practices
tip i18n Tips
- Start with two languages - Don’t add more until needed
- Keep content in sync - Update all translations together
- Use consistent URLs - Match URL structure across languages
- Test thoroughly - Check all pages in all languages
When changing defaultLocale, update all menu and footer links to match the new URL structure.
Congratulations! You’ve completed the configuration guide.
Return to the Documentation Home for more topics.