From 07195f40967fb68069874611bee455b23519b021 Mon Sep 17 00:00:00 2001 From: Jamie Kyle <113370520+jamiebuilds-signal@users.noreply.github.com> Date: Mon, 15 Jul 2024 16:15:18 -0700 Subject: [PATCH] Add bidi strip setting and use in os dialogs --- app/main.ts | 9 ++++++--- ts/state/ducks/globalModals.ts | 6 ++---- ts/types/Util.ts | 8 +++++++- ts/util/setupI18nMain.ts | 17 +++++++++++------ ts/util/unicodeBidi.ts | 7 ++++++- 5 files changed, 32 insertions(+), 15 deletions(-) diff --git a/app/main.ts b/app/main.ts index d551f4455dcd..bf4edf82c068 100644 --- a/app/main.ts +++ b/app/main.ts @@ -1676,6 +1676,7 @@ async function initializeSQL( userDataPath: string ): Promise<{ ok: true; error: undefined } | { ok: false; error: Error }> { sqlInitTimeStart = Date.now(); + try { // This should be the first awaited call in this function, otherwise // `sql.sqlCall` will throw an uninitialized error instead of waiting for @@ -1732,9 +1733,11 @@ const onDatabaseError = async (error: string) => { } else { // Otherwise, this is some other kind of DB error, let's give them the option to // delete. - messageDetail = i18n('icu:databaseError__detail', { - link: SIGNAL_SUPPORT_LINK, - }); + messageDetail = i18n( + 'icu:databaseError__detail', + { link: SIGNAL_SUPPORT_LINK }, + { bidi: 'strip' } + ); buttons.push(i18n('icu:deleteAndRestart')); deleteAllDataButtonIndex = 1; diff --git a/ts/state/ducks/globalModals.ts b/ts/state/ducks/globalModals.ts index afdca7769322..c3e9404fb84c 100644 --- a/ts/state/ducks/globalModals.ts +++ b/ts/state/ducks/globalModals.ts @@ -673,10 +673,8 @@ function showShareCallLinkViaSignal( ], messageBody: i18n( 'icu:ShareCallLinkViaSignal__DraftMessageText', - { - url, - }, - { textIsBidiFreeSkipNormalization: true } + { url }, + { bidi: 'strip' } ), }, }) diff --git a/ts/types/Util.ts b/ts/types/Util.ts index 9b703455be27..70a89a504ba8 100644 --- a/ts/types/Util.ts +++ b/ts/types/Util.ts @@ -24,7 +24,13 @@ export type RenderTextCallbackType = (options: { export { ICUJSXMessageParamsByKeyType, ICUStringMessageParamsByKeyType }; export type LocalizerOptions = { - textIsBidiFreeSkipNormalization?: boolean; + /** + * - 'default' will fence all string parameters with unicode bidi isolates + * and balance the control characters within them + * - 'strip' should only be used when all of the parameters are not + * user-generated and should not contain any control characters. + */ + bidi?: 'default' | 'strip'; }; export type LocalizerType = { diff --git a/ts/util/setupI18nMain.ts b/ts/util/setupI18nMain.ts index 541871199974..482306e4af41 100644 --- a/ts/util/setupI18nMain.ts +++ b/ts/util/setupI18nMain.ts @@ -13,7 +13,7 @@ import { strictAssert } from './assert'; import * as log from '../logging/log'; import * as Errors from '../types/errors'; import { Environment, getEnvironment } from '../environment'; -import { bidiIsolate } from './unicodeBidi'; +import { bidiIsolate, bidiStrip } from './unicodeBidi'; export function isLocaleMessageType( value: unknown @@ -65,7 +65,10 @@ export function createCachedIntl( function normalizeSubstitutions< Substitutions extends Record | undefined ->(substitutions?: Substitutions): Substitutions | undefined { +>( + substitutions?: Substitutions, + options?: LocalizerOptions +): Substitutions | undefined { if (!substitutions) { return; } @@ -76,7 +79,11 @@ function normalizeSubstitutions< } for (const [key, value] of entries) { if (typeof value === 'string') { - normalized[key] = bidiIsolate(value); + if (options?.bidi === 'strip') { + normalized[key] = bidiStrip(value); + } else { + normalized[key] = bidiIsolate(value); + } } else { normalized[key] = value; } @@ -123,9 +130,7 @@ export function setupI18n( ) => { const result = intl.formatMessage( { id: key }, - options?.textIsBidiFreeSkipNormalization - ? substitutions - : normalizeSubstitutions(substitutions) + normalizeSubstitutions(substitutions, options) ); strictAssert(result !== key, `i18n: missing translation for "${key}"`); diff --git a/ts/util/unicodeBidi.ts b/ts/util/unicodeBidi.ts index 73a24876b51c..e7d841f67405 100644 --- a/ts/util/unicodeBidi.ts +++ b/ts/util/unicodeBidi.ts @@ -109,7 +109,8 @@ export const ANY_UNICODE_DIR_CONTROL_CHAR_REGEX = new RegExp( POP_DIRECTIONAL_FORMATTING, LTR_OVERRIDE, RTL_OVERRIDE, - ].join('|') + ].join('|'), + 'g' ); export function hasAnyUnicodeDirControlChars(input: string): boolean { @@ -216,3 +217,7 @@ export function bidiIsolate(text: string): string { } return _bidiIsolate(text); } + +export function bidiStrip(text: string): string { + return text.replace(ANY_UNICODE_DIR_CONTROL_CHAR_REGEX, ''); +}