---
name: vitepress-internationalization
description: Setting up multi-language sites with locale configuration and RTL support
---
# Internationalization
VitePress supports multi-language sites through locale configuration.
## Directory Structure
Organize content by locale:
```
docs/
├─ en/
│ ├─ guide.md
│ └─ index.md
├─ zh/
│ ├─ guide.md
│ └─ index.md
└─ fr/
├─ guide.md
└─ index.md
```
Or with root as default language:
```
docs/
├─ guide.md # English (root)
├─ index.md
├─ zh/
│ ├─ guide.md
│ └─ index.md
└─ fr/
├─ guide.md
└─ index.md
```
## Configuration
```ts
// .vitepress/config.ts
import { defineConfig } from 'vitepress';
export default defineConfig({
locales: {
root: {
label: 'English',
lang: 'en',
},
zh: {
label: '简体中文',
lang: 'zh-CN',
link: '/zh/',
},
fr: {
label: 'Français',
lang: 'fr',
link: '/fr/',
},
},
});
```
## Locale-Specific Config
Override site config per locale:
```ts
locales: {
root: {
label: 'English',
lang: 'en',
title: 'My Docs',
description: 'Documentation site',
themeConfig: {
nav: [
{ text: 'Guide', link: '/guide/' }
],
sidebar: {
'/guide/': [
{ text: 'Introduction', link: '/guide/' }
]
}
}
},
zh: {
label: '简体中文',
lang: 'zh-CN',
link: '/zh/',
title: '我的文档',
description: '文档站点',
themeConfig: {
nav: [
{ text: '指南', link: '/zh/guide/' }
],
sidebar: {
'/zh/guide/': [
{ text: '介绍', link: '/zh/guide/' }
]
}
}
}
}
```
## Locale-Specific Properties
Each locale can override:
```ts
interface LocaleSpecificConfig {
lang?: string;
dir?: string; // 'ltr' or 'rtl'
title?: string;
titleTemplate?: string | boolean;
description?: string;
head?: HeadConfig[]; // Merged with existing
themeConfig?: ThemeConfig; // Shallow merged
}
```
## Search i18n
### Local Search
```ts
themeConfig: {
search: {
provider: 'local',
options: {
locales: {
zh: {
translations: {
button: {
buttonText: '搜索',
buttonAriaLabel: '搜索'
},
modal: {
noResultsText: '没有结果',
resetButtonTitle: '重置搜索',
footer: {
selectText: '选择',
navigateText: '导航',
closeText: '关闭'
}
}
}
}
}
}
}
}
```
### Algolia Search
```ts
themeConfig: {
search: {
provider: 'algolia',
options: {
appId: '...',
apiKey: '...',
indexName: '...',
locales: {
zh: {
placeholder: '搜索文档',
translations: {
button: { buttonText: '搜索文档' }
}
}
}
}
}
}
```
## Separate Locale Directories
For fully separated locales without root fallback:
```
docs/
├─ en/
│ └─ index.md
├─ zh/
│ └─ index.md
└─ fr/
└─ index.md
```
Requires server redirect for `/` → `/en/`. Netlify example:
```
/* /en/:splat 302 Language=en
/* /zh/:splat 302 Language=zh
/* /en/:splat 302
```
## Persisting Language Choice
Set cookie on language change:
```vue
```
## RTL Support (Experimental)
For right-to-left languages:
```ts
locales: {
ar: {
label: 'العربية',
lang: 'ar',
dir: 'rtl'
}
}
```
Requires PostCSS plugin like `postcss-rtlcss`:
```ts
// postcss.config.js
import rtlcss from 'postcss-rtlcss';
export default {
plugins: [
rtlcss({
ltrPrefix: ':where([dir="ltr"])',
rtlPrefix: ':where([dir="rtl"])',
}),
],
};
```
## Organizing Config
Split config into separate files:
```
.vitepress/
├─ config/
│ ├─ index.ts # Main config, merges locales
│ ├─ en.ts # English config
│ ├─ zh.ts # Chinese config
│ └─ shared.ts # Shared config
```
```ts
// .vitepress/config/index.ts
import { defineConfig } from 'vitepress';
import { shared } from './shared';
import { en } from './en';
import { zh } from './zh';
export default defineConfig({
...shared,
locales: {
root: { label: 'English', ...en },
zh: { label: '简体中文', ...zh },
},
});
```
## Key Points
- Use `locales` object in config with `root` for default language
- Each locale can override title, description, and themeConfig
- `themeConfig` is shallow merged (define complete nav/sidebar per locale)
- Don't override `themeConfig.algolia` at locale level
- `dir: 'rtl'` enables RTL with PostCSS plugin
- Language switcher appears automatically in nav