Skip to content

Michael-Obele/vite-plugin-lingo

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

55 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

🌍 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.

npm version License: AGPL-3.0

✨ Features

  • 🎨 Visual Translation Editor - Browse and edit .po files 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 .po files change
  • πŸ› οΈ Framework Agnostic - Works with React, Vue, Svelte, SolidJS, or any Vite-powered project
  • 🎯 wuchale Integration - Auto-detect config and .po locations

πŸ“¦ 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.ts

3. Start your dev server

bun run dev
# or
npm run dev

4. 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 .po file changes
  • ❌ Don't use: As your primary reload strategy (use reloadOnPoChange instead)
  • ⚠️ 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.js

React/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 test

Project 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 --tags

Quick 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.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

πŸ“„ License

AGPL-3.0 Β© Michael-Obele

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

About

A Vite plugin that provides a visual editor for .po (Gettext) translation files. Designed to work seamlessly with wuchale and other i18n solutions.

Resources

License

Stars

Watchers

Forks

Contributors