Vite Inline i18n Editor Demo
June 24, 2026 · View on GitHub
React + Vite + i18next project that supports inline translation editing on localhost.
You can:
- Run the app locally.
- Switch language to Hebrew or Arabic.
- Alt/Option-click translated text.
- Edit the value in the popup.
- Save directly into the local JSON file under
src/i18n/resources/<language>/<namespace>.json.
No Chrome extension. No hosted translation service. No localization SaaS.
Run
npm install
npm run dev
Then open the Vite URL shown in the terminal, usually:
http://localhost:5173
Try the editor
- Switch to Hebrew or Arabic using the language buttons.
- Hold
Alt/Optionand click the large title, login button, or any highlighted translated text. - Edit the text.
- Click Save, or press
Cmd/Ctrl + Enter. - The matching JSON file updates, and the page reloads.
For example, editing the Hebrew login button updates:
src/i18n/resources/he/common.json
File structure
src/
App.jsx
main.jsx
styles.css
i18n/
i18n.js
T.jsx
resources/
en/common.json
he/common.json
ar/common.json
dev/
I18nDevOverlay.jsx
i18n-dev.css
scripts/
vite-plugin-i18n-editor.js
vite.config.js
The important pieces
src/i18n/T.jsx
Use this instead of direct {t('key')} for visible text you want editable:
<T k="auth.login.submit" />
<T k="auth.login.welcome" values={{ name: 'Amir' }} />
<T as="h1" k="app.title" />
In development, it renders data attributes like:
<span
data-i18n-editable="true"
data-i18n-key="auth.login.submit"
data-i18n-ns="common"
data-i18n-locale="he"
>
המשך
</span>
In production, it renders only the translated text.
src/i18n/dev/I18nDevOverlay.jsx
Listens for Alt/Option + click, opens an editor popup, and calls the dev API.
scripts/vite-plugin-i18n-editor.js
Adds Vite dev-server endpoints:
GET /__i18n/value
POST /__i18n/update
These endpoints are dev-only because the plugin uses:
apply: 'serve'
Adapting to your app
Your existing setup probably uses:
src/i18n/resources/<language>/<namespace>.json
This demo already uses that structure.
In your app, copy these files:
src/i18n/T.jsx
src/i18n/dev/I18nDevOverlay.jsx
src/i18n/dev/i18n-dev.css
scripts/vite-plugin-i18n-editor.js
Then add the plugin to vite.config.js:
import path from 'node:path'
import { fileURLToPath } from 'node:url'
import { i18nEditorPlugin } from './scripts/vite-plugin-i18n-editor.js'
const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)
export default defineConfig({
plugins: [
react(),
i18nEditorPlugin({
resourcesDir: path.resolve(__dirname, 'src/i18n/resources'),
baseLanguage: 'en',
}),
],
})
Mount the overlay once in App.jsx:
<AuthProvider>
<AppWithLocale />
{import.meta.env.DEV && <I18nDevOverlay />}
</AuthProvider>
Convert visible translated text gradually:
<Button>{t('auth.login.submit')}</Button>
becomes:
<Button><T k="auth.login.submit" /></Button>
Keep t(...) for string-only props such as placeholder, aria-label, title, alt, validation messages, and toast strings unless the component explicitly accepts React nodes.
Notes
- The plugin supports nested JSON keys like
auth.login.submit. - It also supports flat JSON keys like
{ "auth.login.submit": "Continue" }. - Interpolation variables such as
{{name}}are protected. If the base string uses{{name}}, the edited translation must keep{{name}}. - Rich text translations and plurals are intentionally not handled in v1.