Add interpolation for fallback dialog messages
This commit is contained in:
parent
800c7ed31d
commit
afddc852cc
8 changed files with 61 additions and 47 deletions
|
@ -1,6 +1,7 @@
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
|
const { setup } = require('../js/modules/i18n');
|
||||||
|
|
||||||
function normalizeLocaleName(locale) {
|
function normalizeLocaleName(locale) {
|
||||||
if (/^en-/.test(locale)) {
|
if (/^en-/.test(locale)) {
|
||||||
|
@ -58,7 +59,10 @@ function load({ appLocale, logger } = {}) {
|
||||||
messages = english;
|
messages = english;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const i18n = setup(appLocale, messages);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
i18n,
|
||||||
name: localeName,
|
name: localeName,
|
||||||
messages,
|
messages,
|
||||||
};
|
};
|
||||||
|
|
2
main.js
2
main.js
|
@ -421,7 +421,7 @@ async function readyForUpdates() {
|
||||||
|
|
||||||
// Second, start checking for app updates
|
// Second, start checking for app updates
|
||||||
try {
|
try {
|
||||||
await updater.start(getMainWindow, locale.messages, logger);
|
await updater.start(getMainWindow, locale, logger);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(
|
logger.error(
|
||||||
'Error starting update checks:',
|
'Error starting update checks:',
|
||||||
|
|
|
@ -8,6 +8,13 @@ describe('i18n', () => {
|
||||||
it('returns message for given string', () => {
|
it('returns message for given string', () => {
|
||||||
assert.equal(i18n('reportIssue'), 'Report an issue');
|
assert.equal(i18n('reportIssue'), 'Report an issue');
|
||||||
});
|
});
|
||||||
|
it('returns message with single substitution', () => {
|
||||||
|
const actual = i18n('cannotUpdateDetail', 'https://signal.org/download');
|
||||||
|
assert.equal(
|
||||||
|
actual,
|
||||||
|
'Signal Desktop failed to update, but there is a new version available. Please go to https://signal.org/download and install the new version manually, then either contact support or file a bug about this problem.'
|
||||||
|
);
|
||||||
|
});
|
||||||
it('returns message with multiple substitutions', () => {
|
it('returns message with multiple substitutions', () => {
|
||||||
const actual = i18n('theyChangedTheTimer', ['Someone', '5 minutes']);
|
const actual = i18n('theyChangedTheTimer', ['Someone', '5 minutes']);
|
||||||
assert.equal(
|
assert.equal(
|
||||||
|
|
|
@ -27,11 +27,14 @@ import { Dialogs } from '../types/Dialogs';
|
||||||
import * as packageJson from '../../package.json';
|
import * as packageJson from '../../package.json';
|
||||||
import { getSignatureFileName } from './signature';
|
import { getSignatureFileName } from './signature';
|
||||||
|
|
||||||
export type MessagesType = {
|
export type LocaleType = {
|
||||||
|
i18n: (key: string, placeholders: Array<string>) => string;
|
||||||
|
messages: {
|
||||||
[key: string]: {
|
[key: string]: {
|
||||||
message: string;
|
message: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
};
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
type LogFunction = (...args: Array<any>) => void;
|
type LogFunction = (...args: Array<any>) => void;
|
||||||
|
@ -146,19 +149,19 @@ export async function downloadUpdate(
|
||||||
|
|
||||||
async function showFallbackUpdateDialog(
|
async function showFallbackUpdateDialog(
|
||||||
mainWindow: BrowserWindow,
|
mainWindow: BrowserWindow,
|
||||||
messages: MessagesType
|
locale: LocaleType
|
||||||
) {
|
) {
|
||||||
const RESTART_BUTTON = 0;
|
const RESTART_BUTTON = 0;
|
||||||
const LATER_BUTTON = 1;
|
const LATER_BUTTON = 1;
|
||||||
const options = {
|
const options = {
|
||||||
type: 'info',
|
type: 'info',
|
||||||
buttons: [
|
buttons: [
|
||||||
messages.autoUpdateRestartButtonLabel.message,
|
locale.messages.autoUpdateRestartButtonLabel.message,
|
||||||
messages.autoUpdateLaterButtonLabel.message,
|
locale.messages.autoUpdateLaterButtonLabel.message,
|
||||||
],
|
],
|
||||||
title: messages.autoUpdateNewVersionTitle.message,
|
title: locale.messages.autoUpdateNewVersionTitle.message,
|
||||||
message: messages.autoUpdateNewVersionMessage.message,
|
message: locale.messages.autoUpdateNewVersionMessage.message,
|
||||||
detail: messages.autoUpdateNewVersionInstructions.message,
|
detail: locale.messages.autoUpdateNewVersionInstructions.message,
|
||||||
defaultId: LATER_BUTTON,
|
defaultId: LATER_BUTTON,
|
||||||
cancelId: LATER_BUTTON,
|
cancelId: LATER_BUTTON,
|
||||||
};
|
};
|
||||||
|
@ -170,7 +173,7 @@ async function showFallbackUpdateDialog(
|
||||||
|
|
||||||
export function showUpdateDialog(
|
export function showUpdateDialog(
|
||||||
mainWindow: BrowserWindow,
|
mainWindow: BrowserWindow,
|
||||||
messages: MessagesType,
|
locale: LocaleType,
|
||||||
performUpdateCallback: () => void
|
performUpdateCallback: () => void
|
||||||
): void {
|
): void {
|
||||||
let ack = false;
|
let ack = false;
|
||||||
|
@ -185,20 +188,20 @@ export function showUpdateDialog(
|
||||||
|
|
||||||
setTimeout(async () => {
|
setTimeout(async () => {
|
||||||
if (!ack) {
|
if (!ack) {
|
||||||
await showFallbackUpdateDialog(mainWindow, messages);
|
await showFallbackUpdateDialog(mainWindow, locale);
|
||||||
}
|
}
|
||||||
}, ACK_RENDER_TIMEOUT);
|
}, ACK_RENDER_TIMEOUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function showFallbackCannotUpdateDialog(
|
async function showFallbackCannotUpdateDialog(
|
||||||
mainWindow: BrowserWindow,
|
mainWindow: BrowserWindow,
|
||||||
messages: MessagesType
|
locale: LocaleType
|
||||||
) {
|
) {
|
||||||
const options = {
|
const options = {
|
||||||
type: 'error',
|
type: 'error',
|
||||||
buttons: [messages.ok.message],
|
buttons: [locale.messages.ok.message],
|
||||||
title: messages.cannotUpdate.message,
|
title: locale.messages.cannotUpdate.message,
|
||||||
message: messages.cannotUpdateDetail.message,
|
message: locale.i18n('cannotUpdateDetail', ['https://signal.org/download']),
|
||||||
};
|
};
|
||||||
|
|
||||||
await dialog.showMessageBox(mainWindow, options);
|
await dialog.showMessageBox(mainWindow, options);
|
||||||
|
@ -206,7 +209,7 @@ async function showFallbackCannotUpdateDialog(
|
||||||
|
|
||||||
export function showCannotUpdateDialog(
|
export function showCannotUpdateDialog(
|
||||||
mainWindow: BrowserWindow,
|
mainWindow: BrowserWindow,
|
||||||
messages: MessagesType
|
locale: LocaleType
|
||||||
): void {
|
): void {
|
||||||
let ack = false;
|
let ack = false;
|
||||||
|
|
||||||
|
@ -218,7 +221,7 @@ export function showCannotUpdateDialog(
|
||||||
|
|
||||||
setTimeout(async () => {
|
setTimeout(async () => {
|
||||||
if (!ack) {
|
if (!ack) {
|
||||||
await showFallbackCannotUpdateDialog(mainWindow, messages);
|
await showFallbackCannotUpdateDialog(mainWindow, locale);
|
||||||
}
|
}
|
||||||
}, ACK_RENDER_TIMEOUT);
|
}, ACK_RENDER_TIMEOUT);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,13 +3,13 @@ import { BrowserWindow } from 'electron';
|
||||||
|
|
||||||
import { start as startMacOS } from './macos';
|
import { start as startMacOS } from './macos';
|
||||||
import { start as startWindows } from './windows';
|
import { start as startWindows } from './windows';
|
||||||
import { LoggerType, MessagesType } from './common';
|
import { LocaleType, LoggerType } from './common';
|
||||||
|
|
||||||
let initialized = false;
|
let initialized = false;
|
||||||
|
|
||||||
export async function start(
|
export async function start(
|
||||||
getMainWindow: () => BrowserWindow,
|
getMainWindow: () => BrowserWindow,
|
||||||
messages?: MessagesType,
|
locale?: LocaleType,
|
||||||
logger?: LoggerType
|
logger?: LoggerType
|
||||||
) {
|
) {
|
||||||
const { platform } = process;
|
const { platform } = process;
|
||||||
|
@ -19,8 +19,8 @@ export async function start(
|
||||||
}
|
}
|
||||||
initialized = true;
|
initialized = true;
|
||||||
|
|
||||||
if (!messages) {
|
if (!locale) {
|
||||||
throw new Error('updater/start: Must provide messages!');
|
throw new Error('updater/start: Must provide locale!');
|
||||||
}
|
}
|
||||||
if (!logger) {
|
if (!logger) {
|
||||||
throw new Error('updater/start: Must provide logger!');
|
throw new Error('updater/start: Must provide logger!');
|
||||||
|
@ -35,9 +35,9 @@ export async function start(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (platform === 'win32') {
|
if (platform === 'win32') {
|
||||||
await startWindows(getMainWindow, messages, logger);
|
await startWindows(getMainWindow, locale, logger);
|
||||||
} else if (platform === 'darwin') {
|
} else if (platform === 'darwin') {
|
||||||
await startMacOS(getMainWindow, messages, logger);
|
await startMacOS(getMainWindow, locale, logger);
|
||||||
} else {
|
} else {
|
||||||
throw new Error('updater/start: Unsupported platform');
|
throw new Error('updater/start: Unsupported platform');
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,8 +15,8 @@ import {
|
||||||
deleteTempDir,
|
deleteTempDir,
|
||||||
downloadUpdate,
|
downloadUpdate,
|
||||||
getPrintableError,
|
getPrintableError,
|
||||||
|
LocaleType,
|
||||||
LoggerType,
|
LoggerType,
|
||||||
MessagesType,
|
|
||||||
showCannotUpdateDialog,
|
showCannotUpdateDialog,
|
||||||
showUpdateDialog,
|
showUpdateDialog,
|
||||||
} from './common';
|
} from './common';
|
||||||
|
@ -31,7 +31,7 @@ const INTERVAL = MINUTE * 30;
|
||||||
|
|
||||||
export async function start(
|
export async function start(
|
||||||
getMainWindow: () => BrowserWindow,
|
getMainWindow: () => BrowserWindow,
|
||||||
messages: MessagesType,
|
locale: LocaleType,
|
||||||
logger: LoggerType
|
logger: LoggerType
|
||||||
) {
|
) {
|
||||||
logger.info('macos/start: starting checks...');
|
logger.info('macos/start: starting checks...');
|
||||||
|
@ -41,13 +41,13 @@ export async function start(
|
||||||
|
|
||||||
setInterval(async () => {
|
setInterval(async () => {
|
||||||
try {
|
try {
|
||||||
await checkDownloadAndInstall(getMainWindow, messages, logger);
|
await checkDownloadAndInstall(getMainWindow, locale, logger);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('macos/start: error:', getPrintableError(error));
|
logger.error('macos/start: error:', getPrintableError(error));
|
||||||
}
|
}
|
||||||
}, INTERVAL);
|
}, INTERVAL);
|
||||||
|
|
||||||
await checkDownloadAndInstall(getMainWindow, messages, logger);
|
await checkDownloadAndInstall(getMainWindow, locale, logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
let fileName: string;
|
let fileName: string;
|
||||||
|
@ -57,7 +57,7 @@ let loggerForQuitHandler: LoggerType;
|
||||||
|
|
||||||
async function checkDownloadAndInstall(
|
async function checkDownloadAndInstall(
|
||||||
getMainWindow: () => BrowserWindow,
|
getMainWindow: () => BrowserWindow,
|
||||||
messages: MessagesType,
|
locale: LocaleType,
|
||||||
logger: LoggerType
|
logger: LoggerType
|
||||||
) {
|
) {
|
||||||
if (isChecking) {
|
if (isChecking) {
|
||||||
|
@ -98,12 +98,12 @@ async function checkDownloadAndInstall(
|
||||||
const message: string = error.message || '';
|
const message: string = error.message || '';
|
||||||
if (message.includes(readOnly)) {
|
if (message.includes(readOnly)) {
|
||||||
logger.info('checkDownloadAndInstall: showing read-only dialog...');
|
logger.info('checkDownloadAndInstall: showing read-only dialog...');
|
||||||
showReadOnlyDialog(getMainWindow(), messages);
|
showReadOnlyDialog(getMainWindow(), locale);
|
||||||
} else {
|
} else {
|
||||||
logger.info(
|
logger.info(
|
||||||
'checkDownloadAndInstall: showing general update failure dialog...'
|
'checkDownloadAndInstall: showing general update failure dialog...'
|
||||||
);
|
);
|
||||||
showCannotUpdateDialog(getMainWindow(), messages);
|
showCannotUpdateDialog(getMainWindow(), locale);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw error;
|
throw error;
|
||||||
|
@ -114,7 +114,7 @@ async function checkDownloadAndInstall(
|
||||||
|
|
||||||
logger.info('checkDownloadAndInstall: showing update dialog...');
|
logger.info('checkDownloadAndInstall: showing update dialog...');
|
||||||
|
|
||||||
showUpdateDialog(getMainWindow(), messages, () => {
|
showUpdateDialog(getMainWindow(), locale, () => {
|
||||||
logger.info('checkDownloadAndInstall: calling quitAndInstall...');
|
logger.info('checkDownloadAndInstall: calling quitAndInstall...');
|
||||||
markShouldQuit();
|
markShouldQuit();
|
||||||
autoUpdater.quitAndInstall();
|
autoUpdater.quitAndInstall();
|
||||||
|
@ -341,7 +341,7 @@ function shutdown(
|
||||||
|
|
||||||
export function showReadOnlyDialog(
|
export function showReadOnlyDialog(
|
||||||
mainWindow: BrowserWindow,
|
mainWindow: BrowserWindow,
|
||||||
messages: MessagesType
|
locale: LocaleType
|
||||||
): void {
|
): void {
|
||||||
let ack = false;
|
let ack = false;
|
||||||
|
|
||||||
|
@ -353,20 +353,20 @@ export function showReadOnlyDialog(
|
||||||
|
|
||||||
setTimeout(async () => {
|
setTimeout(async () => {
|
||||||
if (!ack) {
|
if (!ack) {
|
||||||
await showFallbackReadOnlyDialog(mainWindow, messages);
|
await showFallbackReadOnlyDialog(mainWindow, locale);
|
||||||
}
|
}
|
||||||
}, ACK_RENDER_TIMEOUT);
|
}, ACK_RENDER_TIMEOUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function showFallbackReadOnlyDialog(
|
async function showFallbackReadOnlyDialog(
|
||||||
mainWindow: BrowserWindow,
|
mainWindow: BrowserWindow,
|
||||||
messages: MessagesType
|
locale: LocaleType
|
||||||
) {
|
) {
|
||||||
const options = {
|
const options = {
|
||||||
type: 'warning',
|
type: 'warning',
|
||||||
buttons: [messages.ok.message],
|
buttons: [locale.messages.ok.message],
|
||||||
title: messages.cannotUpdate.message,
|
title: locale.messages.cannotUpdate.message,
|
||||||
message: messages.readOnlyVolume.message,
|
message: locale.i18n('readOnlyVolume', ['Signal.app', '/Applications']),
|
||||||
};
|
};
|
||||||
|
|
||||||
await dialog.showMessageBox(mainWindow, options);
|
await dialog.showMessageBox(mainWindow, options);
|
||||||
|
|
|
@ -12,8 +12,8 @@ import {
|
||||||
deleteTempDir,
|
deleteTempDir,
|
||||||
downloadUpdate,
|
downloadUpdate,
|
||||||
getPrintableError,
|
getPrintableError,
|
||||||
|
LocaleType,
|
||||||
LoggerType,
|
LoggerType,
|
||||||
MessagesType,
|
|
||||||
showCannotUpdateDialog,
|
showCannotUpdateDialog,
|
||||||
showUpdateDialog,
|
showUpdateDialog,
|
||||||
} from './common';
|
} from './common';
|
||||||
|
@ -30,7 +30,7 @@ const INTERVAL = MINUTE * 30;
|
||||||
|
|
||||||
export async function start(
|
export async function start(
|
||||||
getMainWindow: () => BrowserWindow,
|
getMainWindow: () => BrowserWindow,
|
||||||
messages: MessagesType,
|
locale: LocaleType,
|
||||||
logger: LoggerType
|
logger: LoggerType
|
||||||
) {
|
) {
|
||||||
logger.info('windows/start: starting checks...');
|
logger.info('windows/start: starting checks...');
|
||||||
|
@ -40,14 +40,14 @@ export async function start(
|
||||||
|
|
||||||
setInterval(async () => {
|
setInterval(async () => {
|
||||||
try {
|
try {
|
||||||
await checkDownloadAndInstall(getMainWindow, messages, logger);
|
await checkDownloadAndInstall(getMainWindow, locale, logger);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('windows/start: error:', getPrintableError(error));
|
logger.error('windows/start: error:', getPrintableError(error));
|
||||||
}
|
}
|
||||||
}, INTERVAL);
|
}, INTERVAL);
|
||||||
|
|
||||||
await deletePreviousInstallers(logger);
|
await deletePreviousInstallers(logger);
|
||||||
await checkDownloadAndInstall(getMainWindow, messages, logger);
|
await checkDownloadAndInstall(getMainWindow, locale, logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
let fileName: string;
|
let fileName: string;
|
||||||
|
@ -58,7 +58,7 @@ let loggerForQuitHandler: LoggerType;
|
||||||
|
|
||||||
async function checkDownloadAndInstall(
|
async function checkDownloadAndInstall(
|
||||||
getMainWindow: () => BrowserWindow,
|
getMainWindow: () => BrowserWindow,
|
||||||
messages: MessagesType,
|
locale: LocaleType,
|
||||||
logger: LoggerType
|
logger: LoggerType
|
||||||
) {
|
) {
|
||||||
if (isChecking) {
|
if (isChecking) {
|
||||||
|
@ -93,7 +93,7 @@ async function checkDownloadAndInstall(
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info('checkDownloadAndInstall: showing dialog...');
|
logger.info('checkDownloadAndInstall: showing dialog...');
|
||||||
showUpdateDialog(getMainWindow(), messages, async () => {
|
showUpdateDialog(getMainWindow(), locale, async () => {
|
||||||
try {
|
try {
|
||||||
await verifyAndInstall(updateFilePath, version, logger);
|
await verifyAndInstall(updateFilePath, version, logger);
|
||||||
installing = true;
|
installing = true;
|
||||||
|
@ -101,7 +101,7 @@ async function checkDownloadAndInstall(
|
||||||
logger.info(
|
logger.info(
|
||||||
'checkDownloadAndInstall: showing general update failure dialog...'
|
'checkDownloadAndInstall: showing general update failure dialog...'
|
||||||
);
|
);
|
||||||
showCannotUpdateDialog(getMainWindow(), messages);
|
showCannotUpdateDialog(getMainWindow(), locale);
|
||||||
|
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
"rule": "jQuery-load(",
|
"rule": "jQuery-load(",
|
||||||
"path": "app/locale.js",
|
"path": "app/locale.js",
|
||||||
"line": "function load({ appLocale, logger } = {}) {",
|
"line": "function load({ appLocale, logger } = {}) {",
|
||||||
"lineNumber": 27,
|
"lineNumber": 28,
|
||||||
"reasonCategory": "falseMatch",
|
"reasonCategory": "falseMatch",
|
||||||
"updated": "2018-09-13T21:20:44.234Z"
|
"updated": "2018-09-13T21:20:44.234Z"
|
||||||
},
|
},
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue