@itrocks/translate 0.0.10 → 0.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +289 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -7,3 +7,292 @@
|
|
|
7
7
|
# translate
|
|
8
8
|
|
|
9
9
|
Manage dynamic string translations with support for variables and composite patterns.
|
|
10
|
+
|
|
11
|
+
*This documentation was written by an artificial intelligence and may contain errors or approximations.
|
|
12
|
+
It has not yet been fully reviewed by a human. If anything seems unclear or incomplete,
|
|
13
|
+
please feel free to contact the author of this package.*
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm i @itrocks/translate
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
This package has a runtime dependency on `papaparse`, which is installed automatically
|
|
22
|
+
as a transitive dependency when you install `@itrocks/translate`.
|
|
23
|
+
|
|
24
|
+
## Usage
|
|
25
|
+
|
|
26
|
+
`@itrocks/translate` provides a tiny in-memory translation engine for Node.js.
|
|
27
|
+
|
|
28
|
+
You typically use it to:
|
|
29
|
+
|
|
30
|
+
- declare the current UI language with `trInit()`,
|
|
31
|
+
- load translation keys from a CSV file with `trLoad()`,
|
|
32
|
+
- translate strings at runtime with `tr()`,
|
|
33
|
+
- optionally inspect or extend the in-memory `translations` map.
|
|
34
|
+
|
|
35
|
+
The focus is on **dynamic translations of small text snippets** (labels, button
|
|
36
|
+
texts, messages) with support for:
|
|
37
|
+
|
|
38
|
+
- automatic case handling (uppercasing the first letter),
|
|
39
|
+
- placeholders like `$1`, `$2`, ... replaced by runtime values,
|
|
40
|
+
- composite expressions that can themselves contain expressions.
|
|
41
|
+
|
|
42
|
+
### Minimal example
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
import { tr, trInit, trLoad } from '@itrocks/translate'
|
|
46
|
+
|
|
47
|
+
async function main() {
|
|
48
|
+
// 1. Select the language and reset internal state
|
|
49
|
+
trInit('en-US')
|
|
50
|
+
|
|
51
|
+
// 2. Load translations from a ;‑separated CSV file
|
|
52
|
+
await trLoad('locales/en-US.csv')
|
|
53
|
+
|
|
54
|
+
// 3. Translate a simple key
|
|
55
|
+
console.log(tr('hello')) // e.g. "Hello"
|
|
56
|
+
|
|
57
|
+
// 4. Translate a key with placeholders
|
|
58
|
+
console.log(tr('welcome.user.$1', ['John'])) // e.g. "Welcome, John"
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
main().catch(console.error)
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Complete example with composite patterns
|
|
65
|
+
|
|
66
|
+
`tr()` can both translate **simple keys** and **composite expressions**. Composite
|
|
67
|
+
expressions are translated by splitting them around punctuation and translating
|
|
68
|
+
each part separately while preserving spaces.
|
|
69
|
+
|
|
70
|
+
You can also store patterns with placeholders in the translation file. When a
|
|
71
|
+
pattern matches the source text, `tr()` automatically:
|
|
72
|
+
|
|
73
|
+
- translates each captured part,
|
|
74
|
+
- appends the translated parts to the `parts` array,
|
|
75
|
+
- and reuses them to build the final translated string.
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
import { expressions, lang, tr, trInit, trLoad, translations } from '@itrocks/translate'
|
|
79
|
+
|
|
80
|
+
async function initTranslations() {
|
|
81
|
+
// Initialize the language (any BCP 47 code string is accepted)
|
|
82
|
+
trInit('fr-FR')
|
|
83
|
+
|
|
84
|
+
// Load a ;‑separated CSV file with two columns: source;translation
|
|
85
|
+
// Example content:
|
|
86
|
+
// hello;Bonjour
|
|
87
|
+
// "Hello, $1";"Bonjour, $1"
|
|
88
|
+
// "You have $1 new messages";"Vous avez $1 nouveaux messages"
|
|
89
|
+
await trLoad('locales/fr-FR.csv')
|
|
90
|
+
|
|
91
|
+
console.log('Current language:', lang())
|
|
92
|
+
|
|
93
|
+
console.log(tr('hello')) // "Bonjour"
|
|
94
|
+
console.log(tr('Hello, $1', ['Marie'])) // "Bonjour, Marie"
|
|
95
|
+
console.log(tr('You have $1 new messages', ['3']))
|
|
96
|
+
// => "Vous avez 3 nouveaux messages"
|
|
97
|
+
|
|
98
|
+
// The underlying maps are available if you need to inspect or extend them
|
|
99
|
+
console.log('Loaded translations:', translations.size)
|
|
100
|
+
console.log('Expression patterns:', expressions.size)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
initTranslations().catch(console.error)
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
> **Note**
|
|
107
|
+
> This package is intentionally minimal: it does not manage locales, fallbacks,
|
|
108
|
+
> or pluralization rules on its own. Those concerns are expected to be handled
|
|
109
|
+
> by your application or higher‑level framework.
|
|
110
|
+
|
|
111
|
+
## API
|
|
112
|
+
|
|
113
|
+
### `DefaultOptions`
|
|
114
|
+
|
|
115
|
+
```ts
|
|
116
|
+
export const DefaultOptions: Options
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
The default options used by `tr()` when no explicit `options` are provided.
|
|
120
|
+
|
|
121
|
+
Currently only one option is defined:
|
|
122
|
+
|
|
123
|
+
- `ucFirst: boolean` (default `true`): when `true`, if the input text starts
|
|
124
|
+
with an uppercase ASCII letter (`A`–`Z`), the translated string is forced to
|
|
125
|
+
start with an uppercase letter as well.
|
|
126
|
+
|
|
127
|
+
You can override this behavior per call using the `options` argument of `tr()`.
|
|
128
|
+
|
|
129
|
+
### `expressions`
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
export const expressions: Set<RegExp>
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
The set of **compiled expression patterns** used for advanced matching in `tr()`.
|
|
136
|
+
|
|
137
|
+
You normally do not need to modify this set manually. It is populated by
|
|
138
|
+
`trLoad()` when a source key in the CSV file contains placeholders like `$1`.
|
|
139
|
+
|
|
140
|
+
Each such key generates a regular expression that is later used by `tr()` to
|
|
141
|
+
match dynamic sentences and extract sub‑parts for translation.
|
|
142
|
+
|
|
143
|
+
### `translations`
|
|
144
|
+
|
|
145
|
+
```ts
|
|
146
|
+
export const translations: Map<string, string>
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
The in‑memory translation dictionary. Keys are **source texts** (usually
|
|
150
|
+
English strings or stable identifiers), and values are their translated
|
|
151
|
+
counterparts in the currently active language.
|
|
152
|
+
|
|
153
|
+
This map is cleared each time you call `trInit()`. It is filled by `trLoad()`
|
|
154
|
+
and can be extended or inspected manually if needed.
|
|
155
|
+
|
|
156
|
+
### `type Options`
|
|
157
|
+
|
|
158
|
+
```ts
|
|
159
|
+
export type Options = {
|
|
160
|
+
ucFirst?: boolean
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Additional options that can be passed to `tr()`:
|
|
165
|
+
|
|
166
|
+
- `ucFirst` (default: `DefaultOptions.ucFirst`): whether the first character of
|
|
167
|
+
the translated string should be uppercased when the original first character
|
|
168
|
+
is an uppercase ASCII letter.
|
|
169
|
+
|
|
170
|
+
### `lang()`
|
|
171
|
+
|
|
172
|
+
```ts
|
|
173
|
+
function lang(): string
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Returns the **current language code** previously set with `trInit()`.
|
|
177
|
+
|
|
178
|
+
The package does not interpret the value: you can use any string (for example
|
|
179
|
+
`'en-US'`, `'fr-FR'`, `'de'`), as long as it is meaningful to your
|
|
180
|
+
application.
|
|
181
|
+
|
|
182
|
+
### `tr()`
|
|
183
|
+
|
|
184
|
+
```ts
|
|
185
|
+
// Overload 1: no parts array, only options
|
|
186
|
+
function tr(text: string, options: Options): string
|
|
187
|
+
|
|
188
|
+
// Overload 2: explicit parts and optional options
|
|
189
|
+
function tr(text: string, parts?: string[], options?: Options): string
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Translates the given `text` using the current `translations` map and returns
|
|
193
|
+
the translated string.
|
|
194
|
+
|
|
195
|
+
Behavior details:
|
|
196
|
+
|
|
197
|
+
1. **Spacing preservation** – leading and trailing whitespace in `text` are
|
|
198
|
+
preserved around the translated content.
|
|
199
|
+
2. **Lookup strategy** – for the trimmed `text`, `tr()` looks up, in order:
|
|
200
|
+
- an exact match in `translations`,
|
|
201
|
+
- if `ucFirst` is enabled and the first character is uppercase, the same key
|
|
202
|
+
but with the first letter lower‑cased,
|
|
203
|
+
- the lower‑cased key,
|
|
204
|
+
- a match from expression patterns in `expressions` (see `trLoad()`).
|
|
205
|
+
3. **Composite sentences** – if no translation is found, `tr()` looks for a
|
|
206
|
+
punctuation separator (`.?!;:,()`). When found, the text is split around the
|
|
207
|
+
first such separator, each part is translated separately with `tr()`, and the
|
|
208
|
+
final string is reassembled while preserving spaces (including non‑breaking
|
|
209
|
+
spaces around the separator).
|
|
210
|
+
4. **Fallback** – if no translation or expression match is found, the original
|
|
211
|
+
trimmed text is returned.
|
|
212
|
+
5. **Placeholders** – if a `parts` array is provided, elements are substituted
|
|
213
|
+
into the translated string by replacing `$1`, `$2`, ... from the end of the
|
|
214
|
+
array backwards.
|
|
215
|
+
|
|
216
|
+
Usage patterns:
|
|
217
|
+
|
|
218
|
+
```ts
|
|
219
|
+
tr('hello')
|
|
220
|
+
tr('Hello', { ucFirst: false })
|
|
221
|
+
tr('welcome.$1', ['John'])
|
|
222
|
+
tr('You have $1 new messages', ['3'])
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### `trInit()`
|
|
226
|
+
|
|
227
|
+
```ts
|
|
228
|
+
function trInit(lang: string): void
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
Initializes or switches the current language. This function:
|
|
232
|
+
|
|
233
|
+
- sets the internal language code returned by `lang()`,
|
|
234
|
+
- clears all previously loaded `translations`,
|
|
235
|
+
- clears all compiled `expressions`.
|
|
236
|
+
|
|
237
|
+
Call this once per language at application startup, or whenever you change the
|
|
238
|
+
active language and want to reload translation data.
|
|
239
|
+
|
|
240
|
+
### `trLoad()`
|
|
241
|
+
|
|
242
|
+
```ts
|
|
243
|
+
async function trLoad(file: string): Promise<void | unknown>
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
Loads translations from a **semicolon‑separated CSV file** at the given path.
|
|
247
|
+
|
|
248
|
+
Behavior:
|
|
249
|
+
|
|
250
|
+
- If the file does not exist or cannot be accessed, the function simply
|
|
251
|
+
returns without throwing.
|
|
252
|
+
- It reads the file as UTF‑8 and parses it using `papaparse` with `;` as the
|
|
253
|
+
delimiter.
|
|
254
|
+
- Each row is expected to have at least two columns: `row[0]` is the source
|
|
255
|
+
string, `row[1]` is the translated string. Extra columns are ignored.
|
|
256
|
+
- For each row, the pair is stored in `translations`.
|
|
257
|
+
- If `row[0]` contains a placeholder like `$1`, an expression `RegExp` is
|
|
258
|
+
created and added to `expressions` to support dynamic matching in `tr()`.
|
|
259
|
+
|
|
260
|
+
Typical CSV snippet:
|
|
261
|
+
|
|
262
|
+
```csv
|
|
263
|
+
hello;Hello
|
|
264
|
+
"Hello, $1";"Hello, $1"
|
|
265
|
+
"You have $1 new messages";"You have $1 new messages"
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
## Typical use cases
|
|
269
|
+
|
|
270
|
+
Here are some scenarios where `@itrocks/translate` is a good fit:
|
|
271
|
+
|
|
272
|
+
1. **Translating UI labels and messages in a Node.js application**
|
|
273
|
+
- Keep a simple `locales/<lang>.csv` file with two columns: source and
|
|
274
|
+
translation.
|
|
275
|
+
- At startup, call `trInit('<lang>')` and `trLoad('locales/<lang>.csv')`.
|
|
276
|
+
- Use `tr('settings')`, `tr('Save changes')`, etc., in your rendering
|
|
277
|
+
or logging code.
|
|
278
|
+
|
|
279
|
+
2. **Integrating with a template or transformer system**
|
|
280
|
+
- Combine `@itrocks/translate` with higher‑level packages such as
|
|
281
|
+
`@itrocks/transformer` or `@itrocks/property-translate` to automatically
|
|
282
|
+
translate values when rendering views or model properties.
|
|
283
|
+
|
|
284
|
+
3. **Dynamic messages with parameters**
|
|
285
|
+
- Define entries in your CSV containing `$1`, `$2`, ... placeholders.
|
|
286
|
+
- At runtime, call `tr('You have $1 new messages', ['3'])`.
|
|
287
|
+
- The placeholders are replaced by the elements of the `parts` array.
|
|
288
|
+
|
|
289
|
+
4. **Expression‑based translations**
|
|
290
|
+
- Use keys with `$1` in your CSV (for example, `"Hello, $1"`).
|
|
291
|
+
- When you call `tr('Hello, John')`, `@itrocks/translate` matches the
|
|
292
|
+
pattern, translates `"John"` if possible, and then builds the final
|
|
293
|
+
sentence using the captured parts.
|
|
294
|
+
|
|
295
|
+
5. **Inspecting and debugging translations**
|
|
296
|
+
- Use `translations.size` to quickly see how many entries were loaded.
|
|
297
|
+
- Inspect `translations.get('some key')` or iterate over the map when
|
|
298
|
+
debugging missing or incorrect translations.
|
package/package.json
CHANGED
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
"keywords": [
|
|
31
31
|
"backend",
|
|
32
32
|
"composite",
|
|
33
|
+
"csv",
|
|
33
34
|
"i18n",
|
|
34
35
|
"internationalization",
|
|
35
36
|
"it.rocks",
|
|
@@ -50,5 +51,5 @@
|
|
|
50
51
|
"build:esm": "tsc -p tsconfig.esm.json && node esm/esm"
|
|
51
52
|
},
|
|
52
53
|
"types": "esm/translate.js",
|
|
53
|
-
"version": "0.0.
|
|
54
|
+
"version": "0.0.11"
|
|
54
55
|
}
|