From d6e7f352145a9eb291f6e14ba39da45556357231 Mon Sep 17 00:00:00 2001 From: tresabhi <43380238+tresabhi@users.noreply.github.com> Date: Thu, 2 Jan 2025 19:43:13 -0600 Subject: [PATCH] feat: translators --- packages/prate/package.json | 9 +++ packages/prate/src/index.ts | 102 ++++++++++++++++++++++++++++++++++ packages/website/package.json | 1 + 3 files changed, 112 insertions(+) create mode 100644 packages/prate/package.json create mode 100644 packages/prate/src/index.ts diff --git a/packages/prate/package.json b/packages/prate/package.json new file mode 100644 index 000000000..cab88aa90 --- /dev/null +++ b/packages/prate/package.json @@ -0,0 +1,9 @@ +{ + "name": "prate", + "private": true, + "type": "module", + "main": "src/index.ts", + "devDependencies": { + "@blitzkit/core": "workspace:*" + } +} diff --git a/packages/prate/src/index.ts b/packages/prate/src/index.ts new file mode 100644 index 000000000..ef01a2038 --- /dev/null +++ b/packages/prate/src/index.ts @@ -0,0 +1,102 @@ +import en from '@blitzkit/core/lang/en.json'; +import ru from '@blitzkit/core/lang/ru.json'; + +type Translation = string | TranslationTree; +type TranslationTree = { [key: string]: Translation }; + +// type Options = { +// defaultLocale: DefaultLocale; +// }; + +// export function prate< +// Locale extends string, +// DefaultLocale extends Locale, +// >( +// strings: Record, +// options: Partial>, +// ) { +// function +// } + +// const {prate }= prate({ en, ru }, { defaultLocale: 'en' }); + +class Prate { + private readonly strings = new Map(); + private readonly defaultStrings: Map; + + constructor( + strings: Record, + public defaultLocale: DefaultLocale, + ) { + for (const locale in strings) { + this.strings.set(locale, strings[locale]); + } + + this.defaultStrings = this.flatten(strings[defaultLocale]); + } + + private flatten(strings: TranslationTree) { + const translations = new Map(); + + function traverse(parent: string, tree: Record) { + for (const key in tree) { + const path = `${parent}${key}`; + + if (typeof tree[key] === 'string') { + translations.set(path, tree[key]); + } else { + traverse(`${path}.`, tree[key]); + } + } + } + + traverse('', strings); + + return translations; + } + + locale(locale: Locale) { + const strings = this.strings.get(locale); + const defaultStrings = this.defaultStrings; + const defaultLocale = this.defaultLocale; + + if (strings === undefined) { + throw new TypeError(`Locale "${locale}" is not undefined`); + } + + const translations = this.flatten(strings); + + function translate(path: string, literals?: string[]) { + let translation = translations.get(path) ?? translations.get(`${path}.$`); + + if (translation === undefined) { + translation = + defaultStrings.get(path) ?? defaultStrings.get(`${path}.$`); + + if (translation === undefined) { + throw new Error( + `Undefined translation for "${path}" in locale "${locale}"; no fallback found in "${defaultLocale}"`, + ); + } + + console.warn( + `Undefined translation for "${path}" in locale "${locale}"; falling back to "${defaultLocale}"`, + ); + } + + literals?.forEach((literal, index) => { + translation = translation!.replaceAll(`%s${index + 1}`, literal); + }); + + return translation; + } + + return { translate }; + } +} + +const prate = new Prate({ en, ru }, 'en'); + +const { translate } = prate.locale('ru'); + +console.log(translate('bot.common.wn8')); diff --git a/packages/website/package.json b/packages/website/package.json index 30d60d383..285a772b9 100644 --- a/packages/website/package.json +++ b/packages/website/package.json @@ -11,6 +11,7 @@ }, "dependencies": { "@blitzkit/core": "workspace:*", + "prate": "workspace:*", "@nanostores/persistent": "^0.10.2", "@nanostores/react": "^0.7.3", "@nivo/bar": "^0.87.0",