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.
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:
| Challenge | Description | Impact |
|---|---|---|
| Multi-repository Management | Code distributed across multiple Git repositories | Translation status hard to track uniformly |
| Complex File Structures | Different modules have different directory structures | Complex configuration, error-prone |
| Custom Workflows | Need to adapt to existing development processes | Standard configuration can’t meet needs |
| Permission Control | Different teams have different access permissions | Need fine-grained permission management |
| Large-scale Files | Hundreds or thousands of translation files | Performance becomes bottleneck |
| Multiple Source Languages | Different modules may have different source languages | Complex 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:
| Bottleneck | Cause | Solution |
|---|---|---|
| Too many Git operations | Each file queries Git history | Batch query Git info |
| Too many file I/O | Read files one by one | Parallel reading |
| Slow config parsing | Complex glob patterns | Cache glob results |
| Slow dashboard generation | Large amount of template rendering | Incremental 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:
| Topic | Key Content |
|---|---|
| Custom status rules | Day thresholds, custom check functions |
| Complex path mapping | Multiple file patterns, multiple source languages |
| Multi-repository management | Monorepo, cross-repository dependencies |
| Custom strategies | Strategy interfaces, implementation, registration |
| Performance optimization | Incremental builds, parallel processing, caching |
| Security permissions | Sensitive files, access control, auditing |
| Enterprise integration | TMS, 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: