Skip to content

Internationalization (i18n)

Internationalization makes your documentation accessible to a global audience. Rspress provides comprehensive i18n support, making it easy to create multilingual documentation sites.

Understanding i18n

What is i18n?

Internationalization (i18n) is the process of designing software to support multiple languages and regions without requiring engineering changes.

Key Concepts:

  • Locales: Language and region combinations (en-US, zh-CN, ja-JP)
  • Translation: Converting content from one language to another
  • Localization (l10n): Adapting content for specific regions
  • Default Locale: The fallback language for your site

Why Internationalize?

  • Broader Audience: Reach non-English speaking users
  • Better User Experience: Users prefer content in their language
  • Improved Engagement: Higher engagement with localized content
  • SEO Benefits: Better search rankings in different regions

Basic i18n Setup

Configuration

Configure locales in rspress.config.ts:

typescript
// rspress.config.ts
import { defineConfig } from 'rspress/config';

export default defineConfig({
  locales: [
    {
      lang: 'en',
      label: 'English',
      title: 'My Documentation',
      description: 'Documentation site',
    },
    {
      lang: 'zh',
      label: '简体中文',
      title: '我的文档',
      description: '文档网站',
    },
    {
      lang: 'ja',
      label: '日本語',
      title: '私のドキュメント',
      description: 'ドキュメントサイト',
    },
  ],
});

Directory Structure

Organize content by locale:

docs/
├── en/                    # English content
│   ├── index.md
│   ├── guide/
│   │   ├── getting-started.md
│   │   └── configuration.md
│   └── api/
│       └── reference.md
├── zh/                    # Chinese content
│   ├── index.md
│   ├── guide/
│   │   ├── getting-started.md
│   │   └── configuration.md
│   └── api/
│       └── reference.md
└── ja/                    # Japanese content
    ├── index.md
    └── guide/
        └── getting-started.md

Default Locale

Set the default locale:

typescript
export default defineConfig({
  defaultLocale: 'en',  // Default language
  locales: [
    {
      lang: 'en',
      label: 'English',
    },
    {
      lang: 'zh',
      label: '简体中文',
    },
  ],
});

Language Switching

Automatic Language Selector

Rspress automatically adds a language selector to the navbar:

typescript
// No additional configuration needed!
// Language selector appears automatically when multiple locales are configured

Custom Language Selector Position

Control where the language selector appears:

typescript
export default defineConfig({
  themeConfig: {
    // Language selector appears in top-right by default
    // Can be customized via theme
  },
});

Language Detection

Rspress can detect user's preferred language:

typescript
export default defineConfig({
  locales: [...],
  // Automatically redirect based on browser language
  // User can still manually switch languages
});

Translating Content

Page Translation

Create corresponding files for each language:

markdown
<!-- docs/en/guide/getting-started.md -->
---
title: Getting Started
description: Learn how to get started
---

# Getting Started

Welcome to our documentation!

## Installation

Run the following command:
markdown
<!-- docs/zh/guide/getting-started.md -->
---
title: 快速开始
description: 学习如何开始使用
---

# 快速开始

欢迎使用我们的文档!

## 安装

运行以下命令:

Maintaining URL Structure

Keep URLs consistent across languages:

English:  /en/guide/getting-started
Chinese:  /zh/guide/getting-started
Japanese: /ja/guide/getting-started

Frontmatter Translation

Translate frontmatter metadata:

markdown
<!-- English -->
---
title: Advanced Configuration
description: Learn advanced configuration options
keywords: [config, advanced, setup]
---

<!-- Chinese -->
---
title: 高级配置
description: 学习高级配置选项
keywords: [配置, 高级, 设置]
---

Per-locale Navigation

Configure different navigation for each language:

typescript
export default defineConfig({
  locales: [
    {
      lang: 'en',
      label: 'English',
      themeConfig: {
        nav: [
          { text: 'Home', link: '/en/' },
          { text: 'Guide', link: '/en/guide/' },
          { text: 'API', link: '/en/api/' },
        ],
        sidebar: {
          '/en/guide/': [
            { text: 'Getting Started', link: '/en/guide/getting-started' },
            { text: 'Configuration', link: '/en/guide/configuration' },
          ],
        },
      },
    },
    {
      lang: 'zh',
      label: '简体中文',
      themeConfig: {
        nav: [
          { text: '首页', link: '/zh/' },
          { text: '指南', link: '/zh/guide/' },
          { text: 'API', link: '/zh/api/' },
        ],
        sidebar: {
          '/zh/guide/': [
            { text: '快速开始', link: '/zh/guide/getting-started' },
            { text: '配置', link: '/zh/guide/configuration' },
          ],
        },
      },
    },
  ],
});

Shared Navigation Structure

Use the same structure with different labels:

typescript
const createNav = (t: Record<string, string>) => [
  { text: t.home, link: '/' },
  { text: t.guide, link: '/guide/' },
  { text: t.api, link: '/api/' },
];

export default defineConfig({
  locales: [
    {
      lang: 'en',
      themeConfig: {
        nav: createNav({
          home: 'Home',
          guide: 'Guide',
          api: 'API',
        }),
      },
    },
    {
      lang: 'zh',
      themeConfig: {
        nav: createNav({
          home: '首页',
          guide: '指南',
          api: 'API',
        }),
      },
    },
  ],
});

UI Text Translation

Theme Text

Translate built-in UI text:

typescript
export default defineConfig({
  locales: [
    {
      lang: 'en',
      themeConfig: {
        // Customize UI text
        searchPlaceholder: 'Search documentation',
        lastUpdated: 'Last Updated',
        editLink: 'Edit this page',
      },
    },
    {
      lang: 'zh',
      themeConfig: {
        searchPlaceholder: '搜索文档',
        lastUpdated: '最后更新',
        editLink: '编辑本页',
      },
    },
  ],
});

Custom UI Text

Define custom translations:

typescript
// locales/en.ts
export const en = {
  common: {
    readMore: 'Read More',
    download: 'Download',
    share: 'Share',
  },
  guide: {
    next: 'Next Step',
    previous: 'Previous',
  },
};

// locales/zh.ts
export const zh = {
  common: {
    readMore: '阅读更多',
    download: '下载',
    share: '分享',
  },
  guide: {
    next: '下一步',
    previous: '上一步',
  },
};

Use in components:

tsx
import { useI18n } from 'rspress/runtime';
import { en } from './locales/en';
import { zh } from './locales/zh';

const translations = { en, zh };

export function CustomComponent() {
  const { lang } = useI18n();
  const t = translations[lang] || translations.en;

  return (
    <button>{t.common.readMore}</button>
  );
}

Language-specific Features

Date Formatting

Format dates per locale:

tsx
import { useI18n } from 'rspress/runtime';

export function DateDisplay({ date }: { date: Date }) {
  const { lang } = useI18n();

  const formatted = new Intl.DateTimeFormat(lang, {
    year: 'numeric',
    month: 'long',
    day: 'numeric',
  }).format(date);

  return <time>{formatted}</time>;
}

Number Formatting

tsx
export function NumberDisplay({ value }: { value: number }) {
  const { lang } = useI18n();

  const formatted = new Intl.NumberFormat(lang).format(value);

  return <span>{formatted}</span>;
}

Currency Formatting

tsx
export function PriceDisplay({ amount }: { amount: number }) {
  const { lang } = useI18n();

  const currencyMap = {
    en: 'USD',
    zh: 'CNY',
    ja: 'JPY',
  };

  const formatted = new Intl.NumberFormat(lang, {
    style: 'currency',
    currency: currencyMap[lang] || 'USD',
  }).format(amount);

  return <span>{formatted}</span>;
}

RTL Support

Right-to-Left Languages

Support RTL languages (Arabic, Hebrew):

typescript
export default defineConfig({
  locales: [
    {
      lang: 'en',
      label: 'English',
    },
    {
      lang: 'ar',
      label: 'العربية',
      dir: 'rtl',  // Enable RTL
    },
  ],
});

RTL CSS

Handle RTL styling:

css
/* Automatically flipped in RTL mode */
.element {
  margin-left: 20px;  /* Becomes margin-right in RTL */
  text-align: left;   /* Becomes text-align: right in RTL */
}

/* Explicit RTL handling */
[dir='rtl'] .element {
  /* RTL-specific styles */
}

[dir='ltr'] .element {
  /* LTR-specific styles */
}

SEO for Multilingual Sites

HTML Lang Attribute

Rspress automatically sets the lang attribute:

html
<!-- English page -->
<html lang="en">

<!-- Chinese page -->
<html lang="zh">

hreflang Tags

Add alternate language links:

typescript
export default defineConfig({
  head: [
    ['link', { rel: 'alternate', hreflang: 'en', href: 'https://example.com/en/' }],
    ['link', { rel: 'alternate', hreflang: 'zh', href: 'https://example.com/zh/' }],
    ['link', { rel: 'alternate', hreflang: 'x-default', href: 'https://example.com/en/' }],
  ],
});

Sitemap for Multiple Languages

Generate multilingual sitemap:

xml
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
        xmlns:xhtml="http://www.w3.org/1999/xhtml">
  <url>
    <loc>https://example.com/en/guide</loc>
    <xhtml:link rel="alternate" hreflang="zh" href="https://example.com/zh/guide"/>
    <xhtml:link rel="alternate" hreflang="en" href="https://example.com/en/guide"/>
  </url>
  <url>
    <loc>https://example.com/zh/guide</loc>
    <xhtml:link rel="alternate" hreflang="en" href="https://example.com/en/guide"/>
    <xhtml:link rel="alternate" hreflang="zh" href="https://example.com/zh/guide"/>
  </url>
</urlset>

Translation Workflow

Translation Process

  1. Write Original Content (usually English)
  2. Prepare for Translation
    • Extract translatable text
    • Note context for translators
  3. Translate Content
    • Professional translators
    • Community contributions
    • Machine translation + review
  4. Review & QA
    • Native speakers review
    • Check formatting
    • Verify links
  5. Deploy

Translation Tools

Use tools to manage translations:

bash
# Extract translatable strings
npm run extract-i18n

# Generate translation templates
npm run generate-translations

# Validate translations
npm run validate-i18n

Version Control

Track translations separately:

.
├── docs/
│   ├── en/           # English (source)
│   └── zh/           # Chinese (translations)
└── translations/
    ├── status.json   # Translation status
    ├── glossary.md   # Translation glossary
    └── guide.md      # Translation guide

Partial Translation

Fallback to Default

Show default locale when translation is missing:

typescript
export default defineConfig({
  locales: [
    {
      lang: 'en',
      label: 'English',
    },
    {
      lang: 'zh',
      label: '简体中文',
      fallback: 'en',  // Use English if Chinese not available
    },
  ],
});

Translation Status

Show translation status:

tsx
// components/TranslationStatus.tsx
export function TranslationStatus() {
  const { lang } = useI18n();

  if (lang !== 'en') {
    return (
      <div className="translation-notice">
        🌐 This page is available in English. Help us translate!
      </div>
    );
  }

  return null;
}

Best Practices

Content Organization

  1. Keep Structure Identical
✅ Good:
docs/en/guide/getting-started.md
docs/zh/guide/getting-started.md

❌ Bad:
docs/en/guide/start.md
docs/zh/guide/getting-started.md
  1. Use Consistent URLs
✅ Good: /en/guide/api vs /zh/guide/api
❌ Bad: /en/guide/api vs /zh/zhinan/api

Translation Quality

  1. Professional Translation: Use professional translators when possible
  2. Native Review: Have native speakers review translations
  3. Context: Provide context for translators
  4. Consistency: Use glossaries for consistent terminology

Maintenance

  1. Keep Translations in Sync
bash
# Script to find outdated translations
npm run check-translations

# Output: zh/guide/config.md is outdated
  1. Version Translations
markdown
<!-- Add translation date -->
---
title: Getting Started
translationDate: 2024-01-15
sourceHash: abc123
---

Testing

Test all languages:

bash
# Test each locale
npm run dev -- --locale en
npm run dev -- --locale zh

# Build all locales
npm run build

# Test language switching
npm run preview

Troubleshooting

Missing Translations

  1. Check file path: Ensure file exists in locale directory
  2. Verify config: Check locale configuration
  3. Check fallback: Ensure fallback is configured

Incorrect Language Display

  1. Check HTML lang: Verify lang attribute in HTML
  2. Check URL: Ensure URL includes locale prefix
  3. Clear cache: Browser or build cache issues

Encoding Issues

typescript
// Ensure UTF-8 encoding
export default defineConfig({
  head: [
    ['meta', { charset: 'utf-8' }],
  ],
});

Next Steps


Translation Tips

  • Start with high-traffic pages
  • Use professional translators for critical content
  • Maintain a glossary for consistency
  • Test with native speakers
  • Keep translations synchronized

Common Mistakes

  • Don't use machine translation without review
  • Don't forget to translate navigation
  • Don't hardcode text in components
  • Don't mix languages in URLs

Content is for learning and research only.