Skip to content

Automated markdown translation for Astro & Starlight using LLMs

License

Notifications You must be signed in to change notification settings

AsterisMono/astro-llm-translator

Repository files navigation

astro-llm-translator

An Astro integration that automatically translates your Markdown and MDX content using LLMs (OpenAI, Anthropic, DeepSeek, etc.) during the build process.

It features incremental builds, smart caching, and automatic synchronization of deletions, ensuring you only pay for what needs to be translated.

Installation

npm install astro-llm-translator openai
# or
pnpm add astro-llm-translator openai
# or
bun add astro-llm-translator openai

Note: You also need to install the openai package as a peer dependency.

Usage

Add the integration to your astro.config.mjs:

import { defineConfig } from 'astro/config';
import llmTranslator from 'astro-llm-translator';

export default defineConfig({
  integrations: [
    llmTranslator({
      sourceLang: 'en', // or 'root'
      targetLangs: ['es', 'fr', 'de'],
      contentDir: 'src/content/docs',
      openai: {
        model: 'gpt-4o-mini', // Optional: defaults to gpt-4o-mini
      }
    })
  ]
});

Configuration

Options

Option Type Default Description
sourceLang string Required The language code of your source content (e.g., 'en'). Set to 'root' if your source files are directly inside contentDir.
targetLangs string[] Required Array of language codes to translate into (e.g., ['es', 'fr']).
contentDir string 'src/content/docs' Directory relative to project root containing your content.
customInstructions string undefined Additional instructions to guide the translator (e.g. "Use a friendly tone").
dictionary Record<string, string> {} Key-value pairs of terms to force translation for (e.g. {'Astro': 'AstroFramework'}).
banner Record<string, string> {} Optional configuration to inject banner content into the frontmatter of translated files.
openai object {} Optional configuration for the LLM client.

Banner Configuration

You can inject a banner message into the frontmatter of translated files (e.g., to warn users that the content is AI-translated).

llmTranslator({
  // ...
  banner: {
    en: "This content is AI-translated.",
    es: "Este contenido ha sido traducido por IA."
  }
})

OpenAI Options (openai)

Option Type Default Description
apiKey string process.env.OPENAI_API_KEY Your API key.
baseURL string process.env.OPENAI_BASE_URL Base URL for the API (useful for OpenRouter or local models).
model string 'gpt-4o-mini' The model identifier to use.

Environment Variables

You can configure the LLM client using environment variables in your .env file:

# Standard OpenAI
OPENAI_API_KEY=sk-...

# Or OpenRouter / Custom Provider
OPENROUTER_API_KEY=sk-or-...
OPENROUTER_BASE_URL=https://openrouter.ai/api/v1
OPENAI_MODEL=anthropic/claude-3-haiku

# Skip translation processing (e.g. in CI/Pages build)
ASTRO_LLM_SKIP_TRANSLATE=true

The integration checks for keys in this order:

  1. options.openai.apiKey
  2. OPENAI_API_KEY
  3. OPENROUTER_API_KEY

Starlight Support

If you are using Starlight, you can use the companion plugin to automatically translate sidebar directory labels.

First, the main integration collects and translates directory names during the build process. Then, the Starlight plugin uses this data to reconstruct the sidebar with translated labels.

// astro.config.mjs
import { defineConfig } from 'astro/config';
import starlight from '@astrojs/starlight';
import llmTranslator from 'astro-llm-translator';
import starlightTranslator from 'astro-llm-translator/starlight'; // Import the plugin

export default defineConfig({
  integrations: [
    llmTranslator({
      sourceLang: 'en',
      targetLangs: ['es', 'fr'],
      // ... other options
    }),
    starlight({
      title: 'My Docs',
      defaultLocale: 'en',
      locales: {
        en: { label: 'English', lang: 'en' },
        es: { label: 'Español', lang: 'es' },
        fr: { label: 'Français', lang: 'fr' },
      },
      plugins: [
        starlightTranslator(), // Add the plugin here
      ],
      sidebar: [
        // Works with autogenerate!
        {
          label: 'Guides',
          autogenerate: { directory: 'guides' },
        },
      ],
    }),
  ],
});

Note: The main llmTranslator integration must be present to generate the translation data (src/.translator-segments.json) that the Starlight plugin relies on.

Directory Structure Examples

1. Subdirectory Mode (Default)

Config: sourceLang: 'en'

src/content/docs/
├── en/           <-- Source
│   └── index.md
├── es/           <-- Auto-generated
│   └── index.md
└── fr/           <-- Auto-generated
    └── index.md

2. Root Mode

Config: sourceLang: 'root'

src/content/docs/
├── index.md      <-- Source
├── about.md      <-- Source
├── es/           <-- Auto-generated (ignored by scanner)
│   ├── index.md
│   └── about.md
└── fr/           <-- Auto-generated (ignored by scanner)
    ├── index.md
    └── about.md

About

Automated markdown translation for Astro & Starlight using LLMs

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors