@minejs/i18n 0.0.4 β†’ 0.0.6

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.
Files changed (2) hide show
  1. package/README.md +189 -584
  2. package/package.json +3 -3
package/README.md CHANGED
@@ -8,11 +8,10 @@
8
8
  </div>
9
9
 
10
10
  <div align="center">
11
- <img src="https://img.shields.io/badge/v-0.0.4-black"/>
12
- <img src="https://img.shields.io/badge/πŸ”₯-@minejs-black"/>
13
- <img src="https://img.shields.io/badge/zero-dependencies-black" alt="Test Coverage" />
11
+ <img src="https://img.shields.io/badge/v-0.0.6-black"/>
12
+ <a href="https://img.shields.io/github/stars/minejs-org"><img src="https://img.shields.io/badge/πŸ”₯-@minejs-black"/></a>
14
13
  <br>
15
- <img src="https://img.shields.io/badge/coverage-95.19%25-brightgreen" alt="Test Coverage" />
14
+ <img src="https://img.shields.io/badge/coverage-94.40%25-brightgreen" alt="Test Coverage" />
16
15
  <img src="https://img.shields.io/github/issues/minejs-org/i18n?style=flat" alt="Github Repo Issues" />
17
16
  <img src="https://img.shields.io/github/stars/minejs-org/i18n?style=social" alt="GitHub Repo stars" />
18
17
  </div>
@@ -24,700 +23,305 @@
24
23
 
25
24
  <!-- ╔══════════════════════════════ DOC ══════════════════════════════╗ -->
26
25
 
27
- - ## Quick Start πŸ”₯
28
-
29
- > **_A lightweight, production-ready internationalization (i18n) library with zero dependencies._**
30
-
31
- - ### Setup
32
-
33
- > install [`hmm`](https://github.com/minejs-org/hmm) first.
34
-
35
- ```bash
36
- hmm i @minejs/i18n
37
- ```
26
+ - ## Overview πŸ‘€
38
27
 
39
- <div align="center"> <img src="./assets/img/line.png" alt="line" style="display: block; margin-top:20px;margin-bottom:20px;width:500px;"/> <br> </div>
28
+ - #### Why ?
29
+ > To unify the translation system and languages ​​on the server and client, faster, cleaner, more maintainable.
40
30
 
41
- - ### Usage
31
+ - #### When ?
32
+ > When you need to add a translation to your server or client.
42
33
 
43
- ```ts
44
- import { I18nManager, setupI18n, t, setLanguage } from '@minejs/i18n'
45
- ```
46
-
47
- - ### 1. Basic Translation
48
-
49
- ```typescript
50
- import { I18nManager } from '@minejs/i18n'
51
-
52
- // Create a manager instance
53
- const i18n = new I18nManager()
54
-
55
- // Load translations
56
- i18n.loadLanguage('en', {
57
- greeting: 'Hello',
58
- welcome: 'Welcome to our app'
59
- })
60
-
61
- i18n.loadLanguage('ar', {
62
- greeting: 'Ω…Ψ±Ψ­Ψ¨Ψ§',
63
- welcome: 'Ω…Ψ±Ψ­Ψ¨Ψ§ Ψ¨Ωƒ في ΨͺΨ·Ψ¨ΩŠΩ‚Ω†Ψ§'
64
- })
65
-
66
- // Translate
67
- console.log(i18n.t('greeting')) // "Hello"
68
-
69
- // Switch language
70
- await i18n.setLanguage('ar')
71
- console.log(i18n.t('greeting')) // "Ω…Ψ±Ψ­Ψ¨Ψ§"
72
- ```
73
-
74
- - ### 2. Parameter Replacement
75
-
76
- ```typescript
77
- const i18n = new I18nManager()
78
-
79
- i18n.loadLanguage('en', {
80
- message: 'Hello {name}, you have {count} messages',
81
- userName: 'John'
82
- })
83
-
84
- // Replace parameters
85
- const result = i18n.t('message', {
86
- name: 'John',
87
- count: '5'
88
- })
89
- // "Hello John, you have 5 messages"
34
+ > When you use [@cruxjs/app](https://github.com/cruxjs-org/app).
90
35
 
91
- // Parameters can reference other translation keys
92
- const greeting = i18n.t('message', {
93
- name: 'userName', // References i18n.t('userName')
94
- count: '3'
95
- })
96
- ```
36
+ <br>
37
+ <br>
97
38
 
98
- - ### 3. Nested Translations
39
+ - ## Quick Start πŸ”₯
99
40
 
100
- ```typescript
101
- const i18n = new I18nManager()
102
-
103
- // Deeply nested structures are flattened automatically
104
- i18n.loadLanguage('en', {
105
- app: {
106
- title: 'My App',
107
- pages: {
108
- home: {
109
- title: 'Home',
110
- description: 'Welcome to home page'
111
- },
112
- about: {
113
- title: 'About Us'
114
- }
115
- }
116
- }
117
- })
118
-
119
- console.log(i18n.t('app.title')) // "My App"
120
- console.log(i18n.t('app.pages.home.title')) // "Home"
121
- console.log(i18n.t('app.pages.home.description')) // "Welcome to home page"
122
- ```
41
+ > install [`hmm`](https://github.com/minejs-org/hmm) first.
123
42
 
124
- - ### 4. Parse HTML Tags
43
+ ```bash
44
+ # in your terminal
45
+ hmm i @minejs/i18n
46
+ ```
125
47
 
126
- ```typescript
127
- const i18n = new I18nManager()
48
+ <div align="center"> <img src="./assets/img/line.png" alt="line" style="display: block; margin-top:20px;margin-bottom:20px;width:500px;"/> </div>
128
49
 
129
- i18n.loadLanguage('en', {
130
- message: 'Hello <strong>World</strong>'
131
- })
50
+ - #### Setup
132
51
 
133
- // Parse HTML tags into tokens
134
- const tokens = i18n.tParse('message')
135
- // [
136
- // { type: 'text', content: 'Hello ' },
137
- // { type: 'tag', tag: 'strong', content: 'World' }
138
- // ]
52
+ - ##### JSON
139
53
 
140
- // Convert newlines to <br> tags
141
- i18n.loadLanguage('en', {
142
- multiline: 'Line 1\\nLine 2\\nLine 3'
143
- })
54
+ > Save the translation **keys and their values** ​​in `.json` files.
144
55
 
145
- const lines = i18n.tParse('multiline')
146
- // Includes <br> tags for newlines
147
- ```
56
+ ```jsonc
57
+ // ./src/shared/dist/u18n/en.json
58
+ {
59
+ "key": "value"
60
+ }
61
+ ```
148
62
 
149
- - ### 5. RTL Language Support
63
+ ```jsonc
64
+ // ./src/shared/dist/u18n/ar.json
65
+ {
66
+ "key": "Ω‚ΩŠΩ€Ω…Ψ©"
67
+ }
68
+ ```
150
69
 
151
- ```typescript
152
- const i18n = new I18nManager()
70
+ - ##### I18n
153
71
 
154
- i18n.loadLanguage('en', { title: 'My App' })
155
- i18n.loadLanguage('ar', { title: 'ΨͺΨ·Ψ¨ΩŠΩ‚ΩŠ' })
72
+ > ***🌟 If you are using [`@cruxjs/app`](https://github.com/cruxjs-org/app) you can skip this step. 🌟***
156
73
 
157
- // Check if current language is RTL
158
- await i18n.setLanguage('ar')
159
- console.log(i18n.isRTL()) // true
74
+ > Then in your project ***(works with any environment: `server`, `browser`, ..)***
75
+ >
76
+ > Call the `setupI18n(..)` function **only once** in your application's lifecycle :
160
77
 
161
- // Check specific language
162
- console.log(i18n.isRTLLanguage('ar')) // true
163
- console.log(i18n.isRTLLanguage('en')) // false
78
+ ```ts
79
+ import { setupI18n } from `@minejs/i18n`;
80
+ ```
164
81
 
165
- // Supported RTL languages: ar, he, fa, ur, yi, ji, iw, ku
166
- ```
82
+ ```ts
83
+ await this.setupI18n({
84
+ defaultLanguage : 'en',
85
+ supportedLanguages : ['en', 'ar'],
86
+ basePath : '/static/dist/i18n', // for client side (or your custom public url)
87
+ : './src/shared/dist/i18n', // for server side (or your custom local path)
88
+ });
89
+ ```
167
90
 
168
- - ### 6. Language Change Events
91
+ <div align="center"> <img src="./assets/img/line.png" alt="line" style="display: block; margin-top:20px;margin-bottom:20px;width:500px;"/> </div>
92
+ <br>
169
93
 
170
- ```typescript
171
- const i18n = new I18nManager()
94
+ - #### Usage
172
95
 
173
- i18n.loadLanguage('en', { greeting: 'Hello' })
174
- i18n.loadLanguage('ar', { greeting: 'Ω…Ψ±Ψ­Ψ¨Ψ§' })
96
+ > Now you can call the `t(..)` function anywhere in your project :
175
97
 
176
- // Subscribe to language changes
177
- const unsubscribe = i18n.onChange((lang) => {
178
- console.log('Language changed to:', lang)
179
- })
98
+ ```tsx
99
+ import { t } from `@minejs/i18n`;
100
+ ```
180
101
 
181
- await i18n.setLanguage('ar')
182
- // Logs: "Language changed to: ar"
102
+ ```ts
103
+ t('key', { params }, fallback) // just it !
104
+ ```
183
105
 
184
- // Unsubscribe
185
- unsubscribe()
186
- ```
106
+ <div align="center"> <img src="./assets/img/line.png" alt="line" style="display: block; margin-top:20px;margin-bottom:20px;width:500px;"/> </div>
187
107
 
188
- - ### 7. Storage Integration
108
+ - #### Language Switching
189
109
 
190
110
  ```typescript
191
- import { memoryStorage, browserStorage } from '@minejs/i18n'
192
-
193
- // Use browser localStorage (automatically persists language preference)
194
- const i18n = new I18nManager({
195
- defaultLanguage: 'en',
196
- supportedLanguages: ['en', 'ar', 'fr'],
197
- storage: browserStorage // Or memoryStorage for server
198
- })
199
-
200
- // Language preference is saved and restored automatically
201
- await i18n.setLanguage('ar')
202
- await i18n.init() // Restores 'ar' from storage
203
- ```
204
-
205
- - ### 8. Global Instance
111
+ import { setLanguage, onChange } from '@minejs/i18n';
206
112
 
207
- ```typescript
208
- import {
209
- t, tLang, setLanguage, getLanguage,
210
- isRTL, hasKey, onChange, loadLanguage,
211
- loadTranslations
212
- } from '@minejs/i18n'
213
-
214
- // Use global instance with convenience functions
215
- loadLanguage('en', {
216
- greeting: 'Hello',
217
- farewell: 'Goodbye'
218
- })
219
-
220
- console.log(t('greeting')) // "Hello"
221
- console.log(hasKey('greeting')) // true
222
- console.log(getLanguage()) // "en"
223
-
224
- // Translate with specific language
225
- loadLanguage('ar', { greeting: 'Ω…Ψ±Ψ­Ψ¨Ψ§' })
226
- console.log(tLang('greeting', 'ar')) // "Ω…Ψ±Ψ­Ψ¨Ψ§"
227
-
228
- // Listen for changes
113
+ // Listen to changes
229
114
  onChange((lang) => {
230
- console.log('Switched to:', lang)
231
- })
115
+ console.log('Language changed to:', lang);
116
+ document.documentElement.lang = lang;
117
+ document.dir = isRTL() ? 'rtl' : 'ltr';
118
+ });
232
119
 
233
- await setLanguage('ar')
234
- ```
235
-
236
- - ### 9. Lazy Loading
237
-
238
- ```typescript
239
- import { setupLazy } from '@minejs/i18n'
240
-
241
- // Only load default language at startup
242
- const loader = await setupLazy({
243
- defaultLanguage: 'en',
244
- supportedLanguages: ['en', 'ar', 'fr', 'de', 'zh'],
245
- basePath: 'https://cdn.example.com/i18n/'
246
- })
247
-
248
- // Later, when user switches language
249
- await loader.load('ar')
250
- await setLanguage('ar')
251
-
252
- // Check if language is already loaded
253
- if (!loader.isLoaded('fr')) {
254
- await loader.load('fr')
255
- }
120
+ // Change language
121
+ await setLanguage('ar');
256
122
  ```
257
123
 
258
- - ### 10. Auto-Setup: Environment-Aware Loading
124
+ - #### Parameterized Translations
259
125
 
260
- > Automatically detects browser vs server environment and loads translations from files or URLs
261
-
262
- ```typescript
263
- import { setupAuto } from '@minejs/i18n'
264
-
265
- // Browser: Fetches from http://localhost:3000/static/i18n/en.json
266
- // Server: Reads from ./static/i18n/en.json
267
- const loader = await setupAuto({
268
- defaultLanguage: 'en',
269
- supportedLanguages: ['en', 'ar', 'fr', 'de'],
270
- basePath: 'http://localhost:3000/static/i18n/',
271
- // For server-side, use:
272
- // basePath: './static/i18n/',
273
- fileExtension: 'json' // Optional, defaults to 'json'
274
- })
275
-
276
- // Load other languages on-demand
277
- await loader.load('ar')
278
- await setLanguage('ar')
279
-
280
- // File structure example:
281
- // Browser: /public/static/i18n/en.json
282
- // Server: ./static/i18n/en.json
283
- ```
284
-
285
- **Translation file format** (`en.json`):
286
126
  ```json
287
127
  {
288
- "greeting": "Hello",
289
- "welcome": "Welcome to our app",
290
- "app": {
291
- "name": "MyApp",
292
- "title": "Welcome"
293
- }
128
+ "greeting": "Hello {name}, you have {count} messages"
294
129
  }
295
130
  ```
296
131
 
297
- - ### 11. Utility Functions
298
-
299
- ```typescript
300
- import { genPageTitle, plural } from '@minejs/i18n'
301
-
302
- // Generate page title with app name
303
- const title = genPageTitle('home', 'page.')
304
- // LTR: "Home - MyApp"
305
- // RTL: "MyApp - Ψ§Ω„Ψ±Ψ¦ΩŠΨ³ΩŠΨ©"
306
-
307
- // Pluralization
308
- const itemCount = plural(1, 'item.single', 'item.plural')
309
- // 1 β†’ "1 item"
310
- // 5 β†’ "5 items"
311
- ```
312
-
313
-
314
- <br>
315
-
316
- - ## API Reference πŸ”₯
317
-
318
- - ### I18nManager Class
319
-
320
- - #### `constructor(config?: I18nConfig)`
321
- > Create a new I18n manager instance.
322
-
323
- ```typescript
324
- const i18n = new I18nManager({
325
- defaultLanguage: 'en',
326
- fallbackLanguage: 'en',
327
- supportedLanguages: ['en', 'ar', 'fr'],
328
- storage: browserStorage,
329
- onLanguageChange: (lang) => console.log('Changed to:', lang)
330
- })
331
- ```
332
-
333
- - #### `init(): Promise<void>`
334
- > Initialize manager and restore language from storage.
335
-
336
- ```typescript
337
- const i18n = new I18nManager({ storage: browserStorage })
338
- await i18n.init() // Restores saved language
339
- ```
340
-
341
- - #### `loadLanguage(lang: LanguageCode, translations: object): void`
342
- > Load translations for a specific language. Nested objects are flattened.
343
-
344
- ```typescript
345
- i18n.loadLanguage('en', {
346
- app: { name: 'MyApp' },
347
- greeting: 'Hello'
348
- })
349
-
350
- i18n.t('app.name') // "MyApp"
351
- i18n.t('greeting') // "Hello"
352
- ```
353
-
354
- - #### `loadTranslations(translations: TranslationSet): void`
355
- > Load multiple languages at once.
356
-
357
- ```typescript
358
- i18n.loadTranslations({
359
- en: { greeting: 'Hello' },
360
- ar: { greeting: 'Ω…Ψ±Ψ­Ψ¨Ψ§' },
361
- fr: { greeting: 'Bonjour' }
362
- })
363
- ```
364
-
365
- - #### `t(key: string, params?: object): string`
366
- > Translate a key with optional parameter replacement.
367
-
368
132
  ```typescript
369
- i18n.loadLanguage('en', {
370
- greeting: 'Hello {name}'
371
- })
372
-
373
- i18n.t('greeting', { name: 'John' }) // "Hello John"
374
- i18n.t('missing.key') // "missing.key" (returns key if not found)
133
+ t('greeting', { name: 'John', count: '5' })
134
+ // "Hello John, you have 5 messages"
375
135
  ```
376
136
 
377
- - #### `tLang(key: string, lang: LanguageCode, params?: object): string`
378
- > Translate a key with a specific language temporarily.
379
-
380
- ```typescript
381
- i18n.loadLanguage('ar', { greeting: 'Ω…Ψ±Ψ­Ψ¨Ψ§' })
137
+ - #### HTML Tag Parsing
382
138
 
383
- const result = i18n.tLang('greeting', 'ar')
384
- // Returns Arabic translation without changing current language
139
+ ```json
140
+ {
141
+ "terms": "I agree to the <link>Terms of Service</link>"
142
+ }
385
143
  ```
386
144
 
387
- - #### `tParse(key: string, params?: object): TranslationToken[]`
388
- > Parse translation with HTML tags into tokens. Converts \n and /n to <br> tags.
389
-
390
145
  ```typescript
391
- i18n.loadLanguage('en', {
392
- message: 'Hello <strong>World</strong>\\nLine 2'
393
- })
394
-
395
- const tokens = i18n.tParse('message')
146
+ const tokens = tParse('terms');
396
147
  // [
397
- // { type: 'text', content: 'Hello ' },
398
- // { type: 'tag', tag: 'strong', content: 'World' },
399
- // { type: 'tag', tag: 'br', content: '' },
400
- // { type: 'text', content: 'Line 2' }
148
+ // { type: 'text', content: 'I agree to the ' },
149
+ // { type: 'tag', tag: 'link', content: 'Terms of Service' }
401
150
  // ]
402
151
  ```
403
152
 
404
- - #### `setLanguage(lang: LanguageCode): Promise<void>`
405
- > Set current language and trigger change listeners.
406
-
407
- ```typescript
408
- await i18n.setLanguage('ar')
409
- // Language is changed and persisted to storage if available
410
- ```
411
-
412
- - #### `getLanguage(): LanguageCode`
413
- > Get current language code.
414
-
415
- ```typescript
416
- const lang = i18n.getLanguage() // "en"
417
- ```
418
-
419
- - #### `getSupportedLanguages(): LanguageCode[]`
420
- > Get array of all supported languages.
421
-
422
- ```typescript
423
- const langs = i18n.getSupportedLanguages() // ['en', 'ar', 'fr']
424
- ```
425
-
426
- - #### `isLanguageSupported(lang: LanguageCode): boolean`
427
- > Check if a language is supported.
428
-
429
- ```typescript
430
- i18n.isLanguageSupported('ar') // true
431
- i18n.isLanguageSupported('unsupported') // false
432
- ```
433
-
434
- - #### `hasKey(key: string): boolean`
435
- > Check if translation key exists in current or fallback language.
436
-
437
- ```typescript
438
- i18n.hasKey('greeting') // true
439
- i18n.hasKey('missing') // false
440
- ```
441
-
442
- - #### `getTranslations(): Record<string, string>`
443
- > Get all translations for current language.
444
-
445
- ```typescript
446
- const all = i18n.getTranslations()
447
- ```
448
-
449
- - #### `isRTL(): boolean`
450
- > Check if current language is right-to-left.
451
-
452
- ```typescript
453
- await i18n.setLanguage('ar')
454
- i18n.isRTL() // true
455
-
456
- await i18n.setLanguage('en')
457
- i18n.isRTL() // false
458
- ```
459
-
460
- - #### `isRTLLanguage(lang: LanguageCode): boolean`
461
- > Check if specific language is right-to-left.
462
-
463
- ```typescript
464
- i18n.isRTLLanguage('ar') // true
465
- i18n.isRTLLanguage('he') // true
466
- i18n.isRTLLanguage('en') // false
467
- ```
468
-
469
- - #### `onChange(callback: (lang: LanguageCode) => void): () => void`
470
- > Subscribe to language changes. Returns unsubscribe function.
153
+ - #### Page Titles (with RTL support)
471
154
 
472
155
  ```typescript
473
- const unsubscribe = i18n.onChange((lang) => {
474
- console.log('Language changed to:', lang)
475
- updateUI(lang)
476
- })
156
+ import { genPageTitle } from '@minejs/i18n';
477
157
 
478
- // Unsubscribe later
479
- unsubscribe()
158
+ // en: "Settings - MyApp"
159
+ // ar: "MyApp - Ψ§Ω„Ψ₯ΨΉΨ―Ψ§Ψ―Ψ§Ψͺ"
160
+ const title = genPageTitle('settings');
480
161
  ```
481
162
 
482
163
  <br>
164
+ <br>
483
165
 
484
- - ### LazyLoader Class
485
-
486
- - #### `constructor(baseUrl: string, manager: I18nManager)`
487
- > Create a lazy loader for on-demand language loading.
166
+ - ## Documentation πŸ“‘
488
167
 
489
- ```typescript
490
- const manager = new I18nManager({
491
- supportedLanguages: ['en', 'ar', 'fr']
492
- })
493
- const loader = new LazyLoader('https://cdn.com/i18n/', manager)
494
- ```
168
+ - ### API
495
169
 
496
- - #### `load(lang: LanguageCode): Promise<void>`
497
- > Load a language file on-demand. Caches promises to prevent duplicate requests.
170
+ - #### Types
498
171
 
499
172
  ```typescript
500
- await loader.load('ar')
501
- // Expects https://cdn.com/i18n/ar.json
502
-
503
- // Subsequent calls return cached promise
504
- await loader.load('ar') // Returns immediately
173
+ type LanguageCode = string;
505
174
  ```
506
175
 
507
- - #### `isLoaded(lang: LanguageCode): boolean`
508
- > Check if language is already loaded.
509
-
510
176
  ```typescript
511
- if (!loader.isLoaded('ar')) {
512
- await loader.load('ar')
177
+ interface I18nConfig {
178
+ defaultLanguage? : LanguageCode;
179
+ supportedLanguages? : LanguageCode[];
180
+ fallbackLanguage? : LanguageCode;
181
+ onLanguageChange? : (lang: LanguageCode) => void;
182
+ storage? : I18nStorage;
183
+ basePath? : string;
184
+ fileExtension? : string;
513
185
  }
514
186
  ```
515
187
 
516
- <br>
517
-
518
- - ### Storage Adapters
519
-
520
- - #### `browserStorage: I18nStorage`
521
- > Store language preference in browser localStorage.
522
-
523
188
  ```typescript
524
- import { browserStorage } from '@minejs/i18n'
525
-
526
- const i18n = new I18nManager({
527
- storage: browserStorage
528
- })
189
+ interface TranslationToken {
190
+ type : 'text' | 'tag';
191
+ tag? : string;
192
+ content : string;
193
+ }
529
194
  ```
530
195
 
531
- - #### `memoryStorage: I18nStorage`
532
- > In-memory storage (useful for SSR and testing).
196
+ <div align="center"> <img src="./assets/img/line.png" alt="line" style="display: block; margin-top:20px;margin-bottom:20px;width:500px;"/> </div>
533
197
 
534
- ```typescript
535
- import { memoryStorage } from '@minejs/i18n'
198
+ - #### Functions
536
199
 
537
- const i18n = new I18nManager({
538
- storage: memoryStorage
539
- })
540
- ```
200
+ - #### `setupI18n(config)`
541
201
 
542
- - #### `fetchTranslations(urls: string | string[], manager: I18nManager): Promise<void>`
543
- > Fetch translations from remote URLs. Extracts language from filename (e.g., `en.json`).
202
+ > Initialize i18n with auto-detection
544
203
 
545
- ```typescript
546
- import { fetchTranslations } from '@minejs/i18n'
204
+ ```typescript
205
+ await setupI18n({
206
+ defaultLanguage : 'en',
207
+ supportedLanguages : ['en', 'ar', 'fr'],
208
+ basePath : '/i18n/', // URL (browser) or path (server)
209
+ fileExtension : 'json' // optional
210
+ });
211
+ ```
547
212
 
548
- const manager = new I18nManager()
213
+ - #### `t(key, params?)`
549
214
 
550
- // Single URL
551
- await fetchTranslations('https://cdn.com/i18n/en.json', manager)
215
+ > Translate with parameter replacement
552
216
 
553
- // Multiple URLs
554
- await fetchTranslations([
555
- 'https://cdn.com/i18n/en.json',
556
- 'https://cdn.com/i18n/ar.json'
557
- ], manager)
558
- ```
217
+ ```typescript
218
+ t('greeting', { name: 'John' }) // "Hello John"
219
+ ```
559
220
 
560
- <br>
221
+ - #### `tLang(key, lang, params?)`
561
222
 
562
- - ### Global Instance Functions
223
+ > Translate with specific language
563
224
 
564
- - #### `getI18n(): I18nManager`
565
- > Get or create global I18n instance.
225
+ ```typescript
226
+ tLang('greeting', 'ar', { name: 'Ψ£Ψ­Ω…Ψ―' })
227
+ ```
566
228
 
567
- ```typescript
568
- const i18n = getI18n()
569
- ```
229
+ - #### `tParse(key, params?)`
570
230
 
571
- - #### `setupI18n(config: I18nConfig): Promise<I18nManager>`
572
- > Initialize global instance with config.
231
+ > Parse translation with HTML tags
573
232
 
574
- ```typescript
575
- const i18n = await setupI18n({
576
- defaultLanguage: 'en',
577
- supportedLanguages: ['en', 'ar', 'fr']
578
- })
579
- ```
233
+ ```typescript
234
+ tParse('message') // Returns TokenArray
235
+ ```
580
236
 
581
- - #### `createLazyLoader(baseUrl: string, fileExtension?: string): LazyLoader`
582
- > Create lazy loader for global instance with support for custom file extensions.
237
+ - #### `setLanguage(lang)`
583
238
 
584
- ```typescript
585
- const loader = createLazyLoader('https://cdn.com/i18n/', 'json')
586
- await loader.load('ar')
587
- ```
239
+ > Change current language
588
240
 
589
- - #### `setupLazy(config: I18nConfig & {basePath?: string; baseUrl?: string}): Promise<LazyLoader>`
590
- > Setup with lazy loading and load default language only. Supports both file paths and URLs.
241
+ ```typescript
242
+ await setLanguage('ar')
243
+ ```
591
244
 
592
- ```typescript
593
- const loader = await setupLazy({
594
- defaultLanguage: 'en',
595
- supportedLanguages: ['en', 'ar', 'fr'],
596
- basePath: '/i18n/'
597
- })
598
- ```
245
+ - #### `getLanguage()`
599
246
 
600
- - #### `setupAuto(config: I18nConfig & {basePath: string}): Promise<LazyLoader>`
601
- > Auto-setup with environment detection. Automatically uses fetch in browser and file system on server.
247
+ > Get current language code
602
248
 
603
- ```typescript
604
- // Works in both browser and Node.js
605
- const loader = await setupAuto({
606
- defaultLanguage: 'en',
607
- supportedLanguages: ['en', 'ar', 'fr'],
608
- basePath: 'http://localhost:3000/i18n/',
609
- fileExtension: 'json'
610
- })
611
- ```
249
+ ```typescript
250
+ const lang = getLanguage() // 'en'
251
+ ```
612
252
 
613
- ```typescript
614
- const loader = await setupLazy({
615
- defaultLanguage: 'en',
616
- supportedLanguages: ['en', 'ar', 'fr'],
617
- baseUrl: 'https://cdn.com/i18n/'
618
- })
619
- ```
253
+ - #### `getSupportedLanguages()`
620
254
 
621
- <br>
255
+ > Get all supported languages
622
256
 
623
- - ### Convenience Functions (Global Instance)
257
+ ```typescript
258
+ const langs = getSupportedLanguages() // ['en', 'ar', 'fr']
259
+ ```
624
260
 
625
- - #### `t(key: string, params?: object): string`
626
- > Translate using global instance.
261
+ - #### `isRTL()`
627
262
 
628
- - #### `tLang(key: string, lang: LanguageCode, params?: object): string`
629
- > Translate with specific language using global instance.
263
+ > Check if current language is RTL
630
264
 
631
- - #### `tParse(key: string, params?: object): TranslationToken[]`
632
- > Parse translation using global instance.
265
+ ```typescript
266
+ if (isRTL()) { /* Handle RTL layout */ }
267
+ ```
633
268
 
634
- - #### `setLanguage(lang: LanguageCode): Promise<void>`
635
- > Set language on global instance.
269
+ - #### `onChange(callback)`
636
270
 
637
- - #### `getLanguage(): LanguageCode`
638
- > Get current language from global instance.
271
+ > Subscribe to language changes
639
272
 
640
- - #### `getSupportedLanguages(): LanguageCode[]`
641
- > Get supported languages from global instance.
273
+ ```typescript
274
+ const unsubscribe = onChange((lang) => console.log('Changed to:', lang))
275
+ ```
642
276
 
643
- - #### `hasKey(key: string): boolean`
644
- > Check if key exists in global instance.
277
+ - #### `genPageTitle(key, prefix?)`
645
278
 
646
- - #### `isRTL(): boolean`
647
- > Check if current language is RTL on global instance.
279
+ > Generate page title with app name
648
280
 
649
- - #### `isRTLLanguage(lang: LanguageCode): boolean`
650
- > Check if specific language is RTL.
281
+ ```typescript
282
+ genPageTitle('home') // "Home - MyApp" or "MyApp - Ψ§Ω„Ψ±Ψ¦ΩŠΨ³ΩŠΨ©"
283
+ ```
651
284
 
652
- - #### `onChange(callback: (lang: LanguageCode) => void): () => void`
653
- > Subscribe to language changes on global instance.
285
+ - #### `plural(count, singleKey, pluralKey)`
654
286
 
655
- - #### `loadLanguage(lang: LanguageCode, translations: object): void`
656
- > Load translations using global instance.
287
+ > Handle pluralization
657
288
 
658
- - #### `loadTranslations(translations: TranslationSet): void`
659
- > Load multiple languages using global instance.
289
+ ```typescript
290
+ plural(5, 'item.single', 'item.plural') // "5 items"
291
+ ```
660
292
 
661
- <br>
293
+ - #### `hasKey(key)`
662
294
 
663
- - ### Utility Functions
295
+ > Check if translation exists
664
296
 
665
- - #### `genPageTitle(key: string, prefix?: string): string`
666
- > Generate page title with app name and proper RTL formatting.
297
+ ```typescript
298
+ if (hasKey('settings.theme')) { /* ... */ }
299
+ ```
667
300
 
668
- ```typescript
669
- // LTR: "Page Name - App Name"
670
- // RTL: "App Name - Page Name"
301
+ - #### `loadLanguage(lang, translations)`
671
302
 
672
- const title = genPageTitle('home', 'page.')
673
- // Translates 'page.home' and 'app.name'
674
- ```
303
+ > Load translations for a language
675
304
 
676
- - #### `plural(count: number, singleKey: string, pluralKey: string): string`
677
- > Select translation based on count and replace {count} parameter.
305
+ ```typescript
306
+ loadLanguage('en', { greeting: 'Hello' })
307
+ ```
678
308
 
679
- ```typescript
680
- loadLanguage('en', {
681
- 'item.single': '1 item',
682
- 'item.plural': '{count} items'
683
- })
309
+ - #### `loadTranslations(translations)`
684
310
 
685
- plural(1, 'item.single', 'item.plural') // "1 item"
686
- plural(5, 'item.single', 'item.plural') // "5 items"
687
- ```
311
+ > Load multiple languages at once
688
312
 
689
- <br>
313
+ ```typescript
314
+ loadTranslations({
315
+ en: { greeting: 'Hello' },
316
+ ar: { greeting: 'Ω…Ψ±Ψ­Ψ¨Ψ§' }
317
+ })
318
+ ```
690
319
 
691
- - ## Types πŸ“˜
692
-
693
- ```typescript
694
- type LanguageCode = string
695
-
696
- interface I18nConfig {
697
- defaultLanguage?: LanguageCode
698
- supportedLanguages?: LanguageCode[]
699
- fallbackLanguage?: LanguageCode
700
- onLanguageChange?: (lang: LanguageCode) => void
701
- storage?: I18nStorage
702
- basePath?: string
703
- fileExtension?: string
704
- }
705
-
706
- interface I18nStorage {
707
- get(key: string): string | null | Promise<string | null>
708
- set(key: string, value: string): void | Promise<void>
709
- }
710
-
711
- interface TranslationToken {
712
- type: 'text' | 'tag'
713
- tag?: string
714
- content: string
715
- }
716
-
717
- type TranslationSet = Record<string, Record<string, string>>
718
- ```
320
+ <div align="center"> <img src="./assets/img/line.png" alt="line" style="display: block; margin-top:20px;margin-bottom:20px;width:500px;"/> </div>
719
321
 
720
- <br>
322
+ - #### Related
323
+
324
+ - ##### [@cruxjs/app](https://github.com/cruxjs-org/app)
721
325
 
722
326
  <!-- β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β• -->
723
327
 
@@ -725,6 +329,7 @@
725
329
 
726
330
  <!-- ╔══════════════════════════════ END ══════════════════════════════╗ -->
727
331
 
332
+ <br>
728
333
  <br>
729
334
 
730
335
  ---
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@minejs/i18n",
3
- "version": "0.0.4",
3
+ "version": "0.0.6",
4
4
  "description": "A lightweight, production-ready internationalization (i18n) library with zero dependencies.",
5
5
  "keywords": ["minejs", "i18n"],
6
6
  "license": "MIT",
@@ -41,7 +41,7 @@
41
41
  },
42
42
  "devDependencies": {
43
43
  "@eslint/js": "^9.39.2",
44
- "@stylistic/eslint-plugin": "^5.6.1",
44
+ "@stylistic/eslint-plugin": "^5.7.0",
45
45
  "@types/bun": "^1.3.5",
46
46
  "@types/node": "^20.19.27",
47
47
  "bun-plugin-dts": "^0.3.0",
@@ -49,6 +49,6 @@
49
49
  "ts-node": "^10.9.2",
50
50
  "tsup": "^8.5.1",
51
51
  "typescript": "^5.9.3",
52
- "typescript-eslint": "^8.51.0"
52
+ "typescript-eslint": "^8.52.0"
53
53
  }
54
54
  }