Blog

LunariaJS CI/CD Integration - Automate Your Localization Workflow

Learn how to integrate LunariaJS into GitHub Actions, GitLab CI, and other CI/CD platforms, implement automatic translation status checks, automatic dashboard builds and deployments, making localization workflow fully automated.

LibDoc Team March 6, 2026 LunariaJS Series 84 min read
#LunariaJS #CI/CD #GitHub Actions #automation #continuous integration

LunariaJS CI/CD Integration - Automate Your Localization Workflow

In previous articles, we learned LunariaJS’s core features, Git workflow, and Astro Starlight integration. Today, let’s take the localization workflow to the next level — achieving complete automation through CI/CD.

💡 Official Documentation: LunariaJS Documentation - CI/CD

Value of CI/CD Integration

Why Automation?

Without CI/CD integration, localization management has these issues:

ProblemImpact
Manual translation status checksTime-consuming and error-prone
Dashboard not updated timelyTeam can’t see latest status
Translation issues discovered lateMissing translations found only after release
Lack of automated notificationsContributors don’t know translation is needed

Continuous Localization Concept

Continuous Localization is the practice of integrating translation work into CI/CD pipelines:

Code commit → Auto-detect translation changes → Update dashboard → Notify relevant people → Deploy

Core Values:

  • Instant feedback: Know translation status with every commit
  • Automation: Reduce manual operations, increase efficiency
  • Visibility: Team can check translation progress anytime
  • Quality assurance: Ensure translation completeness before release

GitHub Actions Integration

Basic Workflow Configuration

Create .github/workflows/lunaria.yml:

name: Lunaria Dashboard

on:
  push:
    branches: [main]
    paths:
      - 'docs/**'
      - 'i18n/**'
      - 'lunaria.config.json'
  pull_request:
    branches: [main]
  workflow_dispatch:  # Manual trigger

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 0  # Get complete Git history

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Build Lunaria Dashboard
        run: npx lunaria build

      - name: Upload dashboard artifact
        uses: actions/upload-artifact@v4
        with:
          name: lunaria-dashboard
          path: lunaria-dashboard/
          retention-days: 7

Auto-deploy to GitHub Pages

Automatically deploy dashboard to GitHub Pages:

name: Deploy Lunaria Dashboard

on:
  push:
    branches: [main]
  workflow_dispatch:

permissions:
  contents: read
  pages: write
  id-token: write

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Build main site
        run: npm run build

      - name: Build Lunaria Dashboard
        run: npx lunaria build

      - name: Setup Pages
        uses: actions/configure-pages@v4

      - name: Upload artifact
        uses: actions/upload-pages-artifact@v3
        with:
          path: './dist'

      - name: Deploy to GitHub Pages
        uses: actions/deploy-pages@v4

PR Translation Status Check

Automatically check translation status in Pull Requests:

name: Translation Check

on:
  pull_request:
    branches: [main]

jobs:
  check-translations:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Build Lunaria Dashboard
        run: npx lunaria build --silent

      - name: Check for missing translations
        id: check
        run: |
          # Parse dashboard data, check for new missing translations
          MISSING=$(node scripts/check-new-missing.js)
          echo "missing=$MISSING" >> $GITHUB_OUTPUT

      - name: Comment on PR
        if: steps.check.outputs.missing != ''
        uses: actions/github-script@v7
        with:
          script: |
            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: `## 🌙 Translation Status Update\n\n${{ steps.check.outputs.missing }}`
            })

Complete GitHub Actions Configuration

# .github/workflows/i18n.yml
name: i18n Automation

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
  schedule:
    # Generate report every Monday at 9 AM
    - cron: '0 9 * * 1'
  workflow_dispatch:

env:
  NODE_VERSION: '20'

jobs:
  # Job 1: Check translation status
  check:
    name: Check Translation Status
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Build Lunaria Dashboard
        run: npx lunaria build

      - name: Generate status report
        id: report
        run: |
          # Generate status report
          REPORT=$(node scripts/generate-report.js)
          echo "report<<EOF" >> $GITHUB_OUTPUT
          echo "$REPORT" >> $GITHUB_OUTPUT
          echo "EOF" >> $GITHUB_OUTPUT

      - name: Upload dashboard
        uses: actions/upload-artifact@v4
        with:
          name: lunaria-dashboard
          path: lunaria-dashboard/

    outputs:
      report: ${{ steps.report.outputs.report }}

  # Job 2: Deploy dashboard (main branch only)
  deploy:
    name: Deploy Dashboard
    runs-on: ubuntu-latest
    needs: check
    if: github.ref == 'refs/heads/main'

    permissions:
      contents: read
      pages: write
      id-token: write

    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}

    steps:
      - name: Download dashboard
        uses: actions/download-artifact@v4
        with:
          name: lunaria-dashboard
          path: ./dashboard

      - name: Setup Pages
        uses: actions/configure-pages@v4

      - name: Upload to Pages
        uses: actions/upload-pages-artifact@v3
        with:
          path: ./dashboard

      - name: Deploy
        id: deployment
        uses: actions/deploy-pages@v4

  # Job 3: Send notification (scheduled task)
  notify:
    name: Send Weekly Report
    runs-on: ubuntu-latest
    needs: check
    if: github.event_name == 'schedule'

    steps:
      - name: Send Slack notification
        uses: slackapi/slack-github-action@v1
        with:
          payload: |
            {
              "text": "🌙 Weekly Translation Report",
              "blocks": [
                {
                  "type": "section",
                  "text": {
                    "type": "mrkdwn",
                    "text": "${{ needs.check.outputs.report }}"
                  }
                }
              ]
            }
        env:
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}

GitLab CI Integration

Basic Configuration

Create .gitlab-ci.yml:

# .gitlab-ci.yml
stages:
  - check
  - build
  - deploy

variables:
  NODE_VERSION: '20'

# Cache configuration
.node-cache:
  cache:
    key: ${CI_COMMIT_REF_SLUG}
    paths:
      - node_modules/

# Check translation status
lunaria-check:
  stage: check
  extends: .node-cache
  image: node:${NODE_VERSION}
  script:
    - npm ci
    - npx lunaria build
  artifacts:
    paths:
      - lunaria-dashboard/
    expire_in: 1 week
  only:
    - merge_requests
    - main

# Build and deploy
lunaria-deploy:
  stage: deploy
  image: node:${NODE_VERSION}
  needs:
    - lunaria-check
  script:
    - echo "Deploying Lunaria dashboard..."
    # Add your deployment script
  only:
    - main

GitLab Pages Integration

# .gitlab-ci.yml
image: node:20

stages:
  - deploy

pages:
  stage: deploy
  script:
    - npm ci
    - npm run build
    - npx lunaria build
    - mv lunaria-dashboard public
  artifacts:
    paths:
      - public
  only:
    - main

GitLab CI vs GitHub Actions Comparison

FeatureGitHub ActionsGitLab CI
Get complete historyfetch-depth: 0GIT_DEPTH: 0
Artifact uploadupload-artifactartifacts.paths
Deploy to Pagesdeploy-pagespages job
Secretssecrets.VARIABLEvariables.VARIABLE
Conditional executionif:only:/except:

Automation Task Design

Translation Completeness Check

Create custom check script scripts/check-new-missing.js:

// scripts/check-new-missing.js
const fs = require('fs');
const path = require('path');

function checkMissingTranslations() {
  // Read LunariaJS generated status data
  const statusPath = path.join('lunaria-dashboard', 'data', 'status.json');

  if (!fs.existsSync(statusPath)) {
    console.log('No status file found');
    return '';
  }

  const status = JSON.parse(fs.readFileSync(statusPath, 'utf8'));

  // Find missing translations
  const missing = [];
  for (const [lang, data] of Object.entries(status.languages)) {
    if (data.missing > 0) {
      missing.push({
        language: lang,
        count: data.missing,
        files: data.missingFiles || []
      });
    }
  }

  if (missing.length === 0) {
    return 'All translations are up to date!';
  }

  // Generate report
  let report = '### Missing Translations Found\n\n';
  for (const item of missing) {
    report += `- **${item.language}**: ${item.count} missing files\n`;
  }
  report += '\nPlease check the [Lunaria Dashboard](/i18n-status/) for details.';

  return report;
}

console.log(checkMissingTranslations());

Outdated Translation Alert

Check for outdated translations and issue warnings:

// scripts/check-outdated.js
const { execSync } = require('child_process');

function getOutdatedTranslations() {
  // Get source files updated in the last 7 days
  const recentChanges = execSync(
    'git log --since="7 days ago" --name-only --pretty=format: -- docs/en/',
    { encoding: 'utf8' }
  );

  const changedFiles = recentChanges
    .split('\n')
    .filter(f => f.trim())
    .map(f => f.replace('docs/en/', '').replace('.md', ''));

  if (changedFiles.length === 0) {
    return { hasOutdated: false, files: [] };
  }

  return {
    hasOutdated: true,
    files: changedFiles,
    message: `The following files were updated in the last 7 days and may need translation updates:\n${changedFiles.map(f => `- ${f}`).join('\n')}`
  };
}

const result = getOutdatedTranslations();
if (result.hasOutdated) {
  console.log(result.message);
  process.exit(1);  // Non-zero exit code will fail CI
} else {
  console.log('No recent source changes requiring translation updates.');
}

Dashboard Auto-publish

Automatically publish dashboard after build:

- name: Publish Dashboard
  run: |
    # Copy dashboard to publish directory
    cp -r lunaria-dashboard ./dist/i18n-status

    # Update deployment status
    echo "Dashboard published to /i18n-status/"

Notifications and Reports

Slack Notification

- name: Notify Slack
  if: always()
  uses: slackapi/slack-github-action@v1
  with:
    channel-id: 'C0123456789'
    payload: |
      {
        "text": "Lunaria Dashboard Update",
        "attachments": [
          {
            "color": "${{ job.status == 'success' && 'good' || 'danger' }}",
            "fields": [
              {
                "title": "Status",
                "value": "${{ job.status }}",
                "short": true
              },
              {
                "title": "Branch",
                "value": "${{ github.ref_name }}",
                "short": true
              },
              {
                "title": "Dashboard URL",
                "value": "<https://your-org.github.io/your-repo/i18n-status/|View Dashboard>",
                "short": false
              }
            ]
          }
        ]
      }
  env:
    SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}

PR Comment Bot

Automatically comment translation status in PRs:

- name: Comment on PR
  uses: actions/github-script@v7
  with:
    script: |
      const status = require('./lunaria-dashboard/data/status.json');

      let body = '## 🌙 Translation Status\n\n';
      body += '| Language | Done | Outdated | Missing | Progress |\n';
      body += '|----------|------|----------|---------|----------|\n';

      for (const [lang, data] of Object.entries(status.languages)) {
        const progress = Math.round((data.done / data.total) * 100);
        const emoji = progress >= 90 ? 'Done' : progress >= 70 ? 'Warning' : 'Error';
        body += `| ${lang} | ${data.done} | ${data.outdated} | ${data.missing} | ${progress}% |\n`;
      }

      github.rest.issues.createComment({
        issue_number: context.issue.number,
        owner: context.repo.owner,
        repo: context.repo.repo,
        body: body
      });

Email Report

Send periodic email reports:

- name: Send Email Report
  if: github.event_name == 'schedule'
  uses: dawidd6/action-send-mail@v3
  with:
    server_address: smtp.gmail.com
    server_port: 465
    username: ${{ secrets.EMAIL_USERNAME }}
    password: ${{ secrets.EMAIL_PASSWORD }}
    subject: Weekly Translation Report - ${{ github.repository }}
    to: team@example.com
    from: CI Bot
    body: |
      Hi Team,

      Here's the weekly translation status report:

      ${{ needs.check.outputs.report }}

      View the full dashboard: https://your-org.github.io/your-repo/i18n-status/

      Best regards,
      CI Bot

CI/CD Best Practices

1. Conditional Triggers

Only trigger when relevant files change:

on:
  push:
    branches: [main]
    paths:
      - 'docs/**'
      - 'i18n/**'
      - 'lunaria.config.json'
      - '.github/workflows/lunaria.yml'

2. Cache Optimization

Use caching to speed up builds:

- name: Setup Node.js
  uses: actions/setup-node@v4
  with:
    node-version: '20'
    cache: 'npm'  # Enable npm cache

- name: Cache Lunaria output
  uses: actions/cache@v4
  with:
    path: .lunaria-cache
    key: lunaria-${{ hashFiles('docs/**', 'i18n/**') }}

3. Failure Strategy

Set reasonable failure strategies:

jobs:
  check:
    continue-on-error: true  # Translation check failure doesn't block deployment

  deploy:
    needs: check
    if: always() && needs.check.result == 'success'

4. Parallel Execution

Execute multiple check tasks in parallel:

jobs:
  check-missing:
    # ...

  check-outdated:
    # ...

  report:
    needs: [check-missing, check-outdated]
    # ...

5. Security Best Practices

# Use minimal permissions
permissions:
  contents: read
  pull-requests: write

# Don't expose secrets
env:
  DASHBOARD_URL: ${{ secrets.DASHBOARD_URL }}  # Don't expose in logs

Summary

Through CI/CD integration, LunariaJS can achieve fully automated localization workflows:

FeatureImplementation
Auto-detect translation changesGitHub Actions / GitLab CI
Auto-build dashboardTriggered on every commit
Auto-deployGitHub Pages / GitLab Pages
Auto-notifySlack / Email / PR comments
Periodic reportsScheduled jobs

Key Points:

  • Use fetch-depth: 0 to get complete Git history
  • Configure conditional triggers to reduce unnecessary builds
  • Leverage caching to speed up CI runs
  • Set up reasonable notification mechanisms

Next Steps

Congratulations on completing the LunariaJS introductory series! Starting from the next article, we’ll enter the Deep Dive section, exploring:

  • Part 8: @lunariajs/core Source Code Deep Dive (8,000-15,000 words)
  • Part 9: Advanced Configuration and Custom Strategies (8,000-15,000 words)
  • Part 10: Complete Enterprise-level Implementation (8,000-15,000 words)

Stay tuned!


💡 Recommended Reading: