diff --git a/app/locale.ts b/app/locale.ts index 7bcbc4c110..6bc050679b 100644 --- a/app/locale.ts +++ b/app/locale.ts @@ -10,9 +10,10 @@ import type { LoggerType } from '../ts/types/Logging'; import type { LocaleMessagesType } from '../ts/types/I18N'; import type { LocalizerType } from '../ts/types/Util'; -function normalizeLocaleName(locale: string): string { - if (/^en-/.test(locale)) { - return 'en'; +function removeRegion(locale: string): string { + const match = /^([^-]+)(-.+)$/.exec(locale); + if (match) { + return match[1]; } return locale; @@ -38,12 +39,29 @@ export type LocaleType = { messages: LocaleMessagesType; }; +function finalize( + messages: LocaleMessagesType, + backupMessages: LocaleMessagesType, + localeName: string +) { + // We start with english, then overwrite that with anything present in locale + const finalMessages = merge(backupMessages, messages); + + const i18n = setupI18n(localeName, finalMessages); + + return { + i18n, + name: localeName, + messages: finalMessages, + }; +} + export function load({ appLocale, logger, }: { appLocale: string; - logger: Pick; + logger: Pick; }): LocaleType { if (!appLocale) { throw new TypeError('`appLocale` is required'); @@ -52,6 +70,9 @@ export function load({ if (!logger || !logger.error) { throw new TypeError('`logger.error` is required'); } + if (!logger.warn) { + throw new TypeError('`logger.warn` is required'); + } const english = getLocaleMessages('en'); @@ -59,30 +80,23 @@ export function load({ // default to 'en' // // possible locales: - // https://github.com/electron/electron/blob/master/docs/api/locales.md - let localeName = normalizeLocaleName(appLocale); - let messages; + // https://source.chromium.org/chromium/chromium/src/+/main:ui/base/l10n/l10n_util.cc + const normalized = removeRegion(appLocale); try { - messages = getLocaleMessages(localeName); - - // We start with english, then overwrite that with anything present in locale - messages = merge(english, messages); + return finalize(getLocaleMessages(appLocale), english, appLocale); } catch (e) { - logger.error( - `Problem loading messages for locale ${localeName} ${e.stack}` - ); - logger.error('Falling back to en locale'); - - localeName = 'en'; - messages = english; + logger.warn(`Problem loading messages for locale ${appLocale}`); } - const i18n = setupI18n(appLocale, messages); + try { + logger.warn(`Falling back to parent language: '${normalized}'`); + // Note: messages are from parent language, but we still keep the region + return finalize(getLocaleMessages(normalized), english, appLocale); + } catch (e) { + logger.error(`Problem loading messages for locale ${normalized}`); - return { - i18n, - name: localeName, - messages, - }; + logger.warn("Falling back to 'en' locale"); + return finalize(english, english, 'en'); + } } diff --git a/app/main.ts b/app/main.ts index 58aa3db5ee..ab6d54d25f 100644 --- a/app/main.ts +++ b/app/main.ts @@ -1585,7 +1585,7 @@ app.on('ready', async () => { if (!locale) { const appLocale = getAppLocale(); - locale = loadLocale({ appLocale, logger }); + locale = loadLocale({ appLocale, logger: getLogger() }); } sqlInitPromise = initializeSQL(userDataPath); diff --git a/ts/os-locale.d.ts b/ts/os-locale.d.ts deleted file mode 100644 index a29cff0a8c..0000000000 --- a/ts/os-locale.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2021 Signal Messenger, LLC -// SPDX-License-Identifier: AGPL-3.0-only - -// We need this until we upgrade os-locale. Newer versions include type definitions. - -// We can't upgrade it yet because we patch it to disable its findup/exec behavior. - -declare module 'os-locale' { - export function sync(): string; -} diff --git a/ts/test-node/app/menu_test.ts b/ts/test-node/app/menu_test.ts index 8ff6276bea..7cff15d077 100644 --- a/ts/test-node/app/menu_test.ts +++ b/ts/test-node/app/menu_test.ts @@ -202,6 +202,9 @@ describe('createTemplate', () => { error(arg: unknown) { throw new Error(String(arg)); }, + warn(arg: unknown) { + throw new Error(String(arg)); + }, }, }); diff --git a/ts/util/mapToSupportLocale.ts b/ts/util/mapToSupportLocale.ts index aac60795cb..ed725f821c 100644 --- a/ts/util/mapToSupportLocale.ts +++ b/ts/util/mapToSupportLocale.ts @@ -15,6 +15,7 @@ export type SupportLocaleType = | 'sq' | 'zh-tw'; +// See https://source.chromium.org/chromium/chromium/src/+/main:ui/base/l10n/l10n_util.cc export type ElectronLocaleType = | 'af' | 'ar' @@ -25,8 +26,19 @@ export type ElectronLocaleType = | 'cy' | 'da' | 'de' + | 'de-AT' + | 'de-CH' + | 'de-DE' + | 'de-LI' | 'el' | 'en' + | 'en-AU' + | 'en-CA' + | 'en-GB' + | 'en-GB-oxendict' + | 'en-IN' + | 'en-NZ' + | 'en-US' | 'eo' | 'es' | 'es_419' @@ -35,12 +47,17 @@ export type ElectronLocaleType = | 'fa' | 'fi' | 'fr' + | 'fr-CA' + | 'fr-CH' + | 'fr-FR' | 'he' | 'hi' | 'hr' | 'hu' | 'id' | 'it' + | 'it-CH' + | 'it-IT' | 'ja' | 'km' | 'kn' @@ -72,6 +89,7 @@ export type ElectronLocaleType = | 'ur' | 'vi' | 'zh_CN' + | 'zh-HK' | 'zh_TW'; export function mapToSupportLocale(ourLocale: string): SupportLocaleType {