@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.
- package/LICENSE +21 -0
- package/README.md +188 -0
- package/dist/DataLoader.d.ts +51 -0
- package/dist/DependencyInjection.d.ts +271 -0
- package/dist/DependencyInjectionOld.d.ts +35 -0
- package/dist/Metadata.d.ts +8 -0
- package/dist/SequentialId.d.ts +47 -0
- package/dist/_alt/src/MustardEngine.d.ts +30 -0
- package/dist/_alt/src/MustardParser.d.ts +63 -0
- package/dist/_alt/src/MustardParser2.d.ts +35 -0
- package/dist/_alt/src/pipes.d.ts +93 -0
- package/dist/_alt/src/template.d.ts +166 -0
- package/dist/_alt/src/tools.d.ts +4 -0
- package/dist/_alt/tests/pipes.tests.d.ts +1 -0
- package/dist/_alt/tests/template.tests.d.ts +1 -0
- package/dist/_alt/vitest.config.d.ts +2 -0
- package/dist/collections/Index.d.ts +1 -0
- package/dist/collections/LinkedList.d.ts +75 -0
- package/dist/collections/Pager.d.ts +15 -0
- package/dist/collections/index.js +2 -0
- package/dist/collections/index.js.map +7 -0
- package/dist/collections/index.mjs +2 -0
- package/dist/collections/index.mjs.map +7 -0
- package/dist/components/Table.d.ts +13 -0
- package/dist/components/index.d.ts +4 -0
- package/dist/components/index.js +128 -0
- package/dist/components/index.js.map +7 -0
- package/dist/components/index.mjs +128 -0
- package/dist/components/index.mjs.map +7 -0
- package/dist/components/lists/Table.d.ts +59 -0
- package/dist/components/lists/TreeView.d.ts +67 -0
- package/dist/components/lists/index.d.ts +2 -0
- package/dist/components/loader.d.ts +60 -0
- package/dist/components/menus/MenuItem.d.ts +30 -0
- package/dist/components/menus/TopMenu.d.ts +16 -0
- package/dist/components/menus/index.d.ts +2 -0
- package/dist/components/panels/tabs.d.ts +15 -0
- package/dist/di/index.d.ts +1 -0
- package/dist/di/index.js +2 -0
- package/dist/di/index.js.map +7 -0
- package/dist/di/index.mjs +2 -0
- package/dist/di/index.mjs.map +7 -0
- package/dist/elements/CopyAttributes.d.ts +2 -0
- package/dist/elements/dom.d.ts +18 -0
- package/dist/elements/index.d.ts +2 -0
- package/dist/elements/index.js +2 -0
- package/dist/elements/index.js.map +7 -0
- package/dist/elements/index.mjs +2 -0
- package/dist/elements/index.mjs.map +7 -0
- package/dist/errors.d.ts +71 -0
- package/dist/forms/FormReader.d.ts +182 -0
- package/dist/forms/FormValidator.d.ts +114 -0
- package/dist/forms/ValidationRules.d.ts +103 -0
- package/dist/forms/index.d.ts +4 -0
- package/dist/forms/index.js +2 -0
- package/dist/forms/index.js.map +7 -0
- package/dist/forms/index.mjs +2 -0
- package/dist/forms/index.mjs.map +7 -0
- package/dist/forms/setFormData.d.ts +49 -0
- package/dist/getParentComponent.d.ts +43 -0
- package/dist/html/TableRenderer.d.ts +44 -0
- package/dist/html/TreeBinder.d.ts +9 -0
- package/dist/html/html.d.ts +55 -0
- package/dist/html/index.d.ts +5 -0
- package/dist/html/index.js +2 -0
- package/dist/html/index.js.map +7 -0
- package/dist/html/index.mjs +2 -0
- package/dist/html/index.mjs.map +7 -0
- package/dist/html/template.d.ts +167 -0
- package/dist/http/ServerSentEvents.d.ts +116 -0
- package/dist/http/SimpleWebSocket.d.ts +153 -0
- package/dist/http/http.d.ts +177 -0
- package/dist/http/index.d.ts +3 -0
- package/dist/http/index.js +2 -0
- package/dist/http/index.js.map +7 -0
- package/dist/http/index.mjs +2 -0
- package/dist/http/index.mjs.map +7 -0
- package/dist/i18n/i18n.d.ts +105 -0
- package/dist/i18n/icu.d.ts +64 -0
- package/dist/i18n/index.d.ts +2 -0
- package/dist/i18n/index.js +2 -0
- package/dist/i18n/index.js.map +7 -0
- package/dist/i18n/index.mjs +2 -0
- package/dist/i18n/index.mjs.map +7 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +7 -0
- package/dist/index.mjs +5 -0
- package/dist/index.mjs.map +7 -0
- package/dist/lib/DataLoader.d.ts +51 -0
- package/dist/lib/DependencyInjection.d.ts +271 -0
- package/dist/lib/InvokeParent.d.ts +10 -0
- package/dist/lib/Pipes.d.ts +236 -0
- package/dist/lib/SequentialId.d.ts +47 -0
- package/dist/lib/collections/Index.d.ts +1 -0
- package/dist/lib/collections/LinkedList.d.ts +75 -0
- package/dist/lib/collections/Pager.d.ts +15 -0
- package/dist/lib/collections/TableRenderer.d.ts +44 -0
- package/dist/lib/di/index.d.ts +1 -0
- package/dist/lib/elements/CopyAttributes.d.ts +2 -0
- package/dist/lib/elements/dom.d.ts +18 -0
- package/dist/lib/elements/index.d.ts +2 -0
- package/dist/lib/errors.d.ts +71 -0
- package/dist/lib/forms/FormReader.d.ts +182 -0
- package/dist/lib/forms/FormValidator.d.ts +114 -0
- package/dist/lib/forms/ValidationRules.d.ts +103 -0
- package/dist/lib/forms/index.d.ts +4 -0
- package/dist/lib/forms/setFormData.d.ts +49 -0
- package/dist/lib/getParentComponent.d.ts +43 -0
- package/dist/lib/html/TableRenderer.d.ts +44 -0
- package/dist/lib/html/TreeBinder.d.ts +9 -0
- package/dist/lib/html/html.d.ts +55 -0
- package/dist/lib/html/html2.d.ts +55 -0
- package/dist/lib/html/index.d.ts +5 -0
- package/dist/lib/html/m.d.ts +167 -0
- package/dist/lib/html/m2.d.ts +8 -0
- package/dist/lib/html/m3.d.ts +0 -0
- package/dist/lib/html/template.d.ts +167 -0
- package/dist/lib/http/HttpClient.d.ts +153 -0
- package/dist/lib/http/ServerSentEvents.d.ts +116 -0
- package/dist/lib/http/SimpleWebSocket.d.ts +153 -0
- package/dist/lib/http/http.d.ts +177 -0
- package/dist/lib/http/index.d.ts +3 -0
- package/dist/lib/i18n/i18n.d.ts +105 -0
- package/dist/lib/i18n/icu.d.ts +64 -0
- package/dist/lib/i18n/index.d.ts +2 -0
- package/dist/lib/index.d.ts +16 -0
- package/dist/lib/routing/NavigateRouteEvent.d.ts +52 -0
- package/dist/lib/routing/RouteLink.d.ts +7 -0
- package/dist/lib/routing/Routing.d.ts +270 -0
- package/dist/lib/routing/RoutingTarget.d.ts +22 -0
- package/dist/lib/routing/index.d.ts +7 -0
- package/dist/lib/routing/navigation.d.ts +70 -0
- package/dist/lib/routing/routeMatching.d.ts +21 -0
- package/dist/lib/routing/routeTargetRegistry.d.ts +23 -0
- package/dist/lib/routing/types.d.ts +130 -0
- package/dist/lib/templates/NodeTemplate.d.ts +38 -0
- package/dist/lib/templates/accessorParser.d.ts +87 -0
- package/dist/lib/templates/parseTemplate.d.ts +6 -0
- package/dist/lib/templates/tokenizer.d.ts +76 -0
- package/dist/lib/tools.d.ts +30 -0
- package/dist/lib/utils/index.d.ts +4 -0
- package/dist/pipes.d.ts +236 -0
- package/dist/routing/NavigateRouteEvent.d.ts +52 -0
- package/dist/routing/RouteLink.d.ts +7 -0
- package/dist/routing/RoutingTarget.d.ts +22 -0
- package/dist/routing/index.d.ts +7 -0
- package/dist/routing/index.js +5 -0
- package/dist/routing/index.js.map +7 -0
- package/dist/routing/index.mjs +5 -0
- package/dist/routing/index.mjs.map +7 -0
- package/dist/routing/navigation.d.ts +70 -0
- package/dist/routing/routeMatching.d.ts +21 -0
- package/dist/routing/routeTargetRegistry.d.ts +23 -0
- package/dist/routing/types.d.ts +130 -0
- package/dist/templates/NodeTemplate.d.ts +38 -0
- package/dist/templates/accessorParser.d.ts +87 -0
- package/dist/templates/parseTemplate.d.ts +6 -0
- package/dist/templates/tokenizer.d.ts +76 -0
- package/dist/tools.d.ts +30 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.js +2 -0
- package/dist/utils/index.js.map +7 -0
- package/dist/utils/index.mjs +2 -0
- package/dist/utils/index.mjs.map +7 -0
- package/docs/Architecture.md +333 -0
- package/docs/DependencyInjection.md +237 -0
- package/docs/Errors.md +87 -0
- package/docs/GettingStarted.md +231 -0
- package/docs/Pipes.md +211 -0
- package/docs/Translations.md +312 -0
- package/docs/WhyRelaxjs.md +336 -0
- package/docs/elements/dom.md +102 -0
- package/docs/forms/creating-form-components.md +924 -0
- package/docs/forms/form-api.md +94 -0
- package/docs/forms/forms.md +99 -0
- package/docs/forms/patterns.md +311 -0
- package/docs/forms/reading-writing.md +365 -0
- package/docs/forms/validation.md +351 -0
- package/docs/html/TableRenderer.md +292 -0
- package/docs/html/html.md +175 -0
- package/docs/html/index.md +54 -0
- package/docs/html/template.md +422 -0
- package/docs/http/HttpClient.md +459 -0
- package/docs/http/ServerSentEvents.md +184 -0
- package/docs/http/index.md +109 -0
- package/docs/i18n/i18n.md +309 -0
- package/docs/i18n/intl-standard.md +178 -0
- package/docs/routing/RouteLink.md +98 -0
- package/docs/routing/Routing.md +332 -0
- package/docs/routing/RoutingTarget.md +136 -0
- package/docs/routing/layouts.md +207 -0
- package/docs/utilities.md +143 -0
- 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/).
|