fix: install notice showing in Chinese and not recognizing MSI install path
- Use app.getPreferredSystemLanguages() for reliable OS language detection instead of relying solely on app.getLocale() which returns Chromium's internal locale (was returning zh-CN on pt-BR systems) - Support both Squirrel (%LOCALAPPDATA%) and WiX/MSI (Program Files) install directories when checking if app runs from expected location - Extract matchLocaleTag helper for cleaner language resolution logic - Add getAllExpectedInstallRoots to enumerate all valid install paths
This commit is contained in:
1 parent
4ce8d266ab
commit
0753bbdce6
2 files changed
+117
-17
No files matched your search
@@ -116,6 +116,8 @@ function isRunningFromExpectedInstallDir() {
|
||||
localAppData: process.env.LOCALAPPDATA,
|
||||
appName: app.getName(),
|
||||
execPath: process.execPath,
|
||||
programFiles: process.env.ProgramFiles,
|
||||
programFilesX86: process.env['ProgramFiles(x86)'],
|
||||
});
|
||||
}
|
||||
|
||||
@@ -140,6 +142,7 @@ function showWindowsInstallNoticeIfNeeded() {
|
||||
hasShownInstallNotice = true;
|
||||
const language = resolveInstallNoticeLanguage({
|
||||
configLanguage: startupConfig?.language,
|
||||
preferredLanguages: app.getPreferredSystemLanguages(),
|
||||
locale: app.getLocale(),
|
||||
});
|
||||
const text = getInstallNoticeText(language);
|
||||
|
||||
+114
-17
@@ -48,19 +48,12 @@ const installNoticeText: Record<
|
||||
},
|
||||
};
|
||||
|
||||
export function resolveInstallNoticeLanguage({
|
||||
configLanguage,
|
||||
locale,
|
||||
}: {
|
||||
configLanguage?: string | null;
|
||||
locale?: string | null;
|
||||
}): InstallNoticeLanguage {
|
||||
const rawLanguage = configLanguage || locale;
|
||||
if (!rawLanguage) {
|
||||
return 'en';
|
||||
}
|
||||
|
||||
const normalized = rawLanguage.toLowerCase();
|
||||
/**
|
||||
* Match a locale tag to a supported InstallNoticeLanguage.
|
||||
* Returns the matched language or null if no match found.
|
||||
*/
|
||||
function matchLocaleTag(tag: string): InstallNoticeLanguage | null {
|
||||
const normalized = tag.toLowerCase();
|
||||
if (normalized.startsWith('zh')) {
|
||||
return 'zh-CN';
|
||||
}
|
||||
@@ -77,6 +70,51 @@ export function resolveInstallNoticeLanguage({
|
||||
return 'pt-BR';
|
||||
}
|
||||
|
||||
if (normalized.startsWith('en')) {
|
||||
return 'en';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the language to use for the install notice dialog.
|
||||
*
|
||||
* Priority: configLanguage > preferredLanguages > locale > 'en'
|
||||
*
|
||||
* `preferredLanguages` should come from `app.getPreferredSystemLanguages()`
|
||||
* which returns the OS-level preferred language list and is more reliable
|
||||
* than `app.getLocale()` which can return Chromium's internal locale.
|
||||
*/
|
||||
export function resolveInstallNoticeLanguage({
|
||||
configLanguage,
|
||||
preferredLanguages,
|
||||
locale,
|
||||
}: {
|
||||
configLanguage?: string | null;
|
||||
preferredLanguages?: string[];
|
||||
locale?: string | null;
|
||||
}): InstallNoticeLanguage {
|
||||
// 1. Explicit user config takes highest priority
|
||||
if (configLanguage) {
|
||||
return matchLocaleTag(configLanguage) ?? 'en';
|
||||
}
|
||||
|
||||
// 2. OS preferred languages (most reliable source)
|
||||
if (preferredLanguages && preferredLanguages.length > 0) {
|
||||
for (const lang of preferredLanguages) {
|
||||
const matched = matchLocaleTag(lang);
|
||||
if (matched) {
|
||||
return matched;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Chromium locale (fallback)
|
||||
if (locale) {
|
||||
return matchLocaleTag(locale) ?? 'en';
|
||||
}
|
||||
|
||||
return 'en';
|
||||
}
|
||||
|
||||
@@ -100,6 +138,10 @@ function normalizeWindowsInstallDirName(appName: string) {
|
||||
.toLowerCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the primary expected install root (Squirrel per-user location).
|
||||
* Used for the dialog detail text to tell the user where to find the app.
|
||||
*/
|
||||
export function getExpectedInstallRoot({
|
||||
platform,
|
||||
localAppData,
|
||||
@@ -122,30 +164,85 @@ export function getExpectedInstallRoot({
|
||||
return pathApi.resolve(pathApi.join(localAppData, installDirName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all valid install root directories for the app on Windows.
|
||||
* Includes both Squirrel (%LOCALAPPDATA%) and WiX/MSI (Program Files) paths.
|
||||
*/
|
||||
export function getAllExpectedInstallRoots({
|
||||
platform,
|
||||
localAppData,
|
||||
appName,
|
||||
programFiles,
|
||||
programFilesX86,
|
||||
}: {
|
||||
platform: string;
|
||||
localAppData?: string | null;
|
||||
appName: string;
|
||||
programFiles?: string | null;
|
||||
programFilesX86?: string | null;
|
||||
}): string[] {
|
||||
if (platform !== 'win32') {
|
||||
return [];
|
||||
}
|
||||
|
||||
const pathApi = getPathApi(platform);
|
||||
const roots: string[] = [];
|
||||
|
||||
// Squirrel per-user install: %LOCALAPPDATA%\gemini_nexus
|
||||
if (localAppData) {
|
||||
const installDirName = normalizeWindowsInstallDirName(appName);
|
||||
roots.push(pathApi.resolve(pathApi.join(localAppData, installDirName)));
|
||||
}
|
||||
|
||||
// WiX/MSI system-wide install: C:\Program Files\Gemini Nexus
|
||||
// and C:\Program Files (x86)\Gemini Nexus
|
||||
const displayName = appName.trim();
|
||||
if (programFiles) {
|
||||
roots.push(pathApi.resolve(pathApi.join(programFiles, displayName)));
|
||||
}
|
||||
|
||||
if (programFilesX86) {
|
||||
roots.push(pathApi.resolve(pathApi.join(programFilesX86, displayName)));
|
||||
}
|
||||
|
||||
return roots;
|
||||
}
|
||||
|
||||
export function isRunningFromExpectedInstallDir({
|
||||
platform,
|
||||
isPackaged,
|
||||
localAppData,
|
||||
appName,
|
||||
execPath,
|
||||
programFiles,
|
||||
programFilesX86,
|
||||
}: {
|
||||
platform: string;
|
||||
isPackaged: boolean;
|
||||
localAppData?: string | null;
|
||||
appName: string;
|
||||
execPath: string;
|
||||
programFiles?: string | null;
|
||||
programFilesX86?: string | null;
|
||||
}) {
|
||||
if (platform !== 'win32' || !isPackaged) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const expectedRoot = getExpectedInstallRoot({ platform, localAppData, appName });
|
||||
if (!expectedRoot) {
|
||||
const roots = getAllExpectedInstallRoots({
|
||||
platform,
|
||||
localAppData,
|
||||
appName,
|
||||
programFiles,
|
||||
programFilesX86,
|
||||
});
|
||||
|
||||
if (roots.length === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const pathApi = getPathApi(platform);
|
||||
const normalizedExecPath = pathApi.resolve(execPath);
|
||||
const normalizedExecPath = pathApi.resolve(execPath).toLowerCase();
|
||||
|
||||
return normalizedExecPath.toLowerCase().startsWith(expectedRoot.toLowerCase() + pathApi.sep);
|
||||
return roots.some((root) => normalizedExecPath.startsWith(root.toLowerCase() + pathApi.sep));
|
||||
}
|
||||
Reference in new issue
Block a user