@voilabs/oilang 0.0.7 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -165,6 +165,54 @@ new RedisStore(connectionString: string, options?: { prefix?: string })
165
165
  - `connectionString`: Redis connection URL (default: `redis://localhost:6379`).
166
166
  - `options.prefix`: specific prefix for Redis keys (default: `oilang:`).
167
167
 
168
+ ## Frameworks Support
169
+
170
+ OILang provides built-in handlers to easily integrate with popular web frameworks.
171
+
172
+ ### Elysia.js
173
+
174
+ The `elysiaHandler` allows you to expose RESTful API endpoints for managing locales and translations directly from your Elysia application.
175
+
176
+ #### Usage
177
+
178
+ ```typescript
179
+ import { Elysia } from "elysia";
180
+ import { elysiaHandler } from "@voilabs/oilang/handlers";
181
+
182
+ const app = new Elysia()
183
+ .use(elysiaHandler(oilang)) // oilang instance
184
+ .listen(3000);
185
+ ```
186
+
187
+ #### API Endpoints
188
+
189
+ The handler exposes the following endpoints under the `/oilang` prefix:
190
+
191
+ [oAH] = onAuthHandle is a function that will be called before handling requests, useful for authentication.
192
+
193
+ - **GET /oilang/locales**: List all locales.
194
+ - **POST /oilang/locales**: Create a new locale [oAH].
195
+ - **PUT /oilang/locales/:localeCode**: Update a locale [oAH].
196
+ - **DELETE /oilang/locales/:locale**: Delete a locale [oAH].
197
+ - **GET /oilang/translations/:locale**: Get translations for a locale.
198
+ - **POST /oilang/translations/:locale**: Add translations (bulk) [oAH].
199
+ - **PUT /oilang/translations/:locale**: Update translations (bulk) [oAH].
200
+ - **DELETE /oilang/translations/:locale**: Delete translations (bulk) [oAH].
201
+
202
+ #### Options
203
+
204
+ You can pass an optional configuration object to `elysiaHandler`:
205
+
206
+ ```typescript
207
+ elysiaHandler(oilang, {
208
+ onAuthHandle: async ({ request }) => {
209
+ // Implement authentication logic here
210
+ },
211
+ });
212
+ ```
213
+
214
+ - `onAuthHandle`: A hook to run before handling requests, useful for authentication.
215
+
168
216
  ## Database Schema
169
217
 
170
218
  The PostgreSQL adapter automatically creates the necessary tables if they do not exist.
@@ -0,0 +1 @@
1
+ export * from "./PostgreSQL";
@@ -0,0 +1 @@
1
+ export * from "./PostgreSQL";
@@ -0,0 +1,34 @@
1
+ import { OILang } from "../index";
2
+ import Elysia from "elysia";
3
+ type Options = {
4
+ onAuthHandle?: Elysia["onBeforeHandle"];
5
+ };
6
+ export declare const elysiaHandler: (oilang: OILang, options?: Options) => Elysia<"", {
7
+ decorator: {};
8
+ store: {};
9
+ derive: {};
10
+ resolve: {};
11
+ }, {
12
+ typebox: {};
13
+ error: {};
14
+ }, {
15
+ schema: {};
16
+ standaloneSchema: {};
17
+ macro: {};
18
+ macroFn: {};
19
+ parser: {};
20
+ response: {};
21
+ }, {}, {
22
+ derive: {};
23
+ resolve: {};
24
+ schema: {};
25
+ standaloneSchema: {};
26
+ response: {};
27
+ }, {
28
+ derive: {};
29
+ resolve: {};
30
+ schema: {};
31
+ standaloneSchema: {};
32
+ response: {};
33
+ }>;
34
+ export {};
@@ -0,0 +1,106 @@
1
+ import Elysia, { t } from "elysia";
2
+ const response = (success, message, data) => {
3
+ return {
4
+ success,
5
+ message,
6
+ data,
7
+ __oilang: true,
8
+ };
9
+ };
10
+ export const elysiaHandler = (oilang, options) => {
11
+ return new Elysia({ name: "oilang" }).group("/oilang", (app) => {
12
+ app.group("/locales", (localesApp) => {
13
+ localesApp.get("/", async (app) => {
14
+ const locales = await oilang.locales.list();
15
+ return response(true, "Locales fetched successfully", locales);
16
+ });
17
+ localesApp.post("/locales", async ({ body }) => {
18
+ const translations = await oilang.locales.create(body.locale, body.native_name, body.english_name);
19
+ return response(true, "Locale created successfully", translations);
20
+ }, {
21
+ beforeHandle: options?.onAuthHandle,
22
+ body: t.Object({
23
+ locale: t.String(),
24
+ native_name: t.String(),
25
+ english_name: t.String(),
26
+ }),
27
+ });
28
+ localesApp.put("/locales/:localeCode", async ({ body, params }) => {
29
+ const { localeCode } = params;
30
+ const translations = await oilang.locales.update(localeCode, body.native_name, body.english_name);
31
+ return response(true, "Locale updated successfully", translations);
32
+ }, {
33
+ beforeHandle: options?.onAuthHandle,
34
+ body: t.Object({
35
+ native_name: t.String(),
36
+ english_name: t.String(),
37
+ }),
38
+ });
39
+ localesApp.delete("/locales/:locale", async ({ params }) => {
40
+ const translations = await oilang.locales.delete(params.locale);
41
+ return response(true, "Locale deleted successfully", translations);
42
+ }, {
43
+ beforeHandle: options?.onAuthHandle,
44
+ params: t.Object({
45
+ locale: t.String(),
46
+ }),
47
+ });
48
+ return localesApp;
49
+ });
50
+ app.group("/translations", (translationsApp) => {
51
+ translationsApp.get("/:locale", async ({ params, query }) => {
52
+ const translations = await oilang.translations.list(params.locale);
53
+ return response(true, "Translations fetched successfully", translations);
54
+ });
55
+ translationsApp.post("/:locale", async ({ params, body }) => {
56
+ const { translations } = body;
57
+ for (const t of translations) {
58
+ await oilang.translations.create(params.locale, {
59
+ key: t.key,
60
+ value: t.value,
61
+ });
62
+ }
63
+ return response(true, "Translations updated successfully", {});
64
+ }, {
65
+ beforeHandle: options?.onAuthHandle,
66
+ body: t.Object({
67
+ translations: t.Array(t.Object({
68
+ key: t.String(),
69
+ value: t.String(),
70
+ })),
71
+ }),
72
+ });
73
+ translationsApp.put("/:locale", async ({ params, request, body }) => {
74
+ const { translations } = body;
75
+ for (const t of translations) {
76
+ await oilang.translations.update(params.locale, t.key, t.value);
77
+ }
78
+ return response(true, "Translations updated successfully", {});
79
+ }, {
80
+ beforeHandle: options?.onAuthHandle,
81
+ body: t.Object({
82
+ translations: t.Array(t.Object({
83
+ key: t.String(),
84
+ value: t.String(),
85
+ })),
86
+ }),
87
+ });
88
+ translationsApp.delete("/:locale", async ({ params, request, body }) => {
89
+ const { translations } = body;
90
+ for (const t of translations) {
91
+ await oilang.translations.delete(params.locale, t.key);
92
+ }
93
+ return response(true, "Translations deleted successfully", {});
94
+ }, {
95
+ beforeHandle: options?.onAuthHandle,
96
+ body: t.Object({
97
+ translations: t.Array(t.Object({
98
+ key: t.String(),
99
+ })),
100
+ }),
101
+ });
102
+ return translationsApp;
103
+ });
104
+ return app;
105
+ });
106
+ };
@@ -0,0 +1 @@
1
+ export * from "./Elysia";
@@ -0,0 +1 @@
1
+ export * from "./Elysia";
package/dist/index.d.ts CHANGED
@@ -1,5 +1,72 @@
1
- export { OILang } from "./oilang";
2
- export { PostgreSQL } from "./adapters/PostgreSQL";
3
- export { MemoryStore } from "./stores/MemoryStore";
4
- export { RedisStore } from "./stores/RedisStore";
5
- export * from "./types";
1
+ import type { MemoryStore } from "./stores/MemoryStore";
2
+ import type { PostgreSQL } from "./adapters/PostgreSQL";
3
+ import type { RedisStore } from "./stores/RedisStore";
4
+ import { LocaleData, TranslationData } from "./types";
5
+ type AdapterConfig = {
6
+ database: InstanceType<typeof PostgreSQL>;
7
+ store: InstanceType<typeof MemoryStore> | InstanceType<typeof RedisStore>;
8
+ fallbackLocale?: string;
9
+ };
10
+ type ActionResponse<T> = {
11
+ error: Error & {
12
+ code?: string;
13
+ };
14
+ data: null;
15
+ } | {
16
+ error: null;
17
+ data: T;
18
+ };
19
+ declare class Locale {
20
+ private database;
21
+ private store;
22
+ constructor(database: AdapterConfig["database"], store: AdapterConfig["store"]);
23
+ list(): Promise<{
24
+ error: null;
25
+ data: any[] | Record<string, string>;
26
+ }>;
27
+ create(locale: string, nativeName: string, englishName: string): Promise<ActionResponse<LocaleData>>;
28
+ delete(locale: string): Promise<{
29
+ error: null;
30
+ data: {
31
+ code: string;
32
+ };
33
+ } | {
34
+ error: any;
35
+ data: null;
36
+ }>;
37
+ update(locale: string, nativeName: string, englishName: string): Promise<ActionResponse<LocaleData>>;
38
+ }
39
+ declare class Translation {
40
+ private database;
41
+ private store;
42
+ private fallbackLocale?;
43
+ constructor(database: AdapterConfig["database"], store: AdapterConfig["store"], fallbackLocale?: string);
44
+ list(locale: string): Promise<any[] | Record<string, string>>;
45
+ create(locale: string, config: {
46
+ key: string;
47
+ value: string;
48
+ }): Promise<ActionResponse<TranslationData>>;
49
+ update(locale: string, key: string, newValue: string): Promise<ActionResponse<TranslationData>>;
50
+ delete(locale: string, key: string): Promise<{
51
+ error: null;
52
+ data: {
53
+ locale_id: string;
54
+ key: string;
55
+ };
56
+ } | {
57
+ error: any;
58
+ data: null;
59
+ }>;
60
+ translate(locale: string, key: string, variables?: Record<string, string | number>): Promise<string>;
61
+ }
62
+ export declare class OILang {
63
+ private config;
64
+ private database;
65
+ private store;
66
+ private fallbackLocale;
67
+ locales: Locale;
68
+ translations: Translation;
69
+ constructor(config: AdapterConfig);
70
+ init(): Promise<void>;
71
+ }
72
+ export {};
package/dist/index.js CHANGED
@@ -1,5 +1,224 @@
1
- export { OILang } from "./oilang";
2
- export { PostgreSQL } from "./adapters/PostgreSQL";
3
- export { MemoryStore } from "./stores/MemoryStore";
4
- export { RedisStore } from "./stores/RedisStore";
5
- export * from "./types";
1
+ class Locale {
2
+ database;
3
+ store;
4
+ constructor(database, store) {
5
+ this.database = database;
6
+ this.store = store;
7
+ }
8
+ async list() {
9
+ const response = await this.store.getAll({
10
+ seed: "locales",
11
+ });
12
+ return {
13
+ error: null,
14
+ data: response,
15
+ };
16
+ }
17
+ async create(locale, nativeName, englishName) {
18
+ const response = await this.database.locales.create(locale, nativeName, englishName);
19
+ if (response.success) {
20
+ this.store.set({
21
+ seed: "locales",
22
+ locale: response.data,
23
+ });
24
+ return {
25
+ error: null,
26
+ data: response.data,
27
+ };
28
+ }
29
+ else {
30
+ return {
31
+ error: response.error,
32
+ data: null,
33
+ };
34
+ }
35
+ }
36
+ async delete(locale) {
37
+ const response = await this.database.locales.delete(locale);
38
+ if (response.success) {
39
+ this.store.remove({
40
+ seed: "locales",
41
+ locale,
42
+ });
43
+ return {
44
+ error: null,
45
+ data: response.data,
46
+ };
47
+ }
48
+ else {
49
+ return {
50
+ error: response.error,
51
+ data: null,
52
+ };
53
+ }
54
+ }
55
+ async update(locale, nativeName, englishName) {
56
+ const response = await this.database.locales.update(locale, nativeName, englishName);
57
+ if (response.success) {
58
+ this.store.update({
59
+ seed: "locales",
60
+ code: locale,
61
+ locale: {
62
+ native_name: nativeName,
63
+ english_name: englishName,
64
+ },
65
+ });
66
+ return {
67
+ error: null,
68
+ data: response.data,
69
+ };
70
+ }
71
+ else {
72
+ return {
73
+ error: response.error,
74
+ data: null,
75
+ };
76
+ }
77
+ }
78
+ }
79
+ class Translation {
80
+ database;
81
+ store;
82
+ fallbackLocale;
83
+ constructor(database, store, fallbackLocale) {
84
+ this.database = database;
85
+ this.store = store;
86
+ this.fallbackLocale = fallbackLocale;
87
+ }
88
+ async list(locale) {
89
+ const response = await this.store.getAll({
90
+ seed: "translations",
91
+ locale,
92
+ });
93
+ return response;
94
+ }
95
+ async create(locale, config) {
96
+ const response = await this.database.translations.create(config.key, config.value, locale);
97
+ if (response.success) {
98
+ this.store.set({
99
+ seed: "translations",
100
+ locale,
101
+ key: config.key,
102
+ value: config.value,
103
+ });
104
+ return {
105
+ error: null,
106
+ data: response.data,
107
+ };
108
+ }
109
+ else {
110
+ return {
111
+ error: response.error,
112
+ data: null,
113
+ };
114
+ }
115
+ }
116
+ async update(locale, key, newValue) {
117
+ const response = await this.database.translations.update(key, newValue, locale);
118
+ if (response.success) {
119
+ this.store.update({
120
+ seed: "translations",
121
+ locale,
122
+ key,
123
+ value: newValue,
124
+ });
125
+ return {
126
+ error: null,
127
+ data: response.data,
128
+ };
129
+ }
130
+ else {
131
+ return {
132
+ error: response.error,
133
+ data: null,
134
+ };
135
+ }
136
+ }
137
+ async delete(locale, key) {
138
+ const response = await this.database.translations.delete(key, locale);
139
+ if (response.success) {
140
+ this.store.remove({
141
+ seed: "translations",
142
+ locale,
143
+ key,
144
+ });
145
+ return {
146
+ error: null,
147
+ data: response.data,
148
+ };
149
+ }
150
+ else {
151
+ return {
152
+ error: response.error,
153
+ data: null,
154
+ };
155
+ }
156
+ }
157
+ async translate(locale, key, variables) {
158
+ let translation = await this.store.get({
159
+ seed: "translations",
160
+ locale,
161
+ key,
162
+ });
163
+ if (!translation && this.fallbackLocale) {
164
+ translation = await this.store.get({
165
+ seed: "translations",
166
+ locale: this.fallbackLocale,
167
+ key,
168
+ });
169
+ }
170
+ if (!translation)
171
+ return key;
172
+ if (variables) {
173
+ for (const [varKey, varValue] of Object.entries(variables)) {
174
+ translation = translation.replace(new RegExp(`{{${varKey}}}`, "g"), String(varValue));
175
+ }
176
+ }
177
+ return translation;
178
+ }
179
+ }
180
+ export class OILang {
181
+ config;
182
+ database;
183
+ store;
184
+ fallbackLocale;
185
+ locales;
186
+ translations;
187
+ constructor(config) {
188
+ this.config = config;
189
+ this.database = config.database;
190
+ this.store = config.store;
191
+ this.fallbackLocale = config.fallbackLocale ?? "en-US";
192
+ this.locales = new Locale(this.database, this.store);
193
+ this.translations = new Translation(this.database, this.store, this.fallbackLocale);
194
+ }
195
+ async init() {
196
+ await this.database.connect();
197
+ const [locales, translations] = await Promise.all([
198
+ this.database.locales.list(),
199
+ this.database.translations.list(),
200
+ ]);
201
+ if (locales.success && translations.success) {
202
+ const loadableLocales = locales.data.map((l) => ({
203
+ code: l.code,
204
+ native_name: l.native_name,
205
+ english_name: l.english_name,
206
+ created_at: l.created_at,
207
+ updated_at: l.updated_at,
208
+ }));
209
+ const loadableTranslations = loadableLocales.reduce((acc, l) => {
210
+ acc[l.code] = translations.data
211
+ .filter((t) => t.locale_id === l.code)
212
+ .reduce((accData, t) => {
213
+ accData[t.key] = t.value;
214
+ return accData;
215
+ }, {});
216
+ return acc;
217
+ }, {});
218
+ await this.store.load(loadableLocales, loadableTranslations);
219
+ }
220
+ else {
221
+ throw new Error("Failed to load locales or translations");
222
+ }
223
+ }
224
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./MemoryStore";
2
+ export * from "./RedisStore";
@@ -0,0 +1,2 @@
1
+ export * from "./MemoryStore";
2
+ export * from "./RedisStore";
package/package.json CHANGED
@@ -1,13 +1,20 @@
1
1
  {
2
2
  "name": "@voilabs/oilang",
3
3
  "description": "A robust internationalization (i18n) handling library designed for performance and flexibility.",
4
- "version": "0.0.7",
4
+ "version": "0.0.8",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "scripts": {
8
8
  "build": "tsc",
9
9
  "prepublishOnly": "npm run build"
10
10
  },
11
+ "exports": {
12
+ "./*": "./dist/*",
13
+ "./adapters": "./dist/adapters/index.js",
14
+ "./stores": "./dist/stores/index.js",
15
+ "./handlers": "./dist/handlers/index.js",
16
+ "./types": "./dist/types.d.ts"
17
+ },
11
18
  "devDependencies": {
12
19
  "@types/bun": "latest",
13
20
  "@types/node": "^25.2.3",
@@ -30,6 +37,7 @@
30
37
  "url": "git+https://github.com/voilabs/node-oilang.git"
31
38
  },
32
39
  "dependencies": {
40
+ "elysia": "^1.4.25",
33
41
  "ioredis": "^5.9.3",
34
42
  "pg": "^8.18.0"
35
43
  },
package/dist/oilang.d.ts DELETED
@@ -1,72 +0,0 @@
1
- import type { MemoryStore } from "./stores/MemoryStore";
2
- import type { PostgreSQL } from "./adapters/PostgreSQL";
3
- import type { RedisStore } from "./stores/RedisStore";
4
- import { LocaleData, TranslationData } from "./types";
5
- type AdapterConfig = {
6
- database: InstanceType<typeof PostgreSQL>;
7
- store: InstanceType<typeof MemoryStore> | InstanceType<typeof RedisStore>;
8
- fallbackLocale?: string;
9
- };
10
- type ActionResponse<T> = {
11
- error: Error & {
12
- code?: string;
13
- };
14
- data: null;
15
- } | {
16
- error: null;
17
- data: T;
18
- };
19
- declare class Locale {
20
- private database;
21
- private store;
22
- constructor(database: AdapterConfig["database"], store: AdapterConfig["store"]);
23
- list(): Promise<{
24
- error: null;
25
- data: any[] | Record<string, string>;
26
- }>;
27
- create(locale: string, nativeName: string, englishName: string): Promise<ActionResponse<LocaleData>>;
28
- delete(locale: string): Promise<{
29
- error: null;
30
- data: {
31
- code: string;
32
- };
33
- } | {
34
- error: any;
35
- data: null;
36
- }>;
37
- update(locale: string, nativeName: string, englishName: string): Promise<ActionResponse<LocaleData>>;
38
- }
39
- declare class Translation {
40
- private database;
41
- private store;
42
- private fallbackLocale?;
43
- constructor(database: AdapterConfig["database"], store: AdapterConfig["store"], fallbackLocale?: string);
44
- list(locale: string): Promise<any[] | Record<string, string>>;
45
- create(locale: string, config: {
46
- key: string;
47
- value: string;
48
- }): Promise<ActionResponse<TranslationData>>;
49
- update(locale: string, key: string, newValue: string): Promise<ActionResponse<TranslationData>>;
50
- delete(locale: string, key: string): Promise<{
51
- error: null;
52
- data: {
53
- locale_id: string;
54
- key: string;
55
- };
56
- } | {
57
- error: any;
58
- data: null;
59
- }>;
60
- translate(locale: string, key: string, variables?: Record<string, string | number>): Promise<string>;
61
- }
62
- export declare class OILang {
63
- private config;
64
- private database;
65
- private store;
66
- private fallbackLocale;
67
- locales: Locale;
68
- translations: Translation;
69
- constructor(config: AdapterConfig);
70
- init(): Promise<void>;
71
- }
72
- export {};
package/dist/oilang.js DELETED
@@ -1,224 +0,0 @@
1
- class Locale {
2
- database;
3
- store;
4
- constructor(database, store) {
5
- this.database = database;
6
- this.store = store;
7
- }
8
- async list() {
9
- const response = await this.store.getAll({
10
- seed: "locales",
11
- });
12
- return {
13
- error: null,
14
- data: response,
15
- };
16
- }
17
- async create(locale, nativeName, englishName) {
18
- const response = await this.database.locales.create(locale, nativeName, englishName);
19
- if (response.success) {
20
- this.store.set({
21
- seed: "locales",
22
- locale: response.data,
23
- });
24
- return {
25
- error: null,
26
- data: response.data,
27
- };
28
- }
29
- else {
30
- return {
31
- error: response.error,
32
- data: null,
33
- };
34
- }
35
- }
36
- async delete(locale) {
37
- const response = await this.database.locales.delete(locale);
38
- if (response.success) {
39
- this.store.remove({
40
- seed: "locales",
41
- locale,
42
- });
43
- return {
44
- error: null,
45
- data: response.data,
46
- };
47
- }
48
- else {
49
- return {
50
- error: response.error,
51
- data: null,
52
- };
53
- }
54
- }
55
- async update(locale, nativeName, englishName) {
56
- const response = await this.database.locales.update(locale, nativeName, englishName);
57
- if (response.success) {
58
- this.store.update({
59
- seed: "locales",
60
- code: locale,
61
- locale: {
62
- native_name: nativeName,
63
- english_name: englishName,
64
- },
65
- });
66
- return {
67
- error: null,
68
- data: response.data,
69
- };
70
- }
71
- else {
72
- return {
73
- error: response.error,
74
- data: null,
75
- };
76
- }
77
- }
78
- }
79
- class Translation {
80
- database;
81
- store;
82
- fallbackLocale;
83
- constructor(database, store, fallbackLocale) {
84
- this.database = database;
85
- this.store = store;
86
- this.fallbackLocale = fallbackLocale;
87
- }
88
- async list(locale) {
89
- const response = await this.store.getAll({
90
- seed: "translations",
91
- locale,
92
- });
93
- return response;
94
- }
95
- async create(locale, config) {
96
- const response = await this.database.translations.create(config.key, config.value, locale);
97
- if (response.success) {
98
- this.store.set({
99
- seed: "translations",
100
- locale,
101
- key: config.key,
102
- value: config.value,
103
- });
104
- return {
105
- error: null,
106
- data: response.data,
107
- };
108
- }
109
- else {
110
- return {
111
- error: response.error,
112
- data: null,
113
- };
114
- }
115
- }
116
- async update(locale, key, newValue) {
117
- const response = await this.database.translations.update(key, newValue, locale);
118
- if (response.success) {
119
- this.store.update({
120
- seed: "translations",
121
- locale,
122
- key,
123
- value: newValue,
124
- });
125
- return {
126
- error: null,
127
- data: response.data,
128
- };
129
- }
130
- else {
131
- return {
132
- error: response.error,
133
- data: null,
134
- };
135
- }
136
- }
137
- async delete(locale, key) {
138
- const response = await this.database.translations.delete(key, locale);
139
- if (response.success) {
140
- this.store.remove({
141
- seed: "translations",
142
- locale,
143
- key,
144
- });
145
- return {
146
- error: null,
147
- data: response.data,
148
- };
149
- }
150
- else {
151
- return {
152
- error: response.error,
153
- data: null,
154
- };
155
- }
156
- }
157
- async translate(locale, key, variables) {
158
- let translation = await this.store.get({
159
- seed: "translations",
160
- locale,
161
- key,
162
- });
163
- if (!translation && this.fallbackLocale) {
164
- translation = await this.store.get({
165
- seed: "translations",
166
- locale: this.fallbackLocale,
167
- key,
168
- });
169
- }
170
- if (!translation)
171
- return key;
172
- if (variables) {
173
- for (const [varKey, varValue] of Object.entries(variables)) {
174
- translation = translation.replace(new RegExp(`{{${varKey}}}`, "g"), String(varValue));
175
- }
176
- }
177
- return translation;
178
- }
179
- }
180
- export class OILang {
181
- config;
182
- database;
183
- store;
184
- fallbackLocale;
185
- locales;
186
- translations;
187
- constructor(config) {
188
- this.config = config;
189
- this.database = config.database;
190
- this.store = config.store;
191
- this.fallbackLocale = config.fallbackLocale ?? "en-US";
192
- this.locales = new Locale(this.database, this.store);
193
- this.translations = new Translation(this.database, this.store, this.fallbackLocale);
194
- }
195
- async init() {
196
- await this.database.connect();
197
- const [locales, translations] = await Promise.all([
198
- this.database.locales.list(),
199
- this.database.translations.list(),
200
- ]);
201
- if (locales.success && translations.success) {
202
- const loadableLocales = locales.data.map((l) => ({
203
- code: l.code,
204
- native_name: l.native_name,
205
- english_name: l.english_name,
206
- created_at: l.created_at,
207
- updated_at: l.updated_at,
208
- }));
209
- const loadableTranslations = loadableLocales.reduce((acc, l) => {
210
- acc[l.code] = translations.data
211
- .filter((t) => t.locale_id === l.code)
212
- .reduce((accData, t) => {
213
- accData[t.key] = t.value;
214
- return accData;
215
- }, {});
216
- return acc;
217
- }, {});
218
- await this.store.load(loadableLocales, loadableTranslations);
219
- }
220
- else {
221
- throw new Error("Failed to load locales or translations");
222
- }
223
- }
224
- }