@translation-cms/sync 1.2.1 → 1.2.3

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 (161) hide show
  1. package/dist/bin.d.ts +25 -0
  2. package/dist/bin.d.ts.map +1 -0
  3. package/dist/bin.js +173 -0
  4. package/dist/bin.js.map +1 -0
  5. package/dist/commands/init.d.ts +2 -0
  6. package/dist/commands/init.d.ts.map +1 -0
  7. package/dist/commands/init.js +68 -0
  8. package/dist/commands/init.js.map +1 -0
  9. package/dist/commands/pull.d.ts +3 -0
  10. package/dist/commands/pull.d.ts.map +1 -0
  11. package/dist/commands/pull.js +22 -0
  12. package/dist/commands/pull.js.map +1 -0
  13. package/dist/commands/status.d.ts +3 -0
  14. package/dist/commands/status.d.ts.map +1 -0
  15. package/dist/commands/status.js +46 -0
  16. package/dist/commands/status.js.map +1 -0
  17. package/dist/commands/sync.d.ts +10 -0
  18. package/dist/commands/sync.d.ts.map +1 -0
  19. package/dist/commands/sync.js +20 -0
  20. package/dist/commands/sync.js.map +1 -0
  21. package/dist/commands/watch.d.ts +4 -0
  22. package/dist/commands/watch.d.ts.map +1 -0
  23. package/dist/commands/watch.js +51 -0
  24. package/dist/commands/watch.js.map +1 -0
  25. package/dist/{load-config.d.ts → config/resolve-config.d.ts} +13 -10
  26. package/dist/config/resolve-config.d.ts.map +1 -0
  27. package/dist/{resolve-config.js → config/resolve-config.js} +21 -0
  28. package/dist/config/resolve-config.js.map +1 -0
  29. package/dist/core/api-internals/helpers.d.ts +9 -0
  30. package/dist/core/api-internals/helpers.d.ts.map +1 -0
  31. package/dist/core/api-internals/helpers.js +14 -0
  32. package/dist/core/api-internals/helpers.js.map +1 -0
  33. package/dist/core/api-internals/pull.d.ts +11 -0
  34. package/dist/core/api-internals/pull.d.ts.map +1 -0
  35. package/dist/core/api-internals/pull.js +124 -0
  36. package/dist/core/api-internals/pull.js.map +1 -0
  37. package/dist/core/api-internals/route-config.d.ts +13 -0
  38. package/dist/core/api-internals/route-config.d.ts.map +1 -0
  39. package/dist/core/api-internals/route-config.js +34 -0
  40. package/dist/core/api-internals/route-config.js.map +1 -0
  41. package/dist/core/api-internals/sync.d.ts +12 -0
  42. package/dist/core/api-internals/sync.d.ts.map +1 -0
  43. package/dist/core/api-internals/sync.js +95 -0
  44. package/dist/core/api-internals/sync.js.map +1 -0
  45. package/dist/core/api-internals/types.d.ts +25 -0
  46. package/dist/core/api-internals/types.d.ts.map +1 -0
  47. package/dist/core/api-internals/types.js +5 -0
  48. package/dist/core/api-internals/types.js.map +1 -0
  49. package/dist/core/api.d.ts +11 -0
  50. package/dist/core/api.d.ts.map +1 -0
  51. package/dist/core/api.js +11 -0
  52. package/dist/core/api.js.map +1 -0
  53. package/dist/{sync.d.ts → core/cache.d.ts} +5 -33
  54. package/dist/core/cache.d.ts.map +1 -0
  55. package/dist/core/cache.js +143 -0
  56. package/dist/core/cache.js.map +1 -0
  57. package/dist/core/scanner-internals/ast.d.ts +22 -0
  58. package/dist/core/scanner-internals/ast.d.ts.map +1 -0
  59. package/dist/core/scanner-internals/ast.js +80 -0
  60. package/dist/core/scanner-internals/ast.js.map +1 -0
  61. package/dist/core/scanner-internals/file-walker.d.ts +9 -0
  62. package/dist/core/scanner-internals/file-walker.d.ts.map +1 -0
  63. package/dist/core/scanner-internals/file-walker.js +25 -0
  64. package/dist/core/scanner-internals/file-walker.js.map +1 -0
  65. package/dist/core/scanner-internals/import-resolver.d.ts +13 -0
  66. package/dist/core/scanner-internals/import-resolver.d.ts.map +1 -0
  67. package/dist/core/scanner-internals/import-resolver.js +124 -0
  68. package/dist/core/scanner-internals/import-resolver.js.map +1 -0
  69. package/dist/core/scanner-internals/key-extractor.d.ts +16 -0
  70. package/dist/core/scanner-internals/key-extractor.d.ts.map +1 -0
  71. package/dist/core/scanner-internals/key-extractor.js +168 -0
  72. package/dist/core/scanner-internals/key-extractor.js.map +1 -0
  73. package/dist/core/scanner-internals/route-detector.d.ts +19 -0
  74. package/dist/core/scanner-internals/route-detector.d.ts.map +1 -0
  75. package/dist/core/scanner-internals/route-detector.js +74 -0
  76. package/dist/core/scanner-internals/route-detector.js.map +1 -0
  77. package/dist/core/scanner-internals/types.d.ts +53 -0
  78. package/dist/core/scanner-internals/types.d.ts.map +1 -0
  79. package/dist/core/scanner-internals/types.js +29 -0
  80. package/dist/core/scanner-internals/types.js.map +1 -0
  81. package/dist/core/scanner.d.ts +20 -0
  82. package/dist/core/scanner.d.ts.map +1 -0
  83. package/dist/core/scanner.js +113 -0
  84. package/dist/core/scanner.js.map +1 -0
  85. package/dist/index.d.ts +2 -2
  86. package/dist/index.d.ts.map +1 -1
  87. package/dist/index.js +2 -2
  88. package/dist/index.js.map +1 -1
  89. package/dist/preview/index.d.ts +38 -0
  90. package/dist/preview/index.d.ts.map +1 -0
  91. package/dist/preview/index.js +114 -0
  92. package/dist/preview/index.js.map +1 -0
  93. package/dist/preview/internals/highlight.d.ts +22 -0
  94. package/dist/preview/internals/highlight.d.ts.map +1 -0
  95. package/dist/preview/internals/highlight.js +153 -0
  96. package/dist/preview/internals/highlight.js.map +1 -0
  97. package/dist/preview/internals/interactions.d.ts +15 -0
  98. package/dist/preview/internals/interactions.d.ts.map +1 -0
  99. package/dist/preview/internals/interactions.js +38 -0
  100. package/dist/preview/internals/interactions.js.map +1 -0
  101. package/dist/preview/internals/locales.d.ts +9 -0
  102. package/dist/preview/internals/locales.d.ts.map +1 -0
  103. package/dist/preview/internals/locales.js +24 -0
  104. package/dist/preview/internals/locales.js.map +1 -0
  105. package/dist/preview/internals/state.d.ts +35 -0
  106. package/dist/preview/internals/state.d.ts.map +1 -0
  107. package/dist/preview/internals/state.js +65 -0
  108. package/dist/preview/internals/state.js.map +1 -0
  109. package/dist/preview/internals/styles.d.ts +8 -0
  110. package/dist/preview/internals/styles.d.ts.map +1 -0
  111. package/dist/preview/internals/styles.js +28 -0
  112. package/dist/preview/internals/styles.js.map +1 -0
  113. package/dist/preview/internals/types.d.ts +49 -0
  114. package/dist/preview/internals/types.d.ts.map +1 -0
  115. package/dist/preview/internals/types.js +5 -0
  116. package/dist/preview/internals/types.js.map +1 -0
  117. package/dist/scaffold/index.d.ts +3 -0
  118. package/dist/scaffold/index.d.ts.map +1 -0
  119. package/dist/scaffold/index.js +3 -0
  120. package/dist/scaffold/index.js.map +1 -0
  121. package/dist/scaffold/intenrals/scaffold.d.ts +7 -0
  122. package/dist/scaffold/intenrals/scaffold.d.ts.map +1 -0
  123. package/dist/scaffold/intenrals/scaffold.js +34 -0
  124. package/dist/scaffold/intenrals/scaffold.js.map +1 -0
  125. package/dist/scaffold/intenrals/templates.d.ts +10 -0
  126. package/dist/scaffold/intenrals/templates.d.ts.map +1 -0
  127. package/dist/{scaffold.js → scaffold/intenrals/templates.js} +10 -38
  128. package/dist/scaffold/intenrals/templates.js.map +1 -0
  129. package/dist/{scaffold.d.ts → scaffold/intenrals/types.d.ts} +4 -2
  130. package/dist/scaffold/intenrals/types.d.ts.map +1 -0
  131. package/dist/scaffold/intenrals/types.js +5 -0
  132. package/dist/scaffold/intenrals/types.js.map +1 -0
  133. package/package.json +7 -7
  134. package/schema.json +64 -0
  135. package/dist/cli-entry.d.ts +0 -3
  136. package/dist/cli-entry.d.ts.map +0 -1
  137. package/dist/cli-entry.js +0 -390
  138. package/dist/cli-entry.js.map +0 -1
  139. package/dist/cli.d.ts +0 -16
  140. package/dist/cli.d.ts.map +0 -1
  141. package/dist/cli.js +0 -16
  142. package/dist/cli.js.map +0 -1
  143. package/dist/load-config.d.ts.map +0 -1
  144. package/dist/load-config.js +0 -24
  145. package/dist/load-config.js.map +0 -1
  146. package/dist/preview.d.ts +0 -88
  147. package/dist/preview.d.ts.map +0 -1
  148. package/dist/preview.js +0 -461
  149. package/dist/preview.js.map +0 -1
  150. package/dist/resolve-config.d.ts +0 -15
  151. package/dist/resolve-config.d.ts.map +0 -1
  152. package/dist/resolve-config.js.map +0 -1
  153. package/dist/scaffold.d.ts.map +0 -1
  154. package/dist/scaffold.js.map +0 -1
  155. package/dist/scanner.d.ts +0 -77
  156. package/dist/scanner.d.ts.map +0 -1
  157. package/dist/scanner.js +0 -555
  158. package/dist/scanner.js.map +0 -1
  159. package/dist/sync.d.ts.map +0 -1
  160. package/dist/sync.js +0 -383
  161. package/dist/sync.js.map +0 -1
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Locale switching logic for preview listener.
3
+ */
4
+ import * as state from './state.js';
5
+ /**
6
+ * Handle a locale switch request from the CMS.
7
+ * Tries the provided callback first, then falls back to window.__cmsSetLocale.
8
+ */
9
+ export function handleLocaleSwitch(locale) {
10
+ console.log(`[CMS Preview] Switching locale to: ${locale}`);
11
+ if (state.opts.onLocaleSwitch) {
12
+ state.opts.onLocaleSwitch(locale);
13
+ return;
14
+ }
15
+ // Fallback: look for window.__cmsSetLocale (set by the consuming app)
16
+ const globalObj = globalThis;
17
+ if (typeof globalObj['__cmsSetLocale'] === 'function') {
18
+ globalObj['__cmsSetLocale'](locale);
19
+ return;
20
+ }
21
+ console.warn('[CMS Preview] No locale switch handler found. ' +
22
+ 'Provide onLocaleSwitch option or expose window.__cmsSetLocale(locale).');
23
+ }
24
+ //# sourceMappingURL=locales.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"locales.js","sourceRoot":"","sources":["../../../src/preview/internals/locales.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,KAAK,MAAM,YAAY,CAAC;AAEpC;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAc;IAC7C,OAAO,CAAC,GAAG,CAAC,sCAAsC,MAAM,EAAE,CAAC,CAAC;IAE5D,IAAI,KAAK,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC;QAC5B,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;QAClC,OAAO;IACX,CAAC;IAED,sEAAsE;IACtE,MAAM,SAAS,GAAG,UAAqC,CAAC;IACxD,IAAI,OAAO,SAAS,CAAC,gBAAgB,CAAC,KAAK,UAAU,EAAE,CAAC;QACnD,SAAS,CAAC,gBAAgB,CAAyB,CAAC,MAAM,CAAC,CAAC;QAC7D,OAAO;IACX,CAAC;IAED,OAAO,CAAC,IAAI,CACR,gDAAgD;QAC5C,wEAAwE,CAC/E,CAAC;AACN,CAAC"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * State management for preview listener.
3
+ */
4
+ import type { PreviewListenerOptions } from './types.js';
5
+ export declare let isInitialized: boolean;
6
+ export declare let highlightedElements: HTMLElement[];
7
+ export declare let opts: PreviewListenerOptions;
8
+ export declare let currentLiveValue: string | null;
9
+ export declare let currentSearchValue: string | null;
10
+ export declare let activeLocale: string | null;
11
+ export declare let interactionBlockerOverlay: HTMLDivElement | null;
12
+ export declare let pendingHighlight: {
13
+ key: string;
14
+ value: string;
15
+ } | null;
16
+ /**
17
+ * Reset all state when cleaning up.
18
+ */
19
+ export declare function resetState(): void;
20
+ /**
21
+ * Initialize state with global values.
22
+ */
23
+ export declare function initializeState(options: PreviewListenerOptions): void;
24
+ export declare function setIsInitialized(value: boolean): void;
25
+ export declare function setActiveLocale(value: string | null): void;
26
+ export declare function setCurrentLiveValue(value: string | null): void;
27
+ export declare function setPendingHighlight(value: {
28
+ key: string;
29
+ value: string;
30
+ } | null): void;
31
+ export declare function setCurrentSearchValue(value: string | null): void;
32
+ export declare function setHighlightedElements(value: HTMLElement[]): void;
33
+ export declare function addHighlightedElement(el: HTMLElement): void;
34
+ export declare function setInteractionBlockerOverlay(value: HTMLDivElement | null): void;
35
+ //# sourceMappingURL=state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../src/preview/internals/state.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAEzD,eAAO,IAAI,aAAa,SAAQ,CAAC;AACjC,eAAO,IAAI,mBAAmB,EAAE,WAAW,EAAO,CAAC;AACnD,eAAO,IAAI,IAAI,EAAE,sBAA2B,CAAC;AAC7C,eAAO,IAAI,gBAAgB,EAAE,MAAM,GAAG,IAAW,CAAC;AAClD,eAAO,IAAI,kBAAkB,EAAE,MAAM,GAAG,IAAW,CAAC;AACpD,eAAO,IAAI,YAAY,EAAE,MAAM,GAAG,IAAW,CAAC;AAC9C,eAAO,IAAI,yBAAyB,EAAE,cAAc,GAAG,IAAW,CAAC;AACnE,eAAO,IAAI,gBAAgB,EAAE;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACjB,GAAG,IAAW,CAAC;AAEhB;;GAEG;AACH,wBAAgB,UAAU,IAAI,IAAI,CASjC;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,sBAAsB,GAAG,IAAI,CAUrE;AAGD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAErD;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAE1D;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAE9D;AAED,wBAAgB,mBAAmB,CAC/B,KAAK,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,GAC7C,IAAI,CAEN;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAEhE;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,IAAI,CAEjE;AAED,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,WAAW,GAAG,IAAI,CAE3D;AAED,wBAAgB,4BAA4B,CACxC,KAAK,EAAE,cAAc,GAAG,IAAI,GAC7B,IAAI,CAEN"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * State management for preview listener.
3
+ */
4
+ export let isInitialized = false;
5
+ export let highlightedElements = [];
6
+ export let opts = {};
7
+ export let currentLiveValue = null;
8
+ export let currentSearchValue = null;
9
+ export let activeLocale = null;
10
+ export let interactionBlockerOverlay = null;
11
+ export let pendingHighlight = null;
12
+ /**
13
+ * Reset all state when cleaning up.
14
+ */
15
+ export function resetState() {
16
+ isInitialized = false;
17
+ highlightedElements = [];
18
+ opts = {};
19
+ currentLiveValue = null;
20
+ currentSearchValue = null;
21
+ activeLocale = null;
22
+ interactionBlockerOverlay = null;
23
+ pendingHighlight = null;
24
+ }
25
+ /**
26
+ * Initialize state with global values.
27
+ */
28
+ export function initializeState(options) {
29
+ opts = options;
30
+ // Seed activeLocale from the URL's ?locale= param so that the first
31
+ // CMS_HIGHLIGHT_KEY doesn't needlessly trigger a locale switch (and
32
+ // re-render) when the iframe already loaded with the correct locale.
33
+ try {
34
+ activeLocale = new URL(window.location.href).searchParams.get('locale');
35
+ }
36
+ catch {
37
+ activeLocale = null;
38
+ }
39
+ }
40
+ // Setter functions for accessing from different modules
41
+ export function setIsInitialized(value) {
42
+ isInitialized = value;
43
+ }
44
+ export function setActiveLocale(value) {
45
+ activeLocale = value;
46
+ }
47
+ export function setCurrentLiveValue(value) {
48
+ currentLiveValue = value;
49
+ }
50
+ export function setPendingHighlight(value) {
51
+ pendingHighlight = value;
52
+ }
53
+ export function setCurrentSearchValue(value) {
54
+ currentSearchValue = value;
55
+ }
56
+ export function setHighlightedElements(value) {
57
+ highlightedElements = value;
58
+ }
59
+ export function addHighlightedElement(el) {
60
+ highlightedElements.push(el);
61
+ }
62
+ export function setInteractionBlockerOverlay(value) {
63
+ interactionBlockerOverlay = value;
64
+ }
65
+ //# sourceMappingURL=state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.js","sourceRoot":"","sources":["../../../src/preview/internals/state.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,MAAM,CAAC,IAAI,aAAa,GAAG,KAAK,CAAC;AACjC,MAAM,CAAC,IAAI,mBAAmB,GAAkB,EAAE,CAAC;AACnD,MAAM,CAAC,IAAI,IAAI,GAA2B,EAAE,CAAC;AAC7C,MAAM,CAAC,IAAI,gBAAgB,GAAkB,IAAI,CAAC;AAClD,MAAM,CAAC,IAAI,kBAAkB,GAAkB,IAAI,CAAC;AACpD,MAAM,CAAC,IAAI,YAAY,GAAkB,IAAI,CAAC;AAC9C,MAAM,CAAC,IAAI,yBAAyB,GAA0B,IAAI,CAAC;AACnE,MAAM,CAAC,IAAI,gBAAgB,GAGhB,IAAI,CAAC;AAEhB;;GAEG;AACH,MAAM,UAAU,UAAU;IACtB,aAAa,GAAG,KAAK,CAAC;IACtB,mBAAmB,GAAG,EAAE,CAAC;IACzB,IAAI,GAAG,EAAE,CAAC;IACV,gBAAgB,GAAG,IAAI,CAAC;IACxB,kBAAkB,GAAG,IAAI,CAAC;IAC1B,YAAY,GAAG,IAAI,CAAC;IACpB,yBAAyB,GAAG,IAAI,CAAC;IACjC,gBAAgB,GAAG,IAAI,CAAC;AAC5B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,OAA+B;IAC3D,IAAI,GAAG,OAAO,CAAC;IACf,oEAAoE;IACpE,oEAAoE;IACpE,qEAAqE;IACrE,IAAI,CAAC;QACD,YAAY,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC5E,CAAC;IAAC,MAAM,CAAC;QACL,YAAY,GAAG,IAAI,CAAC;IACxB,CAAC;AACL,CAAC;AAED,wDAAwD;AACxD,MAAM,UAAU,gBAAgB,CAAC,KAAc;IAC3C,aAAa,GAAG,KAAK,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAAoB;IAChD,YAAY,GAAG,KAAK,CAAC;AACzB,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,KAAoB;IACpD,gBAAgB,GAAG,KAAK,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,mBAAmB,CAC/B,KAA4C;IAE5C,gBAAgB,GAAG,KAAK,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,KAAoB;IACtD,kBAAkB,GAAG,KAAK,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,KAAoB;IACvD,mBAAmB,GAAG,KAAK,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,EAAe;IACjD,mBAAmB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACjC,CAAC;AAED,MAAM,UAAU,4BAA4B,CACxC,KAA4B;IAE5B,yBAAyB,GAAG,KAAK,CAAC;AACtC,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * CSS styles for preview highlight elements.
3
+ */
4
+ /**
5
+ * Inject highlight styles into the document.
6
+ */
7
+ export declare function injectStyles(): void;
8
+ //# sourceMappingURL=styles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../../../src/preview/internals/styles.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH;;GAEG;AACH,wBAAgB,YAAY,IAAI,IAAI,CAoBnC"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * CSS styles for preview highlight elements.
3
+ */
4
+ import * as state from './state.js';
5
+ /**
6
+ * Inject highlight styles into the document.
7
+ */
8
+ export function injectStyles() {
9
+ const custom = state.opts.highlightStyles ?? {};
10
+ const outline = custom.outline ?? '2px solid #3B82F6';
11
+ const outlineOffset = custom.outlineOffset ?? '3px';
12
+ const borderRadius = custom.borderRadius ?? '3px';
13
+ const backgroundColor = custom.backgroundColor ?? 'transparent';
14
+ const style = document.createElement('style');
15
+ style.textContent = `
16
+ .cms-preview-highlight {
17
+ outline: ${outline} !important;
18
+ outline-offset: ${outlineOffset} !important;
19
+ border-radius: ${borderRadius};
20
+ background-color: ${backgroundColor};
21
+ position: relative;
22
+ z-index: 9999;
23
+ transition: outline 0.15s ease;
24
+ }
25
+ `;
26
+ document.head.appendChild(style);
27
+ }
28
+ //# sourceMappingURL=styles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"styles.js","sourceRoot":"","sources":["../../../src/preview/internals/styles.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,KAAK,MAAM,YAAY,CAAC;AAEpC;;GAEG;AACH,MAAM,UAAU,YAAY;IACxB,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,eAAe,IAAI,EAAE,CAAC;IAChD,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,mBAAmB,CAAC;IACtD,MAAM,aAAa,GAAG,MAAM,CAAC,aAAa,IAAI,KAAK,CAAC;IACpD,MAAM,YAAY,GAAG,MAAM,CAAC,YAAY,IAAI,KAAK,CAAC;IAClD,MAAM,eAAe,GAAG,MAAM,CAAC,eAAe,IAAI,aAAa,CAAC;IAEhE,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IAC9C,KAAK,CAAC,WAAW,GAAG;;uBAED,OAAO;8BACA,aAAa;6BACd,YAAY;gCACT,eAAe;;;;;KAK1C,CAAC;IACF,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;AACrC,CAAC"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Message types and public API types for preview listener.
3
+ */
4
+ export interface CMSHighlightMessage {
5
+ type: 'CMS_HIGHLIGHT_KEY';
6
+ key: string;
7
+ value: string;
8
+ locale: string;
9
+ }
10
+ export interface CMSLiveUpdateMessage {
11
+ type: 'CMS_LIVE_UPDATE';
12
+ oldValue: string;
13
+ newValue: string;
14
+ }
15
+ /**
16
+ * Switch the active locale without reloading the page.
17
+ * Requires your app to expose a `window.__cmsSetLocale(locale)` callback.
18
+ * The CMS sends this when the user changes locale in the preview toolbar.
19
+ */
20
+ export interface CMSSwitchLocaleMessage {
21
+ type: 'CMS_SWITCH_LOCALE';
22
+ locale: string;
23
+ }
24
+ export interface PreviewListenerOptions {
25
+ /**
26
+ * Custom CSS to apply to highlighted elements.
27
+ * If not provided, uses default blue outline.
28
+ */
29
+ highlightStyles?: {
30
+ outline?: string;
31
+ outlineOffset?: string;
32
+ borderRadius?: string;
33
+ backgroundColor?: string;
34
+ };
35
+ /**
36
+ * Called when the CMS requests a locale switch.
37
+ * Use this to integrate with your i18n library:
38
+ *
39
+ * ```ts
40
+ * initPreviewListener({
41
+ * onLocaleSwitch: (locale) => i18n.changeLanguage(locale),
42
+ * });
43
+ * ```
44
+ *
45
+ * When omitted, the listener looks for `window.__cmsSetLocale(locale)`.
46
+ */
47
+ onLocaleSwitch?: (locale: string) => void;
48
+ }
49
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/preview/internals/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,MAAM,WAAW,mBAAmB;IAChC,IAAI,EAAE,mBAAmB,CAAC;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,oBAAoB;IACjC,IAAI,EAAE,iBAAiB,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED;;;;GAIG;AACH,MAAM,WAAW,sBAAsB;IACnC,IAAI,EAAE,mBAAmB,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;CAClB;AAMD,MAAM,WAAW,sBAAsB;IACnC;;;OAGG;IACH,eAAe,CAAC,EAAE;QACd,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,eAAe,CAAC,EAAE,MAAM,CAAC;KAC5B,CAAC;IACF;;;;;;;;;;;OAWG;IACH,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7C"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Message types and public API types for preview listener.
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/preview/internals/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,3 @@
1
+ export { scaffoldI18n } from './intenrals/scaffold.js';
2
+ export type { ScaffoldOptions, ScaffoldResult } from './intenrals/types.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/scaffold/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,3 @@
1
+ // Re-export public API
2
+ export { scaffoldI18n } from './intenrals/scaffold.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/scaffold/index.ts"],"names":[],"mappings":"AAAA,uBAAuB;AACvB,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * i18n scaffolding logic.
3
+ * Creates i18n configuration files and dictionary placeholders.
4
+ */
5
+ import { ScaffoldOptions, ScaffoldResult } from './types.js';
6
+ export declare function scaffoldI18n(opts: ScaffoldOptions): ScaffoldResult;
7
+ //# sourceMappingURL=scaffold.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../../../src/scaffold/intenrals/scaffold.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAYH,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE7D,wBAAgB,YAAY,CAAC,IAAI,EAAE,eAAe,GAAG,cAAc,CA8BlE"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * i18n scaffolding logic.
3
+ * Creates i18n configuration files and dictionary placeholders.
4
+ */
5
+ import fs from 'fs';
6
+ import path from 'path';
7
+ import { SETTINGS_TS, TYPES_TS, CLIENT_TS, SERVER_TS, PROVIDER_TSX, PLACEHOLDER_DICT, } from './templates.js';
8
+ export function scaffoldI18n(opts) {
9
+ const { i18nDir, overwrite = false } = opts;
10
+ const dictsDir = path.join(i18nDir, 'dictionaries');
11
+ fs.mkdirSync(dictsDir, { recursive: true });
12
+ const files = [
13
+ { rel: 'settings.ts', content: SETTINGS_TS },
14
+ { rel: 'types.ts', content: TYPES_TS },
15
+ { rel: 'client.ts', content: CLIENT_TS },
16
+ { rel: 'server.ts', content: SERVER_TS },
17
+ { rel: 'provider.tsx', content: PROVIDER_TSX },
18
+ { rel: 'dictionaries/en.json', content: PLACEHOLDER_DICT },
19
+ { rel: 'dictionaries/nl.json', content: PLACEHOLDER_DICT },
20
+ ];
21
+ const written = [];
22
+ const skipped = [];
23
+ for (const { rel, content } of files) {
24
+ const abs = path.join(i18nDir, rel);
25
+ if (fs.existsSync(abs) && !overwrite) {
26
+ skipped.push(rel);
27
+ continue;
28
+ }
29
+ fs.writeFileSync(abs, content, 'utf-8');
30
+ written.push(rel);
31
+ }
32
+ return { written, skipped };
33
+ }
34
+ //# sourceMappingURL=scaffold.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scaffold.js","sourceRoot":"","sources":["../../../src/scaffold/intenrals/scaffold.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EACH,WAAW,EACX,QAAQ,EACR,SAAS,EACT,SAAS,EACT,YAAY,EACZ,gBAAgB,GACnB,MAAM,gBAAgB,CAAC;AAGxB,MAAM,UAAU,YAAY,CAAC,IAAqB;IAC9C,MAAM,EAAE,OAAO,EAAE,SAAS,GAAG,KAAK,EAAE,GAAG,IAAI,CAAC;IAC5C,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;IAEpD,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE5C,MAAM,KAAK,GAA4C;QACnD,EAAE,GAAG,EAAE,aAAa,EAAE,OAAO,EAAE,WAAW,EAAE;QAC5C,EAAE,GAAG,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE;QACtC,EAAE,GAAG,EAAE,WAAW,EAAE,OAAO,EAAE,SAAS,EAAE;QACxC,EAAE,GAAG,EAAE,WAAW,EAAE,OAAO,EAAE,SAAS,EAAE;QACxC,EAAE,GAAG,EAAE,cAAc,EAAE,OAAO,EAAE,YAAY,EAAE;QAC9C,EAAE,GAAG,EAAE,sBAAsB,EAAE,OAAO,EAAE,gBAAgB,EAAE;QAC1D,EAAE,GAAG,EAAE,sBAAsB,EAAE,OAAO,EAAE,gBAAgB,EAAE;KAC7D,CAAC;IAEF,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,OAAO,GAAa,EAAE,CAAC;IAE7B,KAAK,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,KAAK,EAAE,CAAC;QACnC,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QACpC,IAAI,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;YACnC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAClB,SAAS;QACb,CAAC;QACD,EAAE,CAAC,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QACxC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACtB,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;AAChC,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * i18n file templates.
3
+ */
4
+ export declare const SETTINGS_TS = "import type { InitOptions } from 'i18next';\n\n// These imports resolve after running: sync-translations pull\nimport en from './dictionaries/en.json';\nimport type nl from './dictionaries/nl.json';\n\nexport const fallbackLng = 'nl' as const;\nexport const languages = ['nl', 'en'] as const;\nexport const defaultNS = 'common' as const;\nexport const cookieName = 'i18next';\n\nexport type Locale = (typeof languages)[number];\n\nexport const allNamespaces = Object.keys(\n en\n) as readonly (keyof typeof en)[];\n\nexport type Dicts = {\n en: typeof en;\n nl: typeof nl;\n};\n\n// Re-export for convenience\nexport type { AppNamespace, Namespace } from './types';\n\nexport function getOptions(\n lng: string = fallbackLng,\n ns: string | readonly string[] = allNamespaces\n): InitOptions {\n return {\n supportedLngs: [...languages],\n fallbackLng: lng,\n lng,\n fallbackNS: defaultNS,\n defaultNS,\n ns,\n resources: {},\n partialBundledLanguages: true,\n interpolation: {\n escapeValue: false,\n },\n };\n}\n";
5
+ export declare const TYPES_TS = "import type { allNamespaces, Dicts, languages } from './settings';\n\nexport type Locale = (typeof languages)[number];\nexport type AppNamespace = (typeof allNamespaces)[number];\nexport type Namespace = AppNamespace | readonly AppNamespace[];\n\ntype PluralSuffix = '_zero' | '_one' | '_two' | '_few' | '_many' | '_other';\n\ntype StripPluralSuffix<K extends string> =\n K extends `${infer Base}${PluralSuffix}` ? Base : K;\n\nexport type LeafPaths<T> = T extends {\n [key: string]: string | number | boolean | null | object;\n}\n ? {\n [K in keyof T & string]: T[K] extends\n | string\n | number\n | boolean\n | null\n ? K | StripPluralSuffix<K>\n : T[K] extends object\n ? `${K}.${LeafPaths<T[K]> & string}`\n : never;\n }[keyof T & string]\n : never;\n\nexport type I18nKey = {\n [Lang in keyof Dicts]: {\n [Ns in keyof Dicts[Lang]]: `${Ns & string}:${LeafPaths<Dicts[Lang][Ns]> & string}`;\n }[keyof Dicts[Lang]];\n}[keyof Dicts];\n\nexport type TranslationKey<\n Ns extends AppNamespace | readonly AppNamespace[] | undefined = undefined,\n> = Ns extends undefined\n ? I18nKey\n : Ns extends readonly (infer N extends AppNamespace)[]\n ? `${N}:${LeafPaths<Dicts['en'][N]> & string}`\n : Ns extends AppNamespace\n ? `${Ns}:${LeafPaths<Dicts['en'][Ns]> & string}`\n : never;\n\nexport type TranslationKeys<\n Ns extends AppNamespace | readonly AppNamespace[] | undefined,\n> = (key: TranslationKey<Ns>, options?: any) => string;\n";
6
+ export declare const CLIENT_TS = "'use client';\n\nimport { useCallback } from 'react';\nimport {\n initReactI18next,\n Trans,\n useTranslation as useTranslationOrg,\n type UseTranslationOptions,\n} from 'react-i18next';\n\nexport { Trans };\n\nimport i18next, { type i18n as I18nInstance, type TOptions } from 'i18next';\n\nimport en from './dictionaries/en.json';\nimport nl from './dictionaries/nl.json';\n\nimport {\n getOptions,\n type AppNamespace,\n type Locale,\n} from './settings';\nimport type { TranslationKeys } from './types';\n\nconst resources = { en, nl } as const;\n\ntype StringTOptions = Omit<TOptions, 'returnDetails' | 'returnObjects'>;\n\nlet i18nInstance: I18nInstance | null = null;\n\nexport async function initI18nClient(locale: Locale): Promise<I18nInstance> {\n if (i18nInstance) {\n if (i18nInstance.language !== locale) {\n await i18nInstance.changeLanguage(locale);\n }\n return i18nInstance;\n }\n\n i18nInstance = i18next.createInstance();\n\n await i18nInstance.use(initReactI18next).init({\n ...getOptions(locale),\n resources,\n });\n\n return i18nInstance;\n}\n\nexport function useTranslation<\n Ns extends AppNamespace | readonly AppNamespace[],\n>(ns: Ns, hookOptions?: UseTranslationOptions<undefined>) {\n const namespacesToLoad: AppNamespace[] = Array.isArray(ns)\n ? [...ns]\n : ns\n ? [ns]\n : [];\n\n const result = useTranslationOrg(namespacesToLoad, hookOptions);\n const { t: tOrg } = result;\n\n const tBase = useCallback(\n (key: string, tOptions?: StringTOptions): string => {\n return tOrg(key, {\n ...tOptions,\n returnDetails: false,\n returnObjects: false,\n } as TOptions) as string;\n },\n [tOrg]\n );\n\n const t = tBase as TranslationKeys<Ns>;\n const tDynamic = tBase;\n\n return {\n ...result,\n t,\n tDynamic,\n };\n}\n";
7
+ export declare const SERVER_TS = "import { initReactI18next } from 'react-i18next/initReactI18next';\nimport { cookies, headers } from 'next/headers';\nimport { createInstance, type TOptions } from 'i18next';\nimport resourcesToBackend from 'i18next-resources-to-backend';\n\nimport {\n cookieName,\n fallbackLng,\n getOptions,\n languages,\n type Locale,\n} from './settings';\nimport type { AppNamespace, I18nKey, TranslationKeys } from './types';\n\ntype StringTOptions = Omit<TOptions, 'returnDetails' | 'returnObjects'>;\n\nexport async function initI18n(locale: string) {\n const i18n = createInstance();\n\n await i18n\n .use(initReactI18next)\n .use(\n resourcesToBackend((language: string, namespace: string) =>\n import(`./dictionaries/${language}.json`).then(module => {\n return (module.default as Record<string, unknown>)[namespace] ?? {};\n })\n )\n )\n .init(getOptions(locale, []));\n\n return i18n;\n}\n\nexport async function getTranslation<\n Ns extends AppNamespace | readonly AppNamespace[],\n>(ns: Ns, options: { keyPrefix?: string } = {}) {\n const lng = await getLocale();\n const i18n = await initI18n(lng);\n\n const namespacesToLoad: readonly AppNamespace[] = ns\n ? Array.isArray(ns)\n ? ns\n : [ns]\n : [];\n\n if (namespacesToLoad.length > 0) {\n await i18n.loadNamespaces(namespacesToLoad);\n }\n\n const fixedT = i18n.getFixedT(lng, namespacesToLoad, options.keyPrefix);\n\n const t = (key: I18nKey, tOptions?: StringTOptions): string => {\n return fixedT(key, {\n ...tOptions,\n returnDetails: false,\n returnObjects: false,\n } as TOptions) as string;\n };\n\n return {\n t: t as TranslationKeys<Ns>,\n tDynamic: t,\n i18n,\n };\n}\n\nexport async function getLocale(): Promise<Locale> {\n const isSupportedLocale = (value: string): value is Locale =>\n (languages as readonly string[]).includes(value);\n\n try {\n const cookieStore = await cookies();\n const localeCookie = cookieStore.get(cookieName);\n if (localeCookie?.value && isSupportedLocale(localeCookie.value)) {\n return localeCookie.value;\n }\n\n const headersList = await headers();\n const acceptLanguage = headersList.get('accept-language') ?? '';\n const supported = new Set(\n (languages as readonly string[]).map(l => l.toLowerCase())\n );\n\n const preferences = acceptLanguage\n .split(',')\n .map((part): { code: string; q: number } | null => {\n const trimmed = part.trim();\n if (!trimmed) return null;\n const [tag = '', qPartRaw] = trimmed.split(';');\n const qPart = qPartRaw?.trim();\n const q = qPart?.startsWith('q=') ? Number(qPart.slice(2)) : 1;\n const code = (tag.trim().split('-')[0] ?? '').toLowerCase();\n if (!code || !Number.isFinite(q) || q <= 0 || q > 1) return null;\n return { code, q };\n })\n .filter((x): x is { code: string; q: number } => x !== null)\n .sort((a, b) => b.q - a.q);\n\n const best = preferences.find(x => supported.has(x.code));\n if (best) return best.code as Locale;\n } catch {\n // cookies()/headers() unavailable at build time\n }\n\n return fallbackLng;\n}\n";
8
+ export declare const PROVIDER_TSX = "'use client';\n\nimport { useEffect, useState } from 'react';\nimport { I18nextProvider } from 'react-i18next';\nimport type { i18n as I18nInstance } from 'i18next';\n\nimport { initI18nClient } from './client';\nimport { cookieName, type Locale } from './settings';\n\ninterface TranslationProviderProps {\n children: React.ReactNode;\n locale: Locale;\n}\n\n/**\n * Root provider for i18n. Add to your root layout:\n *\n * ```tsx\n * import { TranslationProvider } from '@/lib/i18n/provider';\n * import { getLocale } from '@/lib/i18n/server';\n *\n * export default async function RootLayout({ children }) {\n * const locale = await getLocale();\n * return (\n * <html lang={locale}>\n * <body>\n * <TranslationProvider locale={locale}>\n * {children}\n * </TranslationProvider>\n * </body>\n * </html>\n * );\n * }\n * ```\n */\nexport function TranslationProvider({ children, locale }: TranslationProviderProps) {\n const [i18n, setI18n] = useState<I18nInstance | null>(null);\n\n useEffect(() => {\n initI18nClient(locale).then(setI18n);\n }, [locale]);\n\n useEffect(() => {\n if (!i18n) return;\n const handleLanguageChanged = (lng: string) => {\n document.documentElement.lang = lng;\n const expires = new Date();\n expires.setFullYear(expires.getFullYear() + 1);\n document.cookie = `${cookieName}=${encodeURIComponent(lng)}; expires=${expires.toUTCString()}; path=/; SameSite=Lax`;\n };\n handleLanguageChanged(i18n.language);\n i18n.on('languageChanged', handleLanguageChanged);\n return () => { i18n.off('languageChanged', handleLanguageChanged); };\n }, [i18n]);\n\n if (!i18n) return null;\n\n return <I18nextProvider i18n={i18n}>{children}</I18nextProvider>;\n}\n";
9
+ export declare const PLACEHOLDER_DICT: string;
10
+ //# sourceMappingURL=templates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../../../src/scaffold/intenrals/templates.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,eAAO,MAAM,WAAW,gmCA2CvB,CAAC;AAEF,eAAO,MAAM,QAAQ,qlDA8CpB,CAAC;AAEF,eAAO,MAAM,SAAS,09DAgFrB,CAAC;AAEF,eAAO,MAAM,SAAS,k+GA0GrB,CAAC;AAEF,eAAO,MAAM,YAAY,o3DA2DxB,CAAC;AAEF,eAAO,MAAM,gBAAgB,QAA0C,CAAC"}
@@ -1,9 +1,7 @@
1
- import fs from 'fs';
2
- import path from 'path';
3
- // ---------------------------------------------------------------------------
4
- // File templates
5
- // ---------------------------------------------------------------------------
6
- const SETTINGS_TS = `import type { InitOptions } from 'i18next';
1
+ /**
2
+ * i18n file templates.
3
+ */
4
+ export const SETTINGS_TS = `import type { InitOptions } from 'i18next';
7
5
 
8
6
  // These imports resolve after running: sync-translations pull
9
7
  import en from './dictionaries/en.json';
@@ -47,7 +45,7 @@ export function getOptions(
47
45
  };
48
46
  }
49
47
  `;
50
- const TYPES_TS = `import type { allNamespaces, Dicts, languages } from './settings';
48
+ export const TYPES_TS = `import type { allNamespaces, Dicts, languages } from './settings';
51
49
 
52
50
  export type Locale = (typeof languages)[number];
53
51
  export type AppNamespace = (typeof allNamespaces)[number];
@@ -94,7 +92,7 @@ export type TranslationKeys<
94
92
  Ns extends AppNamespace | readonly AppNamespace[] | undefined,
95
93
  > = (key: TranslationKey<Ns>, options?: any) => string;
96
94
  `;
97
- const CLIENT_TS = `'use client';
95
+ export const CLIENT_TS = `'use client';
98
96
 
99
97
  import { useCallback } from 'react';
100
98
  import {
@@ -175,7 +173,7 @@ export function useTranslation<
175
173
  };
176
174
  }
177
175
  `;
178
- const SERVER_TS = `import { initReactI18next } from 'react-i18next/initReactI18next';
176
+ export const SERVER_TS = `import { initReactI18next } from 'react-i18next/initReactI18next';
179
177
  import { cookies, headers } from 'next/headers';
180
178
  import { createInstance, type TOptions } from 'i18next';
181
179
  import resourcesToBackend from 'i18next-resources-to-backend';
@@ -282,7 +280,7 @@ export async function getLocale(): Promise<Locale> {
282
280
  return fallbackLng;
283
281
  }
284
282
  `;
285
- const PROVIDER_TSX = `'use client';
283
+ export const PROVIDER_TSX = `'use client';
286
284
 
287
285
  import { useEffect, useState } from 'react';
288
286
  import { I18nextProvider } from 'react-i18next';
@@ -342,31 +340,5 @@ export function TranslationProvider({ children, locale }: TranslationProviderPro
342
340
  return <I18nextProvider i18n={i18n}>{children}</I18nextProvider>;
343
341
  }
344
342
  `;
345
- const PLACEHOLDER_DICT = JSON.stringify({ common: {} }, null, 4);
346
- export function scaffoldI18n(opts) {
347
- const { i18nDir, overwrite = false } = opts;
348
- const dictsDir = path.join(i18nDir, 'dictionaries');
349
- fs.mkdirSync(dictsDir, { recursive: true });
350
- const files = [
351
- { rel: 'settings.ts', content: SETTINGS_TS },
352
- { rel: 'types.ts', content: TYPES_TS },
353
- { rel: 'client.ts', content: CLIENT_TS },
354
- { rel: 'server.ts', content: SERVER_TS },
355
- { rel: 'provider.tsx', content: PROVIDER_TSX },
356
- { rel: 'dictionaries/en.json', content: PLACEHOLDER_DICT },
357
- { rel: 'dictionaries/nl.json', content: PLACEHOLDER_DICT },
358
- ];
359
- const written = [];
360
- const skipped = [];
361
- for (const { rel, content } of files) {
362
- const abs = path.join(i18nDir, rel);
363
- if (fs.existsSync(abs) && !overwrite) {
364
- skipped.push(rel);
365
- continue;
366
- }
367
- fs.writeFileSync(abs, content, 'utf-8');
368
- written.push(rel);
369
- }
370
- return { written, skipped };
371
- }
372
- //# sourceMappingURL=scaffold.js.map
343
+ export const PLACEHOLDER_DICT = JSON.stringify({ common: {} }, null, 4);
344
+ //# sourceMappingURL=templates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templates.js","sourceRoot":"","sources":["../../../src/scaffold/intenrals/templates.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,CAAC,MAAM,WAAW,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2C1B,CAAC;AAEF,MAAM,CAAC,MAAM,QAAQ,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8CvB,CAAC;AAEF,MAAM,CAAC,MAAM,SAAS,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgFxB,CAAC;AAEF,MAAM,CAAC,MAAM,SAAS,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0GxB,CAAC;AAEF,MAAM,CAAC,MAAM,YAAY,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2D3B,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC"}
@@ -1,3 +1,6 @@
1
+ /**
2
+ * Types for i18n scaffolding.
3
+ */
1
4
  export interface ScaffoldOptions {
2
5
  /** Absolute path to the i18n directory, e.g. /project/src/lib/i18n */
3
6
  i18nDir: string;
@@ -8,5 +11,4 @@ export interface ScaffoldResult {
8
11
  written: string[];
9
12
  skipped: string[];
10
13
  }
11
- export declare function scaffoldI18n(opts: ScaffoldOptions): ScaffoldResult;
12
- //# sourceMappingURL=scaffold.d.ts.map
14
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/scaffold/intenrals/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,eAAe;IAC5B,sEAAsE;IACtE,OAAO,EAAE,MAAM,CAAC;IAChB,0CAA0C;IAC1C,SAAS,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,cAAc;IAC3B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;CACrB"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Types for i18n scaffolding.
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/scaffold/intenrals/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
package/package.json CHANGED
@@ -1,28 +1,25 @@
1
1
  {
2
2
  "name": "@translation-cms/sync",
3
- "version": "1.2.1",
3
+ "version": "1.2.3",
4
4
  "description": "Scan translation keys in your codebase and sync them to the Translations CMS",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "bin": {
8
- "sync-translations": "./dist/cli-entry.js"
8
+ "sync-translations": "./dist/bin.js"
9
9
  },
10
10
  "exports": {
11
11
  ".": {
12
12
  "import": "./dist/index.js",
13
13
  "types": "./dist/index.d.ts"
14
14
  },
15
- "./cli": {
16
- "import": "./dist/cli.js",
17
- "types": "./dist/cli.d.ts"
18
- },
19
15
  "./preview": {
20
16
  "import": "./dist/preview.js",
21
17
  "types": "./dist/preview.d.ts"
22
18
  }
23
19
  },
24
20
  "files": [
25
- "dist"
21
+ "dist",
22
+ "schema.json"
26
23
  ],
27
24
  "scripts": {
28
25
  "build": "tsc",
@@ -49,5 +46,8 @@
49
46
  "devDependencies": {
50
47
  "@types/react": "^18",
51
48
  "typescript": "^5.9.3"
49
+ },
50
+ "dependencies": {
51
+ "@babel/parser": "^7.29.2"
52
52
  }
53
53
  }
package/schema.json ADDED
@@ -0,0 +1,64 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "title": "sync-translations config",
4
+ "description": "Configuration file for the sync-translations CLI. Place as .translationsrc.json in your project root.",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "properties": {
8
+ "$schema": {
9
+ "type": "string"
10
+ },
11
+ "cmsUrl": {
12
+ "type": "string",
13
+ "description": "CMS URL — overrides NEXT_PUBLIC_CMS_URL env var.",
14
+ "examples": ["https://cms.example.com"]
15
+ },
16
+ "projectId": {
17
+ "type": "string",
18
+ "description": "Project ID — overrides NEXT_PUBLIC_CMS_PROJECT_ID env var."
19
+ },
20
+ "apiKey": {
21
+ "type": "string",
22
+ "description": "API key — overrides NEXT_PUBLIC_CMS_ANON_KEY / CMS_SYNC_API_KEY env var."
23
+ },
24
+ "excludedDirs": {
25
+ "type": "array",
26
+ "items": { "type": "string" },
27
+ "description": "Additional directories to exclude when scanning for translation keys. Merged with built-in defaults: node_modules, .next, dist, .git, out, .turbo, scripts, packages, .storybook, coverage.",
28
+ "examples": [["e2e", "fixtures", "mocks"]]
29
+ },
30
+ "sourceExtensions": {
31
+ "type": "array",
32
+ "items": { "type": "string" },
33
+ "description": "File extensions to scan. When set, replaces the default list.",
34
+ "default": [".ts", ".tsx", ".js", ".jsx"],
35
+ "examples": [[".ts", ".tsx", ".js", ".jsx", ".vue"]]
36
+ },
37
+ "outputDir": {
38
+ "type": "string",
39
+ "description": "Default output directory for pulled translation files.",
40
+ "default": "./public/locales",
41
+ "examples": ["./src/lib/i18n/dictionaries", "./public/locales"]
42
+ },
43
+ "pullTtlMs": {
44
+ "type": "number",
45
+ "description": "TTL in milliseconds before the pull cache expires and translations are re-fetched.",
46
+ "default": 300000,
47
+ "examples": [300000, 600000]
48
+ },
49
+ "routeParams": {
50
+ "type": "object",
51
+ "description": "Mock params for dynamic route segments, used to generate preview URLs. Keys are route patterns, values are param maps.",
52
+ "additionalProperties": {
53
+ "type": "object",
54
+ "additionalProperties": { "type": "string" }
55
+ },
56
+ "examples": [
57
+ {
58
+ "/[locale]/blog/[slug]": { "slug": "first-post" },
59
+ "/[locale]/products/[id]": { "id": "product-a" }
60
+ }
61
+ ]
62
+ }
63
+ }
64
+ }
@@ -1,3 +0,0 @@
1
- #!/usr/bin/env node
2
- export {};
3
- //# sourceMappingURL=cli-entry.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cli-entry.d.ts","sourceRoot":"","sources":["../src/cli-entry.ts"],"names":[],"mappings":""}