@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.
Files changed (2) hide show
  1. package/README.md +289 -0
  2. 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.10"
54
+ "version": "0.0.11"
54
55
  }