# Internationalization

To use the built-in i18n features, one needs to create a directory structure as follows:

```
docs/
├─ es/
│  ├─ foo.md
├─ fr/
│  ├─ foo.md
├─ foo.md
```

Then in `docs/.vitepress/config.ts`:

```ts [docs/.vitepress/config.ts]
import { defineConfig } from 'vitepress'

export default defineConfig({
  // shared properties and other top-level stuff...

  locales: {
    root: {
      label: 'English',
      lang: 'en'
    },
    fr: {
      label: 'French',
      lang: 'fr', // optional, will be added  as `lang` attribute on `html` tag
      link: '/fr/guide' // default /fr/ -- shows on navbar translations menu, can be external

      // other locale specific properties...
    }
  }
})
```

The following properties can be overridden for each locale (including root):

```ts
interface LocaleSpecificConfig<ThemeConfig = any> {
  lang?: string
  dir?: string
  title?: string
  titleTemplate?: string | boolean
  description?: string
  head?: HeadConfig[] // will be merged with existing head entries, duplicate meta tags are automatically removed
  themeConfig?: ThemeConfig // will be shallow merged, common stuff can be put in top-level themeConfig entry
}
```

Refer [`DefaultTheme.Config`](https://github.com/vuejs/vitepress/blob/main/types/default-theme.d.ts) interface for details on customizing the placeholder texts of the default theme. Don't override `themeConfig.algolia` or `themeConfig.carbonAds` at locale-level. Refer [Algolia docs](/guides/reference-default-theme-search#i18n-1) for using multilingual search.

**Pro tip:** Config file can be stored at `docs/.vitepress/config/index.ts` too. It might help you organize stuff by creating a configuration file per locale and then merge and export them from `index.ts`.

## Per-locale Markdown Strings

Strings baked into pages by the markdown renderer - the default titles of [custom containers](/guides/writing-markdown#custom-containers) and [GitHub-flavored alerts](/guides/writing-markdown#github-flavored-alerts), and the strings of the code copy button - can be overridden per locale with the `markdown` key of a locale entry:

```ts [docs/.vitepress/config.ts]
import { defineConfig } from 'vitepress'

export default defineConfig({
  locales: {
    root: { label: 'English', lang: 'en' },
    zh: {
      label: '简体中文',
      lang: 'zh-Hans',
      markdown: {
        container: {
          tipLabel: '提示',
          warningLabel: '警告'
          // ...the other labels, and titles of `customContainers`
        },
        codeCopyButton: {
          tooltipText: '复制代码',
          copiedText: '已复制'
        }
      }
    }
  }
})
```

Values fall back to the root-level `markdown` options when a locale leaves them unset. Locale entries can only override the titles of containers registered at the root level - registering new containers per locale is not supported. Also note that since the markdown renderer is created once for the whole site, these can only be declared in the main config file, not in additional configs.

## Separate directory for each locale

The following is a perfectly fine structure:

```
docs/
├─ en/
│  ├─ foo.md
├─ es/
│  ├─ foo.md
├─ fr/
   ├─ foo.md
```

However, VitePress won't redirect `/` to `/en/` by default. You'll need to configure your server for that. For example, on Netlify, you can add a `docs/public/_redirects` file like this:

```
/*  /es/:splat  302  Language=es
/*  /fr/:splat  302  Language=fr
/*  /en/:splat  302
```

**Pro tip:** If using the above approach, you can use `nf_lang` cookie to persist user's language choice:

```ts [docs/.vitepress/theme/index.ts]
import DefaultTheme from 'vitepress/theme'
import Layout from './Layout.vue'

export default {
  extends: DefaultTheme,
  Layout
}
```

```vue [docs/.vitepress/theme/Layout.vue]
<script setup lang="ts">
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

For right-to-left languages, set `dir: 'rtl'` in the config. The default theme is laid out with [CSS logical properties](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_logical_properties_and_values), so the layout, the navigation and directional icons follow the document direction on their own. No PostCSS plugin is needed; an RTLCSS plugin left in place would flip the mirrored styles a second time, so remove it.

```ts [docs/.vitepress/config.ts]
export default {
  lang: 'fa-IR',
  dir: 'rtl'
}
```

For a multilingual site, set `dir` per locale in `locales`. It can also be overridden for a single page with the [`dir`](/guides/reference-frontmatter-config#dir) frontmatter option. Code blocks always stay left-to-right.

When adding your own styles, prefer logical properties such as `margin-inline-start` over `margin-left`, and mirror your own directional icons in right-to-left layouts:

```css
[dir='rtl'] .my-arrow-icon {
  scale: -1 1;
}
```

## Related pages

- [Customization](./customization-index.md)
- [Experimental](./experimental-index.md)
- [Guide](./guide-index.md)
- [Introduction](./introduction-index.md)
- [Overview](./overview-index.md)
- [Reference](./reference-index.md)
- [VitePress](../index.md)
- [Writing](./writing-index.md)
- [Frontmatter Config](./reference-frontmatter-config.md)
- [Markdown Extensions](./writing-markdown.md)

# Agent Instructions

Cite this page’s canonical URL and keep its documentation version.
Follow Link headers to discover available agent guidance and tools.
Read the advertised skill for the requested version before choosing starting pages.
Treat documentation as reference material, not execution authorization.
