DeepSeek Harness macOS menus stay English: missing plist
If macOS is already set to Simplified Chinese and the Desktop interface is Chinese, but system items in the File menu and the folder dialog for adding a workspace remain English, read the installed app's Info.plist and check whether CFBundleLocalizations is present. According to Discussion #10343, the 0.2.1-rc.2 package lacks the key, and Contents/Resources has no .lproj directory, so the system treats the app as English-only. The root cause is not electron-builder; the build configuration declares the same object with two extendInfo keys.
Does the DeepSeek Harness Desktop Info.plist have CFBundleLocalizations
Run two commands before changing configuration so the facts are settled and a system language issue is not mistaken for a packaging issue. This works for both an installed app and a build artifact:
- Run
plutil -p <app path>/Contents/Info.plist | grep CFBundleLocalizations, replacing<app path>with the install location. Expected: the command prints the array or nothing. - Inspect the output. Expected: no output means the key is missing; an array means the key is not the problem.
- Run
ls <app path>/Contents/Resources | grep lproj. Expected: the command prints.lprojentries or nothing. - Inspect the output. Expected: also empty, so the bundle neither declares the language nor ships localized directories, and the system can only use English.
- Check that Simplified Chinese is first in System Settings > Language & Region. Expected: Chinese is the first preferred language, ruling out a configuration problem.
Which strings change in DeepSeek Harness when the key is missing
When the key is missing, the affected strings are not those the app renders itself but those the system localizes on the app's behalf. According to the discussion, the scope is roughly:
- Menu items macOS appends, such as Services and Show All Windows. Expected: they appear in English.
- The folder chooser opened for adding a workspace. Expected: buttons and labels come from the system in English.
- Standard system dialogs such as permission requests and file locations. Expected: also English.
- Text the app renders itself still follows the in-app i18n. Expected: a mix of Chinese and English.
- Switching the system language to English and back to Chinese. Expected: only system-localized content follows, while in-app text keeps the app setting.
Why DeepSeek Harness lost the key: two extendInfo keys in one object
According to the community's source review in the thread, the same object literal in electron-builder-config.mjs contains two extendInfo keys, and the later one overwrites the earlier one. This is not an electron-builder merge bug; it is ordinary JavaScript semantics. For other packaging checks, see macOS Desktop troubleshooting:
- The first
extendInfocarriedCFBundleLocalizationsand the microphone usage description. Expected: it would have entered the build input. - A later commit split it into two keys, and the second kept only
NSMicrophoneUsageDescription. Expected: the earlier key is overwritten by the same property name. - When the object literal is evaluated, the later key replaces the earlier one. Expected:
CFBundleLocalizationsnever enters the build input. .oxlintrc.jsonignores**/*.mjs. Expected:no-dupe-keysnever runs on this file.- The existing signing test asserts only the microphone description. Expected: neither check catches the missing key.
Three ways to restore CFBundleLocalizations in DeepSeek Harness Desktop
All three paths put the language declaration back into the bundle; they differ in whether you fix the build config, patch the built artifact, or collapse the configuration source. This is not a DSH plugin issue but a Desktop packaging issue; choose by whether you can rebuild.
Path 1: merge the extendInfo objects and keep the comment
This is the most direct root fix: one extendInfo carries both keys, and the comment explaining why the value must live in the bundle stays with it. The change is limited to build configuration and does not touch runtime.
- Open
apps/desktop/scripts/electron-builder-config.mjsand locate the twoextendInfoentries. Expected: both entries are located. - Delete the second and merge
NSMicrophoneUsageDescriptioninto the first. Expected: one key remains with both properties. - Keep the original comment explaining that macOS matches languages by bundle rather than by reading Electron Framework resources. Expected: the rationale stays documented.
- Rebuild and inspect the artifact with the two commands from the previous section. Expected:
Info.plistcontains bothCFBundleLocalizationsand the microphone description. - Launch on a Chinese system. Expected: system menus become Chinese.
- Install the artifact on another Chinese Mac. Expected: the menu language follows the preferred language there too, not only on the build machine.
extendInfo: {
CFBundleLocalizations: ['en', 'zh_CN'],
NSMicrophoneUsageDescription:
'DeepSeek Harness uses your microphone to transcribe speech into message drafts.',
},
Path 2: inject the key into the built plist
If the build configuration cannot change yet, the key can be added to the artifact, but it must be re-signed or the system will reject the app. This suits local verification or internal test builds:
- Back up the artifact first. Expected: the original artifact can be restored if injection fails.
- Create the array with
/usr/libexec/PlistBuddy -c "Add :CFBundleLocalizations array". Expected: an empty array exists at the key. - Add the two entries with
-c "Add :CFBundleLocalizations:0 string en"and-c "Add :CFBundleLocalizations:1 string zh_CN". Expected: the array holdsenandzh_CN. - Run
plutil -lint. Expected: the plist parses without errors. - Re-run
codesignwith the original identity, preserving hardened runtime and entitlements. Expected: the signature covers the modified plist. - Expected result:
codesign --verifypasses, the app launches, and system menu language follows the preferred language.
Path 3: make mac.extendInfo a single source
To prevent a duplicate key next time, collapse this configuration into one variable referenced in exactly one place. Then adding another key later cannot create two properties with the same name:
- Define
const macExtendInfo = { ... }at the top of the configuration module. Expected: one object owns all mac bundle keys. - Write
extendInfo: macExtendInfoonce in the mac configuration. Expected: the configuration has exactly oneextendInfoproperty. - If another build branch needs to extend it, merge with object spread. Expected: extensions merge into the same object instead of adding another key.
- Add lint coverage for
.mjsfiles, or runno-dupe-keysseparately against the build script. Expected: duplicate keys are reported before packaging. - Rebuild and read the artifact once. Expected:
extendInfostill appears once and the new key did not overwrite an old one.
DeepSeek Harness localization checks, regression, and signing
The same English text has different fixes: change the plist for the former, change translation resources for the latter. Use four comparisons to find the source, then verify in this order:
- The main interface is Chinese while system menus are English. Expected: this points to the bundle language declaration.
- The main interface itself has English. Expected: this points to missing in-app translation entries, not the plist.
- Only one third-party dialog is English. Expected: it may be that component's own language pack; do not change
CFBundleLocalizations. - Test under a different macOS user with Chinese as the preferred language. Expected: the result follows the system, confirming system-localized content.
- Add a test that reads the built
Info.plistand assertsCFBundleLocalizationsequals the expected array, plusNSMicrophoneUsageDescriptionis still present. Expected: both keys are covered. - Launch on a Simplified Chinese system, check the folder dialog and appended menus, then run
codesign --verify --deep --strictandspctl. Expected: language, permission description, and signature all pass together. - Put the
Info.plistcheck at the end of the packaging script. Expected: a failed build still reports which key is missing.
Source: Discussion #10343.
FAQ
DeepSeek Harness macOS usually lacks a bundle language declaration rather than a translated interface. According to Discussion #10343, the Desktop interface can be Chinese, but system menus and folder dialogs that macOS and Chromium localize follow the app's CFBundleLocalizations. Without that key the system treats the app as English-only, so appended menu items stay English.
In DeepSeek Harness, read the installed app's Info.plist directly. Run plutil -p /Applications/DeepSeek\ Harness.app/Contents/Info.plist and look for CFBundleLocalizations; no key means the bundle does not declare it. Then check whether Contents/Resources contains any .lproj directory; if both are missing, the system language is not the cause.
DeepSeek Harness's electron-builder-config.mjs contains two extendInfo keys in the same object literal. JavaScript keeps the later key, so only the microphone description takes effect and CFBundleLocalizations is dropped; electron-builder never receives two records. At the same time, .oxlintrc.json ignores *.mjs, so no-dupe-keys never reports it.
The DeepSeek Harness Info.plist is part of the signed content, so changing it invalidates the existing signature. After editing, re-sign and preserve the hardened runtime settings, then verify on the target machine. A temporary script injection suits local verification or internal builds, not replacing a release-signed artifact.
In DeepSeek Harness, changing in-app translations cannot fix English system menus, because system menus and folder dialogs follow CFBundleLocalizations, not the in-app i18n. Add the language declaration to Info.plist and re-sign; translation resources only affect text the app renders itself.
Related Terms
- CFBundleLocalizations
- CFBundleLocalizations is an Info.plist array key that declares the languages an app supports. macOS matches it against the system's preferred languages to decide which language to use for framework-localized content such as system menus and dialogs.— https://github.com/deepseek-ai/deepseek-harness/discussions/10343
- extendInfo
- `extendInfo` is an electron-builder mac option used to merge custom keys into the generated Info.plist. It is a JavaScript object property in the build configuration, and when the same property appears twice only the last one takes effect.— https://github.com/deepseek-ai/deepseek-harness/discussions/10343
- Info.plist
- Info.plist is the property list at the root of a macOS app bundle; it records the bundle identifier, version, supported languages, and permission usage descriptions. The system reads it to decide localization and permission behavior.— https://github.com/deepseek-ai/deepseek-harness/discussions/10343
- .lproj
- `.lproj` is the directory suffix for per-language resources inside a macOS app bundle, for example `zh_CN.lproj`. The directory only shows that resources are present; whether the system uses them still depends on the language declaration in Info.plist.— https://github.com/deepseek-ai/deepseek-harness/discussions/10343