perf(translateText): speed up translateText (#3296)

## Description:

Cache lang-selector lookup
Avoid per-call empty params allocation
Add fast-path for non-ICU strings

## Please complete the following:

- [ ] I have added screenshots for all UI updates
- [ ] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [ ] I have added relevant tests to the test directory
- [ ] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced

## Please put your Discord username so you can be contacted if a bug or
regression is found:

DISCORD_USERNAME
This commit is contained in:
scamiv
2026-02-28 03:20:04 +01:00
committed by GitHub
parent f09177f8fe
commit 1cafc6bc25
+34 -19
View File
@@ -318,50 +318,65 @@ export function formatDebugTranslation(
return `${key}::${serializedParams}`;
}
const EMPTY_TRANSLATION_PARAMS: Record<string, string | number> = {};
function getCachedLangSelector(): LangSelector | null {
const self = translateText as any;
const cached = self.langSelector as LangSelector | null | undefined;
if (cached && cached.isConnected) return cached;
const found = document.querySelector("lang-selector") as LangSelector | null;
self.langSelector = found ?? null;
return found;
}
export const translateText = (
key: string,
params: Record<string, string | number> = {},
params?: Record<string, string | number>,
): string => {
const self = translateText as any;
self.formatterCache ??= new Map();
self.lastLang ??= null;
const langSelector = document.querySelector("lang-selector") as LangSelector;
const langSelector = getCachedLangSelector();
if (!langSelector) {
console.warn("LangSelector not found in DOM");
return key;
}
const resolvedParams = params ?? EMPTY_TRANSLATION_PARAMS;
if (langSelector.currentLang === "debug") {
return formatDebugTranslation(key, params);
return formatDebugTranslation(key, resolvedParams);
}
if (
!langSelector.translations ||
Object.keys(langSelector.translations).length === 0
) {
return key;
}
const translations = langSelector.translations;
const defaultTranslations = langSelector.defaultTranslations;
if (!translations && !defaultTranslations) return key;
if (self.lastLang !== langSelector.currentLang) {
self.formatterCache.clear();
self.lastLang = langSelector.currentLang;
}
let message = langSelector.translations[key];
let message = translations?.[key];
const hasPrimaryTranslation = message !== undefined;
if (!message && langSelector.defaultTranslations) {
const defaultTranslations = langSelector.defaultTranslations;
if (defaultTranslations && defaultTranslations[key]) {
message = defaultTranslations[key];
}
message ??= defaultTranslations?.[key];
if (message === undefined) return key;
// Fast path: no params and no ICU placeholders.
if (
resolvedParams === EMPTY_TRANSLATION_PARAMS &&
message.indexOf("{") === -1
) {
return message;
}
if (!message) return key;
try {
const locale =
!langSelector.translations[key] && langSelector.currentLang !== "en"
!hasPrimaryTranslation && langSelector.currentLang !== "en"
? "en"
: langSelector.currentLang;
const cacheKey = `${key}:${locale}:${message}`;
@@ -372,7 +387,7 @@ export const translateText = (
self.formatterCache.set(cacheKey, formatter);
}
return formatter.format(params) as string;
return formatter.format(resolvedParams) as string;
} catch (e) {
console.warn("ICU format error", e);
return message;