Symptom
On a macOS system whose first preferred language is Simplified Chinese (AppleLanguages = [zh-Hans-CN, en-CN, ...]), a fresh dev instance (clean userData, no stored language preference) launches with an English UI.
Root cause (verified 2026-06-07)
macOS resolves an app's preferred language as system language list ∩ localizations declared by the app bundle (.lproj folders in Contents/Resources). When the bundle declares zero .lproj folders, macOS decides the app only supports its development language and prepends en-US to the app's language list — even though the user's raw AppleLanguages contains no English variant at all. app.getLocale() then returns en-US, and matchSystemLanguage("en-US") → "en".
Evidence chain:
| Copy |
.lproj count |
Result |
| Official electron-v41.7.1-darwin-arm64.zip (cache) |
495 entries |
upstream is fine |
Main repo node_modules/electron/dist/Electron.app |
55 |
fine → dev + packaged releases show Chinese correctly |
Worktree node_modules/electron/dist/Electron.app |
0 |
broken → English first launch |
.lproj folders are empty directories; some unzip/copy step in this worktree's install dropped all empty directories. Per-app language overrides and userData Local State were ruled out (both empty). The app-side language chain (app.getLocale() → sync IPC → resolveInitialLanguage) works as designed at every step.
Why this matters beyond one broken worktree
- Any environment that loses the empty
.lproj dirs (fresh clone, CI, another worktree) silently gets English-only first launch in dev.
- If a release is ever packaged from such an environment, every non-English macOS user gets an English app. No app-side defense is possible: the injected
en-US is indistinguishable from a genuine user preference.
Suggested direction
- Find which step drops empty directories for the worktree copy (electron's postinstall
install.js unzip vs pnpm hoisted copy) and fix or work around it.
- Add a packaging-time guard: assert
Contents/Resources/*.lproj count > 0 in the package verification step (alongside the existing native-module smoke), so a poisoned build can never ship.
Source: user-confirmed investigation 2026-06-07 (smoke testing #29 surfaced the symptom)
Symptom
On a macOS system whose first preferred language is Simplified Chinese (
AppleLanguages = [zh-Hans-CN, en-CN, ...]), a fresh dev instance (clean userData, no stored language preference) launches with an English UI.Root cause (verified 2026-06-07)
macOS resolves an app's preferred language as system language list ∩ localizations declared by the app bundle (
.lprojfolders inContents/Resources). When the bundle declares zero.lprojfolders, macOS decides the app only supports its development language and prependsen-USto the app's language list — even though the user's rawAppleLanguagescontains no English variant at all.app.getLocale()then returnsen-US, andmatchSystemLanguage("en-US") → "en".Evidence chain:
node_modules/electron/dist/Electron.appnode_modules/electron/dist/Electron.app.lprojfolders are empty directories; some unzip/copy step in this worktree's install dropped all empty directories. Per-app language overrides and userData Local State were ruled out (both empty). The app-side language chain (app.getLocale()→ sync IPC →resolveInitialLanguage) works as designed at every step.Why this matters beyond one broken worktree
.lprojdirs (fresh clone, CI, another worktree) silently gets English-only first launch in dev.en-USis indistinguishable from a genuine user preference.Suggested direction
install.jsunzip vs pnpm hoisted copy) and fix or work around it.Contents/Resources/*.lprojcount > 0 in the package verification step (alongside the existing native-module smoke), so a poisoned build can never ship.Source: user-confirmed investigation 2026-06-07 (smoke testing #29 surfaced the symptom)