PronounsPage/shared/translator.ts

74 lines
2.3 KiB
TypeScript

import * as Sentry from '@sentry/browser';
import type { Config } from '../locale/config.ts';
import type { Translations } from '../locale/translations.ts';
import { deepGet } from './helpers.ts';
import { listMissingTranslations } from './missingTranslations.ts';
export class Translator {
translations: Translations;
baseTranslations: Translations;
config: Config;
constructor(translations: Translations, baseTranslations: Translations, config: Config) {
this.translations = translations;
this.baseTranslations = baseTranslations;
this.config = config;
}
translate<T extends string | string[] = string>(
key: string,
params: Record<string, string | number> = {},
warn: boolean = false,
): NoInfer<T> {
return this.applyParams(
this.get<T>(key, warn),
params,
);
}
get<T = string>(
key: string,
warn: boolean = false,
base: boolean = false,
useFallback: boolean = true,
): NoInfer<T> {
const translations = base ? this.baseTranslations : this.translations;
const value = deepGet(translations, key);
if (value === undefined) {
if (warn) {
Sentry.captureMessage(`Cannot find translation: ${key}`, 'warning');
}
if (!base && useFallback) {
return this.get(key, warn, true) as T;
}
}
return value as T;
}
has(key: string): boolean {
return this.get(key, false, false, false) !== undefined;
}
hasFallback(key: string): boolean {
return this.get(key, false, true, false) !== undefined;
}
applyParams<T extends string | string[] = string>(value: T, params: Record<string, string | number> = {}): T {
if (!value) {
return value;
}
for (const [placeholder, placeholderValue] of Object.entries(params)) {
value = (Array.isArray(value)
? value.map((v) => v.replaceAll(`%${placeholder}%`, placeholderValue?.toString()))
: value.replaceAll(`%${placeholder}%`, placeholderValue?.toString())) as T;
}
return value;
}
listMissingTranslations(): string[] {
return listMissingTranslations(this.translations, this.baseTranslations, this.config);
}
}