Add interpolation for fallback dialog messages

This commit is contained in:
Josh Perez 2020-02-13 10:14:08 -08:00 committed by GitHub
parent 800c7ed31d
commit afddc852cc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 61 additions and 47 deletions

View file

@ -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,
}; };

View file

@ -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:',

View file

@ -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(

View file

@ -27,12 +27,15 @@ 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);
} }

View file

@ -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');
} }

View file

@ -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);

View file

@ -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;
} }

View file

@ -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"
}, },