mirror of
https://github.com/sern-handler/tools
synced 2026-06-06 01:16:59 +00:00
147 lines
4.8 KiB
TypeScript
147 lines
4.8 KiB
TypeScript
import { type Init, Service, CommandInitPlugin, CommandType, controller } from '@sern/handler'
|
|
import { Localization as LocalsProvider } from 'shrimple-locales'
|
|
import fs from 'node:fs/promises'
|
|
import { existsSync } from 'node:fs'
|
|
import { join, resolve } from 'node:path';
|
|
import assert from 'node:assert';
|
|
import { dfsApplyLocalization } from './internal'
|
|
|
|
|
|
/**
|
|
* @since 3.4.0
|
|
* @internal
|
|
*/
|
|
class ShrimpleLocalizer implements Init {
|
|
private __localization!: LocalsProvider;
|
|
private currentLocale: string = "en";
|
|
|
|
translationsFor(path: string): Record<string, any> {
|
|
return this.__localization.localizationFor(path);
|
|
}
|
|
|
|
translate(text: string, local?: string): string {
|
|
return this.__localization.get(text, local);
|
|
}
|
|
|
|
setCurrentLocale(local: string): void {
|
|
this.__localization.changeLanguage(local);
|
|
}
|
|
|
|
async init() {
|
|
const map = await this.readLocalizationDirectory();
|
|
this.__localization = new LocalsProvider({
|
|
defaultLocale: this.currentLocale,
|
|
fallbackLocale: "en",
|
|
locales: map
|
|
});
|
|
}
|
|
|
|
private async readLocalizationDirectory() {
|
|
const translationFiles = [];
|
|
const localPath = resolve('assets', 'locals');
|
|
assert(existsSync(localPath), "No directory \"assets/locals\" found for the localizer")
|
|
for(const json_path of await fs.readdir(localPath)) {
|
|
const parsed = JSON.parse(await fs.readFile(join(localPath, json_path), 'utf8'))
|
|
const name = json_path.substring(0, json_path.lastIndexOf('.'));
|
|
translationFiles.push({ [name]: parsed })
|
|
}
|
|
return translationFiles.reduce((acc, cur) => ({ ...cur, ...acc }), {});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Translates a string to its respective local
|
|
* Note: this method only works AFTER your container has been initiated
|
|
* @example
|
|
* ```ts
|
|
* assert.deepEqual(locals("salute.hello", "es-ES"), "hola")
|
|
* ```
|
|
*/
|
|
export const local = (i: string, local: string) => {
|
|
return Service('localizer').translate(i, local)
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
* An init plugin to add localization fields to a command module.
|
|
* Your localization configuration should look like,
|
|
* sets nloc and dloc on locals field of module.
|
|
* @param root {string} If you have conflicting command names, you may configure the root of the name. (= command/{root})
|
|
* Below is es-ES.json (spanish)
|
|
* ```json
|
|
{
|
|
"command/comer" : {
|
|
"description": "Comer en Texas",
|
|
"options": {
|
|
"chicken": {
|
|
"name": "pollo",
|
|
"description": "un pollo largo"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
*/
|
|
export const localize = (root?: string) =>
|
|
//@ts-ignore
|
|
CommandInitPlugin(({ module, deps }) => {
|
|
if(module.type === CommandType.Slash || module.type === CommandType.Both) {
|
|
const { localizer, '@sern/logger':log } = deps
|
|
const resolvedRoot = 'command/'+(root??module.name);
|
|
log?.info({ message: "Localizing "+ resolvedRoot });
|
|
//@ts-ignore
|
|
dfsApplyLocalization(module.options ?? [], deps, [resolvedRoot]);
|
|
Reflect.set(module.locals, 'nloc', localizer.translationsFor(resolvedRoot+".name"))
|
|
Reflect.set(module.locals, 'dloc', localizer.translationsFor(resolvedRoot+'.description'))
|
|
return controller.next();
|
|
} else {
|
|
//@ts-ignore
|
|
return controller.stop("Cannot localize this type of module " + module.name);
|
|
}
|
|
})
|
|
|
|
export interface Localizer {
|
|
/**
|
|
* Returns an object containing translations for the given path.
|
|
* The object keys are the translation keys, and the values are the translated strings.
|
|
*
|
|
* @param path - The path to the translations file or directory.
|
|
* @returns An object with translation keys and their corresponding translated strings.
|
|
*/
|
|
translationsFor(path: string): Record<string, any>;
|
|
|
|
/**
|
|
* Translates the given text to the specified locale.
|
|
*
|
|
* @param text - The text to be translated.
|
|
* @param locale - The locale to translate the text to.
|
|
* @returns The translated text.
|
|
*/
|
|
translate(text: string, locale?: string): string;
|
|
|
|
/**
|
|
* Sets the current locale to be used for translation.
|
|
* @param locale - The locale to set as the current locale.
|
|
*/
|
|
setCurrentLocale(locale: string): void;
|
|
}
|
|
|
|
/**
|
|
* A service which provides simple file based localization. Add this while making dependencies.
|
|
* @example
|
|
* ```ts
|
|
* await makeDependencies(({ add }) => {
|
|
* add('localizer', Localization());
|
|
* });
|
|
* ```
|
|
**/
|
|
export const Localization = (defaultLocale?: string) => {
|
|
const localizer = new ShrimpleLocalizer;
|
|
if (defaultLocale) {
|
|
localizer.setCurrentLocale(defaultLocale);
|
|
}
|
|
return localizer as Localizer;
|
|
}
|