Files
agent-skills/skills/vitepress/references/advanced-i18n.md
Jason Woltje f5792c40be feat: Complete fleet — 94 skills across 10+ domains
Pulled ALL skills from 15 source repositories:
- anthropics/skills: 16 (docs, design, MCP, testing)
- obra/superpowers: 14 (TDD, debugging, agents, planning)
- coreyhaines31/marketingskills: 25 (marketing, CRO, SEO, growth)
- better-auth/skills: 5 (auth patterns)
- vercel-labs/agent-skills: 5 (React, design, Vercel)
- antfu/skills: 16 (Vue, Vite, Vitest, pnpm, Turborepo)
- Plus 13 individual skills from various repos

Mosaic Stack is not limited to coding — the Orchestrator and
subagents serve coding, business, design, marketing, writing,
logistics, analysis, and more.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 16:27:42 -06:00

5.2 KiB

name, description
name description
vitepress-internationalization 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

// .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:

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:

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

themeConfig: {
  search: {
    provider: 'local',
    options: {
      locales: {
        zh: {
          translations: {
            button: {
              buttonText: '搜索',
              buttonAriaLabel: '搜索'
            },
            modal: {
              noResultsText: '没有结果',
              resetButtonTitle: '重置搜索',
              footer: {
                selectText: '选择',
                navigateText: '导航',
                closeText: '关闭'
              }
            }
          }
        }
      }
    }
  }
}
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:

<!-- .vitepress/theme/Layout.vue -->
<script setup>
import DefaultTheme from 'vitepress/theme'
import { useData, inBrowser } from 'vitepress'
import { watchEffect } from 'vue'

const { lang } = useData()

watchEffect(() => {
  if (inBrowser) {
    document.cookie = `nf_lang=${lang.value}; expires=Mon, 1 Jan 2030 00:00:00 UTC; path=/`
  }
})
</script>

<template>
  <DefaultTheme.Layout />
</template>

RTL Support (Experimental)

For right-to-left languages:

locales: {
  ar: {
    label: 'العربية',
    lang: 'ar',
    dir: 'rtl'
  }
}

Requires PostCSS plugin like postcss-rtlcss:

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