Blog

Astro Starlight + LunariaJS - Building the Perfect Multilingual Documentation Site

Step-by-step guide to integrating LunariaJS into Astro Starlight documentation sites, from installation and configuration to dashboard embedding, creating a professional documentation site with multilingual support and visual translation progress tracking.

LibDoc Team March 6, 2026 LunariaJS Series 81 min read
#LunariaJS #Astro #Starlight #documentation site #multilingual

Astro Starlight + LunariaJS - Building the Perfect Multilingual Documentation Site

In previous articles, we learned LunariaJS’s core features and Git workflow integration. Today, let’s explore the perfect combination of LunariaJS and Astro Starlight, guiding you step-by-step to build a professional multilingual documentation site.

💡 Official Documentation: LunariaJS Documentation - Starlight Integration

Starlight Introduction

What is Astro Starlight?

Astro Starlight is a modern documentation theme built on the Astro framework, providing:

FeatureDescription
Rocket performanceAstro’s partial hydration technology, blazing fast page loads
Beautiful designProfessional documentation interface out of the box
ResponsivePerfect adaptation for desktop and mobile devices
Built-in searchPagefind full-text search
Dark modeAutomatic system preference detection
InternationalizationNative multilingual support

Why Do You Need LunariaJS?

While Starlight provides internationalization (i18n) support, it doesn’t include translation management features:

NeedStarlight+ LunariaJS
Multilingual routingSupportedSupported
Language switcherSupportedSupported
Translated UI componentsSupportedSupported
Translation status trackingNot supportedSupported
Visual dashboardNot supportedSupported
Git workflow integrationNot supportedSupported

LunariaJS fills the gap in Starlight’s translation management capabilities.

@lunariajs/starlight Installation

Prerequisites

Ensure your project meets these conditions:

  • Astro 4.0+ or 5.0+
  • Starlight installed
  • Project uses Git for version control

Installation Steps

1. Install Dependencies

# Using npm
npm install @lunariajs/starlight

# Using yarn
yarn add @lunariajs/starlight

# Using pnpm
pnpm add @lunariajs/starlight

2. Check Version Compatibility

# View installed versions
npm list @astrojs/starlight @lunariajs/starlight

Ensure versions are compatible:

@astrojs/starlight@lunariajs/starlight
0.25.x0.4.x
0.26.x+0.5.x+

Starlight Configuration Integration

Basic Configuration

Add LunariaJS integration in astro.config.mjs:

// astro.config.mjs
import { defineConfig } from 'astro/config';
import starlight from '@astrojs/starlight';
import lunaria from '@lunariajs/starlight';

export default defineConfig({
  integrations: [
    starlight({
      title: 'My Documentation',
      defaultLocale: 'en',
      locales: {
        en: { label: 'English' },
        'zh-cn': { label: '简体中文' },
        ja: { label: '日本語' },
        ko: { label: '한국어' },
      },
      sidebar: [
        { label: 'Guide', link: '/guide/' },
        { label: 'Reference', link: '/reference/' },
      ],
    }),
    lunaria({
      // LunariaJS configuration
      sourceLanguage: 'en',
      languages: ['en', 'zh-cn', 'ja', 'ko'],
    }),
  ],
});

Sync i18n Configuration with LunariaJS

Ensure Starlight’s i18n configuration is consistent with LunariaJS:

// astro.config.mjs
const languages = ['en', 'zh-cn', 'ja', 'ko'];
const sourceLanguage = 'en';

export default defineConfig({
  integrations: [
    starlight({
      title: 'My Documentation',
      defaultLocale: sourceLanguage,
      locales: Object.fromEntries(
        languages.map(lang => [
          lang,
          { label: getLanguageLabel(lang) }
        ])
      ),
    }),
    lunaria({
      sourceLanguage,
      languages,
    }),
  ],
});

function getLanguageLabel(lang) {
  const labels = {
    en: 'English',
    'zh-cn': '简体中文',
    ja: '日本語',
    ko: '한국어',
  };
  return labels[lang] || lang;
}

Routing Structure Design

Recommended directory structure for Starlight + LunariaJS:

src/
└── content/
    └── docs/
        ├── en/                    # English (source language)
        │   ├── index.md
        │   ├── guide.md
        │   └── reference.md
        ├── zh-cn/                 # Chinese translation
        │   ├── index.md
        │   ├── guide.md
        │   └── reference.md
        ├── ja/                    # Japanese translation
        │   └── ...
        └── ko/                    # Korean translation
            └── ...

Complete Configuration Example

// astro.config.mjs
import { defineConfig } from 'astro/config';
import starlight from '@astrojs/starlight';
import lunaria from '@lunariajs/starlight';

// Language configuration
const config = {
  sourceLanguage: 'en',
  languages: ['en', 'zh-cn', 'ja', 'ko'],
  languageLabels: {
    en: 'English',
    'zh-cn': '简体中文',
    ja: '日本語',
    ko: '한국어',
  },
};

export default defineConfig({
  site: 'https://docs.example.com',
  integrations: [
    starlight({
      title: 'My Project',
      defaultLocale: config.sourceLanguage,
      locales: Object.fromEntries(
        config.languages.map(lang => [
          lang,
          { label: config.languageLabels[lang] }
        ])
      ),
      sidebar: {
        en: [
          { label: 'Home', link: '/' },
          { label: 'Guide', link: '/guide/' },
          { label: 'API Reference', link: '/reference/' },
        ],
        'zh-cn': [
          { label: '首页', link: '/' },
          { label: '指南', link: '/guide/' },
          { label: 'API 参考', link: '/reference/' },
        ],
        // Other languages...
      },
      social: {
        github: 'https://github.com/your-org/your-repo',
      },
    }),
    lunaria({
      sourceLanguage: config.sourceLanguage,
      languages: config.languages,
      files: [
        {
          sourcePath: 'src/content/docs/{lang}/{slug}.md',
          localizationPath: 'src/content/docs/{lang}/{slug}.md',
        },
      ],
      dashboard: {
        outputDir: 'public/i18n-status',
        title: 'My Project - Translation Status',
      },
    }),
  ],
});

Dashboard Embedding

Method 1: As Standalone Path

Place LunariaJS dashboard under /i18n-status/ path:

// astro.config.mjs
lunaria({
  dashboard: {
    outputDir: 'public/i18n-status',
  },
})

After building, visit /i18n-status/ to view the dashboard.

Method 2: Add to Navigation Menu

Add dashboard link in Starlight navigation:

// astro.config.mjs
starlight({
  title: 'My Documentation',
  sidebar: [
    { label: 'Guide', link: '/guide/' },
    { label: 'Reference', link: '/reference/' },
    {
      label: 'Translation Status',
      link: '/i18n-status/',
      badge: 'New',
    },
  ],
})

Method 3: Custom Navigation Component

Create custom navigation component to display translation progress:

---
// src/components/I18nStatus.astro
---
<a href="/i18n-status/" class="i18n-status-link">
  <span class="icon">🌐</span>
  <span>Translation Status</span>
</a>

<style>
  .i18n-status-link {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 1rem;
    background: var(--sl-color-bg);
    border-radius: 0.5rem;
    text-decoration: none;
    color: var(--sl-color-text);
    transition: background 0.2s;
  }

  .i18n-status-link:hover {
    background: var(--sl-color-bg-hover);
  }
</style>

Style Customization

Override LunariaJS dashboard default styles:

/* src/styles/lunaria-custom.css */
:root {
  /* Use Starlight's color variables */
  --lunaria-color-primary: var(--sl-color-accent);
  --lunaria-color-success: var(--sl-color-green);
  --lunaria-color-warning: var(--sl-color-orange);
  --lunaria-color-danger: var(--sl-color-red);

  /* Background colors */
  --lunaria-bg-primary: var(--sl-color-bg);
  --lunaria-bg-secondary: var(--sl-color-bg-sidebar);
}

Then reference in configuration:

// astro.config.mjs
lunaria({
  dashboard: {
    customCss: './src/styles/lunaria-custom.css',
  },
})

Hands-on: Building a Trilingual Documentation Site

Let’s build a trilingual documentation site supporting Chinese, Japanese, and Korean through a complete hands-on example.

Step 1: Create Starlight Project

# Create project using template
npm create astro@latest -- --template starlight

# Enter project directory
cd my-docs

# Install dependencies
npm install

Step 2: Install LunariaJS

npm install @lunariajs/starlight

Step 3: Configure Multilingual

Edit astro.config.mjs:

import { defineConfig } from 'astro/config';
import starlight from '@astrojs/starlight';
import lunaria from '@lunariajs/starlight';

export default defineConfig({
  integrations: [
    starlight({
      title: 'My Project Docs',
      defaultLocale: 'en',
      locales: {
        en: { label: 'English', lang: 'en' },
        'zh-cn': { label: '简体中文', lang: 'zh-CN' },
        ja: { label: '日本語', lang: 'ja' },
        ko: { label: '한국어', lang: 'ko' },
      },
      sidebar: {
        en: [
          { label: 'Home', link: '/' },
          { label: 'Getting Started', items: [
            { label: 'Introduction', link: '/getting-started/' },
            { label: 'Installation', link: '/installation/' },
          ]},
        ],
        'zh-cn': [
          { label: '首页', link: '/' },
          { label: '快速开始', items: [
            { label: '简介', link: '/getting-started/' },
            { label: '安装', link: '/installation/' },
          ]},
        ],
        ja: [
          { label: 'ホーム', link: '/' },
          { label: 'はじめに', items: [
            { label: '概要', link: '/getting-started/' },
            { label: 'インストール', link: '/installation/' },
          ]},
        ],
        ko: [
          { label: '홈', link: '/' },
          { label: '시작하기', items: [
            { label: '소개', link: '/getting-started/' },
            { label: '설치', link: '/installation/' },
          ]},
        ],
      },
    }),
    lunaria({
      sourceLanguage: 'en',
      languages: ['en', 'zh-cn', 'ja', 'ko'],
    }),
  ],
});

Step 4: Create Content Files

src/content/docs/
├── en/
│   ├── index.md
│   ├── getting-started.md
│   └── installation.md
├── zh-cn/
│   ├── index.md
│   └── getting-started.md      # Assume installation doc not yet translated
├── ja/
│   ├── index.md
│   └── getting-started.md
└── ko/
    └── index.md                 # Other docs not yet translated

Step 5: Add Translation Metadata

Each Markdown file should include frontmatter:

---
title: Getting Started
description: Learn how to get started with our project.
---

# Getting Started

Welcome to our project! This guide will help you...

Step 6: Build and Preview

# Build site and dashboard
npm run build

# Preview
npm run preview

Visit:

  • Documentation site: http://localhost:4321/
  • Translation dashboard: http://localhost:4321/i18n-status/

Step 7: Verify Translation Status

Open the dashboard, you should see something like:

Translation Status
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Language         Progress    Status
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
🇺🇸 English       100%        Source
🇨🇳 Chinese       67%         2/3 done, 1 missing
🇯🇵 Japanese      67%         2/3 done, 1 missing
🇰🇷 Korean        33%         1/3 done, 2 missing
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Common Issues and Solutions

Q1: Dashboard 404 Error

Problem: Accessing /i18n-status/ shows 404.

Solution:

# Ensure LunariaJS configured output directory is under public/
lunaria({
  dashboard: {
    outputDir: 'public/i18n-status',  // Must be under public/ directory
  },
})

# Ensure build is run first
npm run build

Q2: Inconsistent Language Codes

Problem: Starlight uses zh-CN, LunariaJS uses zh-cn.

Solution:

starlight({
  locales: {
    'zh-cn': { label: '简体中文', lang: 'zh-CN' },  // Note the difference
  },
})

Q3: Dashboard Style Conflicts

Problem: Dashboard styles inconsistent with documentation site.

Solution: Use custom CSS for unified styling:

/* Use Starlight variables in lunaria dashboard */
:root {
  --lunaria-color-primary: var(--sl-color-accent);
  --lunaria-bg-primary: var(--sl-color-bg);
}

Q4: Out of Memory During Build

Problem: Large documentation sites run out of memory during build.

Solution:

# Increase Node.js memory limit
NODE_OPTIONS="--max-old-space-size=4096" npm run build

Q5: Routing Conflicts

Problem: Dashboard path conflicts with documentation paths.

Solution: Choose a path that won’t conflict with documentation:

// Avoid common documentation paths like /docs/, /guide/
lunaria({
  dashboard: {
    outputDir: 'public/localization-status',  // Use unique path
  },
})

Best Practices

1. Unified Language Configuration

Create shared configuration file:

// src/i18n-config.js
export const languages = ['en', 'zh-cn', 'ja', 'ko'];
export const sourceLanguage = 'en';
export const languageLabels = {
  en: 'English',
  'zh-cn': '简体中文',
  ja: '日本語',
  ko: '한국어',
};

Reference in multiple places:

// astro.config.mjs
import { languages, sourceLanguage, languageLabels } from './src/i18n-config.js';

2. Automated Translation Checking

Add scripts in package.json:

{
  "scripts": {
    "dev": "astro dev",
    "build": "astro build",
    "preview": "astro preview",
    "i18n:check": "lunaria build",
    "i18n:preview": "lunaria preview"
  }
}

3. Add Translation Guide

Add translation contribution guide in documentation:

# Contributing Translations

We welcome translation contributions! Here's how to help:

1. Check the [Translation Status Dashboard](/i18n-status/)
2. Find a file marked as "missing" or "outdated"
3. Fork the repository and create a translation
4. Submit a pull request

Thank you for helping make our documentation accessible to everyone!

4. Setup CI/CD Checks

# .github/workflows/i18n-check.yml
name: i18n Status

on: [pull_request]

jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - uses: actions/setup-node@v4
        with:
          node-version: '20'

      - run: npm ci
      - run: npm run i18n:check

      - name: Upload Dashboard
        uses: actions/upload-artifact@v4
        with:
          name: i18n-dashboard
          path: public/i18n-status/

Summary

LunariaJS integration with Astro Starlight provides a complete multilingual documentation solution:

FeatureStarlight+ LunariaJS
Multilingual routingSupportedSupported
Language switchingSupportedSupported
Translated UISupportedSupported
Translation status trackingNot supportedSupported
Visual dashboardNot supportedSupported
Git workflowNot supportedSupported

Key Points:

  • Use @lunariajs/starlight package for seamless integration
  • Ensure language codes are consistent between Starlight and LunariaJS
  • Embed dashboard in navigation menu for easy access
  • Use unified configuration file to avoid duplicate maintenance

Next Steps

In the next article, we’ll explore LunariaJS CI/CD integration, learning how to:

  • Configure GitHub Actions automated builds
  • Design translation status check pipelines
  • Setup notification and reporting mechanisms
  • Implement continuous localization workflows

Stay tuned!


💡 Recommended Reading: