lino-i18n 0.2.0 → 0.4.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 (82) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/README.md +106 -1
  3. package/bin/lino-i18n.js +67 -34
  4. package/package.json +226 -20
  5. package/src/browser.d.ts +58 -0
  6. package/src/browser.js +58 -0
  7. package/src/catalogs.js +512 -0
  8. package/src/compiler.d.ts +53 -0
  9. package/src/compiler.js +72 -0
  10. package/src/content.js +135 -0
  11. package/src/converters/react-intl.js +10 -26
  12. package/src/dictionary.js +169 -0
  13. package/src/eslint.d.ts +15 -0
  14. package/src/eslint.js +244 -0
  15. package/src/extract-bindings.js +41 -0
  16. package/src/extract-derived.js +85 -0
  17. package/src/extract-dictionary.js +122 -0
  18. package/src/extract-jsx.js +176 -0
  19. package/src/extract-project.js +314 -0
  20. package/src/extract.js +365 -0
  21. package/src/format.js +23 -23
  22. package/src/i18n.js +4 -29
  23. package/src/index.d.ts +25 -7
  24. package/src/index.js +13 -2
  25. package/src/intl.d.ts +176 -0
  26. package/src/intl.js +407 -0
  27. package/src/language.js +46 -0
  28. package/src/loaders.js +9 -481
  29. package/src/message-schema.js +26 -0
  30. package/src/messages.d.ts +187 -0
  31. package/src/messages.js +397 -0
  32. package/src/native-state.js +72 -0
  33. package/src/next/client.d.ts +62 -0
  34. package/src/next/client.js +159 -0
  35. package/src/next/proxy.d.ts +17 -0
  36. package/src/next/proxy.js +39 -0
  37. package/src/next/server.d.ts +28 -0
  38. package/src/next/server.js +101 -0
  39. package/src/node-i18n.js +25 -0
  40. package/src/node.d.ts +37 -0
  41. package/src/node.js +61 -0
  42. package/src/providers/gt-locales.d.ts +2 -0
  43. package/src/providers/gt-locales.js +5 -0
  44. package/src/providers/gt.d.ts +75 -0
  45. package/src/providers/gt.js +158 -0
  46. package/src/python-extract.d.ts +16 -0
  47. package/src/python-extract.js +134 -0
  48. package/src/python-extract.py +300 -0
  49. package/src/react-content.js +69 -0
  50. package/src/react-native.d.ts +92 -0
  51. package/src/react-native.js +110 -0
  52. package/src/react-server.d.ts +14 -0
  53. package/src/react-server.js +28 -0
  54. package/src/react.d.ts +112 -9
  55. package/src/react.js +162 -8
  56. package/src/remark.d.ts +11 -0
  57. package/src/remark.js +35 -0
  58. package/src/rrweb/catalog.d.ts +29 -0
  59. package/src/rrweb/catalog.js +158 -0
  60. package/src/rrweb/harvest.d.ts +24 -0
  61. package/src/rrweb/harvest.js +102 -0
  62. package/src/rrweb/index.d.ts +36 -0
  63. package/src/rrweb/index.js +135 -0
  64. package/src/rrweb/replay.d.ts +1 -0
  65. package/src/rrweb/replay.js +3 -0
  66. package/src/server.d.ts +26 -0
  67. package/src/server.js +137 -0
  68. package/src/source-project-files.js +170 -0
  69. package/src/static-values.js +122 -0
  70. package/src/tanstack-start/client.d.ts +20 -0
  71. package/src/tanstack-start/client.js +97 -0
  72. package/src/tanstack-start/server.d.ts +19 -0
  73. package/src/tanstack-start/server.js +41 -0
  74. package/src/tooling-files.js +134 -0
  75. package/src/tooling.d.ts +56 -0
  76. package/src/tooling.js +90 -0
  77. package/src/transform-jsx.js +236 -0
  78. package/src/vue-content.js +82 -0
  79. package/src/vue-extract.d.ts +8 -0
  80. package/src/vue-extract.js +303 -0
  81. package/src/vue.d.ts +120 -0
  82. package/src/vue.js +309 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,45 @@
1
1
  # lino-i18n Changelog
2
2
 
3
+ ## 0.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Add source-message and ICU translation, rich React content and branches,
8
+ request-isolated server helpers, locale utilities, lazy catalog caching,
9
+ AST extraction, catalog validation, provider-based translation candidates,
10
+ and a Vite/Rollup extraction plugin over Links Notation.
11
+ Add finite static derivation, ICU dictionaries and source-change review checks.
12
+ Add typed dictionary schemas, canonical/custom locale configuration, scoped Node
13
+ request access, automatic JSX/attribute compilation and an optional GT SDK bridge.
14
+ Round-trip quoted source keys without interpreting prototype property names.
15
+ Preserve complete ICU semantics when converting compiled FormatJS catalogs.
16
+
17
+ Add an optional Next 16 App Router adapter for request-scoped server access, hydration, locale proxy/cookies, localized navigation, static params and SEO, verified with a production build and browser tests.
18
+
19
+ Resolve shared translator factories, imported finite derivation and dictionary schemas through bounded static module graphs in the CLI and Vite/Rollup plugin.
20
+
21
+ Add optional Vue 3.5 reactive source components, formatting, lazy initialization and SSR snapshots, plus SFC/module-aware extraction and CLI integration with compiler and browser regression coverage.
22
+
23
+ Add bounded Python AST extraction into shared manifests, optional upstream Markdown helpers with safe entity serialization, and a GT service locale registry bridge.
24
+
25
+ Add an injected React Native Text adapter with rich content, native formatter wrappers, headless selectors, serialized locale persistence and matching JSX extraction.
26
+
27
+ Add optional TanStack Start request middleware and Router hydration/navigation adapters, verified with actual server functions, a production build and browser tests.
28
+
29
+ Add optional rrweb recording/replay over `.lino` catalogs using the published GT player/recorder, bounded ICU harvesting, stable variable leaves and protected source values, with an actual browser privacy/playback regression.
30
+
31
+ Add an optional ESLint flat-config plugin sharing the static extractor, with source/JSX/headless-Branch diagnostics, explicit named-variable suggestions and bounded analysis.
32
+
33
+ Repair release verification and CI change detection, audit dependencies, and preserve translation behavior while resolving lint warnings.
34
+
35
+ Update all JavaScript dependencies to their latest releases (`links-notation` 0.23, `lino-objects-codec` 0.9, ESLint 10.12, Prettier 3.9, Playwright 1.64, React 19.3 typings) and raise the supported Node.js floor to 22.11, which `lino-objects-codec` 0.9 requires; Node.js 20 reached end of life on 2026-04-30.
36
+
37
+ ## 0.3.0
38
+
39
+ ### Minor Changes
40
+
41
+ - f73aa48: Add a tree-shakeable browser entry point with URL-based Links Notation catalog loading, navigator language detection, and the shared translation runtime.
42
+
3
43
  ## 0.2.0
4
44
 
5
45
  ### Minor Changes
package/README.md CHANGED
@@ -7,12 +7,45 @@
7
7
  Universal internationalization for JavaScript with translations stored in
8
8
  [Links Notation](https://github.com/linksplatform/Protocols.Lino) (`.lino`).
9
9
 
10
- Runs on Node.js (≥ 20), Bun, Deno, and bundlers like Vite/Webpack/esbuild.
10
+ Runs on Node.js (≥ 22.11), Bun, Deno, and bundlers like Vite/Webpack/esbuild.
11
11
 
12
12
  ```bash
13
13
  npm install lino-i18n
14
14
  ```
15
15
 
16
+ ## Source messages and tooling
17
+
18
+ ```js
19
+ import { createTranslator, msg } from 'lino-i18n/messages';
20
+ const i18n = createTranslator({
21
+ locales: { fr: { greeting: 'Bonjour {name}' } },
22
+ defaultLocale: 'fr',
23
+ });
24
+ i18n.gt(msg('Hello {name}', { id: 'greeting' }), { name: 'Ada' });
25
+ i18n.gt('{n, plural, one {# file} other {# files}}', { n: 2 });
26
+ ```
27
+
28
+ `lino-i18n/react` provides source `T`, `Var`, `Derive`, `Branch`, `Plural` and
29
+ formatting components alongside the existing keyed adapter. Optional exports
30
+ include `messages`, `intl`, `server`, `react-server`, `tooling` and `compiler`.
31
+ [Optional Vue components and SFC extraction](../docs/vue.md) provide reactive
32
+ source messages, SSR/hydration and template-scope diagnostics.
33
+ [TanStack Start integration](../docs/tanstack-start.md) adds request middleware,
34
+ server functions, loader snapshots and localized Router navigation.
35
+ The native browser entry retains its dependency-free keyed runtime; source ICU
36
+ and React browser applications use a bundler.
37
+
38
+ ```bash
39
+ lino-i18n extract --in src --out locales --locale en
40
+ lino-i18n check --dir locales --manifest locales/messages.json
41
+ ```
42
+
43
+ The complete [source-message guide](../docs/source-messages.md)
44
+ covers dictionaries, static derivation, provider candidates, versioned loading,
45
+ request isolation and snapshot hydration. The
46
+ [GT capability study](../docs/case-studies/issue-25/README.md)
47
+ records supported workflows and remaining ecosystem integrations.
48
+
16
49
  ## Usage
17
50
 
18
51
  ```js
@@ -33,6 +66,64 @@ i18n.t('role', { context: 'female' }); // → "She is a developer"
33
66
  i18n.t('telegram.help.solve.alias.detail'); // → "Tool aliases imply `--tool <tool>`"
34
67
  ```
35
68
 
69
+ ## Browser
70
+
71
+ Import `lino-i18n/browser` for native ES modules or browser bundles. This
72
+ entry point has no Node built-ins and uses the same translation engine and
73
+ `t(key, params, options)` API as the main entry point:
74
+
75
+ ```js
76
+ import { createI18n, detectLanguage, loadCatalogs } from 'lino-i18n/browser';
77
+
78
+ const locales = await loadCatalogs(['/locales/en.lino', '/locales/ru.lino']);
79
+ const i18n = createI18n({
80
+ locales,
81
+ defaultLocale: detectLanguage('auto', {
82
+ supportedLanguages: Object.keys(locales),
83
+ defaultLocale: 'en',
84
+ }),
85
+ fallback: ['en'],
86
+ });
87
+
88
+ i18n.t('greeting', { name: 'Ada' });
89
+ i18n.setLocale('ru');
90
+ i18n.t('greeting', { name: 'Ada' });
91
+ ```
92
+
93
+ `loadCatalogs(urls, options)` fetches URLs concurrently and merges every locale
94
+ root in URL order. Later catalogs override earlier values for matching keys.
95
+ It returns locale tables ready for `createI18n`; errors reject the promise and
96
+ identify the failing URL. `options.requestInit` forwards fetch options such as
97
+ `cache`, `credentials`, and `signal`. `options.fetch` overrides the platform
98
+ fetch, and `options.compatibilityAliases` enables migration aliases after merging.
99
+
100
+ `detectLanguage(preference, options)` checks an explicit preference first, then
101
+ `navigator.languages` in preference order. It uses `navigator.language` when
102
+ the language list is empty. `resolveLanguage(preference, candidates, options)`
103
+ performs the same matching with a supplied list, without reading the navigator.
104
+ Both accept `supportedLanguages` (default `['en']`) and `defaultLocale` (default
105
+ `'en'`). Tags are compared without case sensitivity, underscores become hyphens,
106
+ and exact tags are tried before parent tags (`pt-BR` before `pt`). An unsupported
107
+ preference or `'auto'` defers to candidates, then the default locale, then the
108
+ first supported locale. With no supported locales, the default is returned.
109
+ Detection also works in environments without a navigator.
110
+
111
+ The browser instance includes `subscribe`, `addLocale`, and `loadLocale` and
112
+ works with `lino-i18n/react`. File methods `loadLocaleFile` and `loadDirectory`
113
+ are available through the main entry point. URL loading stays explicit: fetch
114
+ more catalogs with `loadCatalogs`, then register their tables with `addLocale`.
115
+ ES module exports and `sideEffects: false` let bundlers remove unused helpers.
116
+ For TypeScript browser hooks, pass the exported `I18nCoreInstance` type to
117
+ `useI18n<I18nCoreInstance>()` or `useTranslation<I18nCoreInstance>()`. Their
118
+ default type preserves the main entry point's existing file-loading API.
119
+
120
+ Run the static browser example from `js/`:
121
+
122
+ ```bash
123
+ node examples/browser-usage/server.mjs
124
+ # Open http://127.0.0.1:4173/examples/browser-usage/
125
+ ```
126
+
36
127
  ## React
37
128
 
38
129
  React is an optional peer dependency. The `lino-i18n/react` adapter uses the
@@ -191,9 +282,23 @@ Run `npx lino-i18n --help` for every option.
191
282
 
192
283
  ```bash
193
284
  npm test # node --test --test-timeout=30000 tests/*.test.js
285
+ npm run test:types # browser and React TypeScript API checks
286
+ npx playwright install chromium
287
+ npm run test:browser # real browser catalog loading and runtime language switching
194
288
  ```
195
289
 
196
290
  ## License
197
291
 
198
292
  Released into the public domain under the
199
293
  [Unlicense](https://unlicense.org/).
294
+
295
+ See [Python extraction, Markdown helpers and GT locale data](../docs/ecosystem-tools.md) for optional source and content tools.
296
+
297
+ See [React Native source messages](../docs/react-native.md) for native text,
298
+ formatters, selectors and persisted locale choices.
299
+
300
+ See [session recording and replay](../docs/rrweb.md) for the optional published GT recorder/player, `.lino` overlays and protected recorded variables.
301
+
302
+ See [source-message lint rules](../docs/eslint.md) for optional ESLint diagnostics.
303
+ The [Sanity investigation](../docs/sanity.md) records a deferred integration and
304
+ the upstream dependency-review blocker.
package/bin/lino-i18n.js CHANGED
@@ -2,9 +2,7 @@
2
2
 
3
3
  // `lino-i18n` command-line entry point.
4
4
  //
5
- // Built on top of `lino-arguments` so configuration follows the same
6
- // priority chain as the rest of the Link Foundation stack: CLI flags
7
- // > environment variables > config file > defaults.
5
+ // Configuration priority: CLI flags > JSON `--config` file > defaults.
8
6
 
9
7
  import { promises as fs } from 'node:fs';
10
8
  import path from 'node:path';
@@ -32,12 +30,20 @@ function usage() {
32
30
  ' convert Convert i18next / i18n-js / react-intl JSON files to .lino',
33
31
  ' check Compare locales against a reference locale and report missing keys',
34
32
  ' t Translate a key from the CLI for quick debugging',
33
+ ' extract Extract source messages and JSX to .lino and a manifest',
34
+ ' translate-catalog Generate validated candidates with a provider module',
35
35
  '',
36
36
  'Run `lino-i18n <command> --help` for command-specific options.',
37
37
  ].join('\n');
38
38
  }
39
39
 
40
40
  function commandHelp(command) {
41
+ if (command === 'extract') {
42
+ return 'Usage: lino-i18n extract --in <source file or directory> --out <directory> [--locale en] [--syntax js|vue|python] [--max-files 1000] [--max-bytes 10485760]';
43
+ }
44
+ if (command === 'translate-catalog') {
45
+ return 'Usage: lino-i18n translate-catalog --manifest <messages.json> --dir <catalogs> --locale <locale> --provider <module.mjs> --out <locale.lino>';
46
+ }
41
47
  if (command === 'convert') {
42
48
  return [
43
49
  'Usage: lino-i18n convert --in <path> --out <dir> [options]',
@@ -60,6 +66,8 @@ function commandHelp(command) {
60
66
  ' --dir <dir> Directory containing .lino files',
61
67
  ' --reference <locale> Reference locale to diff against (default: en)',
62
68
  ' --config <path> Read command defaults from a JSON config file',
69
+ ' --manifest <path> Validate ICU syntax and variables against extraction',
70
+ ' --previous-manifest <path> Flag stable ids whose source changed for review',
63
71
  ].join('\n');
64
72
  }
65
73
  if (command === 't') {
@@ -175,6 +183,27 @@ async function readJsonInput(inputPath) {
175
183
  return out;
176
184
  }
177
185
 
186
+ function convertInputs(inputs, requestedFormat, flags, err) {
187
+ const aggregated = {};
188
+ for (const { data, baseName } of inputs) {
189
+ const format = requestedFormat || detectFormat(data);
190
+ const convert = pickConverter(format);
191
+ if (!convert) {
192
+ err(`lino-i18n convert: no converter for format '${format}'`);
193
+ return null;
194
+ }
195
+ const result = convert(data, {
196
+ locale: flags.locale || baseName,
197
+ defaultLocale: flags.default || 'en',
198
+ });
199
+ for (const [locale, table] of Object.entries(result)) {
200
+ aggregated[locale] = { ...(aggregated[locale] || {}), ...table };
201
+ }
202
+ }
203
+
204
+ return aggregated;
205
+ }
206
+
178
207
  async function commandConvert(flags, log = console.log, err = console.error) {
179
208
  if (!flags.in || !flags.out) {
180
209
  err('lino-i18n convert: --in and --out are required');
@@ -196,21 +225,9 @@ async function commandConvert(flags, log = console.log, err = console.error) {
196
225
  return 1;
197
226
  }
198
227
 
199
- const aggregated = {};
200
- for (const { data, baseName } of inputs) {
201
- const format = requestedFormat || detectFormat(data);
202
- const convert = pickConverter(format);
203
- if (!convert) {
204
- err(`lino-i18n convert: no converter for format '${format}'`);
205
- return 1;
206
- }
207
- const result = convert(data, {
208
- locale: flags.locale || baseName,
209
- defaultLocale: flags.default || 'en',
210
- });
211
- for (const [locale, table] of Object.entries(result)) {
212
- aggregated[locale] = { ...(aggregated[locale] || {}), ...table };
213
- }
228
+ const aggregated = convertInputs(inputs, requestedFormat, flags, err);
229
+ if (!aggregated) {
230
+ return 1;
214
231
  }
215
232
 
216
233
  const singleFile = flagValue(flags, 'single-file', 'singleFile');
@@ -241,6 +258,15 @@ async function commandCheck(flags, log = console.log, err = console.error) {
241
258
  }
242
259
  const reference = flags.reference || 'en';
243
260
  const catalogues = await loadLocalesFromDirectory(flags.dir);
261
+ if (flags.manifest) {
262
+ const { checkManifest } = await import('../src/tooling-files.js');
263
+ return checkManifest(
264
+ flags.manifest,
265
+ catalogues,
266
+ log,
267
+ flags['previous-manifest']
268
+ );
269
+ }
244
270
  if (!catalogues[reference]) {
245
271
  err(
246
272
  `lino-i18n check: reference locale '${reference}' not found in ${flags.dir}`
@@ -253,18 +279,10 @@ async function commandCheck(flags, log = console.log, err = console.error) {
253
279
  if (locale === reference) {
254
280
  continue;
255
281
  }
256
- const missing = [];
257
- const unknown = [];
258
- for (const key of referenceKeys) {
259
- if (!Object.prototype.hasOwnProperty.call(table, key)) {
260
- missing.push(key);
261
- }
262
- }
263
- for (const key of Object.keys(table)) {
264
- if (!referenceKeys.has(key)) {
265
- unknown.push(key);
266
- }
267
- }
282
+ const missing = [...referenceKeys].filter(
283
+ (key) => !Object.prototype.hasOwnProperty.call(table, key)
284
+ );
285
+ const unknown = Object.keys(table).filter((key) => !referenceKeys.has(key));
268
286
  if (missing.length === 0 && unknown.length === 0) {
269
287
  continue;
270
288
  }
@@ -339,18 +357,33 @@ export async function runCli(argv, io = {}) {
339
357
  }
340
358
  const configuredFlags = await withConfig(command, flags);
341
359
  switch (command) {
360
+ case 'extract': {
361
+ const { commandExtract } = await import('../src/tooling-files.js');
362
+ return commandExtract(configuredFlags, log, err);
363
+ }
364
+ case 'translate-catalog': {
365
+ const { commandTranslateCatalog } =
366
+ await import('../src/tooling-files.js');
367
+ return commandTranslateCatalog(configuredFlags, log, err);
368
+ }
342
369
  case 'convert':
343
370
  return commandConvert(configuredFlags, log, err);
344
371
  case 'check':
345
372
  return commandCheck(configuredFlags, log, err);
346
373
  case 't':
347
- case 'translate':
348
374
  return commandTranslate(configuredFlags, positional, log, err);
349
375
  default:
350
- err(`Unknown command: ${command}`);
351
- err(usage());
352
- return 1;
376
+ return unknownCommand(command, configuredFlags, positional, log, err);
377
+ }
378
+ }
379
+
380
+ function unknownCommand(command, flags, rest, log, err) {
381
+ if (command === 'translate') {
382
+ return commandTranslate(flags, rest, log, err);
353
383
  }
384
+ err(`Unknown command: ${command}`);
385
+ err(usage());
386
+ return 1;
354
387
  }
355
388
 
356
389
  function isCliEntryPoint() {
package/package.json CHANGED
@@ -1,8 +1,9 @@
1
1
  {
2
2
  "name": "lino-i18n",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "Universal i18n library that stores translations in Links Notation (.lino) instead of JSON.",
5
5
  "type": "module",
6
+ "sideEffects": false,
6
7
  "main": "./src/index.js",
7
8
  "types": "./src/index.d.ts",
8
9
  "bin": {
@@ -22,23 +23,130 @@
22
23
  },
23
24
  "./converters": "./src/converters/index.js",
24
25
  "./loaders": "./src/loaders.js",
26
+ "./browser": {
27
+ "types": "./src/browser.d.ts",
28
+ "import": "./src/browser.js"
29
+ },
25
30
  "./react": {
26
31
  "types": "./src/react.d.ts",
27
32
  "import": "./src/react.js"
33
+ },
34
+ "./messages": {
35
+ "types": "./src/messages.d.ts",
36
+ "import": "./src/messages.js"
37
+ },
38
+ "./intl": {
39
+ "types": "./src/intl.d.ts",
40
+ "import": "./src/intl.js"
41
+ },
42
+ "./server": {
43
+ "types": "./src/server.d.ts",
44
+ "import": "./src/server.js"
45
+ },
46
+ "./react-server": {
47
+ "types": "./src/react-server.d.ts",
48
+ "import": "./src/react-server.js"
49
+ },
50
+ "./node": {
51
+ "types": "./src/node.d.ts",
52
+ "import": "./src/node.js"
53
+ },
54
+ "./tooling": {
55
+ "types": "./src/tooling.d.ts",
56
+ "import": "./src/tooling.js"
57
+ },
58
+ "./compiler": {
59
+ "types": "./src/compiler.d.ts",
60
+ "import": "./src/compiler.js"
61
+ },
62
+ "./providers/gt": {
63
+ "types": "./src/providers/gt.d.ts",
64
+ "import": "./src/providers/gt.js"
65
+ },
66
+ "./next/server": {
67
+ "types": "./src/next/server.d.ts",
68
+ "import": "./src/next/server.js"
69
+ },
70
+ "./next/client": {
71
+ "types": "./src/next/client.d.ts",
72
+ "import": "./src/next/client.js"
73
+ },
74
+ "./next/proxy": {
75
+ "types": "./src/next/proxy.d.ts",
76
+ "import": "./src/next/proxy.js"
77
+ },
78
+ "./vue": {
79
+ "types": "./src/vue.d.ts",
80
+ "import": "./src/vue.js"
81
+ },
82
+ "./vue/extract": {
83
+ "types": "./src/vue-extract.d.ts",
84
+ "import": "./src/vue-extract.js"
85
+ },
86
+ "./python/extract": {
87
+ "types": "./src/python-extract.d.ts",
88
+ "import": "./src/python-extract.js"
89
+ },
90
+ "./remark": {
91
+ "types": "./src/remark.d.ts",
92
+ "import": "./src/remark.js"
93
+ },
94
+ "./providers/gt-locales": {
95
+ "types": "./src/providers/gt-locales.d.ts",
96
+ "import": "./src/providers/gt-locales.js"
97
+ },
98
+ "./react-native": {
99
+ "types": "./src/react-native.d.ts",
100
+ "import": "./src/react-native.js"
101
+ },
102
+ "./tanstack-start/server": {
103
+ "types": "./src/tanstack-start/server.d.ts",
104
+ "import": "./src/tanstack-start/server.js"
105
+ },
106
+ "./tanstack-start/client": {
107
+ "types": "./src/tanstack-start/client.d.ts",
108
+ "import": "./src/tanstack-start/client.js"
109
+ },
110
+ "./rrweb": {
111
+ "types": "./src/rrweb/index.d.ts",
112
+ "import": "./src/rrweb/index.js"
113
+ },
114
+ "./rrweb/catalog": {
115
+ "types": "./src/rrweb/catalog.d.ts",
116
+ "import": "./src/rrweb/catalog.js"
117
+ },
118
+ "./rrweb/harvest": {
119
+ "types": "./src/rrweb/harvest.d.ts",
120
+ "import": "./src/rrweb/harvest.js"
121
+ },
122
+ "./rrweb/replay": {
123
+ "types": "./src/rrweb/replay.d.ts",
124
+ "import": "./src/rrweb/replay.js"
125
+ },
126
+ "./eslint": {
127
+ "types": "./src/eslint.d.ts",
128
+ "import": "./src/eslint.js"
28
129
  }
29
130
  },
30
131
  "scripts": {
31
- "test": "node --test --test-timeout=30000 tests/*.test.js",
32
- "lint": "eslint .",
132
+ "test": "node --throw-deprecation --test --test-timeout=30000 tests/*.test.js",
133
+ "test:browser": "playwright test",
134
+ "test:types": "tsc --project tests/types/tsconfig.json && tsc --project tests/types/tsconfig.next.json && tsc --project tests/types/tsconfig.native.json && tsc --project tests/types/tsconfig.tanstack.json && tsc --project tests/types/tsconfig.rrweb.json",
135
+ "lint": "eslint . --max-warnings 0",
33
136
  "lint:fix": "eslint . --fix",
34
137
  "format": "prettier --write .",
35
138
  "format:check": "prettier --check .",
36
- "check:duplication": "jscpd .",
139
+ "check:duplication": "jscpd --fail-on-empty .",
37
140
  "check": "npm run lint && npm run format:check && npm run check:duplication",
38
141
  "changeset": "changeset",
39
- "changeset:version": "changeset version",
142
+ "changeset:version": "node scripts/changeset-version.mjs",
40
143
  "changeset:publish": "changeset publish",
41
- "pack:dry-run": "npm pack --dry-run"
144
+ "pack:dry-run": "npm pack --dry-run",
145
+ "lint:secrets": "secretlint \"bin/**\" \"src/**\" \"scripts/**\" \"tests/**\" \"../scripts/**\" \"../rust/scripts/**\" \"../rust/lino-i18n/src/**\" \"../rust/lino-i18n/tests/**\" \"../rust/lino-i18n-macros/src/**\" \"../.github/**\" \"../.githooks/**\"",
146
+ "test:next": "playwright test --config playwright-next.config.js",
147
+ "build:next": "next build examples/next-usage --webpack",
148
+ "build:tanstack": "vite build --config examples/tanstack-usage/vite.config.js",
149
+ "test:tanstack": "playwright test --config playwright-tanstack.config.js"
42
150
  },
43
151
  "keywords": [
44
152
  "i18n",
@@ -63,33 +171,131 @@
63
171
  "provenance": true
64
172
  },
65
173
  "engines": {
66
- "node": ">=20.0.0"
174
+ "node": ">=22.11.0"
67
175
  },
68
176
  "dependencies": {
69
- "links-notation": "^0.13.0",
177
+ "@babel/generator": "^7.29.8",
178
+ "@babel/parser": "^7.29.9",
179
+ "@babel/traverse": "^7.29.10",
180
+ "@babel/types": "^7.29.8",
181
+ "@formatjs/icu-messageformat-parser": "^3.5.21",
182
+ "intl-messageformat": "^12.1.3",
183
+ "links-notation": "^0.23.0",
70
184
  "lino-arguments": "^0.3.0",
71
- "lino-objects-codec": "^0.4.0"
185
+ "lino-objects-codec": "^0.9.0"
72
186
  },
73
187
  "devDependencies": {
74
- "@changesets/cli": "^2.31.0",
188
+ "@babel/core": "^8.0.7",
189
+ "@babel/eslint-parser": "^8.0.7",
190
+ "@changesets/cli": "^3.0.3",
75
191
  "@eslint/js": "^10.0.1",
76
- "@types/node": "^26.1.1",
77
- "@types/react": "^19.2.17",
78
- "eslint": "^10.4.0",
192
+ "@generaltranslation/supported-locales": "2.1.41",
193
+ "@playwright/test": "^1.64.0",
194
+ "@rrweb/record": "2.1.7",
195
+ "@rrweb/replay": "2.1.7",
196
+ "@rrweb/types": "2.1.7",
197
+ "@secretlint/secretlint-rule-preset-recommend": "^13.0.7",
198
+ "@tanstack/react-router": "1.170.41",
199
+ "@tanstack/react-start": "1.168.60",
200
+ "@testing-library/react": "^16.3.3",
201
+ "@types/eslint": "^9.6.1",
202
+ "@types/node": "^26.6.4",
203
+ "@types/react": "^19.3.0",
204
+ "@vitejs/plugin-react": "6.1.2",
205
+ "@vue/compiler-sfc": "3.5.43",
206
+ "@vue/server-renderer": "3.5.43",
207
+ "esbuild": "^0.28.2",
208
+ "eslint": "^10.12.0",
79
209
  "eslint-config-prettier": "^10.1.8",
80
- "eslint-plugin-prettier": "^5.5.5",
81
- "jscpd": "^4.2.2",
82
- "prettier": "^3.8.3",
83
- "react": "^19.1.1",
84
- "react-test-renderer": "^19.1.1",
85
- "test-anywhere": "^0.9.1"
210
+ "eslint-plugin-prettier": "^5.5.6",
211
+ "eslint9": "npm:eslint@^9.39.5",
212
+ "generaltranslation": "9.5.5",
213
+ "gt-remark": "1.0.12",
214
+ "gt-rrweb": "0.2.0",
215
+ "jscpd": "^5.4.0",
216
+ "jsdom": "^30.1.2",
217
+ "next": "16.4.0",
218
+ "prettier": "^3.9.9",
219
+ "react": "^19.3.0",
220
+ "react-dom": "^19.3.0",
221
+ "react-native-web": "0.21.4",
222
+ "remark-mdx": "3.1.1",
223
+ "remark-parse": "11.0.0",
224
+ "remark-stringify": "11.0.0",
225
+ "rollup": "^4.64.2",
226
+ "secretlint": "^13.0.7",
227
+ "srvx": "0.11.22",
228
+ "test-anywhere": "^0.9.1",
229
+ "typescript": "^7.0.2",
230
+ "unified": "11.0.5",
231
+ "vite": "8.3.4",
232
+ "vue": "3.5.43"
86
233
  },
87
234
  "peerDependencies": {
88
- "react": ">=18.0.0"
235
+ "@generaltranslation/supported-locales": ">=2.1.41 <3",
236
+ "@rrweb/record": ">=2.1 <3",
237
+ "@rrweb/replay": ">=2.1 <3",
238
+ "@rrweb/types": ">=2.1 <3",
239
+ "@tanstack/react-router": ">=1.170 <2",
240
+ "@tanstack/react-start": ">=1.168 <2",
241
+ "@vue/compiler-sfc": ">=3.5 <4",
242
+ "eslint": ">=9 <11",
243
+ "generaltranslation": ">=9.5.5 <10",
244
+ "gt-remark": ">=1.0.12 <2",
245
+ "gt-rrweb": ">=0.2 <0.3",
246
+ "next": ">=16 <17",
247
+ "react": ">=18.0.0",
248
+ "react-dom": ">=18",
249
+ "vue": ">=3.5 <4"
89
250
  },
90
251
  "peerDependenciesMeta": {
252
+ "next": {
253
+ "optional": true
254
+ },
255
+ "generaltranslation": {
256
+ "optional": true
257
+ },
91
258
  "react": {
92
259
  "optional": true
260
+ },
261
+ "vue": {
262
+ "optional": true
263
+ },
264
+ "@vue/compiler-sfc": {
265
+ "optional": true
266
+ },
267
+ "gt-remark": {
268
+ "optional": true
269
+ },
270
+ "@generaltranslation/supported-locales": {
271
+ "optional": true
272
+ },
273
+ "@tanstack/react-start": {
274
+ "optional": true
275
+ },
276
+ "@tanstack/react-router": {
277
+ "optional": true
278
+ },
279
+ "gt-rrweb": {
280
+ "optional": true
281
+ },
282
+ "@rrweb/record": {
283
+ "optional": true
284
+ },
285
+ "@rrweb/replay": {
286
+ "optional": true
287
+ },
288
+ "@rrweb/types": {
289
+ "optional": true
290
+ },
291
+ "react-dom": {
292
+ "optional": true
293
+ },
294
+ "eslint": {
295
+ "optional": true
93
296
  }
297
+ },
298
+ "allowScripts": {
299
+ "esbuild@0.28.2": true
94
300
  }
95
301
  }