next-i18n-lens
v0.1.7
Published
A local-first, zero-dependency visual translation studio for Next.js (App Router) and React.
Maintainers
Readme
🔍 next-i18n-lens
💡 How It Works: Zero-Width Unicode Watermarking
next-i18n-lens bridges your running application UI with your local JSON translation files using Zero-Width Unicode Watermarking.
- Watermark Encoding: In development, when a translation key is looked up, the library prepends an invisible Unicode watermark (using combinations of
\u200D(ZWJ),\u200B(ZWS), and\u200C(ZWNJ)) to the text. - DOM Scanning: A lightweight dev-only browser listener scans the active DOM, decodes the watermarks, and dynamically hooks visual highlights onto translated elements.
- Input & Clipboard Sanitization: To ensure the watermarks never pollute your database, forms, or clipboard, the library automatically intercepts
'copy'/'paste'events and patches controlled input elements at runtime. - Zero Production Footprint: In production mode, all interceptors, listeners, and wrapper logic are bypassed completely, returning plain strings without overhead.
✨ Features
- 🎯 In-Context Visual Editing: Hover over any translated text to highlight it; click to instantly edit in the visual panel.
- 🔴 Missing Key Indicators: Identifies translation keys that are missing in the active locale but exist in the codebase or other translation files, highlighting them with red indicators.
- 🔄 Smart Fallback Placeholders: Automatically renders translation placeholders from alternative languages for missing keys in development, keeping them visible and fully click-to-edit inline.
- 📁 Namespaced Folder Support: Handles nested multi-file folder layouts (e.g.,
locales/en/auth.json) natively, merging files during load and separating them during mutation. - 🧼 Input & Form Sanitization: Patches controlled inputs and intercepts clipboard actions to strip watermarks in development automatically.
- ⚡ Atomic File Operations: Prevents Next.js hot module replacement (HMR) reading corrupt half-written files via atomic temp-to-final writes.
- 🔒 Secure Local Boundaries: Restricts directory traversal, verifies origins, and supports deep schemas up to 30 levels of recursion.
- 🤖 CLI Migration Tool: Automatically parses and wraps standard
react-i18nexthooks with a single command.
⚡ Quick Setup
1. Install Dependency
npm install next-i18n-lens2. Add the Client Listener
Mount the I18nLensProvider inside your root layout. This launches the dev-mode DOM scanners and intercepts clipboard copy/paste actions.
// app/layout.tsx
import { I18nLensProvider } from 'next-i18n-lens/react';
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
<I18nLensProvider />
{children}
</body>
</html>
);
}3. Initialize Server Mutation Handler
Initialize the server-side API endpoints automatically by running:
npx next-i18n-lens initThe CLI will check for TypeScript/JavaScript and write the appropriate mutation file (/app/api/i18n-lens/mutate/route.ts or /pages/api/i18n-lens/mutate.ts) directly into your project.
[!NOTE] For manual setup, create
app/api/i18n-lens/mutate/route.tswith:import { createI18nLensHandler } from 'next-i18n-lens/server'; import * as path from 'path'; const handler = createI18nLensHandler({ localesPath: path.resolve('./locales'), }); export const GET = handler; export const POST = handler; export const OPTIONS = handler;
4. Enable Key Watermarking
Wrap translation lookups to inject dev-only watermarks.
Option A: Server Components (Direct Loader)
Use createTranslations to load flat JSON files or directory-based namespaces:
import { createTranslations } from 'next-i18n-lens/server';
export default async function Page({ searchParams }) {
const { locale = 'en' } = await searchParams;
const t = createTranslations(locale, {
supportedLocales: ['en', 'ar', 'es'],
localesDir: './locales',
});
return <h1>{t.home?.welcome}</h1>;
}Option B: Client-side Hooks (react-i18next or next-intl)
Wrap hook return values with wrapTranslationEngine:
'use client';
import { useTranslation } from 'react-i18next';
import { wrapTranslationEngine } from 'next-i18n-lens/client';
export default function Page() {
const { t: rawT } = useTranslation('auth');
const t = wrapTranslationEngine(rawT, { keyPrefix: 'auth' });
return <h1>{t('login.title')}</h1>;
}5. Launch the Visual Studio
Boot the editing studio next to your local development server:
npx next-i18n-lens studio --port 3010Open http://localhost:3010 to view the Studio, loaded with your app running at http://localhost:3000.
🛠️ CLI Reference
init
Generates API route handlers based on your router structure (App vs Pages Router) and configuration language (TypeScript vs JavaScript).
npx next-i18n-lens init [--dir <path>]studio
Spins up a lightweight, CORS-enabled HTTP server serving the Visual Studio assets statically.
npx next-i18n-lens studio [--port <number>]migrate
Performs static analysis to scan and automatically wrap existing react-i18next hooks with wrapTranslationEngine.
npx next-i18n-lens migrate [--dir <path>] [--exclude <dirs>] [--dry-run]⚙️ Non-Next.js Integration (React + Vite SPA)
If you are using a standard React Client-Side SPA (like Vite), you don't have Next.js API endpoints. You can use the built-in Vite plugin inside vite.config.ts to automatically capture the mutation endpoints:
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { i18nLensVite } from 'next-i18n-lens/vite';
export default defineConfig({
plugins: [
react(),
i18nLensVite({
localesPath: './locales', // path to your locales directory
}),
],
});⚖️ License
MIT License. See LICENSE for more details.
