Skip to content

Commit

Permalink
feat: typed translation keys
Browse files Browse the repository at this point in the history
  • Loading branch information
Sv443 committed Jan 2, 2025
1 parent 6dfdbc9 commit ea6b2e0
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 16 deletions.
8 changes: 4 additions & 4 deletions src/commands/Config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { capitalize } from "@lib/text.ts";
import localesJson from "@assets/locales.json" with { type: "json" };
import type { Stringifiable } from "@src/types.ts";
import { registerCommandsForGuild } from "@lib/registry.ts";
import { getLocMap, tr } from "@lib/translate.ts";
import { getLocMap, tr, type TrKeyEn } from "@lib/translate.ts";

//#region constants

Expand Down Expand Up @@ -112,7 +112,7 @@ export class ConfigCmd extends SlashCommand {
.setName(CmdBase.getCmdName(tr.forLang("en-US", "commands.config.names.command")))
.setNameLocalizations(getLocMap("commands.config.names.command", ConfigCmd.cmdPrefix))
.setDescription(tr.forLang("en-US", "commands.config.descriptions.command"))
.setDescriptionLocalizations(getLocMap("config", ConfigCmd.cmdPrefix))
.setDescriptionLocalizations(getLocMap("commands.config.descriptions.command", ConfigCmd.cmdPrefix))
.setDefaultMemberPermissions(PermissionFlagsBits.ManageGuild)
.addSubcommand(option => option
.setName(tr.forLang("en-US", "commands.config.names.subcmd.reset"))
Expand Down Expand Up @@ -274,10 +274,10 @@ export class ConfigCmd extends SlashCommand {
int: CommandInteraction;
opt: CommandInteractionOption;
cfgProp: TCfgKey;
settingNameTrKey: string;
settingNameTrKey: TrKeyEn;
getValueLabel?: (value: TCfgValue, locale: string) => Stringifiable | undefined;
validateValue?: (value: TCfgValue) => boolean;
invalidHintTrKey?: string;
invalidHintTrKey?: TrKeyEn;
}) {
if(!ConfigCmd.checkInGuild(int))
return;
Expand Down
4 changes: 2 additions & 2 deletions src/commands/Privacy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export class PrivacyCmd extends SlashCommand {
const sub = int.options.data[0].name;

if(sub === "info")
return int.editReply(useEmbedify(Array.from({ length: 5 }).map((_, i) => tr.forLang(locale, `commands.privacy.info.line${i + 1}`))));
return int.editReply(useEmbedify(Array.from({ length: 5 }).map((_, i) => tr.forLang(locale, `commands.privacy.info.line${(i + 1) as 1}`))));

if(sub === "delete_data") {
if(!await em.findOne(UserSettings, { id: int.user.id }))
Expand All @@ -67,7 +67,7 @@ export class PrivacyCmd extends SlashCommand {

const reply = await int.editReply({
embeds: [
embedify(Array.from({ length: 4 }).map((_, i) => tr.forLang(locale, `commands.privacy.delete.confirmLine${i + 1}`)), Col.Warning)
embedify(Array.from({ length: 4 }).map((_, i) => tr.forLang(locale, `commands.privacy.delete.confirmLine${(i + 1) as 1}`)), Col.Warning)
.setFooter({ text: tr.forLang(locale, "general.promptExpiryNotice", promptSec) }),
],
...useButtons([confirmBtns]),
Expand Down
10 changes: 5 additions & 5 deletions src/commands/Template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ import { getLocMap, tr } from "@lib/translate.ts";
export class TemplateCmd extends SlashCommand {
constructor() {
super(new SlashCommandBuilder()
.setName(CmdBase.getCmdName(tr.forLang("en-US", "commands.template_command.name")))
.setNameLocalizations(getLocMap("commands.template_command.name", TemplateCmd.cmdPrefix))
.setDescription(tr.forLang("en-US", "commands.template_command.description"))
.setDescriptionLocalizations(getLocMap("commands.template_command.description"))
.setName(CmdBase.getCmdName(tr.forLang("en-US", "commands.template_command.name" as "_")))
.setNameLocalizations(getLocMap("commands.template_command.name" as "_", TemplateCmd.cmdPrefix))
.setDescription(tr.forLang("en-US", "commands.template_command.description" as "_"))
.setDescriptionLocalizations(getLocMap("commands.template_command.description" as "_"))
);
}

Expand All @@ -23,7 +23,7 @@ export class TemplateCmd extends SlashCommand {
const locale = await TemplateCmd.getGuildLocale(int);

return int.editReply({
...useEmbedify(tr.forLang(locale, "TEMPLATE")),
...useEmbedify(tr.forLang(locale, "commands.template_command.embedContent" as "_")),
});
}
}
4 changes: 2 additions & 2 deletions src/contexts/Template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import { ContextMenuCommandBuilder, type ContextMenuCommandInteraction } from "d
export class TemplateCtx extends ContextCommand {
constructor() {
super(new ContextMenuCommandBuilder()
.setName(tr.forLang("en-US", "commands.template_ctx.name"))
.setNameLocalizations(getLocMap("commands.template_ctx.name"))
.setName(tr.forLang("en-US", "commands.template_ctx.name" as "_"))
.setNameLocalizations(getLocMap("commands.template_ctx.name" as "_"))
);
}

Expand Down
21 changes: 18 additions & 3 deletions src/lib/translate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { Stringifiable } from "@src/types.ts";
import type { LocalizationMap } from "discord.js";
import k from "kleur";
import { readdir, readFile } from "node:fs/promises";
import trEn from "@assets/translations/en-US.json" with { type: "json" };

//#region tr system

Expand Down Expand Up @@ -31,6 +32,15 @@ export interface TrObject {
/** Function that transforms a matched translation string into something else */
export type TransformFn = (language: string, trValue: string, matchesArr: RegExpMatchArray, ...trArgs: (Stringifiable | Record<string, Stringifiable>)[]) => Stringifiable;

/** Pass a translation object to this function to get all keys in the object */
export type TrKeys<TTrObj, P extends string = ""> = {
[K in keyof TTrObj]: K extends string | number | boolean | null | undefined
? TTrObj[K] extends object
? TrKeys<TTrObj[K], `${P}${K}.`>
: `${P}${K}`
: never
}[keyof TTrObj];

/** All translations loaded into memory */
const trans: {
[language: string]: TrObject;
Expand Down Expand Up @@ -155,7 +165,7 @@ const deleteTranslations = (language = curLang): void => {
* @param language Language code or name to check in - defaults to the currently active language (set by {@linkcode tr.setLanguage()})
* @returns Whether the translation key exists in the specified language - always returns `false` if no language is given and no active language was set
*/
const hasKey = (key: string, language = curLang): boolean => {
const hasKey = (key: TrKeyEn, language = curLang): boolean => {
return tr.forLang(language, key) !== key;
};

Expand Down Expand Up @@ -235,7 +245,7 @@ const deleteTransform = (patternOrFn: RegExp | string | TransformFn): void => {
* @param key Key of the translation to return
* @param args Optional arguments to be passed to the translated text. They will replace placeholders in the format `%n`, where `n` is the 1-indexed argument number
*/
const forLang = (language: string, key: string, ...args: (Stringifiable | Record<string, Stringifiable>)[]) => {
const forLang = (language: string, key: TrKeyEn, ...args: (Stringifiable | Record<string, Stringifiable>)[]) => {
const txt = translate(language, key, ...args);
if(txt === key)
return translate(defaultLocale, key, ...args);
Expand All @@ -258,6 +268,11 @@ export { tr };

//#region custom stuff

/** All translation keys from the file `@assets/translations/en-US.json` */
export type TrKeyEn = TrKeys<typeof trEn> | "_";
// export type TrKeyEn = TrKeys<typeof trEn> | (string & {});

/** The default and fallback locale */
export const defaultLocale = "en-US";

/** Array of tuples containing the regular expression and the transformation function */
Expand Down Expand Up @@ -327,7 +342,7 @@ export async function initTranslations(): Promise<void> {
//#region getLocMap

/** Returns the localization map for all locales, given the common translation key */
export function getLocMap(trKey: string, prefix = ""): LocalizationMap {
export function getLocMap(trKey: TrKeyEn, prefix = ""): LocalizationMap {
const locMap = {} as LocalizationMap;

for(const [locale, trObj] of Object.entries(trans)) {
Expand Down

0 comments on commit ea6b2e0

Please # to comment.