Add bidi strip setting and use in os dialogs

This commit is contained in:
Jamie Kyle 2024-07-15 16:15:18 -07:00 committed by GitHub
parent a710f09977
commit 07195f4096
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 32 additions and 15 deletions

View file

@ -1676,6 +1676,7 @@ async function initializeSQL(
userDataPath: string userDataPath: string
): Promise<{ ok: true; error: undefined } | { ok: false; error: Error }> { ): Promise<{ ok: true; error: undefined } | { ok: false; error: Error }> {
sqlInitTimeStart = Date.now(); sqlInitTimeStart = Date.now();
try { try {
// This should be the first awaited call in this function, otherwise // This should be the first awaited call in this function, otherwise
// `sql.sqlCall` will throw an uninitialized error instead of waiting for // `sql.sqlCall` will throw an uninitialized error instead of waiting for
@ -1732,9 +1733,11 @@ const onDatabaseError = async (error: string) => {
} else { } else {
// Otherwise, this is some other kind of DB error, let's give them the option to // Otherwise, this is some other kind of DB error, let's give them the option to
// delete. // delete.
messageDetail = i18n('icu:databaseError__detail', { messageDetail = i18n(
link: SIGNAL_SUPPORT_LINK, 'icu:databaseError__detail',
}); { link: SIGNAL_SUPPORT_LINK },
{ bidi: 'strip' }
);
buttons.push(i18n('icu:deleteAndRestart')); buttons.push(i18n('icu:deleteAndRestart'));
deleteAllDataButtonIndex = 1; deleteAllDataButtonIndex = 1;

View file

@ -673,10 +673,8 @@ function showShareCallLinkViaSignal(
], ],
messageBody: i18n( messageBody: i18n(
'icu:ShareCallLinkViaSignal__DraftMessageText', 'icu:ShareCallLinkViaSignal__DraftMessageText',
{ { url },
url, { bidi: 'strip' }
},
{ textIsBidiFreeSkipNormalization: true }
), ),
}, },
}) })

View file

@ -24,7 +24,13 @@ export type RenderTextCallbackType = (options: {
export { ICUJSXMessageParamsByKeyType, ICUStringMessageParamsByKeyType }; export { ICUJSXMessageParamsByKeyType, ICUStringMessageParamsByKeyType };
export type LocalizerOptions = { 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 = { export type LocalizerType = {

View file

@ -13,7 +13,7 @@ import { strictAssert } from './assert';
import * as log from '../logging/log'; import * as log from '../logging/log';
import * as Errors from '../types/errors'; import * as Errors from '../types/errors';
import { Environment, getEnvironment } from '../environment'; import { Environment, getEnvironment } from '../environment';
import { bidiIsolate } from './unicodeBidi'; import { bidiIsolate, bidiStrip } from './unicodeBidi';
export function isLocaleMessageType( export function isLocaleMessageType(
value: unknown value: unknown
@ -65,7 +65,10 @@ export function createCachedIntl(
function normalizeSubstitutions< function normalizeSubstitutions<
Substitutions extends Record<string, string | number | Date> | undefined Substitutions extends Record<string, string | number | Date> | undefined
>(substitutions?: Substitutions): Substitutions | undefined { >(
substitutions?: Substitutions,
options?: LocalizerOptions
): Substitutions | undefined {
if (!substitutions) { if (!substitutions) {
return; return;
} }
@ -76,7 +79,11 @@ function normalizeSubstitutions<
} }
for (const [key, value] of entries) { for (const [key, value] of entries) {
if (typeof value === 'string') { if (typeof value === 'string') {
if (options?.bidi === 'strip') {
normalized[key] = bidiStrip(value);
} else {
normalized[key] = bidiIsolate(value); normalized[key] = bidiIsolate(value);
}
} else { } else {
normalized[key] = value; normalized[key] = value;
} }
@ -123,9 +130,7 @@ export function setupI18n(
) => { ) => {
const result = intl.formatMessage( const result = intl.formatMessage(
{ id: key }, { id: key },
options?.textIsBidiFreeSkipNormalization normalizeSubstitutions(substitutions, options)
? substitutions
: normalizeSubstitutions(substitutions)
); );
strictAssert(result !== key, `i18n: missing translation for "${key}"`); strictAssert(result !== key, `i18n: missing translation for "${key}"`);

View file

@ -109,7 +109,8 @@ export const ANY_UNICODE_DIR_CONTROL_CHAR_REGEX = new RegExp(
POP_DIRECTIONAL_FORMATTING, POP_DIRECTIONAL_FORMATTING,
LTR_OVERRIDE, LTR_OVERRIDE,
RTL_OVERRIDE, RTL_OVERRIDE,
].join('|') ].join('|'),
'g'
); );
export function hasAnyUnicodeDirControlChars(input: string): boolean { export function hasAnyUnicodeDirControlChars(input: string): boolean {
@ -216,3 +217,7 @@ export function bidiIsolate(text: string): string {
} }
return _bidiIsolate(text); return _bidiIsolate(text);
} }
export function bidiStrip(text: string): string {
return text.replace(ANY_UNICODE_DIR_CONTROL_CHAR_REGEX, '');
}