vite-plugin-lingo
v0.1.4
Published
Visual translation editor for .po files in Vite projects
Maintainers
Readme
🌍 vite-plugin-lingo
A Vite plugin that provides a visual editor for .po (Gettext) translation files. Designed to work seamlessly with wuchale and other i18n solutions.
✨ Features
- 🎨 Visual Translation Editor - Browse and edit
.pofiles in a beautiful web UI - 📊 Language Overview - See all locales with translation progress at a glance
- 🔍 Search & Filter - Find translations by text, filter by status
- ⌨️ Keyboard Shortcuts - Ctrl+S save, arrow keys navigate
- 🔄 HMR Support - Live reload when
.pofiles change - 🛠️ Framework Agnostic - Works with React, Vue, Svelte, SolidJS, or any Vite-powered project
- 🎯 wuchale Integration - Auto-detect config and
.polocations
📦 Installation
# npm
npm install vite-plugin-lingo --save-dev
# pnpm
pnpm add -D vite-plugin-lingo
# bun (recommended)
bun add -d vite-plugin-lingo
# yarn
yarn add -D vite-plugin-lingo🚀 Quick Start
1. Add to your Vite config
// vite.config.ts
import { defineConfig } from 'vite';
import lingo from 'vite-plugin-lingo';
export default defineConfig({
plugins: [
lingo({
route: '/_translations', // Route where editor UI is served
localesDir: './locales', // Path to .po files
})
]
});Note for SvelteKit users: If your locales are in
src/locales/(common SvelteKit convention), use:lingo({ route: '/_translations', localesDir: './src/locales', // Common in SvelteKit projects })
2. Create your locales directory
your-project/
├── locales/ # Default location
│ ├── en.po
│ ├── es.po
│ └── fr.po
├── src/
│ └── locales/ # Alternative: SvelteKit convention
│ ├── en.po
│ ├── es.po
│ └── fr.po
└── vite.config.ts3. Start your dev server
bun run dev
# or
npm run dev4. Open the translation editor
Navigate to http://localhost:5173/_translations to access the visual editor.
⚙️ Configuration Options
lingo({
// Route where editor UI is served (default: '/_translations')
route: '/_translations',
// Path to .po files relative to project root (default: './locales')
// For SvelteKit projects, commonly './src/locales'
// For other frameworks, './locales' at project root is typical
localesDir: './locales',
// ⚠️ NUCLEAR OPTION - Only use if another plugin conflicts with .po file changes
// Restart the dev server when a .po file is updated (default: false)
// Advanced: Use this only when reloadOnPoChange is insufficient and another
// plugin (like wuchale) stops reacting to changes. Most users won't need this.
restartOnPoChange: false,
// Trigger a full page reload when a .po file is updated (default: true)
// Ensures UI stays in sync with backend translation files
reloadOnPoChange: true,
// Enable in production (default: false)
// ⚠️ Only enable with proper authentication!
production: false,
// 🔒 PREMIUM FEATURE (Coming Soon)
// License key for premium features
// licenseKey: 'your-license-key',
// 🔒 PREMIUM FEATURE (Coming Soon)
// AI configuration for translation assistance
// ai: {
// provider: 'openai' | 'anthropic' | 'google',
// apiKey: 'your-api-key'
// },
})📖 API Reference
Plugin Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| route | string | '/_translations' | URL path where the editor is served |
| localesDir | string | './locales' | Directory containing .po files. For SvelteKit projects, commonly './src/locales'. Relative to project root. |
| restartOnPoChange | boolean | false | Nuclear Option ⚠️ - Only use when another plugin conflicts with .po file changes (e.g., wuchale). Restarts the dev server when a .po file is updated. Most users won't need this. |
| reloadOnPoChange | boolean | true | Trigger a full page reload when a .po file is updated. Ensures UI stays in sync with backend translation files. |
| production | boolean | false | Enable editor in production builds. ⚠️ Only enable with proper authentication! |
| licenseKey | string | undefined | Coming Soon 🔒 - License key for premium features (not yet available). |
| ai | object | undefined | Coming Soon 🔒 - AI configuration for translation assistance (not yet available). Will support 'openai', 'anthropic', or 'google' as provider with optional apiKey. |
Premium Features (Coming Soon)
The following premium features are currently in development and will be available in future releases:
License Key System (licenseKey)
- Status: Under development
- Purpose: Enable premium features with license validation
- Expected: Q1 2026
AI-Powered Translation (ai)
- Status: Under development
- Purpose: Assist with translations using your preferred AI provider
- Supported Providers: OpenAI, Anthropic, Google
- Expected: Q1 2026
Advanced Configuration Notes
restartOnPoChange - Nuclear Option
This is an advanced fallback option that should only be used in specific situations:
- ✅ Use when: Another plugin (like wuchale) doesn't respond to
.pofile changes - ❌ Don't use: As your primary reload strategy (use
reloadOnPoChangeinstead) - ⚠️ Impact: Full dev server restart is slower than page reload
Example scenario where this might be needed:
lingo({
localesDir: './locales',
restartOnPoChange: true, // Only if wuchale or other plugins conflict
reloadOnPoChange: false, // Disable the default fast reload
})Type Definitions
PluginOptions
Main configuration interface for the Vite plugin. See Plugin Options table above.
Translation
Represents a single translation entry in a .po file:
interface Translation {
msgid: string; // Message ID (original text)
msgstr: string; // Message string (translated text)
context?: string; // Optional context for disambiguation
comments?: { // Optional metadata
reference?: string; // File reference where string is used
translator?: string; // Translator notes
extracted?: string; // Extracted comments
flag?: string; // Fuzzy or other flags
};
fuzzy?: boolean; // Whether translation is marked as fuzzy
}Language
Represents a language with all its translations:
interface Language {
code: string; // Language code (e.g., 'en', 'es', 'fr')
name: string; // Language name (e.g., 'English', 'Spanish')
path: string; // Path to the .po file
translations: Translation[]; // Array of translation entries
progress: {
total: number; // Total number of strings
translated: number; // Number of translated strings
fuzzy: number; // Number of fuzzy translations
};
}LanguageStats
Statistics for language translation progress:
interface LanguageStats {
code: string; // Language code
name: string; // Language name
total: number; // Total number of strings
translated: number; // Number of translated strings
fuzzy: number; // Number of fuzzy translations
untranslated: number; // Number of untranslated strings
progress: number; // Progress percentage (0-100)
}Exported Types
All types are exported from the main package:
import type {
PluginOptions,
Translation,
Language,
LanguageStats
} from 'vite-plugin-lingo';🎯 Framework Examples
SvelteKit
SvelteKit projects commonly place locales in the src/ directory:
// vite.config.ts
import { defineConfig } from 'vite';
import lingo from 'vite-plugin-lingo';
export default defineConfig({
plugins: [
lingo({
route: '/_translations',
localesDir: './src/locales', // SvelteKit convention
})
]
});Project structure:
sveltekit-project/
├── src/
│ ├── locales/ # ← Locales directory
│ │ ├── en.po
│ │ ├── es.po
│ │ └── fr.po
│ ├── routes/
│ └── app.html
├── vite.config.ts
└── svelte.config.jsReact/Vite
Standard Vite projects typically use the root-level locales/ directory:
// vite.config.ts
import { defineConfig } from 'vite';
import lingo from 'vite-plugin-lingo';
export default defineConfig({
plugins: [
lingo({
route: '/_translations',
localesDir: './locales', // Default location
})
]
});Project structure:
vite-react-project/
├── locales/ # ← Locales directory
│ ├── en.po
│ ├── es.po
│ └── fr.po
├── src/
├── index.html
└── vite.config.ts🔧 How It Works
┌─────────────────────────────────────────────────────────┐
│ Vite Dev Server │
├─────────────────────────────────────────────────────────┤
│ ┌─────────────────┐ ┌─────────────────────────────┐ │
│ │ Your App │ │ vite-plugin-lingo │ │
│ │ (React/Svelte/ │ │ ├─ Middleware (/_translations)│
│ │ Vue/Solid) │ │ ├─ API (GET/PUT /api/*) │ │
│ │ │ │ ├─ Editor UI (Svelte SPA) │ │
│ │ │ │ └─ File Watcher (.po files) │ │
│ └─────────────────┘ └─────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────┐
│ .po Files │
│ └─ locales/ │
│ ├─ en.po │
│ ├─ es.po │
│ └─ fr.po │
└─────────────────┘📁 .po File Format
The plugin works with standard Gettext .po files:
# English translations
msgid ""
msgstr ""
"Language: en\n"
"Content-Type: text/plain; charset=UTF-8\n"
#: src/components/Header.svelte:5
msgid "Welcome to our website"
msgstr "Welcome to our website"
#: src/components/Header.svelte:10
msgid "Hello, {name}!"
msgstr "Hello, {name}!"🛠️ Development
Prerequisites
- Bun (recommended) or Node.js 18+
- Git
Setup
# Clone the repository
git clone https://github.com/Michael-Obele/vite-plugin-lingo.git
cd vite-plugin-lingo
# Install dependencies
bun install
# Start development server
bun run dev
# Build the plugin
bun run build
# Run type checking
bun run check
# Run tests
bun run testProject Structure
vite-plugin-lingo/
├── src/
│ ├── lib/
│ │ ├── plugin/ # Vite plugin source
│ │ │ ├── index.ts # Main plugin entry
│ │ │ ├── middleware.ts # API endpoints
│ │ │ ├── po-parser.ts # .po file parser
│ │ │ └── types.ts # TypeScript types
│ │ └── ui/ # Editor UI (Svelte)
│ │ ├── App.svelte # Main editor component
│ │ └── components/ # UI components
│ └── routes/ # Demo/showcase app
├── locales/ # Sample .po files
├── dist/ # Built output
└── package.json📤 Publishing to npm
📚 For detailed publishing instructions, see PUBLISHING.md
Quick Publishing Guide
# 1. Login to npm (first time only)
npm login
# 2. Build and verify
bun run build
# 3. Bump version
npm version patch # or minor/major
# 4. Publish
npm publish
# 5. Push tags
git push && git push --tagsQuick Reference
| Command | Description |
|---------|-------------|
| npm version patch | Bug fixes (0.0.1 → 0.0.2) |
| npm version minor | New features (0.0.2 → 0.1.0) |
| npm version major | Breaking changes (0.1.0 → 1.0.0) |
| npm publish | Publish to npm registry |
| npm pack --dry-run | Preview what will be published |
🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
📄 License
This is a copyleft license that requires anyone who distributes your code or a derivative work to make the source available under the same terms.
🔗 Links
Made with ❤️ for the i18n community
