electron-menu-i18next

Skip repetitive menu labeling in your main process and localize native Electron menu items without losing their native role behavior. Role labels come from your own i18next instance, with readable English fallbacks when translations are missing.

version
v0.1.0
license
MIT
runtime deps
0
i18next
≥21
node
≥16
npm install @solisware/electron-menu-i18next

The problem

Menus built from Electron roles do not speak your language

Assign a shorthand role such as viewMenu or editMenu and Electron creates the complete submenu for you, labels included. It is quick to build, but those labels are not consistently driven by your translations, and the shorthand hides the individual items you need to localize. Both approaches require i18next to be initialized in the main process; the difference is how much wiring for menu labels you maintain yourself.

Without electron-menu-i18next
// Convenient, but its labels cannot use i18next
{ role: "editMenu" }

// To localize it, expand and label every item
{
  label: t("menu.edit"),
  submenu: [
    { label: t("menu.undo"), role: "undo" },
    { label: t("menu.redo"), role: "redo" },
    { label: t("menu.copy"), role: "copy" }
  ]
}
With electron-menu-i18next
const template = [{
  label: t("menu.edit"),
  submenu: [
    { role: "undo" },
    { role: "redo" },
    { role: "copy" }
  ]
}];

const localizedTemplate =
  localizeMenuTemplate(template, { t });

What it does

One template. Every locale.Native behavior preserved.

Pass in your i18next translation function and menu template. The package walks every nested role item, resolves its label, and returns a localized copy while Electron keeps control of native actions and shortcuts.

Role behavior stays native

Only the label changes. Undo, redo, shortcuts, and platform behavior remain under Electron’s control.

Nested templates are covered

Every submenu is walked recursively, so deeply nested role items receive localized labels too.

Designed for the main process

Use the i18next translator initialized in your main process, right where Electron builds the application menu.

Ready for language changes

Localize the template again after a language change and rebuild the menu without restarting the app.

Usage

Drop it into an existing menu template

Once your main process has initialized i18next, pass its translator into your existing Electron menu setup. The package returns a localized copy of your template that is ready for Electron to build, while roles, shortcuts, and native behavior remain untouched. Reuse the same installer whenever the language changes.

main/menu.ts
TypeScript
import { app, Menu, type MenuItemConstructorOptions } from "electron";
import { localizeMenuTemplate } from "@solisware/electron-menu-i18next";
import { translate as t } from "./i18n.js";

function createMenuTemplate(): MenuItemConstructorOptions[] {
  return [{
    label: t("menu.edit"),
    submenu: [
      { role: "undo" },
      { role: "redo" },
      { type: "separator" },
      { role: "cut" },
      { role: "copy" },
      { role: "paste" }
    ]
  }];
}

export function installApplicationMenu(): void {
  const localizedTemplate = localizeMenuTemplate(createMenuTemplate(), {
    t,
    appName: app.name
  });

  Menu.setApplicationMenu(Menu.buildFromTemplate(localizedTemplate));
}

// Call this after initializeI18n() and again after a language change.

Supports ESM and CommonJS. TypeScript declarations are included.

API

Two functions. Minimal configuration.

Export Description
localizeMenuTemplate(template, options) Returns a localized copy of the template

Walks the complete menu tree and adds a localized label to every role item that does not already define one. It returns a new template and leaves the original unchanged.

getRoleLabel(role, options) Returns one localized label

Resolves the localized label for one role. It is useful for tray menus, context menus, and individual menu items built outside a complete template.

Shared options

Both functions accept the same options object as their second argument

Option Description
trequired

An i18next TFunction, such as i18next.t, a bound translator, or a translator returned by getFixedT().

keyPrefixoptional

The prefix used to build translation keys. It defaults to "menu.roles".

appNameoptional

The application name inserted into labels such as About and Quit. Generic labels are used when it is omitted.

fallbackLabelsoptional

Overrides for individual English fallback labels when your application needs different wording.

How it works

From template to native menu

Keep your existing Electron workflow and add localization at the boundary before the menu is built.

Your menu template

Define native roles, custom items, and nested submenus as usual.

Localize role labels

localizeMenuTemplate() resolves every eligible role label.

Build the native menu

Electron creates the final menu with its native behavior intact.

Safe by default

Explicit labels stay untouched

Items that already define a label remain exactly as provided.

Your template stays unchanged

Localization returns a new menu tree and does not mutate the original.

Missing translations stay readable

Known Electron roles fall back to clear English labels included with the package.

Get started

Install it and localize your menu bar today

Free, open source, and built from a real problem in Axion Notes.