--- 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