@owlmeans/i18n 0.1.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 OwlMeans Common — Fullstack typescript framework
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,323 @@
1
+ # OwlMeans I18n — Common Library
2
+
3
+ **@owlmeans/i18n** is a core implementation of the OwlMeans Common Internationalization Subsystem. It provides a flexible, multi-level translation system designed to work across different application contexts with namespace-based organization and priority-based resource loading.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @owlmeans/i18n
9
+ ```
10
+
11
+ ## Core Concepts
12
+
13
+ ### Translation Levels
14
+ The i18n system supports three levels of translations with different priorities:
15
+ - **Library Level**: Lowest priority, used for basic library translations
16
+ - **App Level**: Medium priority, used for application-specific translations
17
+ - **Service Level**: Highest priority, used for service-specific overrides
18
+
19
+ ### Namespaces
20
+ Translations are organized into namespaces to avoid conflicts:
21
+ - `translation` - Default namespace for general translations
22
+ - `lib` - Library-specific translations
23
+ - `service` - Service-specific translations
24
+ - Custom namespaces can be defined as needed
25
+
26
+ ### Resources
27
+ Each translation resource represents a collection of translations for a specific language and context, with optional priority settings for ordering.
28
+
29
+ ## API Reference
30
+
31
+ ### Types
32
+
33
+ #### `I18nStorage`
34
+ Main storage interface for the i18n system.
35
+ ```typescript
36
+ interface I18nStorage {
37
+ data: I18nNamespaces
38
+ }
39
+ ```
40
+
41
+ #### `I18nNamespaces`
42
+ Collection of namespaces, each containing resources.
43
+ ```typescript
44
+ interface I18nNamespaces extends Record<string, I18nResources> { }
45
+ ```
46
+
47
+ #### `I18nResources`
48
+ Collection of resources within a namespace.
49
+ ```typescript
50
+ interface I18nResources extends Record<string, I18nLanguages> { }
51
+ ```
52
+
53
+ #### `I18nLanguages`
54
+ Language-specific data containing resources and initialization status.
55
+ ```typescript
56
+ interface I18nLanguages extends Record<string, {
57
+ resources: I18nResource[],
58
+ lngInitialized: string[]
59
+ }> { }
60
+ ```
61
+
62
+ #### `I18nResource`
63
+ Individual translation resource with metadata.
64
+ ```typescript
65
+ interface I18nResource {
66
+ ns?: string // Namespace (optional)
67
+ lng?: string // Language code (optional)
68
+ level: I18nLevel // Translation level
69
+ resource: string // Resource identifier
70
+ priority?: number // Priority for ordering (optional)
71
+ data: Record<string, any> // Translation data
72
+ }
73
+ ```
74
+
75
+ #### `I18nResourceOptions`
76
+ Options for resource operations.
77
+ ```typescript
78
+ interface I18nResourceOptions {
79
+ priroty?: number // Priority for resource ordering (note: typo in source)
80
+ ns?: string // Namespace override
81
+ }
82
+ ```
83
+
84
+ #### `I18nConfig`
85
+ Configuration interface for the i18n system.
86
+ ```typescript
87
+ interface I18nConfig {
88
+ defaultLng?: string // Default language code
89
+ defaultNs?: string // Default namespace
90
+ }
91
+ ```
92
+
93
+ #### `I18nLevel`
94
+ Enumeration of translation levels.
95
+ ```typescript
96
+ enum I18nLevel {
97
+ Library = 'library',
98
+ App = 'app',
99
+ Service = 'service'
100
+ }
101
+ ```
102
+
103
+ ### Functions
104
+
105
+ #### `addI18nLib(lng, resource, data, opts?)`
106
+ Add library-level translations.
107
+ ```typescript
108
+ function addI18nLib(
109
+ lng: string, // Language code
110
+ resource: string, // Resource identifier
111
+ data: Record<string, any>, // Translation data
112
+ opts?: I18nResourceOptions | string // Options or namespace
113
+ ): void
114
+ ```
115
+
116
+ **Example:**
117
+ ```typescript
118
+ import { addI18nLib } from '@owlmeans/i18n'
119
+
120
+ addI18nLib('en', 'common', {
121
+ 'button.save': 'Save',
122
+ 'button.cancel': 'Cancel'
123
+ })
124
+ ```
125
+
126
+ #### `addI18nApp(lng, resource, data, opts?)`
127
+ Add application-level translations.
128
+ ```typescript
129
+ function addI18nApp(
130
+ lng: string, // Language code
131
+ resource: string, // Resource identifier
132
+ data: Record<string, any>, // Translation data
133
+ opts?: I18nResourceOptions | string // Options or namespace
134
+ ): void
135
+ ```
136
+
137
+ **Example:**
138
+ ```typescript
139
+ import { addI18nApp } from '@owlmeans/i18n'
140
+
141
+ addI18nApp('en', 'user-profile', {
142
+ 'title': 'User Profile',
143
+ 'form.username': 'Username',
144
+ 'form.email': 'Email Address'
145
+ })
146
+ ```
147
+
148
+ #### `addCommonI18n(lng, resource, data, opts?)`
149
+ Add service-level translations (highest priority).
150
+ ```typescript
151
+ function addCommonI18n(
152
+ lng: string, // Language code
153
+ resource: string, // Resource identifier
154
+ data: Record<string, any>, // Translation data
155
+ opts?: I18nResourceOptions | string // Options or namespace
156
+ ): void
157
+ ```
158
+
159
+ **Example:**
160
+ ```typescript
161
+ import { addCommonI18n } from '@owlmeans/i18n'
162
+
163
+ addCommonI18n('en', 'api-messages', {
164
+ 'error.unauthorized': 'Access denied',
165
+ 'error.notfound': 'Resource not found'
166
+ })
167
+ ```
168
+
169
+ #### `initI18nResource(lng, resource, ns?)`
170
+ Initialize translation resources for a specific language and resource.
171
+ ```typescript
172
+ function initI18nResource(
173
+ lng: string, // Language code
174
+ resource: string, // Resource identifier
175
+ ns?: string // Namespace (optional)
176
+ ): null | I18nResource[]
177
+ ```
178
+
179
+ Returns `null` if the resource is already initialized, or an array of `I18nResource` objects sorted by level and priority.
180
+
181
+ **Example:**
182
+ ```typescript
183
+ import { initI18nResource } from '@owlmeans/i18n'
184
+
185
+ const resources = initI18nResource('en', 'common')
186
+ if (resources) {
187
+ // Process initialized resources
188
+ resources.forEach(resource => {
189
+ console.log(`Loading ${resource.level} level translations:`, resource.data)
190
+ })
191
+ }
192
+ ```
193
+
194
+ ### Constants
195
+
196
+ #### `DEFAULT_NAMESPACE`
197
+ Default namespace for translations.
198
+ ```typescript
199
+ const DEFAULT_NAMESPACE = 'translation'
200
+ ```
201
+
202
+ #### `LIB_NAMESPACE`
203
+ Namespace for library translations.
204
+ ```typescript
205
+ const LIB_NAMESPACE = 'lib'
206
+ ```
207
+
208
+ #### `SRV_NAMESPACE`
209
+ Namespace for service translations.
210
+ ```typescript
211
+ const SRV_NAMESPACE = 'service'
212
+ ```
213
+
214
+ #### `DEFAULT_LNG`
215
+ Default language code.
216
+ ```typescript
217
+ const DEFAULT_LNG = 'en'
218
+ ```
219
+
220
+ #### `MAX_PRIORITY`
221
+ Maximum priority value for resource ordering.
222
+ ```typescript
223
+ const MAX_PRIORITY = Number.MAX_SAFE_INTEGER
224
+ ```
225
+
226
+ ### Utils
227
+
228
+ The package also exports utility functions under the `/utils` subpackage:
229
+
230
+ ```typescript
231
+ import { ensureStructure, levelCost } from '@owlmeans/i18n/utils'
232
+ ```
233
+
234
+ #### `ensureStructure(lng, resource, ns?)`
235
+ Ensures the storage structure exists for the given language, resource, and namespace.
236
+ ```typescript
237
+ function ensureStructure(
238
+ lng: string, // Language code
239
+ resource: string, // Resource identifier
240
+ ns?: string // Namespace (optional)
241
+ ): I18nLanguages[string]
242
+ ```
243
+
244
+ #### `levelCost`
245
+ Mapping of translation levels to their priority costs:
246
+ ```typescript
247
+ const levelCost = {
248
+ [I18nLevel.Library]: 0,
249
+ [I18nLevel.App]: 1,
250
+ [I18nLevel.Service]: 2
251
+ }
252
+ ```
253
+
254
+ #### `_OwlMeansI18nStorage`
255
+ Internal storage instance (use with caution):
256
+ ```typescript
257
+ const _OwlMeansI18nStorage: I18nStorage
258
+ ```
259
+
260
+ > **Note:** This is an internal storage variable. Direct manipulation is not recommended for normal usage.
261
+
262
+ ## Usage Examples
263
+
264
+ ### Basic Usage
265
+ ```typescript
266
+ import { addI18nLib, addI18nApp, initI18nResource } from '@owlmeans/i18n'
267
+
268
+ // Add library translations
269
+ addI18nLib('en', 'common', {
270
+ 'yes': 'Yes',
271
+ 'no': 'No'
272
+ })
273
+
274
+ // Add app-specific translations
275
+ addI18nApp('en', 'common', {
276
+ 'yes': 'OK', // This will override the library translation
277
+ 'save': 'Save Changes'
278
+ })
279
+
280
+ // Initialize resources (sorted by level and priority)
281
+ const resources = initI18nResource('en', 'common')
282
+ // resources will contain both library and app translations, with app taking priority
283
+ ```
284
+
285
+ ### Working with Namespaces
286
+ ```typescript
287
+ import { addI18nLib, addI18nApp } from '@owlmeans/i18n'
288
+
289
+ // Add translations to specific namespace
290
+ addI18nLib('en', 'buttons', {
291
+ 'save': 'Save',
292
+ 'cancel': 'Cancel'
293
+ }, 'ui')
294
+
295
+ // Add with namespace in options
296
+ addI18nApp('en', 'forms', {
297
+ 'required': 'This field is required'
298
+ }, { ns: 'validation' })
299
+ ```
300
+
301
+ ### Priority-based Loading
302
+ ```typescript
303
+ import { addI18nLib, addI18nApp, addCommonI18n } from '@owlmeans/i18n'
304
+
305
+ // Add translations with different priorities
306
+ addI18nLib('en', 'messages', { 'welcome': 'Welcome' })
307
+ addI18nApp('en', 'messages', { 'welcome': 'Welcome to App' })
308
+ addCommonI18n('en', 'messages', { 'welcome': 'Service Welcome' })
309
+
310
+ // When initialized, service translation will have highest priority
311
+ const resources = initI18nResource('en', 'messages')
312
+ // The 'welcome' key will resolve to 'Service Welcome'
313
+ ```
314
+
315
+ ## Integration with OwlMeans Common
316
+
317
+ This package follows the OwlMeans Common library structure:
318
+ - **types**: TypeScript interfaces and type definitions
319
+ - **consts**: Static values and constants
320
+ - **helper**: Consumer-facing utility functions
321
+ - **utils**: Internal utility functions for storage management
322
+
323
+ The i18n system is designed to integrate seamlessly with other OwlMeans Common packages and can be extended with custom resource loaders and translation providers.
@@ -0,0 +1,11 @@
1
+ export declare const DEFAULT_NAMESPACE = "translation";
2
+ export declare const LIB_NAMESPACE = "lib";
3
+ export declare const DEFAULT_LNG = "en";
4
+ export declare const SRV_NAMESPACE = "service";
5
+ export declare const MAX_PRIORITY: number;
6
+ export declare enum I18nLevel {
7
+ Library = "library",
8
+ App = "app",
9
+ Service = "service"
10
+ }
11
+ //# sourceMappingURL=consts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consts.d.ts","sourceRoot":"","sources":["../src/consts.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,iBAAiB,gBAAgB,CAAA;AAE9C,eAAO,MAAM,aAAa,QAAQ,CAAA;AAElC,eAAO,MAAM,WAAW,OAAO,CAAA;AAE/B,eAAO,MAAM,aAAa,YAAY,CAAA;AAEtC,eAAO,MAAM,YAAY,QAA0B,CAAA;AAEnD,oBAAY,SAAS;IACnB,OAAO,YAAY;IACnB,GAAG,QAAQ;IACX,OAAO,YAAY;CACpB"}
@@ -0,0 +1,12 @@
1
+ export const DEFAULT_NAMESPACE = 'translation';
2
+ export const LIB_NAMESPACE = 'lib';
3
+ export const DEFAULT_LNG = 'en';
4
+ export const SRV_NAMESPACE = 'service';
5
+ export const MAX_PRIORITY = Number.MAX_SAFE_INTEGER;
6
+ export var I18nLevel;
7
+ (function (I18nLevel) {
8
+ I18nLevel["Library"] = "library";
9
+ I18nLevel["App"] = "app";
10
+ I18nLevel["Service"] = "service";
11
+ })(I18nLevel || (I18nLevel = {}));
12
+ //# sourceMappingURL=consts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consts.js","sourceRoot":"","sources":["../src/consts.ts"],"names":[],"mappings":"AACA,MAAM,CAAC,MAAM,iBAAiB,GAAG,aAAa,CAAA;AAE9C,MAAM,CAAC,MAAM,aAAa,GAAG,KAAK,CAAA;AAElC,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,CAAA;AAE/B,MAAM,CAAC,MAAM,aAAa,GAAG,SAAS,CAAA;AAEtC,MAAM,CAAC,MAAM,YAAY,GAAG,MAAM,CAAC,gBAAgB,CAAA;AAEnD,MAAM,CAAN,IAAY,SAIX;AAJD,WAAY,SAAS;IACnB,gCAAmB,CAAA;IACnB,wBAAW,CAAA;IACX,gCAAmB,CAAA;AACrB,CAAC,EAJW,SAAS,KAAT,SAAS,QAIpB"}
@@ -0,0 +1,6 @@
1
+ import type { I18nLeveledResourceSignature, I18nResource } from './types.js';
2
+ export declare const addI18nLib: I18nLeveledResourceSignature;
3
+ export declare const addI18nApp: I18nLeveledResourceSignature;
4
+ export declare const addCommonI18n: I18nLeveledResourceSignature;
5
+ export declare const initI18nResource: (lng: string, resource: string, ns?: string) => null | I18nResource[];
6
+ //# sourceMappingURL=helper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helper.d.ts","sourceRoot":"","sources":["../src/helper.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,4BAA4B,EAAE,YAAY,EAA8C,MAAM,YAAY,CAAA;AA6BxH,eAAO,MAAM,UAAU,EAAE,4BAGxB,CAAA;AAED,eAAO,MAAM,UAAU,EAAE,4BAGxB,CAAA;AAED,eAAO,MAAM,aAAa,EAAE,4BAG3B,CAAA;AAED,eAAO,MAAM,gBAAgB,QAAS,MAAM,YAAY,MAAM,OAAO,MAAM,KAAG,IAAI,GAAG,YAAY,EAoBhG,CAAA"}
@@ -0,0 +1,54 @@
1
+ import { DEFAULT_NAMESPACE, I18nLevel, LIB_NAMESPACE, MAX_PRIORITY } from './consts.js';
2
+ import { levelCost } from './utils/consts.js';
3
+ import { ensureStructure } from './utils/storage.js';
4
+ const prepareOptions = (opts, ns) => {
5
+ if (typeof opts === 'string') {
6
+ opts = { ns: opts };
7
+ }
8
+ else if (typeof opts === 'undefined') {
9
+ opts = {};
10
+ }
11
+ if (opts.ns == null && ns != null) {
12
+ opts.ns = ns;
13
+ }
14
+ return opts;
15
+ };
16
+ const _addI18n = (level, lng, resource, data, opts) => {
17
+ opts = prepareOptions(opts);
18
+ const storage = ensureStructure(lng, resource, opts.ns);
19
+ const ns = opts.ns ?? DEFAULT_NAMESPACE;
20
+ const translation = {
21
+ ns, lng, level, resource, data, priority: opts.priroty
22
+ };
23
+ storage.resources.push(translation);
24
+ };
25
+ export const addI18nLib = (lng, resource, data, opts) => {
26
+ opts = prepareOptions(opts, LIB_NAMESPACE);
27
+ _addI18n(I18nLevel.Library, lng, resource, data, opts);
28
+ };
29
+ export const addI18nApp = (lng, resource, data, opts) => {
30
+ opts = prepareOptions(opts, resource);
31
+ _addI18n(I18nLevel.App, lng, resource, data, opts);
32
+ };
33
+ export const addCommonI18n = (lng, resource, data, opts) => {
34
+ opts = prepareOptions(opts);
35
+ _addI18n(I18nLevel.Service, lng, resource, data, opts);
36
+ };
37
+ export const initI18nResource = (lng, resource, ns) => {
38
+ ns = ns ?? DEFAULT_NAMESPACE;
39
+ const translation = ensureStructure(lng, resource, ns);
40
+ if (translation.lngInitialized.includes(lng)) {
41
+ return null;
42
+ }
43
+ const result = [...translation.resources].sort((a, b) => {
44
+ const aLev = levelCost[a.level];
45
+ const bLev = levelCost[b.level];
46
+ if (aLev !== bLev) {
47
+ return aLev - bLev;
48
+ }
49
+ return (a.priority ?? MAX_PRIORITY) - (b.priority ?? MAX_PRIORITY);
50
+ });
51
+ translation.lngInitialized.push(lng);
52
+ return result;
53
+ };
54
+ //# sourceMappingURL=helper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helper.js","sourceRoot":"","sources":["../src/helper.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export type * from './types.js';
2
+ export * from './helper.js';
3
+ export * from './consts.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,mBAAmB,YAAY,CAAA;AAC/B,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA"}
package/build/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export * from './helper.js';
2
+ export * from './consts.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA"}
@@ -0,0 +1,36 @@
1
+ import type { I18nLevel } from './consts.js';
2
+ export interface I18nStorage {
3
+ data: I18nNamespaces;
4
+ }
5
+ export interface I18nNamespaces extends Record<string, I18nResources> {
6
+ }
7
+ export interface I18nResources extends Record<string, I18nLanguages> {
8
+ }
9
+ export interface I18nLanguages extends Record<string, {
10
+ resources: I18nResource[];
11
+ lngInitialized: string[];
12
+ }> {
13
+ }
14
+ export interface I18nResource {
15
+ ns?: string;
16
+ lng?: string;
17
+ level: I18nLevel;
18
+ resource: string;
19
+ priority?: number;
20
+ data: Record<string, any>;
21
+ }
22
+ export interface I18nResourceOptions {
23
+ priroty?: number;
24
+ ns?: string;
25
+ }
26
+ export interface I18nResourceSignature {
27
+ (level: I18nLevel, lng: string, resource: string, data: Record<string, any>, opts?: I18nResourceOptions | string): void;
28
+ }
29
+ export interface I18nLeveledResourceSignature {
30
+ (lng: string, resource: string, data: Record<string, any>, opts?: I18nResourceOptions | string): void;
31
+ }
32
+ export interface I18nConfig {
33
+ defaultLng?: string;
34
+ defaultNs?: string;
35
+ }
36
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAE5C,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,cAAc,CAAA;CACrB;AAED,MAAM,WAAW,cAAe,SAAQ,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC;CAAI;AAEzE,MAAM,WAAW,aAAc,SAAQ,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC;CAAI;AAExE,MAAM,WAAW,aAAc,SAAQ,MAAM,CAAC,MAAM,EAAE;IACpD,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,cAAc,EAAE,MAAM,EAAE,CAAA;CACzB,CAAC;CAAI;AAEN,MAAM,WAAW,YAAY;IAC3B,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,SAAS,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;CAC1B;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,EAAE,CAAC,EAAE,MAAM,CAAA;CACZ;AAED,MAAM,WAAW,qBAAqB;IACpC,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,IAAI,CAAC,EAAE,mBAAmB,GAAG,MAAM,GAAG,IAAI,CAAA;CACxH;AAED,MAAM,WAAW,4BAA4B;IAC3C,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,IAAI,CAAC,EAAE,mBAAmB,GAAG,MAAM,GAAG,IAAI,CAAA;CACtG;AAED,MAAM,WAAW,UAAU;IACzB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB"}
package/build/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,6 @@
1
+ export declare const levelCost: {
2
+ library: number;
3
+ app: number;
4
+ service: number;
5
+ };
6
+ //# sourceMappingURL=consts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consts.d.ts","sourceRoot":"","sources":["../../src/utils/consts.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,SAAS;;;;CAIrB,CAAA"}
@@ -0,0 +1,7 @@
1
+ import { I18nLevel } from '../consts.js';
2
+ export const levelCost = {
3
+ [I18nLevel.Library]: 0,
4
+ [I18nLevel.App]: 1,
5
+ [I18nLevel.Service]: 2
6
+ };
7
+ //# sourceMappingURL=consts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consts.js","sourceRoot":"","sources":["../../src/utils/consts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAExC,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC;IACtB,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC;IAClB,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC;CACvB,CAAA"}
@@ -0,0 +1,3 @@
1
+ export * from './storage.js';
2
+ export * from './consts.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AACA,cAAc,cAAc,CAAA;AAC5B,cAAc,aAAa,CAAA"}
@@ -0,0 +1,3 @@
1
+ export * from './storage.js';
2
+ export * from './consts.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AACA,cAAc,cAAc,CAAA;AAC5B,cAAc,aAAa,CAAA"}
@@ -0,0 +1,7 @@
1
+ import type { I18nStorage } from '../types.js';
2
+ export declare const _OwlMeansI18nStorage: I18nStorage;
3
+ export declare const ensureStructure: (lng: string, resource: string, ns?: string) => {
4
+ resources: import("../types.js").I18nResource[];
5
+ lngInitialized: string[];
6
+ };
7
+ //# sourceMappingURL=storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/utils/storage.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAE9C,eAAO,MAAM,oBAAoB,EAAE,WAElC,CAAA;AAED,eAAO,MAAM,eAAe,QAAS,MAAM,YAAY,MAAM,OAAO,MAAM;;;CAgBzE,CAAA"}
@@ -0,0 +1,21 @@
1
+ import { DEFAULT_NAMESPACE } from '../consts.js';
2
+ export const _OwlMeansI18nStorage = {
3
+ data: {}
4
+ };
5
+ export const ensureStructure = (lng, resource, ns) => {
6
+ ns = ns ?? DEFAULT_NAMESPACE;
7
+ if (!_OwlMeansI18nStorage.data[ns]) {
8
+ _OwlMeansI18nStorage.data[ns] = {};
9
+ }
10
+ if (!_OwlMeansI18nStorage.data[ns][resource]) {
11
+ _OwlMeansI18nStorage.data[ns][resource] = {};
12
+ }
13
+ if (!_OwlMeansI18nStorage.data[ns][resource][lng]) {
14
+ _OwlMeansI18nStorage.data[ns][resource][lng] = {
15
+ resources: [],
16
+ lngInitialized: []
17
+ };
18
+ }
19
+ return _OwlMeansI18nStorage.data[ns][resource][lng];
20
+ };
21
+ //# sourceMappingURL=storage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/utils/storage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAGhD,MAAM,CAAC,MAAM,oBAAoB,GAAgB;IAC/C,IAAI,EAAE,EAAE;CACT,CAAA;AAED,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,GAAW,EAAE,QAAgB,EAAE,EAAW,EAAE,EAAE;IAC5E,EAAE,GAAG,EAAE,IAAI,iBAAiB,CAAA;IAC5B,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;QACnC,oBAAoB,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,CAAA;IACpC,CAAC;IACD,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC7C,oBAAoB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAA;IAC9C,CAAC;IACD,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;QAClD,oBAAoB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,GAAG;YAC7C,SAAS,EAAE,EAAE;YACb,cAAc,EAAE,EAAE;SACnB,CAAA;IACH,CAAC;IAED,OAAO,oBAAoB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAA;AACrD,CAAC,CAAA"}
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@owlmeans/i18n",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "scripts": {
6
+ "build": "tsc -b",
7
+ "dev": "sleep 168 && nodemon -e ts,tsx,json --watch src --exec \"tsc -p ./tsconfig.json\"",
8
+ "watch": "tsc -b -w --preserveWatchOutput --pretty"
9
+ },
10
+ "main": "build/index.js",
11
+ "module": "build/index.js",
12
+ "types": "build/index.d.ts",
13
+ "exports": {
14
+ ".": {
15
+ "import": "./build/index.js",
16
+ "require": "./build/index.js",
17
+ "default": "./build/index.js",
18
+ "module": "./build/index.js",
19
+ "types": "./build/index.d.ts"
20
+ },
21
+ "./utils": {
22
+ "import": "./build/utils/index.js",
23
+ "require": "./build/utils/index.js",
24
+ "default": "./build/utils/index.js",
25
+ "module": "./build/utils/index.js",
26
+ "types": "./build/utils/index.d.ts"
27
+ }
28
+ },
29
+ "devDependencies": {
30
+ "nodemon": "^3.1.7",
31
+ "typescript": "^5.6.3"
32
+ },
33
+ "private": false,
34
+ "publishConfig": {
35
+ "access": "public"
36
+ }
37
+ }
package/src/consts.ts ADDED
@@ -0,0 +1,16 @@
1
+
2
+ export const DEFAULT_NAMESPACE = 'translation'
3
+
4
+ export const LIB_NAMESPACE = 'lib'
5
+
6
+ export const DEFAULT_LNG = 'en'
7
+
8
+ export const SRV_NAMESPACE = 'service'
9
+
10
+ export const MAX_PRIORITY = Number.MAX_SAFE_INTEGER
11
+
12
+ export enum I18nLevel {
13
+ Library = 'library',
14
+ App = 'app',
15
+ Service = 'service'
16
+ }
package/src/helper.ts ADDED
@@ -0,0 +1,66 @@
1
+ import { DEFAULT_NAMESPACE, I18nLevel, LIB_NAMESPACE, MAX_PRIORITY } from './consts.js'
2
+ import type { I18nLeveledResourceSignature, I18nResource, I18nResourceOptions, I18nResourceSignature } from './types.js'
3
+ import { levelCost } from './utils/consts.js'
4
+ import { ensureStructure } from './utils/storage.js'
5
+
6
+ const prepareOptions: (opts: I18nResourceOptions | string | undefined, ns?: string) => I18nResourceOptions = (opts, ns) => {
7
+ if (typeof opts === 'string') {
8
+ opts = { ns: opts }
9
+ } else if (typeof opts === 'undefined') {
10
+ opts = {}
11
+ }
12
+ if (opts.ns == null && ns != null) {
13
+ opts.ns = ns
14
+ }
15
+ return opts
16
+ }
17
+
18
+ const _addI18n: I18nResourceSignature = (level, lng, resource, data, opts) => {
19
+ opts = prepareOptions(opts)
20
+ const storage = ensureStructure(lng, resource, opts.ns)
21
+
22
+ const ns = opts.ns ?? DEFAULT_NAMESPACE
23
+
24
+ const translation: I18nResource = {
25
+ ns, lng, level, resource, data, priority: opts.priroty
26
+ }
27
+
28
+ storage.resources.push(translation)
29
+ }
30
+
31
+ export const addI18nLib: I18nLeveledResourceSignature = (lng, resource, data, opts) => {
32
+ opts = prepareOptions(opts, LIB_NAMESPACE)
33
+ _addI18n(I18nLevel.Library, lng, resource, data, opts)
34
+ }
35
+
36
+ export const addI18nApp: I18nLeveledResourceSignature = (lng, resource, data, opts) => {
37
+ opts = prepareOptions(opts, resource)
38
+ _addI18n(I18nLevel.App, lng, resource, data, opts)
39
+ }
40
+
41
+ export const addCommonI18n: I18nLeveledResourceSignature = (lng, resource, data, opts) => {
42
+ opts = prepareOptions(opts)
43
+ _addI18n(I18nLevel.Service, lng, resource, data, opts)
44
+ }
45
+
46
+ export const initI18nResource = (lng: string, resource: string, ns?: string): null | I18nResource[] => {
47
+ ns = ns ?? DEFAULT_NAMESPACE
48
+ const translation = ensureStructure(lng, resource, ns)
49
+ if (translation.lngInitialized.includes(lng)) {
50
+ return null
51
+ }
52
+
53
+ const result = [...translation.resources].sort((a, b) => {
54
+ const aLev = levelCost[a.level]
55
+ const bLev = levelCost[b.level]
56
+ if (aLev !== bLev) {
57
+ return aLev - bLev
58
+ }
59
+
60
+ return (a.priority ?? MAX_PRIORITY) - (b.priority ?? MAX_PRIORITY)
61
+ })
62
+
63
+ translation.lngInitialized.push(lng)
64
+
65
+ return result
66
+ }
package/src/index.ts ADDED
@@ -0,0 +1,4 @@
1
+
2
+ export type * from './types.js'
3
+ export * from './helper.js'
4
+ export * from './consts.js'
package/src/types.ts ADDED
@@ -0,0 +1,41 @@
1
+ import type { I18nLevel } from './consts.js'
2
+
3
+ export interface I18nStorage {
4
+ data: I18nNamespaces
5
+ }
6
+
7
+ export interface I18nNamespaces extends Record<string, I18nResources> { }
8
+
9
+ export interface I18nResources extends Record<string, I18nLanguages> { }
10
+
11
+ export interface I18nLanguages extends Record<string, {
12
+ resources: I18nResource[],
13
+ lngInitialized: string[]
14
+ }> { }
15
+
16
+ export interface I18nResource {
17
+ ns?: string
18
+ lng?: string
19
+ level: I18nLevel
20
+ resource: string
21
+ priority?: number
22
+ data: Record<string, any>
23
+ }
24
+
25
+ export interface I18nResourceOptions {
26
+ priroty?: number
27
+ ns?: string
28
+ }
29
+
30
+ export interface I18nResourceSignature {
31
+ (level: I18nLevel, lng: string, resource: string, data: Record<string, any>, opts?: I18nResourceOptions | string): void
32
+ }
33
+
34
+ export interface I18nLeveledResourceSignature {
35
+ (lng: string, resource: string, data: Record<string, any>, opts?: I18nResourceOptions | string): void
36
+ }
37
+
38
+ export interface I18nConfig {
39
+ defaultLng?: string
40
+ defaultNs?: string
41
+ }
@@ -0,0 +1,7 @@
1
+ import { I18nLevel } from '../consts.js'
2
+
3
+ export const levelCost = {
4
+ [I18nLevel.Library]: 0,
5
+ [I18nLevel.App]: 1,
6
+ [I18nLevel.Service]: 2
7
+ }
@@ -0,0 +1,3 @@
1
+
2
+ export * from './storage.js'
3
+ export * from './consts.js'
@@ -0,0 +1,24 @@
1
+ import { DEFAULT_NAMESPACE } from '../consts.js'
2
+ import type { I18nStorage } from '../types.js'
3
+
4
+ export const _OwlMeansI18nStorage: I18nStorage = {
5
+ data: {}
6
+ }
7
+
8
+ export const ensureStructure = (lng: string, resource: string, ns?: string) => {
9
+ ns = ns ?? DEFAULT_NAMESPACE
10
+ if (!_OwlMeansI18nStorage.data[ns]) {
11
+ _OwlMeansI18nStorage.data[ns] = {}
12
+ }
13
+ if (!_OwlMeansI18nStorage.data[ns][resource]) {
14
+ _OwlMeansI18nStorage.data[ns][resource] = {}
15
+ }
16
+ if (!_OwlMeansI18nStorage.data[ns][resource][lng]) {
17
+ _OwlMeansI18nStorage.data[ns][resource][lng] = {
18
+ resources: [],
19
+ lngInitialized: []
20
+ }
21
+ }
22
+
23
+ return _OwlMeansI18nStorage.data[ns][resource][lng]
24
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "extends": [
3
+ "../tsconfig.default.json",
4
+ "../tsconfig.react.json",
5
+ ],
6
+ "compilerOptions": {
7
+ "rootDir": "./src/", /* Specify the root folder within your source files. */
8
+ "outDir": "./build/", /* Specify an output folder for all emitted files. */
9
+ "moduleResolution": "Bundler"
10
+ },
11
+ "exclude": [
12
+ "./dist/**/*",
13
+ "./build/**/*",
14
+ "./*.ts"
15
+ ]
16
+ }
@@ -0,0 +1 @@
1
+ {"root":["./src/consts.ts","./src/helper.ts","./src/index.ts","./src/types.ts","./src/utils/consts.ts","./src/utils/index.ts","./src/utils/storage.ts"],"version":"5.6.3"}