From ccb1f77054e38fa44e63b761f6d60062f89ff798 Mon Sep 17 00:00:00 2001 From: Adam Fraser Date: Wed, 21 Aug 2024 13:33:27 -0400 Subject: [PATCH] Add localization strings --- .../__tests__/localization.test.ts | 24 +++++++ .../notifications/src/localization.ts | 26 +++---- .../notifications/src/localizedMessages.ts | 69 +++++++++++++++++++ indexer/packages/notifications/src/types.ts | 7 +- 4 files changed, 110 insertions(+), 16 deletions(-) create mode 100644 indexer/packages/notifications/src/localizedMessages.ts diff --git a/indexer/packages/notifications/__tests__/localization.test.ts b/indexer/packages/notifications/__tests__/localization.test.ts index c504f898cf..c3051ce4e7 100644 --- a/indexer/packages/notifications/__tests__/localization.test.ts +++ b/indexer/packages/notifications/__tests__/localization.test.ts @@ -5,6 +5,7 @@ import { NotificationType, NotificationDynamicFieldKey, createNotification, + isValidLanguageCode, } from '../src/types'; describe('deriveLocalizedNotificationMessage', () => { @@ -38,4 +39,27 @@ describe('deriveLocalizedNotificationMessage', () => { const result = deriveLocalizedNotificationMessage(notification); expect(result).toEqual(expected); }); + + describe('isValidLanguageCode', () => { + test('should return true for valid language codes', () => { + const validCodes = ['en', 'es', 'fr', 'de', 'it', 'ja', 'ko', 'zh']; + validCodes.forEach((code) => { + expect(isValidLanguageCode(code)).toBe(true); + }); + }); + + test('should return false for invalid language codes', () => { + const invalidCodes = ['', 'EN', 'eng', 'esp', 'fra', 'deu', 'ita', 'jpn', 'kor', 'zho', 'xx']; + invalidCodes.forEach((code) => { + expect(isValidLanguageCode(code)).toBe(false); + }); + }); + + test('should return false for non-string inputs', () => { + const nonStringInputs = [null, undefined, 123, {}, []]; + nonStringInputs.forEach((input) => { + expect(isValidLanguageCode(input as any)).toBe(false); + }); + }); + }); }); diff --git a/indexer/packages/notifications/src/localization.ts b/indexer/packages/notifications/src/localization.ts index fbba24ba04..9383cadddb 100644 --- a/indexer/packages/notifications/src/localization.ts +++ b/indexer/packages/notifications/src/localization.ts @@ -1,31 +1,27 @@ +import { LOCALIZED_MESSAGES } from './localizedMessages'; import { - LocalizationKey, Notification, NotificationMesage, + LanguageCode, } from './types'; function replacePlaceholders(template: string, variables: Record): string { return template.replace(/{(\w+)}/g, (_, key) => variables[key] || `{${key}}`); } -export function deriveLocalizedNotificationMessage(notification: Notification): NotificationMesage { - const tempLocalizationFields = { - [LocalizationKey.DEPOSIT_SUCCESS_TITLE]: 'Deposit Successful', - [LocalizationKey.DEPOSIT_SUCCESS_BODY]: 'You have successfully deposited {AMOUNT} {MARKET} to your dYdX account.', - [LocalizationKey.ORDER_FILLED_TITLE]: 'Order Filled', - // eslint-disable-next-line no-template-curly-in-string - [LocalizationKey.ORDER_FILLED_BODY]: 'Your order for {AMOUNT} {MARKET} was filled at ${AVERAGE_PRICE}', - // eslint-disable-next-line no-template-curly-in-string - [LocalizationKey.ORDER_TRIGGERED_BODY]: 'Your order for {AMOUNT} {MARKET} was triggered at ${PRICE}', - [LocalizationKey.ORDER_TRIGGERED_TITLE]: '{MARKET} Order Triggered', - }; +export function deriveLocalizedNotificationMessage( + notification: Notification, + languageCode: LanguageCode = 'en', +): NotificationMesage { + const localizationFields = LOCALIZED_MESSAGES[languageCode] || LOCALIZED_MESSAGES.en; return { title: replacePlaceholders( - tempLocalizationFields[notification.titleKey], - notification.dynamicValues), + localizationFields[notification.titleKey], + notification.dynamicValues, + ), body: replacePlaceholders( - tempLocalizationFields[notification.bodyKey], + localizationFields[notification.bodyKey], notification.dynamicValues, ), }; diff --git a/indexer/packages/notifications/src/localizedMessages.ts b/indexer/packages/notifications/src/localizedMessages.ts new file mode 100644 index 0000000000..5d0d55c80a --- /dev/null +++ b/indexer/packages/notifications/src/localizedMessages.ts @@ -0,0 +1,69 @@ +/* eslint-disable no-template-curly-in-string */ +import { LocalizationKey, LanguageCode } from './types'; + +export const LOCALIZED_MESSAGES: Record> = { + en: { + [LocalizationKey.DEPOSIT_SUCCESS_TITLE]: 'Deposit Successful', + [LocalizationKey.DEPOSIT_SUCCESS_BODY]: 'You have successfully deposited {AMOUNT} {MARKET} to your dYdX account.', + [LocalizationKey.ORDER_FILLED_TITLE]: 'Order Filled', + [LocalizationKey.ORDER_FILLED_BODY]: 'Your order for {AMOUNT} {MARKET} was filled at ${AVERAGE_PRICE}', + [LocalizationKey.ORDER_TRIGGERED_TITLE]: '{MARKET} Order Triggered', + [LocalizationKey.ORDER_TRIGGERED_BODY]: 'Your order for {AMOUNT} {MARKET} was triggered at ${PRICE}', + }, + es: { + [LocalizationKey.DEPOSIT_SUCCESS_TITLE]: 'Depósito Exitoso', + [LocalizationKey.DEPOSIT_SUCCESS_BODY]: 'Has depositado exitosamente {AMOUNT} {MARKET} en tu cuenta dYdX.', + [LocalizationKey.ORDER_FILLED_TITLE]: 'Orden Ejecutada', + [LocalizationKey.ORDER_FILLED_BODY]: 'Tu orden de {AMOUNT} {MARKET} se ejecutó a ${AVERAGE_PRICE}', + [LocalizationKey.ORDER_TRIGGERED_TITLE]: 'Orden de {MARKET} Activada', + [LocalizationKey.ORDER_TRIGGERED_BODY]: 'Tu orden de {AMOUNT} {MARKET} se activó a ${PRICE}', + }, + fr: { + [LocalizationKey.DEPOSIT_SUCCESS_TITLE]: 'Dépôt Réussi', + [LocalizationKey.DEPOSIT_SUCCESS_BODY]: 'Vous avez déposé avec succès {AMOUNT} {MARKET} sur votre compte dYdX.', + [LocalizationKey.ORDER_FILLED_TITLE]: 'Ordre Exécuté', + [LocalizationKey.ORDER_FILLED_BODY]: 'Votre ordre de {AMOUNT} {MARKET} a été exécuté à ${AVERAGE_PRICE}', + [LocalizationKey.ORDER_TRIGGERED_TITLE]: 'Ordre {MARKET} Déclenché', + [LocalizationKey.ORDER_TRIGGERED_BODY]: 'Votre ordre de {AMOUNT} {MARKET} a été déclenché à ${PRICE}', + }, + de: { + [LocalizationKey.DEPOSIT_SUCCESS_TITLE]: 'Einzahlung Erfolgreich', + [LocalizationKey.DEPOSIT_SUCCESS_BODY]: 'Sie haben erfolgreich {AMOUNT} {MARKET} auf Ihr dYdX-Konto eingezahlt.', + [LocalizationKey.ORDER_FILLED_TITLE]: 'Auftrag Ausgeführt', + [LocalizationKey.ORDER_FILLED_BODY]: 'Ihr Auftrag für {AMOUNT} {MARKET} wurde zu ${AVERAGE_PRICE} ausgeführt', + [LocalizationKey.ORDER_TRIGGERED_TITLE]: '{MARKET} Auftrag Ausgelöst', + [LocalizationKey.ORDER_TRIGGERED_BODY]: 'Ihr Auftrag für {AMOUNT} {MARKET} wurde bei ${PRICE} ausgelöst', + }, + it: { + [LocalizationKey.DEPOSIT_SUCCESS_TITLE]: 'Deposito Riuscito', + [LocalizationKey.DEPOSIT_SUCCESS_BODY]: 'Hai depositato con successo {AMOUNT} {MARKET} sul tuo account dYdX.', + [LocalizationKey.ORDER_FILLED_TITLE]: 'Ordine Eseguito', + [LocalizationKey.ORDER_FILLED_BODY]: 'Il tuo ordine di {AMOUNT} {MARKET} è stato eseguito a ${AVERAGE_PRICE}', + [LocalizationKey.ORDER_TRIGGERED_TITLE]: 'Ordine {MARKET} Attivato', + [LocalizationKey.ORDER_TRIGGERED_BODY]: 'Il tuo ordine di {AMOUNT} {MARKET} è stato attivato a ${PRICE}', + }, + ja: { + [LocalizationKey.DEPOSIT_SUCCESS_TITLE]: '入金成功', + [LocalizationKey.DEPOSIT_SUCCESS_BODY]: 'dYdXアカウントに{AMOUNT} {MARKET}を正常に入金しました。', + [LocalizationKey.ORDER_FILLED_TITLE]: '注文約定', + [LocalizationKey.ORDER_FILLED_BODY]: '{AMOUNT} {MARKET}の注文が${AVERAGE_PRICE}で約定しました', + [LocalizationKey.ORDER_TRIGGERED_TITLE]: '{MARKET}注文トリガー', + [LocalizationKey.ORDER_TRIGGERED_BODY]: '{AMOUNT} {MARKET}の注文が${PRICE}でトリガーされました', + }, + ko: { + [LocalizationKey.DEPOSIT_SUCCESS_TITLE]: '입금 성공', + [LocalizationKey.DEPOSIT_SUCCESS_BODY]: 'dYdX 계정에 {AMOUNT} {MARKET}을(를) 성공적으로 입금했습니다.', + [LocalizationKey.ORDER_FILLED_TITLE]: '주문 체결', + [LocalizationKey.ORDER_FILLED_BODY]: '{AMOUNT} {MARKET} 주문이 ${AVERAGE_PRICE}에 체결되었습니다', + [LocalizationKey.ORDER_TRIGGERED_TITLE]: '{MARKET} 주문 트리거', + [LocalizationKey.ORDER_TRIGGERED_BODY]: '{AMOUNT} {MARKET} 주문이 ${PRICE}에서 트리거되었습니다', + }, + zh: { + [LocalizationKey.DEPOSIT_SUCCESS_TITLE]: '存款成功', + [LocalizationKey.DEPOSIT_SUCCESS_BODY]: '您已成功将 {AMOUNT} {MARKET} 存入您的 dYdX 账户。', + [LocalizationKey.ORDER_FILLED_TITLE]: '订单已成交', + [LocalizationKey.ORDER_FILLED_BODY]: '您的 {AMOUNT} {MARKET} 订单已以 ${AVERAGE_PRICE} 成交', + [LocalizationKey.ORDER_TRIGGERED_TITLE]: '{MARKET} 订单已触发', + [LocalizationKey.ORDER_TRIGGERED_BODY]: '您的 {AMOUNT} {MARKET} 订单已在 ${PRICE} 触发', + }, +}; \ No newline at end of file diff --git a/indexer/packages/notifications/src/types.ts b/indexer/packages/notifications/src/types.ts index 056d1782ee..f7145c9183 100644 --- a/indexer/packages/notifications/src/types.ts +++ b/indexer/packages/notifications/src/types.ts @@ -39,6 +39,11 @@ export enum Topic { PRICE_ALERTS = 'price_alerts', } +export type LanguageCode = 'en' | 'es' | 'fr' | 'de' | 'it' | 'ja' | 'ko' | 'zh'; +export function isValidLanguageCode(code: string): code is LanguageCode { + return ['en', 'es', 'fr', 'de', 'it', 'ja', 'ko', 'zh'].includes(code); +} + interface BaseNotification > { type: NotificationType, titleKey: LocalizationKey; @@ -144,4 +149,4 @@ export function createNotification( default: throw new Error('Unknown notification type'); } -} +} \ No newline at end of file