Blog

LunariaJS Advanced Configuration - Building Enterprise-grade Localization Management Solutions

Explore LunariaJS's advanced configuration options and custom localization strategies, learn multi-repository support, custom status rules, complex file structure handling, and other solutions for enterprise scenarios.

LibDoc Team March 6, 2026 LunariaJS Series 104 min read
#LunariaJS #advanced configuration #enterprise #custom strategies #Monorepo

LunariaJS Advanced Configuration - Building Enterprise-grade Localization Management Solutions

In the previous article, we took a deep dive into @lunariajs/core’s source code architecture. Today, let’s apply this knowledge in practice, exploring LunariaJS’s advanced configuration options to solve complex localization management needs in enterprise scenarios.

Official Documentation: LunariaJS Documentation - Advanced Configuration

Enterprise Scenario Challenges

Typical Enterprise Requirements

Enterprise projects typically face these localization challenges:

ChallengeDescriptionImpact
Multi-repository ManagementCode distributed across multiple Git repositoriesTranslation status hard to track uniformly
Complex File StructuresDifferent modules have different directory structuresComplex configuration, error-prone
Custom WorkflowsNeed to adapt to existing development processesStandard configuration can’t meet needs
Permission ControlDifferent teams have different access permissionsNeed fine-grained permission management
Large-scale FilesHundreds or thousands of translation filesPerformance becomes bottleneck
Multiple Source LanguagesDifferent modules may have different source languagesComplex status calculation logic

Chapter Learning Objectives

Through this chapter, you will learn to:

  • Configure complex multi-repository projects
  • Design custom status determination rules
  • Optimize performance for large projects
  • Integrate with enterprise tools and systems
  • Implement advanced security and permission controls

Advanced Configuration Options

Custom Status Rules

LunariaJS allows you to customize translation status determination logic:

// lunaria.config.ts
import { defineConfig } from '@lunariajs/core';

export default defineConfig({
  sourceLanguage: 'en',
  languages: ['en', 'zh-cn', 'ja', 'ko'],

  // Custom status determination
  statusRules: {
    // Customize "outdated" criteria
    outdated: {
      // Day threshold: how many days source is newer than translation to be considered outdated
      dayThreshold: 7,  // Default is 0, here set to 7 days

      // Or use custom function
      customCheck: async (source, translation) => {
        // Check if source has significant changes
        const changes = await getSignificantChanges(source.path);
        return changes.length > 0;
      },
    },

    // Customize "missing" criteria
    missing: {
      // Ignore certain file patterns
      ignorePatterns: ['**/internal/**', '**/draft/**'],

      // Or use custom function
      customCheck: (sourcePath, translationPath) => {
        // Check if translation is needed (some files may not need translation)
        const content = fs.readFileSync(sourcePath, 'utf-8');
        return !content.includes('<!-- no-translate -->');
      },
    },
  },

  files: [
    {
      sourcePath: 'docs/{slug}.md',
      localizationPath: 'i18n/{lang}/{slug}.md',
    },
  ],
});

Complex Path Mapping

Handle complex project structures:

// lunaria.config.ts
export default defineConfig({
  sourceLanguage: 'en',
  languages: ['en', 'zh-cn', 'ja', 'ko'],

  files: [
    // Documentation files
    {
      sourcePath: 'docs/guides/{slug}.md',
      localizationPath: 'docs/{lang}/guides/{slug}.md',
      include: ['**/*.md'],
      exclude: ['**/draft/**'],
    },

    // API reference documentation
    {
      sourcePath: 'docs/api/{category}/{slug}.md',
      localizationPath: 'docs/{lang}/api/{category}/{slug}.md',
    },

    // UI translation files (JSON)
    {
      sourcePath: 'src/locales/en/{module}.json',
      localizationPath: 'src/locales/{lang}/{module}.json',
    },

    // Configuration files
    {
      sourcePath: 'config/en/{slug}.yaml',
      localizationPath: 'config/{lang}/{slug}.yaml',
    },
  ],
});

Multi-source File Configuration

Some projects may have multiple source language directories:

// lunaria.config.ts
export default defineConfig({
  // Main source language
  sourceLanguage: 'en',

  // Secondary source languages (for specific modules)
  secondarySourceLanguages: {
    'packages/japanese-sdk': 'ja',  // This package's source language is Japanese
  },

  languages: ['en', 'ja', 'zh-cn', 'ko'],

  files: [
    // Main project - English as source language
    {
      sourcePath: 'docs/{slug}.md',
      localizationPath: 'docs/{lang}/{slug}.md',
      sourceLanguage: 'en',  // Explicitly specify
    },

    // Japanese SDK - Japanese as source language
    {
      sourcePath: 'packages/japanese-sdk/docs/{slug}.md',
      localizationPath: 'packages/japanese-sdk/docs/{lang}/{slug}.md',
      sourceLanguage: 'ja',  // Override global config
    },
  ],
});

Conditional Processing

Dynamically adjust configuration based on conditions:

// lunaria.config.ts
const isProduction = process.env.NODE_ENV === 'production';
const isCI = process.env.CI === 'true';

export default defineConfig({
  sourceLanguage: 'en',

  // Adjust language list based on environment
  languages: isProduction
    ? ['en', 'zh-cn', 'ja', 'ko', 'es', 'fr', 'de']
    : ['en', 'zh-cn'],  // Only track two languages in development environment

  files: [
    {
      sourcePath: 'docs/{slug}.md',
      localizationPath: 'i18n/{lang}/docs/{slug}.md',

      // Exclude draft files in CI environment
      exclude: isCI ? ['**/draft/**', '**/wip/**'] : [],
    },
  ],

  dashboard: {
    outputDir: isProduction ? 'dist/i18n-status' : 'public/i18n-status',
    title: isProduction ? 'Production i18n Status' : 'Development i18n Status',
  },
});

Multi-repository Localization Management

Monorepo Scenario Configuration

For Monorepo projects (using pnpm workspaces or Turborepo):

my-monorepo/
+-- packages/
|   +-- core/
|   |   +-- docs/
|   |   |   +-- en/
|   |   +-- i18n/
|   |       +-- zh-cn/
|   |       +-- ja/
|   +-- cli/
|   |   +-- docs/
|   |   |   +-- en/
|   |   +-- i18n/
|   |       +-- zh-cn/
|   |       +-- ja/
|   +-- ui/
|       +-- docs/
|       |   +-- en/
|       +-- i18n/
|           +-- zh-cn/
|           +-- ja/
+-- lunaria.config.ts
+-- package.json

Configuration Example:

// lunaria.config.ts
import { defineConfig } from '@lunariajs/core';
import { glob } from 'glob';

// Auto-discover all packages
const packages = await glob('packages/*');

export default defineConfig({
  sourceLanguage: 'en',
  languages: ['en', 'zh-cn', 'ja', 'ko'],

  // Generate independent file configuration for each package
  files: packages.flatMap(pkg => [
    {
      sourcePath: `${pkg}/docs/{slug}.md`,
      localizationPath: `${pkg}/i18n/{lang}/{slug}.md`,
      // Use package name as grouping
      group: pkg.replace('packages/', ''),
    },
  ]),

  dashboard: {
    outputDir: 'docs/i18n-status',
    title: 'My Monorepo - Translation Status',

    // Display grouped by package
    groupBy: 'group',
  },
});

Multi-repository Unified Dashboard

For multiple independent Git repositories, you can create an “aggregator” project:

i18n-aggregator/
+-- lunaria.config.ts
+-- package.json
+-- repos/
|   +-- main-docs/        # Main docs repository
|   +-- api-docs/         # API docs repository
|   +-- blog-content/     # Blog content repository

Aggregation Configuration:

// lunaria.config.ts
import { defineConfig } from '@lunariajs/core';

export default defineConfig({
  sourceLanguage: 'en',
  languages: ['en', 'zh-cn', 'ja', 'ko'],

  // Aggregate multiple repositories
  repositories: [
    {
      name: 'main-docs',
      path: './repos/main-docs',
      files: [
        {
          sourcePath: 'docs/{slug}.md',
          localizationPath: 'i18n/{lang}/{slug}.md',
        },
      ],
    },
    {
      name: 'api-docs',
      path: './repos/api-docs',
      files: [
        {
          sourcePath: 'src/content/docs/{slug}.md',
          localizationPath: 'src/content/docs/{lang}/{slug}.md',
        },
      ],
    },
    {
      name: 'blog-content',
      path: './repos/blog-content',
      files: [
        {
          sourcePath: 'posts/{slug}.md',
          localizationPath: 'posts/{lang}/{slug}.md',
        },
      ],
    },
  ],

  dashboard: {
    outputDir: 'public/i18n-status',
    title: 'All Projects - Translation Status',
  },
});

Custom Localization Strategies

Strategy Interface Design

Define custom localization strategy interfaces:

// src/strategies/types.ts
import { TranslationStatus, FileInfo } from '@lunariajs/core';

/**
 * Localization strategy interface
 */
export interface LocalizationStrategy {
  /** Strategy name */
  name: string;

  /** Strategy description */
  description: string;

  /**
   * Calculate translation status
   */
  calculateStatus(
    source: FileInfo,
    translation: FileInfo | null,
    context: StrategyContext
  ): Promise<TranslationStatus>;

  /**
   * Whether translation is needed
   */
  needsTranslation?(
    source: FileInfo,
    context: StrategyContext
  ): Promise<boolean>;

  /**
   * Get translation priority
   */
  getPriority?(
    source: FileInfo,
    translation: FileInfo | null,
    context: StrategyContext
  ): Promise<'high' | 'medium' | 'low'>;
}

/**
 * Strategy context
 */
export interface StrategyContext {
  /** Language code */
  language: string;

  /** Project configuration */
  config: LunariaConfig;

  /** Git information */
  git: {
    lastCommit: string;
    author: string;
    date: Date;
  };

  /** Custom data */
  data?: Record<string, unknown>;
}

Implement Custom Strategy

Create content complexity-based strategy:

// src/strategies/content-complexity.ts
import { LocalizationStrategy, StrategyContext, FileInfo } from './types';

/**
 * Content complexity-based strategy
 * Dynamically adjusts "outdated" criteria based on source file complexity
 */
export const ContentComplexityStrategy: LocalizationStrategy = {
  name: 'content-complexity',
  description: 'Adjust translation status criteria based on content complexity',

  async calculateStatus(
    source: FileInfo,
    translation: FileInfo | null,
    context: StrategyContext
  ) {
    // If translation doesn't exist, return missing
    if (!translation) {
      return { status: 'missing', reason: 'Translation file not found' };
    }

    // Calculate content complexity
    const complexity = calculateComplexity(source.content);

    // Determine day threshold based on complexity
    const dayThreshold = getDayThreshold(complexity);

    // Check time difference
    const sourceTime = source.lastModified.getTime();
    const translationTime = translation.lastModified.getTime();
    const daysDiff = (sourceTime - translationTime) / (1000 * 60 * 60 * 24);

    if (daysDiff > dayThreshold) {
      return {
        status: 'outdated',
        reason: `Source is ${daysDiff.toFixed(0)} days newer (threshold: ${dayThreshold})`,
        complexity,
      };
    }

    return {
      status: 'done',
      complexity,
    };
  },

  async getPriority(source: FileInfo, translation: FileInfo | null) {
    const complexity = calculateComplexity(source.content);

    if (complexity > 0.8) return 'high';
    if (complexity > 0.5) return 'medium';
    return 'low';
  },
};

/**
 * Calculate content complexity (0-1)
 */
function calculateComplexity(content: string): number {
  const factors = {
    // Code block count
    codeBlocks: (content.match(/```/g) || []).length / 10,

    // Link count
    links: (content.match(/\[.*?\]\(.*?\)/g) || []).length / 20,

    // Special syntax
    specialSyntax: (content.match(/\{.*?\}/g) || []).length / 30,

    // File length
    length: content.length / 10000,
  };

  // Weighted average
  return (
    factors.codeBlocks * 0.3 +
    factors.links * 0.2 +
    factors.specialSyntax * 0.3 +
    factors.length * 0.2
  );
}

/**
 * Get day threshold based on complexity
 */
function getDayThreshold(complexity: number): number {
  // Higher complexity, larger threshold (give translators more time)
  if (complexity > 0.8) return 30;
  if (complexity > 0.5) return 14;
  return 7;
}

Register Custom Strategy

// lunaria.config.ts
import { defineConfig } from '@lunariajs/core';
import { ContentComplexityStrategy } from './src/strategies/content-complexity';

export default defineConfig({
  sourceLanguage: 'en',
  languages: ['en', 'zh-cn', 'ja', 'ko'],

  // Register custom strategies
  strategies: {
    // Default strategy
    default: 'git-timestamp',

    // Apply different strategies by file pattern
    rules: [
      {
        pattern: 'docs/guides/**/*.md',
        strategy: 'content-complexity',
      },
      {
        pattern: 'docs/api/**/*.md',
        strategy: 'strict',  // API docs use strict mode
      },
      {
        pattern: '**/changelog.md',
        strategy: 'lenient',  // Changelog uses lenient mode
      },
    ],

    // Register custom strategies
    custom: [ContentComplexityStrategy],
  },

  files: [
    {
      sourcePath: 'docs/{slug}.md',
      localizationPath: 'i18n/{lang}/{slug}.md',
    },
  ],
});

Large Project Optimization

Performance Bottleneck Analysis

Common performance bottlenecks in large projects:

BottleneckCauseSolution
Too many Git operationsEach file queries Git historyBatch query Git info
Too many file I/ORead files one by oneParallel reading
Slow config parsingComplex glob patternsCache glob results
Slow dashboard generationLarge amount of template renderingIncremental rendering

Incremental Build Strategy

Only process changed files:

// lunaria.config.ts
export default defineConfig({
  sourceLanguage: 'en',
  languages: ['en', 'zh-cn', 'ja', 'ko'],

  // Enable incremental build
  incremental: {
    enabled: true,

    // Cache directory
    cacheDir: '.lunaria/cache',

    // Cache TTL (seconds)
    cacheTTL: 3600,

    // Force full rebuild conditions
    forceRebuild: {
      // Force full rebuild when config changes
      configChanged: true,
      // Force full rebuild when new language added
      languageAdded: true,
    },
  },

  files: [
    {
      sourcePath: 'docs/{slug}.md',
      localizationPath: 'i18n/{lang}/docs/{slug}.md',
    },
  ],
});

Parallel Processing

Enable parallel processing to speed up builds:

// lunaria.config.ts
export default defineConfig({
  sourceLanguage: 'en',
  languages: ['en', 'zh-cn', 'ja', 'ko'],

  // Parallel processing configuration
  parallel: {
    enabled: true,

    // Number of workers (default is CPU cores)
    workers: 4,

    // Number of files per batch
    batchSize: 100,

    // Timeout (milliseconds)
    timeout: 60000,
  },

  files: [
    // ...
  ],
});

Caching Mechanism

Configure caching to speed up repeated builds:

// lunaria.config.ts
export default defineConfig({
  sourceLanguage: 'en',
  languages: ['en', 'zh-cn', 'ja', 'ko'],

  // Cache configuration
  cache: {
    // Git info cache
    git: {
      enabled: true,
      ttl: 86400,  // 24 hours
    },

    // File content cache
    content: {
      enabled: true,
      ttl: 3600,  // 1 hour
    },

    // Status calculation cache
    status: {
      enabled: true,
      ttl: 3600,  // 1 hour
    },
  },

  files: [
    // ...
  ],
});

Security and Permissions

Sensitive File Handling

Exclude sensitive files from tracking:

// lunaria.config.ts
export default defineConfig({
  sourceLanguage: 'en',
  languages: ['en', 'zh-cn', 'ja', 'ko'],

  files: [
    {
      sourcePath: 'docs/{slug}.md',
      localizationPath: 'i18n/{lang}/docs/{slug}.md',

      // Exclude sensitive files
      exclude: [
        '**/internal/**',
        '**/.env*',
        '**/secrets/**',
        '**/admin/**',
      ],
    },
  ],

  // Global exclude rules
  globalExclude: [
    '**/node_modules/**',
    '**/.git/**',
    '**/dist/**',
    '**/.env*',
    '**/credentials*',
  ],
});

Access Control

Add access control for dashboard:

// lunaria.config.ts
export default defineConfig({
  // ...other config

  dashboard: {
    outputDir: 'public/i18n-status',
    title: 'Translation Status',

    // Access control
    accessControl: {
      enabled: true,

      // Basic authentication
      basicAuth: {
        enabled: process.env.NODE_ENV === 'production',
        username: process.env.I18N_DASHBOARD_USER,
        password: process.env.I18N_DASHBOARD_PASS,
      },

      // IP whitelist
      ipWhitelist: [
        '192.168.1.0/24',
        '10.0.0.0/8',
      ],

      // Or use custom authentication function
      customAuth: async (request) => {
        const token = request.headers.get('Authorization');
        return validateToken(token);
      },
    },
  },
});

Audit Logging

Enable audit logging:

// lunaria.config.ts
export default defineConfig({
  // ...other config

  // Audit logging
  audit: {
    enabled: true,

    // Log level
    level: 'info',  // 'debug' | 'info' | 'warn' | 'error'

    // Log outputs
    outputs: [
      { type: 'file', path: 'logs/lunaria.log' },
      { type: 'console' },
    ],

    // Events to record
    events: [
      'config.load',
      'status.calculate',
      'dashboard.generate',
      'api.access',
    ],
  },
});

Enterprise Tool Integration

Translation Management System Integration

Integrate with professional translation management platforms:

// lunaria.config.ts
export default defineConfig({
  // ...other config

  // Integration configuration
  integrations: {
    // Crowdin integration
    crowdin: {
      enabled: true,
      projectId: process.env.CROWDIN_PROJECT_ID,
      apiToken: process.env.CROWDIN_API_TOKEN,

      // Sync configuration
      sync: {
        direction: 'bidirectional',  // 'push' | 'pull' | 'bidirectional'
        interval: 3600,  // Sync interval (seconds)
      },
    },

    // Or use Transifex
    transifex: {
      enabled: false,
      organization: 'your-org',
      project: 'your-project',
      apiToken: process.env.TRANSIFEX_API_TOKEN,
    },
  },
});

CMS Integration

Integrate with content management systems:

// lunaria.config.ts
export default defineConfig({
  // ...other config

  integrations: {
    // Contentful CMS
    contentful: {
      enabled: true,
      spaceId: process.env.CONTENTFUL_SPACE_ID,
      accessToken: process.env.CONTENTFUL_ACCESS_TOKEN,

      // Content mapping
      contentMapping: {
        'blogPost': 'posts/{slug}.md',
        'documentation': 'docs/{slug}.md',
      },
    },

    // Or use Strapi
    strapi: {
      enabled: false,
      apiUrl: process.env.STRAPI_API_URL,
      apiToken: process.env.STRAPI_API_TOKEN,
    },
  },
});

Summary

This chapter explored LunariaJS’s advanced configuration and enterprise applications:

TopicKey Content
Custom status rulesDay thresholds, custom check functions
Complex path mappingMultiple file patterns, multiple source languages
Multi-repository managementMonorepo, cross-repository dependencies
Custom strategiesStrategy interfaces, implementation, registration
Performance optimizationIncremental builds, parallel processing, caching
Security permissionsSensitive files, access control, auditing
Enterprise integrationTMS, CMS, internal tools

Key Takeaways:

  • Use conditional configuration flexibly for different environments
  • Design custom strategies for specific business needs
  • Enable performance optimization for large-scale files
  • Configure security measures to protect sensitive information

Next Steps

In the next article, we’ll do a complete enterprise-level implementation, building a complete multilingual documentation platform from scratch, applying all the knowledge from this series.

Stay tuned!


Recommended Reading: