npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

vite-plugin-lingo

v0.1.4

Published

Visual translation editor for .po files in Vite projects

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.

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