diff --git a/.changeset/flat-pets-taste.md b/.changeset/flat-pets-taste.md new file mode 100644 index 00000000000..458554083be --- /dev/null +++ b/.changeset/flat-pets-taste.md @@ -0,0 +1,5 @@ +--- +'@clerk/localizations': minor +--- + +Added en-XA locale to highlight unlocalized strings. diff --git a/packages/localizations/src/en-XA.ts b/packages/localizations/src/en-XA.ts new file mode 100644 index 00000000000..24b0b46087b --- /dev/null +++ b/packages/localizations/src/en-XA.ts @@ -0,0 +1,80 @@ +import type { LocalizationResource } from '@clerk/shared/types'; + +import { enUS } from './en-US'; + +const pseudoCharacterMap = { + a: 'å', + b: 'ƀ', + c: 'ç', + d: 'ð', + e: 'é', + f: 'ƒ', + g: 'ğ', + h: 'ħ', + i: 'ï', + j: 'ĵ', + k: 'ķ', + l: 'ľ', + m: 'ɱ', + n: 'ñ', + o: 'ø', + p: 'þ', + q: 'ʠ', + r: 'ř', + s: 'š', + t: 'ŧ', + u: 'ü', + v: 'ṽ', + w: 'ŵ', + x: 'ẋ', + y: 'ÿ', + z: 'ž', +} as const; + +const pseudoCharacterMapWithUppercase = Object.fromEntries( + Object.entries(pseudoCharacterMap).flatMap(([source, target]) => [ + [source, target], + [source.toUpperCase(), target.toLocaleUpperCase('en-US')], + ]), +) as Record; + +const tokenOrLetterPattern = /\{\{[^{}]*\}\}|\{[^{}]*\}|[a-zA-Z]/g; + +function pseudoLocalizeString(value: string): string { + return value.replace(tokenOrLetterPattern, segment => { + if (segment.startsWith('{')) { + return segment; + } + + return pseudoCharacterMapWithUppercase[segment] ?? segment; + }); +} + +function pseudoLocalizeValue(value: T): T { + if (typeof value === 'string') { + return pseudoLocalizeString(value) as T; + } + + if (Array.isArray(value)) { + return value.map(item => pseudoLocalizeValue(item)) as T; + } + + if (value && typeof value === 'object') { + const localized: Record = {}; + + for (const [key, nestedValue] of Object.entries(value)) { + localized[key] = pseudoLocalizeValue(nestedValue); + } + + return localized as T; + } + + return value; +} + +const enXAFromEnUS = pseudoLocalizeValue(enUS); + +export const enXA: LocalizationResource = { + ...enXAFromEnUS, + locale: 'en-XA', +}; diff --git a/packages/localizations/src/index.ts b/packages/localizations/src/index.ts index e481e142175..30e728afd22 100644 --- a/packages/localizations/src/index.ts +++ b/packages/localizations/src/index.ts @@ -9,6 +9,7 @@ export { deDE } from './de-DE'; export { elGR } from './el-GR'; export { enUS } from './en-US'; export { enGB } from './en-GB'; +export { enXA } from './en-XA'; export { esCR } from './es-CR'; export { esES } from './es-ES'; export { esMX } from './es-MX';