@relax.js/core 1.0.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.
Files changed (194) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +188 -0
  3. package/dist/DataLoader.d.ts +51 -0
  4. package/dist/DependencyInjection.d.ts +271 -0
  5. package/dist/DependencyInjectionOld.d.ts +35 -0
  6. package/dist/Metadata.d.ts +8 -0
  7. package/dist/SequentialId.d.ts +47 -0
  8. package/dist/_alt/src/MustardEngine.d.ts +30 -0
  9. package/dist/_alt/src/MustardParser.d.ts +63 -0
  10. package/dist/_alt/src/MustardParser2.d.ts +35 -0
  11. package/dist/_alt/src/pipes.d.ts +93 -0
  12. package/dist/_alt/src/template.d.ts +166 -0
  13. package/dist/_alt/src/tools.d.ts +4 -0
  14. package/dist/_alt/tests/pipes.tests.d.ts +1 -0
  15. package/dist/_alt/tests/template.tests.d.ts +1 -0
  16. package/dist/_alt/vitest.config.d.ts +2 -0
  17. package/dist/collections/Index.d.ts +1 -0
  18. package/dist/collections/LinkedList.d.ts +75 -0
  19. package/dist/collections/Pager.d.ts +15 -0
  20. package/dist/collections/index.js +2 -0
  21. package/dist/collections/index.js.map +7 -0
  22. package/dist/collections/index.mjs +2 -0
  23. package/dist/collections/index.mjs.map +7 -0
  24. package/dist/components/Table.d.ts +13 -0
  25. package/dist/components/index.d.ts +4 -0
  26. package/dist/components/index.js +128 -0
  27. package/dist/components/index.js.map +7 -0
  28. package/dist/components/index.mjs +128 -0
  29. package/dist/components/index.mjs.map +7 -0
  30. package/dist/components/lists/Table.d.ts +59 -0
  31. package/dist/components/lists/TreeView.d.ts +67 -0
  32. package/dist/components/lists/index.d.ts +2 -0
  33. package/dist/components/loader.d.ts +60 -0
  34. package/dist/components/menus/MenuItem.d.ts +30 -0
  35. package/dist/components/menus/TopMenu.d.ts +16 -0
  36. package/dist/components/menus/index.d.ts +2 -0
  37. package/dist/components/panels/tabs.d.ts +15 -0
  38. package/dist/di/index.d.ts +1 -0
  39. package/dist/di/index.js +2 -0
  40. package/dist/di/index.js.map +7 -0
  41. package/dist/di/index.mjs +2 -0
  42. package/dist/di/index.mjs.map +7 -0
  43. package/dist/elements/CopyAttributes.d.ts +2 -0
  44. package/dist/elements/dom.d.ts +18 -0
  45. package/dist/elements/index.d.ts +2 -0
  46. package/dist/elements/index.js +2 -0
  47. package/dist/elements/index.js.map +7 -0
  48. package/dist/elements/index.mjs +2 -0
  49. package/dist/elements/index.mjs.map +7 -0
  50. package/dist/errors.d.ts +71 -0
  51. package/dist/forms/FormReader.d.ts +182 -0
  52. package/dist/forms/FormValidator.d.ts +114 -0
  53. package/dist/forms/ValidationRules.d.ts +103 -0
  54. package/dist/forms/index.d.ts +4 -0
  55. package/dist/forms/index.js +2 -0
  56. package/dist/forms/index.js.map +7 -0
  57. package/dist/forms/index.mjs +2 -0
  58. package/dist/forms/index.mjs.map +7 -0
  59. package/dist/forms/setFormData.d.ts +49 -0
  60. package/dist/getParentComponent.d.ts +43 -0
  61. package/dist/html/TableRenderer.d.ts +44 -0
  62. package/dist/html/TreeBinder.d.ts +9 -0
  63. package/dist/html/html.d.ts +55 -0
  64. package/dist/html/index.d.ts +5 -0
  65. package/dist/html/index.js +2 -0
  66. package/dist/html/index.js.map +7 -0
  67. package/dist/html/index.mjs +2 -0
  68. package/dist/html/index.mjs.map +7 -0
  69. package/dist/html/template.d.ts +167 -0
  70. package/dist/http/ServerSentEvents.d.ts +116 -0
  71. package/dist/http/SimpleWebSocket.d.ts +153 -0
  72. package/dist/http/http.d.ts +177 -0
  73. package/dist/http/index.d.ts +3 -0
  74. package/dist/http/index.js +2 -0
  75. package/dist/http/index.js.map +7 -0
  76. package/dist/http/index.mjs +2 -0
  77. package/dist/http/index.mjs.map +7 -0
  78. package/dist/i18n/i18n.d.ts +105 -0
  79. package/dist/i18n/icu.d.ts +64 -0
  80. package/dist/i18n/index.d.ts +2 -0
  81. package/dist/i18n/index.js +2 -0
  82. package/dist/i18n/index.js.map +7 -0
  83. package/dist/i18n/index.mjs +2 -0
  84. package/dist/i18n/index.mjs.map +7 -0
  85. package/dist/index.d.ts +16 -0
  86. package/dist/index.js +5 -0
  87. package/dist/index.js.map +7 -0
  88. package/dist/index.mjs +5 -0
  89. package/dist/index.mjs.map +7 -0
  90. package/dist/lib/DataLoader.d.ts +51 -0
  91. package/dist/lib/DependencyInjection.d.ts +271 -0
  92. package/dist/lib/InvokeParent.d.ts +10 -0
  93. package/dist/lib/Pipes.d.ts +236 -0
  94. package/dist/lib/SequentialId.d.ts +47 -0
  95. package/dist/lib/collections/Index.d.ts +1 -0
  96. package/dist/lib/collections/LinkedList.d.ts +75 -0
  97. package/dist/lib/collections/Pager.d.ts +15 -0
  98. package/dist/lib/collections/TableRenderer.d.ts +44 -0
  99. package/dist/lib/di/index.d.ts +1 -0
  100. package/dist/lib/elements/CopyAttributes.d.ts +2 -0
  101. package/dist/lib/elements/dom.d.ts +18 -0
  102. package/dist/lib/elements/index.d.ts +2 -0
  103. package/dist/lib/errors.d.ts +71 -0
  104. package/dist/lib/forms/FormReader.d.ts +182 -0
  105. package/dist/lib/forms/FormValidator.d.ts +114 -0
  106. package/dist/lib/forms/ValidationRules.d.ts +103 -0
  107. package/dist/lib/forms/index.d.ts +4 -0
  108. package/dist/lib/forms/setFormData.d.ts +49 -0
  109. package/dist/lib/getParentComponent.d.ts +43 -0
  110. package/dist/lib/html/TableRenderer.d.ts +44 -0
  111. package/dist/lib/html/TreeBinder.d.ts +9 -0
  112. package/dist/lib/html/html.d.ts +55 -0
  113. package/dist/lib/html/html2.d.ts +55 -0
  114. package/dist/lib/html/index.d.ts +5 -0
  115. package/dist/lib/html/m.d.ts +167 -0
  116. package/dist/lib/html/m2.d.ts +8 -0
  117. package/dist/lib/html/m3.d.ts +0 -0
  118. package/dist/lib/html/template.d.ts +167 -0
  119. package/dist/lib/http/HttpClient.d.ts +153 -0
  120. package/dist/lib/http/ServerSentEvents.d.ts +116 -0
  121. package/dist/lib/http/SimpleWebSocket.d.ts +153 -0
  122. package/dist/lib/http/http.d.ts +177 -0
  123. package/dist/lib/http/index.d.ts +3 -0
  124. package/dist/lib/i18n/i18n.d.ts +105 -0
  125. package/dist/lib/i18n/icu.d.ts +64 -0
  126. package/dist/lib/i18n/index.d.ts +2 -0
  127. package/dist/lib/index.d.ts +16 -0
  128. package/dist/lib/routing/NavigateRouteEvent.d.ts +52 -0
  129. package/dist/lib/routing/RouteLink.d.ts +7 -0
  130. package/dist/lib/routing/Routing.d.ts +270 -0
  131. package/dist/lib/routing/RoutingTarget.d.ts +22 -0
  132. package/dist/lib/routing/index.d.ts +7 -0
  133. package/dist/lib/routing/navigation.d.ts +70 -0
  134. package/dist/lib/routing/routeMatching.d.ts +21 -0
  135. package/dist/lib/routing/routeTargetRegistry.d.ts +23 -0
  136. package/dist/lib/routing/types.d.ts +130 -0
  137. package/dist/lib/templates/NodeTemplate.d.ts +38 -0
  138. package/dist/lib/templates/accessorParser.d.ts +87 -0
  139. package/dist/lib/templates/parseTemplate.d.ts +6 -0
  140. package/dist/lib/templates/tokenizer.d.ts +76 -0
  141. package/dist/lib/tools.d.ts +30 -0
  142. package/dist/lib/utils/index.d.ts +4 -0
  143. package/dist/pipes.d.ts +236 -0
  144. package/dist/routing/NavigateRouteEvent.d.ts +52 -0
  145. package/dist/routing/RouteLink.d.ts +7 -0
  146. package/dist/routing/RoutingTarget.d.ts +22 -0
  147. package/dist/routing/index.d.ts +7 -0
  148. package/dist/routing/index.js +5 -0
  149. package/dist/routing/index.js.map +7 -0
  150. package/dist/routing/index.mjs +5 -0
  151. package/dist/routing/index.mjs.map +7 -0
  152. package/dist/routing/navigation.d.ts +70 -0
  153. package/dist/routing/routeMatching.d.ts +21 -0
  154. package/dist/routing/routeTargetRegistry.d.ts +23 -0
  155. package/dist/routing/types.d.ts +130 -0
  156. package/dist/templates/NodeTemplate.d.ts +38 -0
  157. package/dist/templates/accessorParser.d.ts +87 -0
  158. package/dist/templates/parseTemplate.d.ts +6 -0
  159. package/dist/templates/tokenizer.d.ts +76 -0
  160. package/dist/tools.d.ts +30 -0
  161. package/dist/utils/index.d.ts +4 -0
  162. package/dist/utils/index.js +2 -0
  163. package/dist/utils/index.js.map +7 -0
  164. package/dist/utils/index.mjs +2 -0
  165. package/dist/utils/index.mjs.map +7 -0
  166. package/docs/Architecture.md +333 -0
  167. package/docs/DependencyInjection.md +237 -0
  168. package/docs/Errors.md +87 -0
  169. package/docs/GettingStarted.md +231 -0
  170. package/docs/Pipes.md +211 -0
  171. package/docs/Translations.md +312 -0
  172. package/docs/WhyRelaxjs.md +336 -0
  173. package/docs/elements/dom.md +102 -0
  174. package/docs/forms/creating-form-components.md +924 -0
  175. package/docs/forms/form-api.md +94 -0
  176. package/docs/forms/forms.md +99 -0
  177. package/docs/forms/patterns.md +311 -0
  178. package/docs/forms/reading-writing.md +365 -0
  179. package/docs/forms/validation.md +351 -0
  180. package/docs/html/TableRenderer.md +292 -0
  181. package/docs/html/html.md +175 -0
  182. package/docs/html/index.md +54 -0
  183. package/docs/html/template.md +422 -0
  184. package/docs/http/HttpClient.md +459 -0
  185. package/docs/http/ServerSentEvents.md +184 -0
  186. package/docs/http/index.md +109 -0
  187. package/docs/i18n/i18n.md +309 -0
  188. package/docs/i18n/intl-standard.md +178 -0
  189. package/docs/routing/RouteLink.md +98 -0
  190. package/docs/routing/Routing.md +332 -0
  191. package/docs/routing/RoutingTarget.md +136 -0
  192. package/docs/routing/layouts.md +207 -0
  193. package/docs/utilities.md +143 -0
  194. package/package.json +93 -0
package/docs/Pipes.md ADDED
@@ -0,0 +1,211 @@
1
+ # Pipes
2
+
3
+ Data transformation functions for use in template expressions. Pipes transform values for display without modifying the underlying data.
4
+
5
+ ## Usage
6
+
7
+ In templates with `compileTemplate`:
8
+
9
+ ```html
10
+ <span>{{name | uppercase}}</span>
11
+ <span>{{price | currency}}</span>
12
+ <span>{{description | shorten:50}}</span>
13
+ <span>{{tags | join:, }}</span>
14
+ ```
15
+
16
+ Pipes can be chained:
17
+
18
+ ```html
19
+ <span>{{text | trim | uppercase | shorten:20}}</span>
20
+ ```
21
+
22
+ ## Localization
23
+
24
+ Several pipes are locale-aware and use the [i18n](i18n/i18n.md) system:
25
+
26
+ - `currency` - Formats numbers according to locale
27
+ - `date` - Formats dates according to locale
28
+ - `daysAgo` - Translates "today", "yesterday", "X days ago"
29
+ - `pieces` - Translates piece counts
30
+
31
+ To use localized pipes:
32
+
33
+ ```typescript
34
+ import { setLocale, loadNamespace } from 'relaxjs/i18n';
35
+
36
+ // Set locale and load pipe translations
37
+ await setLocale('sv');
38
+ await loadNamespace('r-pipes');
39
+
40
+ // Now pipes will output Swedish
41
+ // {{createdAt | daysAgo}} → "idag", "igår", "3 dagar sedan"
42
+ // {{price | currency:SEK}} → "1 234,56 kr"
43
+ ```
44
+
45
+ ### Translation Keys
46
+
47
+ Translation keys in the `r-pipes` namespace:
48
+
49
+ | Key | Message (EN) | Message (SV) |
50
+ |-----|-------------|-------------|
51
+ | `today` | `today` | `idag` |
52
+ | `yesterday` | `yesterday` | `igår` |
53
+ | `daysAgo` | `{count, plural, one {# day ago} other {# days ago}}` | `{count, plural, one {# dag sedan} other {# dagar sedan}}` |
54
+ | `pieces` | `{count, plural, =0 {none} one {one} other {# pcs}}` | `{count, plural, =0 {inga} one {en} other {# st}}` |
55
+
56
+ ### Translation Files
57
+
58
+ Pipe translations are stored in `src/i18n/locales/{locale}/r-pipes.json`:
59
+
60
+ ```json
61
+ {
62
+ "today": "today",
63
+ "yesterday": "yesterday",
64
+ "daysAgo": "{count, plural, one {# day ago} other {# days ago}}",
65
+ "pieces": "{count, plural, =0 {none} one {one} other {# pcs}}"
66
+ }
67
+ ```
68
+
69
+ To add a new locale, create `src/i18n/locales/{locale}/r-pipes.json` with the translated strings.
70
+
71
+ ## Programmatic Usage
72
+
73
+ ```typescript
74
+ import { applyPipes, defaultPipes, createPipeRegistry } from 'relaxjs/utils';
75
+
76
+ // Apply pipes to a value
77
+ const result = applyPipes('hello world', ['uppercase', 'shorten:8']);
78
+ // Returns: 'HELLO...'
79
+
80
+ // Use the default registry directly
81
+ const upper = defaultPipes.get('uppercase');
82
+ console.log(upper('hello')); // 'HELLO'
83
+
84
+ // Create a fresh registry
85
+ const registry = createPipeRegistry();
86
+ ```
87
+
88
+ ## Built-in Pipes
89
+
90
+ ### Text
91
+
92
+ | Pipe | Description | Example | Result |
93
+ |------|-------------|---------|--------|
94
+ | `uppercase` | Convert to uppercase | `{{"hello" \| uppercase}}` | `HELLO` |
95
+ | `lowercase` | Convert to lowercase | `{{"HELLO" \| lowercase}}` | `hello` |
96
+ | `capitalize` | Capitalize first letter | `{{"hello" \| capitalize}}` | `Hello` |
97
+ | `trim` | Remove leading/trailing whitespace | `{{" hello " \| trim}}` | `hello` |
98
+ | `shorten:n` | Limit to n characters with ellipsis | `{{"hello world" \| shorten:8}}` | `hello...` |
99
+
100
+ ### Formatting (Locale-Aware)
101
+
102
+ These pipes use the current i18n locale for formatting.
103
+
104
+ | Pipe | Description | Example | en | sv |
105
+ |------|-------------|---------|----|----|
106
+ | `currency` | Format as currency (default USD) | `{{1234.5 \| currency}}` | `$1,234.50` | `1 234,50 US$` |
107
+ | `currency:CODE` | Format with specific currency | `{{1234.5 \| currency:SEK}}` | `SEK 1,234.50` | `1 234,50 kr` |
108
+ | `date` | Format date (ISO) | `{{date \| date}}` | `2024-01-15T...` | `2024-01-15T...` |
109
+ | `date:short` | Short date format | `{{date \| date:short}}` | `1/15/2024` | `2024-01-15` |
110
+ | `date:long` | Long date format | `{{date \| date:long}}` | `Monday, January 15, 2024` | `måndag 15 januari 2024` |
111
+ | `daysAgo` | Relative date | `{{date \| daysAgo}}` | `3 days ago` | `3 dagar sedan` |
112
+ | `pieces` | Piece count | `{{3 \| pieces}}` | `3 pcs` | `3 st` |
113
+
114
+ ### Arrays
115
+
116
+ | Pipe | Description | Example | Result |
117
+ |------|-------------|---------|--------|
118
+ | `join` | Join with comma | `{{tags \| join}}` | `a,b,c` |
119
+ | `join:sep` | Join with custom separator | `{{tags \| join: \| }}` | `a \| b \| c` |
120
+ | `first` | Get first element | `{{items \| first}}` | First item |
121
+ | `last` | Get last element | `{{items \| last}}` | Last item |
122
+
123
+ ### Objects
124
+
125
+ | Pipe | Description | Example | Result |
126
+ |------|-------------|---------|--------|
127
+ | `keys` | Get object keys as array | `{{user \| keys}}` | `["name", "email"]` |
128
+
129
+ ### Conditionals
130
+
131
+ | Pipe | Description | Example | Result |
132
+ |------|-------------|---------|--------|
133
+ | `default:val` | Fallback for falsy values | `{{name \| default:Anonymous}}` | Value or `Anonymous` |
134
+ | `ternary:t:f` | Conditional value | `{{active \| ternary:Yes:No}}` | `Yes` or `No` |
135
+
136
+ ## Pipe Arguments
137
+
138
+ Arguments are passed after a colon:
139
+
140
+ ```html
141
+ <!-- Single argument -->
142
+ <span>{{text | shorten:50}}</span>
143
+ <span>{{price | currency:EUR}}</span>
144
+
145
+ <!-- Multiple arguments -->
146
+ <span>{{status | ternary:Active:Inactive}}</span>
147
+ ```
148
+
149
+ ## Configuration
150
+
151
+ Pass a pipe registry to `compileTemplate`:
152
+
153
+ ```typescript
154
+ import { compileTemplate } from 'relaxjs/html';
155
+ import { createPipeRegistry } from 'relaxjs/utils';
156
+
157
+ const pipeRegistry = createPipeRegistry();
158
+ const { content, render } = compileTemplate(
159
+ '<span>{{name | uppercase}}</span>',
160
+ { strict: false, pipeRegistry }
161
+ );
162
+ ```
163
+
164
+ ## API Reference
165
+
166
+ ### Types
167
+
168
+ ```typescript
169
+ type PipeFunction = (value: any, ...args: any[]) => any;
170
+
171
+ interface PipeRegistry {
172
+ lookup(name: string): PipeFunction | null;
173
+ get(name: string): PipeFunction; // Throws if not found
174
+ has(name: string): boolean;
175
+ }
176
+ ```
177
+
178
+ ### Functions
179
+
180
+ | Function | Description |
181
+ |----------|-------------|
182
+ | `createPipeRegistry()` | Create a new registry with all built-in pipes |
183
+ | `applyPipes(value, pipes, registry?)` | Apply an array of pipe strings to a value |
184
+ | `defaultPipes` | Pre-created registry instance |
185
+
186
+ ### Individual Pipe Functions
187
+
188
+ All pipes are also exported as individual functions for direct use:
189
+
190
+ ```typescript
191
+ import {
192
+ uppercasePipe,
193
+ lowercasePipe,
194
+ capitalizePipe,
195
+ trimPipe,
196
+ shortenPipe,
197
+ currencyPipe,
198
+ datePipe,
199
+ daysAgoPipe,
200
+ piecesPipe,
201
+ joinPipe,
202
+ firstPipe,
203
+ lastPipe,
204
+ keysPipe,
205
+ defaultPipe,
206
+ ternaryPipe
207
+ } from 'relaxjs/utils';
208
+
209
+ const result = uppercasePipe('hello'); // 'HELLO'
210
+ const formatted = currencyPipe(1234.56); // '$1,234.56' (depends on locale)
211
+ ```
@@ -0,0 +1,312 @@
1
+ # Translation Library Documentation
2
+
3
+ This library helps you internationalize (i18n) your application using namespace-based translations and ICU message format for pluralization and formatting.
4
+
5
+ ---
6
+
7
+ ## Table of Contents
8
+
9
+ 1. [Installation](#installation)
10
+ 2. [Initialization and Loading Translations](#initialization-and-loading-translations)
11
+ 3. [Setting the Locale](#setting-the-locale)
12
+ 4. [Translation Function (`t`)](#translation-function-t)
13
+ 5. [Using Parameters in Translations](#using-parameters-in-translations)
14
+ 6. [Namespaces](#namespaces)
15
+ 7. [ICU Message Format](#icu-message-format)
16
+ 8. [Error Handling](#error-handling)
17
+ 9. [Example Translation Files](#example-translation-files)
18
+ 10. [Best Practices](#best-practices)
19
+
20
+ ---
21
+
22
+ ## Installation
23
+
24
+ Import the library functions in your code:
25
+
26
+ ```ts
27
+ import { setLocale, loadNamespace, t, getCurrentLocale } from 'relaxjs/i18n';
28
+ ```
29
+
30
+ ---
31
+
32
+ ## Initialization and Loading Translations
33
+
34
+ When you first start your application, set the locale and the library will automatically load the `common` namespace.
35
+
36
+ **Example:**
37
+
38
+ ```ts
39
+ import { setLocale } from 'relaxjs/i18n';
40
+
41
+ // Set locale at application startup
42
+ await setLocale('en');
43
+ ```
44
+
45
+ Under the hood, the library will:
46
+ 1. Normalize the locale (e.g., 'en-US' becomes 'en')
47
+ 2. Clear any previously loaded translations
48
+ 3. Load the `common` namespace from `/locales/{locale}/common.json`
49
+ 4. Fall back to English (`en`) if the requested locale is not found
50
+
51
+ ---
52
+
53
+ ## Setting the Locale
54
+
55
+ Use `setLocale(locale: string)` to switch or explicitly set the user's locale. The function returns a Promise that resolves once the `common` namespace is loaded.
56
+
57
+ **Example:**
58
+
59
+ ```ts
60
+ import { setLocale } from 'relaxjs/i18n';
61
+
62
+ async function switchToSwedish() {
63
+ await setLocale('sv');
64
+ console.log('Switched to Swedish!');
65
+ }
66
+ ```
67
+
68
+ > **Important**: Setting the locale clears all previously loaded translations and reloads the `common` namespace.
69
+
70
+ ---
71
+
72
+ ## Translation Function (`t`)
73
+
74
+ Use the `t` function to translate a key into the current locale's string. The signature is:
75
+ ```ts
76
+ t(fullKey: string, values?: Record<string, any>): string;
77
+ ```
78
+
79
+ - **fullKey**: A string key in format `namespace:key` or just `key` (defaults to `common` namespace)
80
+ - **values**: An optional object for ICU message interpolation
81
+
82
+ **Basic Example:**
83
+ ```ts
84
+ import { t } from 'relaxjs/i18n';
85
+
86
+ console.log(t("welcome_message"));
87
+ // Uses common:welcome_message
88
+
89
+ console.log(t("errors:notFound"));
90
+ // Uses errors namespace
91
+ ```
92
+
93
+ ---
94
+
95
+ ## Using Parameters in Translations
96
+
97
+ If your translation string includes placeholders, provide dynamic values in the `values` argument. The library uses ICU message format for interpolation.
98
+
99
+ **Example:**
100
+
101
+ ```ts
102
+ // In your .json translation file (e.g. locales/en/common.json)
103
+ {
104
+ "greeting": "Hello, {name}!"
105
+ }
106
+
107
+ // In your code:
108
+ import { t } from 'relaxjs/i18n';
109
+
110
+ console.log(t("greeting", { name: "Alice" }));
111
+ // Output: "Hello, Alice!"
112
+ ```
113
+
114
+ ---
115
+
116
+ ## Namespaces
117
+
118
+ Translations are organized into namespaces. Each namespace corresponds to a JSON file in the locales directory.
119
+
120
+ ### Directory Structure
121
+
122
+ ```
123
+ /locales
124
+ /en
125
+ common.json
126
+ errors.json
127
+ shop.json
128
+ /sv
129
+ common.json
130
+ errors.json
131
+ shop.json
132
+ ```
133
+
134
+ ### Loading Namespaces
135
+
136
+ The `common` namespace is loaded automatically when setting the locale. Load additional namespaces on demand:
137
+
138
+ ```ts
139
+ import { loadNamespace, t } from 'relaxjs/i18n';
140
+
141
+ // Load the shop namespace before using its translations
142
+ await loadNamespace('shop');
143
+
144
+ // Now you can use shop translations
145
+ const price = t('shop:priceLabel');
146
+ const items = t('shop:itemCount', { count: 5 });
147
+ ```
148
+
149
+ ### Key Format
150
+
151
+ Use `namespace:key` format to reference translations:
152
+
153
+ ```ts
154
+ t('common:greeting'); // Explicit common namespace
155
+ t('greeting'); // Implicit common namespace (same as above)
156
+ t('errors:notFound'); // errors namespace
157
+ t('shop:checkout'); // shop namespace
158
+ ```
159
+
160
+ ---
161
+
162
+ ## ICU Message Format
163
+
164
+ The library uses ICU message format for advanced formatting, including pluralization and selection.
165
+
166
+ ### Simple Interpolation
167
+
168
+ ```json
169
+ {
170
+ "welcome": "Welcome, {name}!"
171
+ }
172
+ ```
173
+
174
+ ```ts
175
+ t('welcome', { name: 'John' }); // "Welcome, John!"
176
+ ```
177
+
178
+ ### Pluralization
179
+
180
+ ```json
181
+ {
182
+ "items": "{count, plural, =0 {No items} one {# item} other {# items}}"
183
+ }
184
+ ```
185
+
186
+ ```ts
187
+ t('items', { count: 0 }); // "No items"
188
+ t('items', { count: 1 }); // "1 item"
189
+ t('items', { count: 5 }); // "5 items"
190
+ ```
191
+
192
+ ### Selection
193
+
194
+ ```json
195
+ {
196
+ "userStatus": "{gender, select, male {He is online} female {She is online} other {They are online}}"
197
+ }
198
+ ```
199
+
200
+ ```ts
201
+ t('userStatus', { gender: 'female' }); // "She is online"
202
+ ```
203
+
204
+ ### Number and Date Formatting
205
+
206
+ ICU format supports locale-aware number and date formatting:
207
+
208
+ ```json
209
+ {
210
+ "price": "Price: {amount, number, currency}",
211
+ "date": "Date: {date, date, medium}"
212
+ }
213
+ ```
214
+
215
+ ---
216
+
217
+ ## Error Handling
218
+
219
+ 1. **Missing translations**: If a translation key is not found, the function returns the key itself
220
+ 2. **Missing namespace**: If a namespace fails to load, the library falls back to the English locale
221
+ 3. **Format errors**: If ICU formatting fails, the function returns the key
222
+
223
+ **Example:**
224
+
225
+ ```ts
226
+ // If 'unknownKey' doesn't exist
227
+ const result = t('unknownKey');
228
+ // Returns: "unknownKey"
229
+
230
+ // Namespace loading with fallback
231
+ try {
232
+ await loadNamespace('shop');
233
+ } catch (error) {
234
+ console.warn('Shop namespace not found, using fallback');
235
+ }
236
+ ```
237
+
238
+ ---
239
+
240
+ ## Example Translation Files
241
+
242
+ Below are example JSON translation files:
243
+
244
+ **`/locales/en/common.json`**:
245
+ ```json
246
+ {
247
+ "welcome_message": "Welcome to our site!",
248
+ "greeting": "Hello, {name}!",
249
+ "items": "{count, plural, =0 {No items} one {# item} other {# items}}",
250
+ "goodbye": "Goodbye!"
251
+ }
252
+ ```
253
+
254
+ **`/locales/en/errors.json`**:
255
+ ```json
256
+ {
257
+ "notFound": "Page not found",
258
+ "unauthorized": "You are not authorized to view this page",
259
+ "serverError": "An unexpected error occurred"
260
+ }
261
+ ```
262
+
263
+ **`/locales/sv/common.json`** (Swedish):
264
+ ```json
265
+ {
266
+ "welcome_message": "Välkommen till vår sida!",
267
+ "greeting": "Hej, {name}!",
268
+ "items": "{count, plural, =0 {Inga föremål} one {# föremål} other {# föremål}}",
269
+ "goodbye": "Hejdå!"
270
+ }
271
+ ```
272
+
273
+ ---
274
+
275
+ ## Best Practices
276
+
277
+ - **Keep your translation keys consistent**: Use descriptive keys like `"user_profile_update_success"` instead of just `"message4"`.
278
+ - **Organize by feature**: Use namespaces to group related translations (e.g., `shop`, `auth`, `errors`)
279
+ - **Load namespaces lazily**: Only load namespaces when needed to reduce initial load time
280
+ - **Use ICU format for plurals**: Instead of `item`/`items` keys, use ICU plural syntax
281
+ - **Test across locales**: Different locales format numbers, dates, and plurals differently
282
+ - **Provide fallbacks**: The library falls back to English, so ensure all keys exist in the English locale
283
+
284
+ ---
285
+
286
+ ## API Reference
287
+
288
+ ### `setLocale(locale: string): Promise<void>`
289
+ Sets the current locale and loads the `common` namespace.
290
+
291
+ ### `loadNamespace(namespace: string): Promise<void>`
292
+ Loads a translation namespace on demand.
293
+
294
+ ### `t(fullKey: string, values?: Record<string, any>): string`
295
+ Translates a key with optional value interpolation using ICU format.
296
+
297
+ ### `getCurrentLocale(): string`
298
+ Returns the current normalized locale code.
299
+
300
+ ---
301
+
302
+ ## Summary
303
+
304
+ With this translation library, you can:
305
+
306
+ - Organize translations into namespaces for better structure
307
+ - Use the `t` function to substitute placeholders using ICU message format
308
+ - Handle pluralization and selection with standard ICU syntax
309
+ - Load namespaces on demand to optimize performance
310
+ - Fall back to English for missing translations
311
+
312
+ For more information on ICU message format, see the [ICU User Guide](https://unicode-org.github.io/icu/userguide/format_parse/messages/).