Skip to content

Commit

Permalink
Added i18n Module
Browse files Browse the repository at this point in the history
  • Loading branch information
GaryCraft committed Apr 22, 2024
1 parent d5a26de commit 462f136
Show file tree
Hide file tree
Showing 13 changed files with 173 additions and 1 deletion.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ So the main template remains clean and without bloat.
- [ ] Mattermost Client
- [ ] OCR Module
- [ ] Twitch Module
- [ ] Discord-Music Module
- [ ] Service Polling Module
- [ ] Orizuru Module
- [x] i18n Module (internal)

but you can also create your own modules, and publish them to npm.
we'll try to mantain the name format as `udm-<name>`
Expand Down
9 changes: 9 additions & 0 deletions config/example.index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,15 @@ module.exports = {
discord: {
prefix: "!",
token: process.env.DISCORD_TOKEN,
activity: {
type: "PLAYING",
name: "UtilityDust development",
}
},
//$StripStart
i18n: {
baseLanguage: "en",
}
//$StripEnd
}
};
3 changes: 3 additions & 0 deletions lang/en/default.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"i18nModuleInitialized": "i18n Module has been initialized correctly"
}
45 changes: 45 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@
"discord.js": "^14.14.1",
"eventemitter2": "^6.4.9",
"express": "^4.18.2",
"i18next": "^23.11.2",
"i18next-fs-backend": "^2.3.1",
"mysql2": "^3.6.5",
"node-schedule": "^2.1.1",
"parzival": "^0.5.7",
Expand Down
9 changes: 9 additions & 0 deletions src/config/modules/i18n.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Parseable, ValidateProperty } from "parzival";

@Parseable()
export default class I18nConfig {
@ValidateProperty({
type: "string",
})
baseLanguage!: string;
}
8 changes: 8 additions & 0 deletions src/config/modules/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Parseable, ValidateProperty } from "parzival";
import DiscordConfig from "./discord";
//$StripStart
import I18nConfig from "./i18n";
//$StripEnd

@Parseable()
Expand All @@ -11,6 +12,13 @@ export default class ModuleConfigs {
className: "DiscordConfig",
})
discord!: DiscordConfig;

//$StripStart
@ValidateProperty({
type: "object",
recurse: true,
className: "I18nConfig",
})
i18n!: I18nConfig;
//$StripEnd
}
6 changes: 6 additions & 0 deletions src/modules/i18n/hooks/failedLoading.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { debug, warn } from "@src/engine/utils/Logger";
import { I18nModule } from "../module";

export default async (i18n: I18nModule, lng: string, ns: string, msg: string) => {
warn("Failed to load translation file", { lng, ns, msg });
};
6 changes: 6 additions & 0 deletions src/modules/i18n/hooks/initialized.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { debug } from "@src/engine/utils/Logger";
import { I18nModule } from "../module";

export default async (i18n: I18nModule) => {
debug("I18n Module Initialized");
};
6 changes: 6 additions & 0 deletions src/modules/i18n/hooks/loaded.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { debug, info } from "@src/engine/utils/Logger";
import { I18nModule } from "../module";

export default async (i18n: I18nModule) => {
info("I18n Loaded");
}
6 changes: 6 additions & 0 deletions src/modules/i18n/hooks/missingKey.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { debug, warn } from "@src/engine/utils/Logger";
import { I18nModule } from "../module";

export default async (i18n: I18nModule) => {
warn("Missing key in translation file")
};
16 changes: 16 additions & 0 deletions src/modules/i18n/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import Module from "@src/engine/modules";
import { debug } from "@src/engine/utils/Logger";
import { I18nModule } from "./module";


export default {
name: "i18n",
hooksInnerPath: "hooks",
loadFunction: async (config) => {
return new I18nModule()
},
initFunction: async (ctx, config) => {
await ctx.initialize(config)
debug(ctx.t("default:i18nModuleInitialized") as string)
}
} satisfies Module<I18nModule, "i18n">;
56 changes: 56 additions & 0 deletions src/modules/i18n/module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import I18nConfig from "@src/config/modules/i18n";
import Module from "@src/engine/modules";
import { debug } from "@src/engine/utils/Logger";
import { getProcessPath } from "@src/engine/utils/Runtime";
import { EventEmitter } from "events";
import i18next, { i18n, TFunction } from "i18next";
import Backend, { FsBackendOptions } from 'i18next-fs-backend';
import path from "path";

const ReboundEvents = [
"initialized",
"languageChanged",
"loaded",
"failedLoading",
"missingKey",
] as const


export class I18nModule extends EventEmitter {
private i18n: i18n
private fixedTranslators: Map<string, TFunction> = new Map()
constructor() {
super()

this.i18n = i18next.createInstance()
for (const event of ReboundEvents) {
this.i18n.on(event, (...args) => {
this.emit(event, ...args)
})
}
}
async initialize(config: I18nConfig) {
await this.i18n
.use(Backend)
.init<FsBackendOptions>({
fallbackLng: config.baseLanguage,
ns: ["default"],
defaultNS: "default",
backend: {
loadPath: path.join(getProcessPath(), "/lang/{{lng}}/{{ns}}.json"),
addPath: path.join(getProcessPath(), "/lang/{{lng}}/{{ns}}.missing.json"),
}
})
}
translateTo(key: string, lang: string, opts?: any) {
let translator = this.fixedTranslators.get(lang)
if (!translator) {
translator = this.i18n.getFixedT(lang)
this.fixedTranslators.set(lang, translator)
}
return translator(key, opts)
}
t(key: string, opts?: any) {
return this.i18n.t(key, opts)
}
}

0 comments on commit 462f136

Please sign in to comment.