@hkonda/loco-translate
v1.1.11
Published
Self-hosted translation manager — auto-discovers text, AI translations, Svelte dashboard, CDN client.
Maintainers
Readme
Loco
Open-source translation engine for any website or app. Drop in a single <script> tag, manage translations from a dashboard, and let AI handle the heavy lifting.
Two integration modes: Server Mode (live API-driven) and File Mode (static JSON, zero server dependency).
Quick Start — NPM Package
The fastest way to run Loco. No cloning required.
1. Install and Start
npm install -g @hkonda/loco-translate
locoOr without a global install:
npx @hkonda/loco-translateOn first run, the terminal prints your dashboard URL, CDN snippet, and API key:
🌐 Loco Translation Manager
Dashboard : http://<your-ip>:6101/dashboard/
CDN script: http://<your-ip>:6101/cdn/loco.js
API key : <auto-generated>
Paste into any page:
<script src="http://<your-ip>:6101/cdn/loco.js"></script>
<script>Loco.init({ apiUrl: 'http://<your-ip>:6101', apiKey: '<your-key>' });</script>2. Open the Dashboard
Navigate to the Dashboard URL printed above (e.g. http://localhost:6101/dashboard/).
3. Add the Snippet to Your Page
Copy the <script> tags from the terminal output and paste them into any HTML page. When that page loads, Loco auto-discovers all text and sends it to the dashboard as Pending items.
4. Translate
- In the dashboard, approve phrases in the Pending tab
- Use AI Translate (requires a BlueHive API key) or edit translations manually
- Call
Loco.apply('fr')in the browser console to preview translations live
Configuration
Run loco --help to see all options:
Options:
-p, --port <number> Port to listen on (default: 6101)
-d, --data-dir <path> Directory for loco.db (default: .loco/ in cwd)
-h, --help Show this help messageOr set environment variables (in a .env file or your shell):
| Variable | Flag equivalent | Default | Description |
|---|---|---|---|
| PORT | -p, --port | 6101 | Server port |
| LOCO_DATA_DIR | -d, --data-dir | .loco/ in cwd | Directory where loco.db is stored |
| BASE_PATH | — | (empty) | URL prefix for reverse-proxy deployments |
| BLUEHIVE_API_KEY | — | (none) | BlueHive key for AI translations |
| PUBLIC_URL | — | (auto) | Override the printed public URL |
Create a .env file in your working directory to set these:
PORT=6101
BLUEHIVE_API_KEY=BHSK-...Developer Setup (from source)
1. Install & Start the Dashboard
git clone https://github.mieweb.com/hkonda/loco.git
cd loco
npm install
npm run devThis starts two processes:
- Vite dev server on port
6100(dashboard + proxy) - Fastify API on port
6101(backend)
On startup the terminal prints your working URLs:
🌐 Loco Translation Manager
Dashboard : http://<your-ip>:6100/loco/dashboard/
CDN script: http://<your-ip>:6100/loco/cdn/loco.js
API key : <auto-generated>
Paste into any page:
<script src="http://<your-ip>:6100/loco/cdn/loco.js"></script>
<script>Loco.init({ apiUrl: 'http://<your-ip>:6100/loco', apiKey: '<your-key>' });</script>Open the Dashboard URL in your browser to access the Translation Manager.
2. Add the CDN Snippet to Your Page
Copy the snippet from the terminal output (or from Dashboard → Settings → CDN Script Snippet) and paste it into any HTML page you want to translate. When that page loads in a browser, Loco automatically discovers text nodes and sends them to the dashboard as "Pending" items.
3. Install the Chrome Extension (Optional)
The Chrome extension adds a side panel for in-context translation editing on any page running the Loco snippet.
- Open Chrome and go to
chrome://extensions/ - Enable Developer mode (toggle in the top-right corner)
- Click Load unpacked
- Select the
chrome-extension/folder inside this repo - The Loco Translation Editor extension should appear in your extensions list
Configure the Extension
- Click the Loco extension icon in the Chrome toolbar → Options (or right-click → Extension options)
- Fill in the two fields:
- API Base URL — the same base URL from the snippet, e.g.
http://<your-ip>:6100/loco - API Key — the API key from Dashboard → Settings
- API Base URL — the same base URL from the snippet, e.g.
- Click Save Settings, then Test Connection to verify it works
- Navigate to any page running the Loco snippet, then click the extension icon to open the side panel
4. Test Pages
Several test pages are included and served during development:
| Page | URL |
|---|---|
| Server Mode Test | http://<your-ip>:6100/loco/dashboard/test-server-mode.html |
| File Mode Test | http://<your-ip>:6100/loco/dashboard/test-file-mode.html |
| Pattern Test | http://<your-ip>:6100/loco/dashboard/test-patterns.html |
| Basic Test | http://<your-ip>:6100/loco/dashboard/test-page.html |
Open any server-mode test page — text nodes should appear in the dashboard under Pending within a few seconds.
5. Configure BlueHive AI (for AI Translations)
To use AI-powered translations, you need a BlueHive API key:
- Go to Dashboard → Settings
- Under BlueHive API Key, paste your key (starts with
BHSK-...) - Click Save
If you don't have a key, sign up at bluehive.com and generate one from your developer account.
6. Translation Workflow
- Pending — Newly discovered text appears here. Review and approve items you want to translate.
- Approved — Approved phrases are ready for translation. Use AI Translate to batch-translate with BlueHive, or edit translations manually.
- Export — From the Approved tab, click Export JSON to download a translation file for File Mode.
- Apply — On any page with the Loco snippet, call
Loco.apply('zh-CN')in the browser console to see translations live.
Self-Hosting (Production)
Prerequisites
- Node.js 20+
- npm
- Linux server with systemd (for production deployment)
Build & Run
git clone https://github.mieweb.com/hkonda/loco.git
cd loco
npm install
npm run build
npm startDashboard available at http://<your-ip>:6101/dashboard/
An API key is auto-generated on first run — find it in the dashboard under Settings.
To enable AI translations, add your BlueHive API key in the dashboard under Settings > BlueHive API Key.
Deploy with systemd
The included deploy.sh handles everything:
chmod +x deploy.sh
./deploy.sh install # Build + install systemd service + start
./deploy.sh stop # Stop service
./deploy.sh start # Start service
./deploy.sh restart # Restart service
./deploy.sh status # Show status + recent logs
./deploy.sh logs # Tail live logs
./deploy.sh uninstall # Stop + remove serviceAfter install, the script prints your dashboard URL and CDN script URL.
Using Loco in Your App
Server Mode
Server mode connects your site to a running Loco instance. It automatically discovers text on the page, sends it to the server for management, and applies translations in real-time.
<script src="https://your-loco-server.com/cdn/loco.js"></script>
<script>
Loco.init({
apiUrl: 'https://your-loco-server.com',
apiKey: 'YOUR_API_KEY'
});
// Apply a language
Loco.apply('fr');
</script>What happens:
loco.jsscans the DOM and extracts all translatable text nodes- Text nodes are sent to the Loco server and appear in the dashboard as "pending"
- You approve phrases, add languages, and translate (manually or with AI) in the dashboard
Loco.apply('fr')fetches approved translations from the server and swaps text in the DOM- A
MutationObserverwatches for new DOM nodes and registers them automatically
File Mode
File mode uses a static JSON file — no server connection needed. Export the JSON from the dashboard or create it by hand.
<script src="/path/to/loco.js"></script>
<script>
Loco.init({ file: '/translations.json' });
// Apply a language
Loco.apply('zh-CN');
// Optional: render a floating language switcher widget
Loco.widget({ position: 'bottom-right' });
</script>Translation JSON format:
{
"languages": ["fr", "zh-CN"],
"translations": {
"fr": {
"Hello": "Bonjour",
"Sign up": "S'inscrire",
"Welcome back, {{var:0}}": "Bon retour, {{var:0}}"
},
"zh-CN": {
"Hello": "你好",
"Sign up": "注册",
"Welcome back, {{var:0}}": "欢迎回来,{{var:0}}"
}
}
}You can export this file from the dashboard at any time (Translations → Export JSON).
Client API
Loco.init(config) // Initialize (server mode or file mode)
Loco.apply('fr') // Apply translations for a language → Promise
Loco.restore() // Revert all text to original
Loco.rescan() // Re-scan DOM for new text nodes
Loco.widget({ position }) // Render language switcher ('bottom-right', 'bottom-left', 'top-right', 'top-left')
Loco.textnodes() // Get all discovered text nodes
Loco.stopScan() // Pause MutationObserver
Loco.startScan() // Resume MutationObserverVariable Handling
Loco automatically detects dynamic values in text and preserves them across translations:
Original: "You have 5 new messages"
Key: "You have {{var:0}} new messages"
French: "Vous avez {{var:0}} nouveaux messages"
Rendered: "Vous avez 5 nouveaux messages"Architecture
flowchart TB
subgraph Your Website or App
A[loco.js Client Script]
end
subgraph Loco Server
B[Fastify API]
C[SQLite Database]
D[AI Translation Jobs]
E[Dashboard SPA]
end
subgraph External
F[BlueHive AI API]
end
A -->|Register text nodes & screenshots| B
A -->|Fetch translations| B
B <--> C
E -->|Manage phrases & languages & prompts| B
B -->|Queue translation jobs| D
D -->|Send text & context| F
F -->|Return translations| D
D -->|Store results| CHow It Works
- Discover — The client script scans your page, extracts text nodes (respecting blocked/inline tag rules), and sends them to the server along with page context and screenshots
- Manage — In the dashboard, review pending phrases, approve them, add target languages, and configure AI prompt templates
- Translate — Run AI translation jobs that use page screenshots and context for accurate results, or edit translations manually
- Deliver — The client fetches approved translations and swaps DOM text in real-time. Or export a static JSON file for file mode
Tech Stack
| Layer | Technology | |---|---| | Client Script | Vanilla JavaScript (no dependencies) | | Dashboard | Svelte 4 + Tailwind CSS | | Server | Fastify + Node.js | | Database | SQLite (better-sqlite3, WAL mode) | | Build Tool | Vite | | AI | BlueHive API | | Deployment | systemd + deploy.sh |
Performance Benchmarks (Latest)
The performance suite compares Server Mode and File Mode at identical node counts.
Run:
npx playwright test tests/performance.spec.tsConfiguration used for results below:
ITERATIONS=11total per test- first iteration is warm-up and discarded
- reported averages use
n=10recorded samples
Collection (Loco.rescan — full DOM tree walk)
Server
| Nodes | Avg (ms) [n] | Min (ms) | Max (ms) | |---|---:|---:|---:| | 100 | 0.80 [n=10] | 0.4 | 1.9 | | 500 | 1.79 [n=10] | 1.5 | 2.3 | | 1000 | 17.06 [n=10] | 16.0 | 18.0 | | 3000 | 117.49 [n=10] | 115.6 | 118.2 | | 5000 | 217.77 [n=10] | 213.9 | 221.3 |
File
| Nodes | Avg (ms) [n] | Min (ms) | Max (ms) | |---|---:|---:|---:| | 100 | 0.42 [n=10] | 0.3 | 0.7 | | 500 | 1.48 [n=10] | 1.2 | 1.8 | | 1000 | 17.16 [n=10] | 16.6 | 18.2 | | 3000 | 121.34 [n=10] | 112.2 | 125.3 | | 5000 | 223.69 [n=10] | 218.9 | 228.5 |
Apply (Loco.apply)
Server
| Nodes | Avg (ms) [n] | Min (ms) | Max (ms) | |---|---:|---:|---:| | 100 | 7.45 [n=10] | 7.1 | 7.9 | | 500 | 15.56 [n=10] | 10.2 | 17.7 | | 1000 | 23.41 [n=10] | 17.1 | 25.3 | | 3000 | 29.18 [n=10] | 22.7 | 36.1 | | 5000 | 42.72 [n=10] | 39.7 | 44.8 |
File
| Nodes | Avg (ms) [n] | Min (ms) | Max (ms) | |---|---:|---:|---:| | 100 | 1.03 [n=10] | 0.5 | 1.6 | | 500 | 2.85 [n=10] | 1.1 | 3.8 | | 1000 | 5.92 [n=10] | 1.6 | 7.3 | | 3000 | 17.47 [n=10] | 9.5 | 20.0 | | 5000 | 22.96 [n=10] | 18.6 | 25.6 |
Notes:
- Collection measures a full DOM rescan (TreeWalker + context computation), not just reading cached nodes.
- Apply time remains low in both modes; file mode is fastest across all tested node counts.
- Collection uses WeakMap caching for
isAncestorBlocked,hasMixedContent, andbuildContextTraceto avoid redundant ancestor walks. - Server-mode apply at 5000 nodes includes network latency; file mode is pure client-side.
Publishing an NPM Update
Use this checklist whenever you add new features or fixes and want to release a new version.
1. Make your changes
Work on main or a feature branch as normal. Run npm run dev to develop locally.
2. Bump the version
Edit package.json at the root — increment "version" following semver:
patch (1.0.3 → 1.0.4) — bug fixes, small tweaks
minor (1.0.3 → 1.1.0) — new backwards-compatible features
major (1.0.3 → 2.0.0) — breaking changes3. Build the package
node scripts/build-npm.jsThis compiles the TypeScript server, builds the Svelte dashboard (with the correct /dashboard/ base path), builds the CDN client bundles, and assembles everything into npm-package/.
4. Publish
cd npm-package
echo '//registry.npmjs.org/:_authToken=<your-npm-token>' > .npmrc
npm publish --access public
rm .npmrcGet a token at npmjs.com → Access Tokens — use a Classic Automation token (bypasses 2FA).
5. Verify
npm install -g @hkonda/loco-translate@<new-version>
locoOpen http://localhost:6101/dashboard/ to confirm everything loads.
What the build script does
| Step | Command | Output |
|---|---|---|
| Compile server | tsc -p tsconfig.server.json | dist-server/ |
| Build dashboard | vite build (with LOCO_VITE_BASE=/dashboard/) | dist/ |
| Build CDN (minified) | vite build in client/ | public/loco.min.js |
| Build CDN (unminified) | cross-env LOCO_UNMINIFIED=1 vite build in client/ | public/loco.js |
| Assemble | copies all of the above + bin/loco.js + README.md | npm-package/ |
The npm-package/ directory is gitignored — never commit it directly.
