From ce734f1e1c439f757c6772e1156e7361d4700754 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Fri, 17 Jan 2025 13:51:42 +1100 Subject: [PATCH] chore: enforce i18n functions types to match what is in window.d.ts --- ts/localization/localeTools.ts | 47 +++++++++++++++------------------- ts/types/localizer.d.ts | 3 ++- 2 files changed, 22 insertions(+), 28 deletions(-) diff --git a/ts/localization/localeTools.ts b/ts/localization/localeTools.ts index c28c7bd65..326173b30 100644 --- a/ts/localization/localeTools.ts +++ b/ts/localization/localeTools.ts @@ -1,10 +1,12 @@ +// eslint-disable-next-line no-restricted-imports +import type { I18nMethods } from '../types/localizer'; import { CrowdinLocale } from './constants'; import { pluralsDictionary, simpleDictionary } from './locales'; type SimpleDictionary = typeof simpleDictionary; type PluralDictionary = typeof pluralsDictionary; -type SimpleLocalizerTokens = keyof SimpleDictionary; +export type SimpleLocalizerTokens = keyof SimpleDictionary; type PluralLocalizerTokens = keyof PluralDictionary; export type MergedLocalizerTokens = SimpleLocalizerTokens | PluralLocalizerTokens; @@ -133,7 +135,7 @@ function propsToTuple( * @param token - The token identifying the message to retrieve. * @param args - An optional record of substitution variables and their replacement values. This is equired if the string has dynamic variables. */ -export function inEnglish([token, args]: GetMessageArgs) { +export const inEnglish: I18nMethods['inEnglish'] = token => { if (!isSimpleToken(token)) { throw new Error('inEnglish only supports simple strings for now'); } @@ -143,8 +145,8 @@ export function inEnglish([token, args]: GetMes log(`Attempted to get forced en string for nonexistent key: '${token}' in fallback dictionary`); return token; } - return formatMessageWithArgs(rawMessage, args); -} + return formatMessageWithArgs(rawMessage); +}; /** * Retrieves a localized message string, substituting variables where necessary. @@ -176,24 +178,21 @@ export function getMessageDefault( * * @returns The localized message string with substitutions applied. Any HTML and custom tags are removed. */ - -export function stripped( - ...[token, args]: GetMessageArgs -): string { +export const stripped: I18nMethods['stripped'] = (...[token, args]) => { const sanitizedArgs = args ? sanitizeArgs(args, '\u200B') : undefined; - const i18nString = getMessageDefault(...([token, sanitizedArgs] as GetMessageArgs)); + // Note: the `as any` is needed because we don't have the template argument available + // when enforcing the type of the stripped function to be the one defined by I18nMethods + const i18nString = getMessageDefault(...([token, sanitizedArgs] as GetMessageArgs)); const strippedString = i18nString.replaceAll(/<[^>]*>/g, ''); return deSanitizeHtmlTags(strippedString, '\u200B'); -} +}; -export function strippedWithObj( - opts: LocalizerComponentProps -): string { +export const strippedWithObj: I18nMethods['strippedWithObj'] = opts => { return stripped(...propsToTuple(opts)); -} +}; /** * Sanitizes the args to be used in the i18n function @@ -224,17 +223,14 @@ export function sanitizeArgs( * @deprecated * */ -export function formatMessageWithArgs( - rawMessage: string, - args?: ArgsFromToken -): string { +export const formatMessageWithArgs: I18nMethods['formatMessageWithArgs'] = (rawMessage, args) => { /** Find and replace the dynamic variables in a localized string and substitute the variables with the provided values */ return rawMessage.replace(/\{(\w+)\}/g, (match: any, arg: string) => { const matchedArg = args ? args[arg as keyof typeof args] : undefined; return matchedArg?.toString() ?? match; }); -} +}; /** * Retrieves a localized message string, without substituting any variables. This resolves any plural forms using the given args @@ -245,16 +241,13 @@ export function formatMessageWithArgs( * * NOTE: This is intended to be used to get the raw string then format it with {@link formatMessageWithArgs} */ -export function getRawMessage( - crowdinLocale: CrowdinLocale, - ...[token, args]: GetMessageArgs -): string { +export const getRawMessage: I18nMethods['getRawMessage'] = (crowdinLocale, ...[token, args]) => { try { if ( typeof window !== 'undefined' && window?.sessionFeatureFlags?.replaceLocalizedStringsWithKeys ) { - return token as T; + return token; } if (isSimpleToken(token)) { @@ -284,15 +277,15 @@ export function getRawMessage( if (!pluralString) { log(`Plural string not found for cardinal '${cardinalRule}': '${pluralString}'`); - return token as T; + return token; } return pluralString.replaceAll('#', `${num}`); } catch (error) { log(error.message); - return token as T; + return token; } -} +}; function getStringForRule({ dictionary, diff --git a/ts/types/localizer.d.ts b/ts/types/localizer.d.ts index 0b537d0ea..b578d1db9 100644 --- a/ts/types/localizer.d.ts +++ b/ts/types/localizer.d.ts @@ -3,6 +3,7 @@ import type { MergedLocalizerTokens, GetMessageArgs, LocalizerComponentProps, + SimpleLocalizerTokens, } from '../localization/localeTools'; import { CrowdinLocale } from '../localization/constants'; @@ -13,7 +14,7 @@ export type I18nMethods = { opts: LocalizerComponentProps ) => string | T; /** @see {@link window.i18n.inEnglish} */ - inEnglish: (...[token, args]: GetMessageArgs) => string | T; + inEnglish: (token: T) => string | T; /** @see {@link window.i18n.formatMessageWithArgs */ getRawMessage: ( crowdinLocale: CrowdinLocale,