@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.
- package/dist/bin.d.ts +25 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +173 -0
- package/dist/bin.js.map +1 -0
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +68 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/pull.d.ts +3 -0
- package/dist/commands/pull.d.ts.map +1 -0
- package/dist/commands/pull.js +22 -0
- package/dist/commands/pull.js.map +1 -0
- package/dist/commands/status.d.ts +3 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +46 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/sync.d.ts +10 -0
- package/dist/commands/sync.d.ts.map +1 -0
- package/dist/commands/sync.js +20 -0
- package/dist/commands/sync.js.map +1 -0
- package/dist/commands/watch.d.ts +4 -0
- package/dist/commands/watch.d.ts.map +1 -0
- package/dist/commands/watch.js +51 -0
- package/dist/commands/watch.js.map +1 -0
- package/dist/{load-config.d.ts → config/resolve-config.d.ts} +13 -10
- package/dist/config/resolve-config.d.ts.map +1 -0
- package/dist/{resolve-config.js → config/resolve-config.js} +21 -0
- package/dist/config/resolve-config.js.map +1 -0
- package/dist/core/api-internals/helpers.d.ts +9 -0
- package/dist/core/api-internals/helpers.d.ts.map +1 -0
- package/dist/core/api-internals/helpers.js +14 -0
- package/dist/core/api-internals/helpers.js.map +1 -0
- package/dist/core/api-internals/pull.d.ts +11 -0
- package/dist/core/api-internals/pull.d.ts.map +1 -0
- package/dist/core/api-internals/pull.js +124 -0
- package/dist/core/api-internals/pull.js.map +1 -0
- package/dist/core/api-internals/route-config.d.ts +13 -0
- package/dist/core/api-internals/route-config.d.ts.map +1 -0
- package/dist/core/api-internals/route-config.js +34 -0
- package/dist/core/api-internals/route-config.js.map +1 -0
- package/dist/core/api-internals/sync.d.ts +12 -0
- package/dist/core/api-internals/sync.d.ts.map +1 -0
- package/dist/core/api-internals/sync.js +95 -0
- package/dist/core/api-internals/sync.js.map +1 -0
- package/dist/core/api-internals/types.d.ts +25 -0
- package/dist/core/api-internals/types.d.ts.map +1 -0
- package/dist/core/api-internals/types.js +5 -0
- package/dist/core/api-internals/types.js.map +1 -0
- package/dist/core/api.d.ts +11 -0
- package/dist/core/api.d.ts.map +1 -0
- package/dist/core/api.js +11 -0
- package/dist/core/api.js.map +1 -0
- package/dist/{sync.d.ts → core/cache.d.ts} +5 -33
- package/dist/core/cache.d.ts.map +1 -0
- package/dist/core/cache.js +143 -0
- package/dist/core/cache.js.map +1 -0
- package/dist/core/scanner-internals/ast.d.ts +22 -0
- package/dist/core/scanner-internals/ast.d.ts.map +1 -0
- package/dist/core/scanner-internals/ast.js +80 -0
- package/dist/core/scanner-internals/ast.js.map +1 -0
- package/dist/core/scanner-internals/file-walker.d.ts +9 -0
- package/dist/core/scanner-internals/file-walker.d.ts.map +1 -0
- package/dist/core/scanner-internals/file-walker.js +25 -0
- package/dist/core/scanner-internals/file-walker.js.map +1 -0
- package/dist/core/scanner-internals/import-resolver.d.ts +13 -0
- package/dist/core/scanner-internals/import-resolver.d.ts.map +1 -0
- package/dist/core/scanner-internals/import-resolver.js +124 -0
- package/dist/core/scanner-internals/import-resolver.js.map +1 -0
- package/dist/core/scanner-internals/key-extractor.d.ts +16 -0
- package/dist/core/scanner-internals/key-extractor.d.ts.map +1 -0
- package/dist/core/scanner-internals/key-extractor.js +168 -0
- package/dist/core/scanner-internals/key-extractor.js.map +1 -0
- package/dist/core/scanner-internals/route-detector.d.ts +19 -0
- package/dist/core/scanner-internals/route-detector.d.ts.map +1 -0
- package/dist/core/scanner-internals/route-detector.js +74 -0
- package/dist/core/scanner-internals/route-detector.js.map +1 -0
- package/dist/core/scanner-internals/types.d.ts +53 -0
- package/dist/core/scanner-internals/types.d.ts.map +1 -0
- package/dist/core/scanner-internals/types.js +29 -0
- package/dist/core/scanner-internals/types.js.map +1 -0
- package/dist/core/scanner.d.ts +20 -0
- package/dist/core/scanner.d.ts.map +1 -0
- package/dist/core/scanner.js +113 -0
- package/dist/core/scanner.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/preview/index.d.ts +38 -0
- package/dist/preview/index.d.ts.map +1 -0
- package/dist/preview/index.js +114 -0
- package/dist/preview/index.js.map +1 -0
- package/dist/preview/internals/highlight.d.ts +22 -0
- package/dist/preview/internals/highlight.d.ts.map +1 -0
- package/dist/preview/internals/highlight.js +153 -0
- package/dist/preview/internals/highlight.js.map +1 -0
- package/dist/preview/internals/interactions.d.ts +15 -0
- package/dist/preview/internals/interactions.d.ts.map +1 -0
- package/dist/preview/internals/interactions.js +38 -0
- package/dist/preview/internals/interactions.js.map +1 -0
- package/dist/preview/internals/locales.d.ts +9 -0
- package/dist/preview/internals/locales.d.ts.map +1 -0
- package/dist/preview/internals/locales.js +24 -0
- package/dist/preview/internals/locales.js.map +1 -0
- package/dist/preview/internals/state.d.ts +35 -0
- package/dist/preview/internals/state.d.ts.map +1 -0
- package/dist/preview/internals/state.js +65 -0
- package/dist/preview/internals/state.js.map +1 -0
- package/dist/preview/internals/styles.d.ts +8 -0
- package/dist/preview/internals/styles.d.ts.map +1 -0
- package/dist/preview/internals/styles.js +28 -0
- package/dist/preview/internals/styles.js.map +1 -0
- package/dist/preview/internals/types.d.ts +49 -0
- package/dist/preview/internals/types.d.ts.map +1 -0
- package/dist/preview/internals/types.js +5 -0
- package/dist/preview/internals/types.js.map +1 -0
- package/dist/scaffold/index.d.ts +3 -0
- package/dist/scaffold/index.d.ts.map +1 -0
- package/dist/scaffold/index.js +3 -0
- package/dist/scaffold/index.js.map +1 -0
- package/dist/scaffold/intenrals/scaffold.d.ts +7 -0
- package/dist/scaffold/intenrals/scaffold.d.ts.map +1 -0
- package/dist/scaffold/intenrals/scaffold.js +34 -0
- package/dist/scaffold/intenrals/scaffold.js.map +1 -0
- package/dist/scaffold/intenrals/templates.d.ts +10 -0
- package/dist/scaffold/intenrals/templates.d.ts.map +1 -0
- package/dist/{scaffold.js → scaffold/intenrals/templates.js} +10 -38
- package/dist/scaffold/intenrals/templates.js.map +1 -0
- package/dist/{scaffold.d.ts → scaffold/intenrals/types.d.ts} +4 -2
- package/dist/scaffold/intenrals/types.d.ts.map +1 -0
- package/dist/scaffold/intenrals/types.js +5 -0
- package/dist/scaffold/intenrals/types.js.map +1 -0
- package/package.json +7 -7
- package/schema.json +64 -0
- package/dist/cli-entry.d.ts +0 -3
- package/dist/cli-entry.d.ts.map +0 -1
- package/dist/cli-entry.js +0 -390
- package/dist/cli-entry.js.map +0 -1
- package/dist/cli.d.ts +0 -16
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js +0 -16
- package/dist/cli.js.map +0 -1
- package/dist/load-config.d.ts.map +0 -1
- package/dist/load-config.js +0 -24
- package/dist/load-config.js.map +0 -1
- package/dist/preview.d.ts +0 -88
- package/dist/preview.d.ts.map +0 -1
- package/dist/preview.js +0 -461
- package/dist/preview.js.map +0 -1
- package/dist/resolve-config.d.ts +0 -15
- package/dist/resolve-config.d.ts.map +0 -1
- package/dist/resolve-config.js.map +0 -1
- package/dist/scaffold.d.ts.map +0 -1
- package/dist/scaffold.js.map +0 -1
- package/dist/scanner.d.ts +0 -77
- package/dist/scanner.d.ts.map +0 -1
- package/dist/scanner.js +0 -555
- package/dist/scanner.js.map +0 -1
- package/dist/sync.d.ts.map +0 -1
- package/dist/sync.js +0 -383
- package/dist/sync.js.map +0 -1
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types and constants used throughout the scanner module.
|
|
3
|
+
*/
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
// Constants
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
export const DEFAULT_EXCLUDED_DIRS = new Set([
|
|
8
|
+
'node_modules',
|
|
9
|
+
'.next',
|
|
10
|
+
'dist',
|
|
11
|
+
'.git',
|
|
12
|
+
'out',
|
|
13
|
+
'.turbo',
|
|
14
|
+
'scripts',
|
|
15
|
+
'packages',
|
|
16
|
+
'.storybook',
|
|
17
|
+
'coverage',
|
|
18
|
+
]);
|
|
19
|
+
export const DEFAULT_SOURCE_EXTENSIONS = new Set([
|
|
20
|
+
'.ts',
|
|
21
|
+
'.tsx',
|
|
22
|
+
'.js',
|
|
23
|
+
'.jsx',
|
|
24
|
+
]);
|
|
25
|
+
/** Return the route string key used for deduplication. */
|
|
26
|
+
export function routeKey(r) {
|
|
27
|
+
return typeof r === 'string' ? r : r.route;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/core/scanner-internals/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,8EAA8E;AAC9E,YAAY;AACZ,8EAA8E;AAE9E,MAAM,CAAC,MAAM,qBAAqB,GAAG,IAAI,GAAG,CAAC;IACzC,cAAc;IACd,OAAO;IACP,MAAM;IACN,MAAM;IACN,KAAK;IACL,QAAQ;IACR,SAAS;IACT,UAAU;IACV,YAAY;IACZ,UAAU;CACb,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,yBAAyB,GAAG,IAAI,GAAG,CAAC;IAC7C,KAAK;IACL,MAAM;IACN,KAAK;IACL,MAAM;CACT,CAAC,CAAC;AAiDH,0DAA0D;AAC1D,MAAM,UAAU,QAAQ,CAAC,CAAe;IACpC,OAAO,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;AAC/C,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main scanner orchestration.
|
|
3
|
+
* Coordinates the multi-pass scanning process for translation keys.
|
|
4
|
+
* Re-exports public types and functions for backward compatibility.
|
|
5
|
+
*/
|
|
6
|
+
export { DEFAULT_EXCLUDED_DIRS, DEFAULT_SOURCE_EXTENSIONS, type ScanOptions, type PreviewRoute, type NamespaceMap, routeKey, } from './scanner-internals/types.js';
|
|
7
|
+
export { walkFiles } from './scanner-internals/file-walker.js';
|
|
8
|
+
export { isRedirectOnlyPage, filePathToRoute, } from './scanner-internals/route-detector.js';
|
|
9
|
+
export { extractKeysFromFile } from './scanner-internals/key-extractor.js';
|
|
10
|
+
import { type ScanOptions, type NamespaceMap } from './scanner-internals/types.js';
|
|
11
|
+
/**
|
|
12
|
+
* Scans the project for translation keys and optionally merges external preview routes.
|
|
13
|
+
*
|
|
14
|
+
* Pass 1: Scan all files, extracting keys and associating them with page/layout routes.
|
|
15
|
+
* Pass 2: For each page/layout, walk its import tree to assign keys in deeply-nested
|
|
16
|
+
* components to the correct preview route.
|
|
17
|
+
* Pass 3: Merge external preview routes from database or config.
|
|
18
|
+
*/
|
|
19
|
+
export declare function scanProject(root: string, opts?: ScanOptions): NamespaceMap;
|
|
20
|
+
//# sourceMappingURL=scanner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../../src/core/scanner.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,EACH,qBAAqB,EACrB,yBAAyB,EACzB,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,QAAQ,GACX,MAAM,8BAA8B,CAAC;AAGtC,OAAO,EAAE,SAAS,EAAE,MAAM,oCAAoC,CAAC;AAC/D,OAAO,EACH,kBAAkB,EAClB,eAAe,GAClB,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAG3E,OAAO,EAGH,KAAK,WAAW,EAChB,KAAK,YAAY,EAEpB,MAAM,8BAA8B,CAAC;AAatC;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,YAAY,CAoG1E"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main scanner orchestration.
|
|
3
|
+
* Coordinates the multi-pass scanning process for translation keys.
|
|
4
|
+
* Re-exports public types and functions for backward compatibility.
|
|
5
|
+
*/
|
|
6
|
+
import path from 'path';
|
|
7
|
+
// Re-export types and constants
|
|
8
|
+
export { DEFAULT_EXCLUDED_DIRS, DEFAULT_SOURCE_EXTENSIONS, routeKey, } from './scanner-internals/types.js';
|
|
9
|
+
// Re-export public functions from submodules
|
|
10
|
+
export { walkFiles } from './scanner-internals/file-walker.js';
|
|
11
|
+
export { isRedirectOnlyPage, filePathToRoute, } from './scanner-internals/route-detector.js';
|
|
12
|
+
export { extractKeysFromFile } from './scanner-internals/key-extractor.js';
|
|
13
|
+
// Import utilities needed for orchestration
|
|
14
|
+
import { DEFAULT_EXCLUDED_DIRS, DEFAULT_SOURCE_EXTENSIONS, routeKey, } from './scanner-internals/types.js';
|
|
15
|
+
import { walkFiles } from './scanner-internals/file-walker.js';
|
|
16
|
+
import { filePathToRoute } from './scanner-internals/route-detector.js';
|
|
17
|
+
import { extractKeysFromFile } from './scanner-internals/key-extractor.js';
|
|
18
|
+
import { extractLocalImports, getLayoutChain, } from './scanner-internals/import-resolver.js';
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
// Project scan
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
/**
|
|
23
|
+
* Scans the project for translation keys and optionally merges external preview routes.
|
|
24
|
+
*
|
|
25
|
+
* Pass 1: Scan all files, extracting keys and associating them with page/layout routes.
|
|
26
|
+
* Pass 2: For each page/layout, walk its import tree to assign keys in deeply-nested
|
|
27
|
+
* components to the correct preview route.
|
|
28
|
+
* Pass 3: Merge external preview routes from database or config.
|
|
29
|
+
*/
|
|
30
|
+
export function scanProject(root, opts) {
|
|
31
|
+
const excludedDirs = new Set([
|
|
32
|
+
...DEFAULT_EXCLUDED_DIRS,
|
|
33
|
+
...(opts?.excludedDirs ?? []),
|
|
34
|
+
]);
|
|
35
|
+
const sourceExtensions = opts?.sourceExtensions
|
|
36
|
+
? new Set(opts.sourceExtensions)
|
|
37
|
+
: DEFAULT_SOURCE_EXTENSIONS;
|
|
38
|
+
const routeParams = opts?.routeParams;
|
|
39
|
+
const pathMappings = opts?.pathMappings;
|
|
40
|
+
const projectRoot = opts?.projectRoot ?? root;
|
|
41
|
+
const result = {};
|
|
42
|
+
let fileCount = 0;
|
|
43
|
+
// Pass 1: scan all files normally
|
|
44
|
+
const routeByFile = new Map();
|
|
45
|
+
for (const file of walkFiles(root, excludedDirs, sourceExtensions)) {
|
|
46
|
+
const routes = filePathToRoute(root, file);
|
|
47
|
+
routeByFile.set(file, routes);
|
|
48
|
+
extractKeysFromFile(file, routes, result);
|
|
49
|
+
fileCount++;
|
|
50
|
+
}
|
|
51
|
+
// Pass 2: for each page/layout file, transitively walk its import tree and
|
|
52
|
+
// re-scan every non-page/layout component with the same routes. This ensures
|
|
53
|
+
// keys used in deeply-nested components (e.g. layout → Nav → NavItem) are
|
|
54
|
+
// associated with the correct preview routes.
|
|
55
|
+
const scannedWithRoute = new Set(); // "file::route" pairs already done
|
|
56
|
+
for (const [file, routes] of routeByFile) {
|
|
57
|
+
if (routes.length === 0)
|
|
58
|
+
continue;
|
|
59
|
+
const isPage = path.basename(file).startsWith('page.');
|
|
60
|
+
const layoutChain = isPage
|
|
61
|
+
? getLayoutChain(root, file, sourceExtensions)
|
|
62
|
+
: [];
|
|
63
|
+
for (const layout of layoutChain) {
|
|
64
|
+
const layoutKey = `${layout}::${routes.join('|')}`;
|
|
65
|
+
if (!scannedWithRoute.has(layoutKey)) {
|
|
66
|
+
scannedWithRoute.add(layoutKey);
|
|
67
|
+
extractKeysFromFile(layout, routes, result);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const queue = [file, ...layoutChain];
|
|
71
|
+
while (queue.length > 0) {
|
|
72
|
+
const current = queue.shift();
|
|
73
|
+
const imports = extractLocalImports(current, sourceExtensions, projectRoot, pathMappings);
|
|
74
|
+
if (imports.length > 0) {
|
|
75
|
+
console.log(`[Pass 2] ${path.relative(root, current)} (${routes.join(', ')}) imports: ${imports.map(i => path.relative(root, i)).join(', ')}`);
|
|
76
|
+
}
|
|
77
|
+
for (const imported of imports) {
|
|
78
|
+
const key = `${imported}::${routes.join('|')}`;
|
|
79
|
+
if (scannedWithRoute.has(key))
|
|
80
|
+
continue;
|
|
81
|
+
scannedWithRoute.add(key);
|
|
82
|
+
if (!routeByFile.has(imported)) {
|
|
83
|
+
console.log(`[Pass 2] Skipping ${path.relative(root, imported)} — not in walk result`);
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
if (routeByFile.get(imported).length > 0)
|
|
87
|
+
continue;
|
|
88
|
+
console.log(`[Pass 2] Re-scanning ${path.relative(root, imported)} with routes: ${routes.join(', ')}`);
|
|
89
|
+
extractKeysFromFile(imported, routes, result);
|
|
90
|
+
queue.push(imported);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
// Pass 3: upgrade plain dynamic routes to { route, params } objects using routeParams
|
|
95
|
+
if (routeParams) {
|
|
96
|
+
for (const [, keyMap] of Object.entries(result)) {
|
|
97
|
+
for (const [key, routes] of keyMap.entries()) {
|
|
98
|
+
const upgraded = routes.map(r => {
|
|
99
|
+
const rk = routeKey(r);
|
|
100
|
+
const params = routeParams[rk];
|
|
101
|
+
if (params && typeof r === 'string') {
|
|
102
|
+
return { route: rk, params };
|
|
103
|
+
}
|
|
104
|
+
return r;
|
|
105
|
+
});
|
|
106
|
+
keyMap.set(key, upgraded);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
console.log(`Scanned ${fileCount} files.`);
|
|
111
|
+
return result;
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=scanner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scanner.js","sourceRoot":"","sources":["../../src/core/scanner.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { initPreviewListener, cleanupPreviewListener,
|
|
2
|
-
export { type TranslationsConfig } from './
|
|
1
|
+
export { initPreviewListener, cleanupPreviewListener, type PreviewListenerOptions, } from './preview/index.js';
|
|
2
|
+
export { type TranslationsConfig } from './config/resolve-config.js';
|
|
3
3
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EACH,mBAAmB,EACnB,sBAAsB,EACtB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EACH,mBAAmB,EACnB,sBAAsB,EACtB,KAAK,sBAAsB,GAC9B,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAE,KAAK,kBAAkB,EAAE,MAAM,4BAA4B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
//
|
|
2
|
-
export { initPreviewListener, cleanupPreviewListener,
|
|
1
|
+
// Browser: in-context preview listener
|
|
2
|
+
export { initPreviewListener, cleanupPreviewListener, } from './preview/index.js';
|
|
3
3
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,OAAO,EACH,mBAAmB,EACnB,sBAAsB,GAEzB,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Translation CMS — Preview Listener
|
|
3
|
+
*
|
|
4
|
+
* Add this to your client app to enable live in-context preview of translations
|
|
5
|
+
* from the CMS. No per-component setup required.
|
|
6
|
+
*
|
|
7
|
+
* Usage in Next.js root layout:
|
|
8
|
+
* ```tsx
|
|
9
|
+
* 'use client';
|
|
10
|
+
* import { useEffect } from 'react';
|
|
11
|
+
* import { initPreviewListener, cleanupPreviewListener } from '@translation-cms/sync/preview';
|
|
12
|
+
*
|
|
13
|
+
* export function CMSPreview() {
|
|
14
|
+
* useEffect(() => {
|
|
15
|
+
* initPreviewListener({ onLocaleSwitch: (locale) => i18n.changeLanguage(locale) });
|
|
16
|
+
* return () => cleanupPreviewListener();
|
|
17
|
+
* }, []);
|
|
18
|
+
* return null;
|
|
19
|
+
* }
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* Precise highlighting (recommended):
|
|
23
|
+
* Add `data-cms-key="namespace:key"` to elements that render a translation.
|
|
24
|
+
* The listener will target those elements directly, bypassing text-search heuristics.
|
|
25
|
+
* ```tsx
|
|
26
|
+
* <h1 data-cms-key="blog:post.title">{t('blog:post.title')}</h1>
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export type { PreviewListenerOptions } from './internals/types.js';
|
|
30
|
+
import type { PreviewListenerOptions } from './internals/types.js';
|
|
31
|
+
/**
|
|
32
|
+
* Initialize the preview listener.
|
|
33
|
+
* Safe to call multiple times — only initialises once.
|
|
34
|
+
*/
|
|
35
|
+
export declare function initPreviewListener(options?: PreviewListenerOptions): void;
|
|
36
|
+
/** Remove the preview listener and clear all highlights. */
|
|
37
|
+
export declare function cleanupPreviewListener(): void;
|
|
38
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/preview/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAGH,YAAY,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAenE,OAAO,KAAK,EAIR,sBAAsB,EACzB,MAAM,sBAAsB,CAAC;AAM9B;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,CAAC,EAAE,sBAAsB,GAAG,IAAI,CA4B1E;AAED,4DAA4D;AAC5D,wBAAgB,sBAAsB,IAAI,IAAI,CAO7C"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Translation CMS — Preview Listener
|
|
3
|
+
*
|
|
4
|
+
* Add this to your client app to enable live in-context preview of translations
|
|
5
|
+
* from the CMS. No per-component setup required.
|
|
6
|
+
*
|
|
7
|
+
* Usage in Next.js root layout:
|
|
8
|
+
* ```tsx
|
|
9
|
+
* 'use client';
|
|
10
|
+
* import { useEffect } from 'react';
|
|
11
|
+
* import { initPreviewListener, cleanupPreviewListener } from '@translation-cms/sync/preview';
|
|
12
|
+
*
|
|
13
|
+
* export function CMSPreview() {
|
|
14
|
+
* useEffect(() => {
|
|
15
|
+
* initPreviewListener({ onLocaleSwitch: (locale) => i18n.changeLanguage(locale) });
|
|
16
|
+
* return () => cleanupPreviewListener();
|
|
17
|
+
* }, []);
|
|
18
|
+
* return null;
|
|
19
|
+
* }
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* Precise highlighting (recommended):
|
|
23
|
+
* Add `data-cms-key="namespace:key"` to elements that render a translation.
|
|
24
|
+
* The listener will target those elements directly, bypassing text-search heuristics.
|
|
25
|
+
* ```tsx
|
|
26
|
+
* <h1 data-cms-key="blog:post.title">{t('blog:post.title')}</h1>
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
// Internal imports
|
|
30
|
+
import * as state from './internals/state.js';
|
|
31
|
+
import { highlightTranslationKey, clearHighlights, updateLiveText, } from './internals/highlight.js';
|
|
32
|
+
import { handleLocaleSwitch } from './internals/locales.js';
|
|
33
|
+
import { injectInteractionBlocker, removeInteractionBlocker, } from './internals/interactions.js';
|
|
34
|
+
import { injectStyles } from './internals/styles.js';
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
// Public functions
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
/**
|
|
39
|
+
* Initialize the preview listener.
|
|
40
|
+
* Safe to call multiple times — only initialises once.
|
|
41
|
+
*/
|
|
42
|
+
export function initPreviewListener(options) {
|
|
43
|
+
if (state.isInitialized)
|
|
44
|
+
return;
|
|
45
|
+
const isDev = typeof window !== 'undefined' &&
|
|
46
|
+
(window.location.hostname === 'localhost' ||
|
|
47
|
+
window.location.hostname === '127.0.0.1' ||
|
|
48
|
+
window.location.search.includes('preview=true'));
|
|
49
|
+
if (!isDev) {
|
|
50
|
+
console.log('[CMS Preview] Not in development mode, skipping...');
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
state.initializeState(options ?? {});
|
|
54
|
+
state.setIsInitialized(true);
|
|
55
|
+
window.addEventListener('message', handleMessage);
|
|
56
|
+
injectStyles();
|
|
57
|
+
// Only inject the interaction blocker when running inside an iframe
|
|
58
|
+
// (i.e. the CMS preview context). Opening the page directly on localhost
|
|
59
|
+
// should never have interactions blocked.
|
|
60
|
+
if (window.top !== window) {
|
|
61
|
+
injectInteractionBlocker();
|
|
62
|
+
}
|
|
63
|
+
console.log('%c[CMS Preview] Ready', 'color: #10b981; font-weight: bold;');
|
|
64
|
+
}
|
|
65
|
+
/** Remove the preview listener and clear all highlights. */
|
|
66
|
+
export function cleanupPreviewListener() {
|
|
67
|
+
if (!state.isInitialized)
|
|
68
|
+
return;
|
|
69
|
+
window.removeEventListener('message', handleMessage);
|
|
70
|
+
removeInteractionBlocker();
|
|
71
|
+
clearHighlights();
|
|
72
|
+
state.resetState();
|
|
73
|
+
console.log('[CMS Preview] Listener cleaned up');
|
|
74
|
+
}
|
|
75
|
+
// ---------------------------------------------------------------------------
|
|
76
|
+
// Message handler
|
|
77
|
+
// ---------------------------------------------------------------------------
|
|
78
|
+
function handleMessage(event) {
|
|
79
|
+
const { type } = (event.data ?? {});
|
|
80
|
+
if (type === 'CMS_HIGHLIGHT_KEY') {
|
|
81
|
+
const { key, value, locale } = event.data;
|
|
82
|
+
console.log(`[CMS Preview] Highlighting: ${key} (${locale}) = "${value}"`);
|
|
83
|
+
// Only switch locale when it actually changed. Switching unconditionally
|
|
84
|
+
// triggers a re-render in the consuming app, which replaces DOM nodes
|
|
85
|
+
// and immediately removes the highlight class we just applied.
|
|
86
|
+
if (locale && locale !== state.activeLocale) {
|
|
87
|
+
state.setActiveLocale(locale);
|
|
88
|
+
handleLocaleSwitch(locale);
|
|
89
|
+
}
|
|
90
|
+
state.setCurrentLiveValue(null);
|
|
91
|
+
state.setPendingHighlight({ key, value });
|
|
92
|
+
highlightTranslationKey(value, key);
|
|
93
|
+
// If no elements were found (e.g. dialog still animating open), schedule
|
|
94
|
+
// a backup retry after the animation should have settled.
|
|
95
|
+
if (state.highlightedElements.length === 0) {
|
|
96
|
+
setTimeout(() => {
|
|
97
|
+
if (state.pendingHighlight?.key === key) {
|
|
98
|
+
console.log(`[CMS Preview] Retrying highlight for: ${key}`);
|
|
99
|
+
highlightTranslationKey(value, key);
|
|
100
|
+
}
|
|
101
|
+
}, 600);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
else if (type === 'CMS_LIVE_UPDATE') {
|
|
105
|
+
const { oldValue, newValue } = event.data;
|
|
106
|
+
updateLiveText(oldValue, newValue);
|
|
107
|
+
}
|
|
108
|
+
else if (type === 'CMS_SWITCH_LOCALE') {
|
|
109
|
+
const { locale } = event.data;
|
|
110
|
+
state.setActiveLocale(locale);
|
|
111
|
+
handleLocaleSwitch(locale);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/preview/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Translation highlighting logic.
|
|
3
|
+
* Handles searching for and highlighting elements that display translations.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Find and highlight DOM elements that display the given translation.
|
|
7
|
+
*
|
|
8
|
+
* Search order:
|
|
9
|
+
* 0. data-cms-key attribute match (precise — skips all heuristics)
|
|
10
|
+
* 1. Exact text node match
|
|
11
|
+
* 2. Element content match (handles split siblings)
|
|
12
|
+
* 3. Normalized text node match (strips {{interpolation}} placeholders)
|
|
13
|
+
* 4. Normalized element match
|
|
14
|
+
* 5. Key fallback (when value is empty — i18next renders the key as text)
|
|
15
|
+
*/
|
|
16
|
+
export declare function highlightTranslationKey(value: string, key: string): void;
|
|
17
|
+
export declare function clearHighlights(): void;
|
|
18
|
+
/**
|
|
19
|
+
* Update highlighted elements with live translation changes.
|
|
20
|
+
*/
|
|
21
|
+
export declare function updateLiveText(oldValue: string, newValue: string): void;
|
|
22
|
+
//# sourceMappingURL=highlight.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"highlight.d.ts","sourceRoot":"","sources":["../../../src/preview/internals/highlight.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAoEH;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAyExE;AAeD,wBAAgB,eAAe,IAAI,IAAI,CAMtC;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAuBvE"}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Translation highlighting logic.
|
|
3
|
+
* Handles searching for and highlighting elements that display translations.
|
|
4
|
+
*/
|
|
5
|
+
import * as state from './state.js';
|
|
6
|
+
function normalizeForSearch(value) {
|
|
7
|
+
return value
|
|
8
|
+
.replace(/\{\{[^}]+\}\}/g, '')
|
|
9
|
+
.replace(/\{[^}]+\}/g, '')
|
|
10
|
+
.replace(/\s+/g, ' ')
|
|
11
|
+
.trim();
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Strategy 0 (precise): find elements with data-cms-key="key" attribute.
|
|
15
|
+
* When present, this is always preferred over text-content heuristics.
|
|
16
|
+
*/
|
|
17
|
+
function findByDataAttribute(key) {
|
|
18
|
+
return Array.from(document.querySelectorAll(`[data-cms-key="${CSS.escape(key)}"]`));
|
|
19
|
+
}
|
|
20
|
+
/** Strategy 1: walk text nodes, return parent elements whose text includes value. */
|
|
21
|
+
function findByTextNodes(searchValue) {
|
|
22
|
+
const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT, null);
|
|
23
|
+
const results = [];
|
|
24
|
+
let node;
|
|
25
|
+
while ((node = walker.nextNode())) {
|
|
26
|
+
if (node.textContent?.includes(searchValue)) {
|
|
27
|
+
const el = node.parentElement;
|
|
28
|
+
if (el && !el.classList.contains('cms-preview-highlight')) {
|
|
29
|
+
results.push(el);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return results;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Strategy 2: find the most specific element whose combined textContent
|
|
37
|
+
* includes the value. Works when text is split across siblings.
|
|
38
|
+
*/
|
|
39
|
+
function findByElementContent(searchValue) {
|
|
40
|
+
const all = Array.from(document.body.querySelectorAll('*'));
|
|
41
|
+
let best = null;
|
|
42
|
+
let bestLen = Infinity;
|
|
43
|
+
for (const el of all) {
|
|
44
|
+
if (el.textContent?.includes(searchValue) &&
|
|
45
|
+
!el.classList.contains('cms-preview-highlight')) {
|
|
46
|
+
const len = el.textContent.length;
|
|
47
|
+
if (len < bestLen) {
|
|
48
|
+
bestLen = len;
|
|
49
|
+
best = el;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return best ? [best] : [];
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Find and highlight DOM elements that display the given translation.
|
|
57
|
+
*
|
|
58
|
+
* Search order:
|
|
59
|
+
* 0. data-cms-key attribute match (precise — skips all heuristics)
|
|
60
|
+
* 1. Exact text node match
|
|
61
|
+
* 2. Element content match (handles split siblings)
|
|
62
|
+
* 3. Normalized text node match (strips {{interpolation}} placeholders)
|
|
63
|
+
* 4. Normalized element match
|
|
64
|
+
* 5. Key fallback (when value is empty — i18next renders the key as text)
|
|
65
|
+
*/
|
|
66
|
+
export function highlightTranslationKey(value, key) {
|
|
67
|
+
clearHighlights();
|
|
68
|
+
// --- Strategy 0: data-cms-key attribute (precise) -----------------------
|
|
69
|
+
const byAttr = findByDataAttribute(key);
|
|
70
|
+
if (byAttr.length > 0) {
|
|
71
|
+
applyHighlights(byAttr, 'data-cms-key attribute');
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
// --- Heuristic fallback strategies --------------------------------------
|
|
75
|
+
const normalized = value ? normalizeForSearch(value) : '';
|
|
76
|
+
const hasInterpolation = value ? normalized !== value : false;
|
|
77
|
+
const candidates = [];
|
|
78
|
+
if (value && value.trim() !== '') {
|
|
79
|
+
candidates.push({ label: 'exact text node', search: value, fn: findByTextNodes }, {
|
|
80
|
+
label: 'element content',
|
|
81
|
+
search: value,
|
|
82
|
+
fn: findByElementContent,
|
|
83
|
+
});
|
|
84
|
+
if (hasInterpolation && normalized) {
|
|
85
|
+
candidates.push({
|
|
86
|
+
label: 'normalized text node',
|
|
87
|
+
search: normalized,
|
|
88
|
+
fn: findByTextNodes,
|
|
89
|
+
}, {
|
|
90
|
+
label: 'normalized element',
|
|
91
|
+
search: normalized,
|
|
92
|
+
fn: findByElementContent,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
const keyWithoutNs = key.includes(':')
|
|
98
|
+
? key.split(':').slice(1).join(':')
|
|
99
|
+
: key;
|
|
100
|
+
candidates.push({ label: 'key (full)', search: key, fn: findByTextNodes }, { label: 'key (no ns)', search: keyWithoutNs, fn: findByTextNodes }, { label: 'key element', search: key, fn: findByElementContent }, {
|
|
101
|
+
label: 'key element (no ns)',
|
|
102
|
+
search: keyWithoutNs,
|
|
103
|
+
fn: findByElementContent,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
for (const { label, search, fn } of candidates) {
|
|
107
|
+
const found = fn(search);
|
|
108
|
+
if (found.length > 0) {
|
|
109
|
+
state.setCurrentSearchValue(search);
|
|
110
|
+
applyHighlights(found, label);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
console.warn(`[CMS Preview] No elements found for key: "${key}" value: "${value}"`);
|
|
115
|
+
}
|
|
116
|
+
function applyHighlights(elements, matchLabel) {
|
|
117
|
+
console.log(`[CMS Preview] Highlighting ${elements.length} element(s) via ${matchLabel}`);
|
|
118
|
+
elements.forEach((el, i) => {
|
|
119
|
+
el.classList.add('cms-preview-highlight');
|
|
120
|
+
state.addHighlightedElement(el);
|
|
121
|
+
if (i === 0) {
|
|
122
|
+
el.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
export function clearHighlights() {
|
|
127
|
+
for (const el of state.highlightedElements) {
|
|
128
|
+
el.classList.remove('cms-preview-highlight');
|
|
129
|
+
}
|
|
130
|
+
state.setHighlightedElements([]);
|
|
131
|
+
state.setCurrentSearchValue(null);
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Update highlighted elements with live translation changes.
|
|
135
|
+
*/
|
|
136
|
+
export function updateLiveText(oldValue, newValue) {
|
|
137
|
+
if (state.highlightedElements.length === 0)
|
|
138
|
+
return;
|
|
139
|
+
const searchFor = state.currentLiveValue ??
|
|
140
|
+
(oldValue || state.currentSearchValue) ??
|
|
141
|
+
oldValue;
|
|
142
|
+
for (const el of state.highlightedElements) {
|
|
143
|
+
const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT, null);
|
|
144
|
+
let node;
|
|
145
|
+
while ((node = walker.nextNode())) {
|
|
146
|
+
if (node.nodeValue?.includes(searchFor)) {
|
|
147
|
+
node.nodeValue = node.nodeValue.replace(searchFor, newValue);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
state.setCurrentLiveValue(newValue);
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=highlight.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"highlight.js","sourceRoot":"","sources":["../../../src/preview/internals/highlight.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interaction blocking for preview mode.
|
|
3
|
+
* Prevents users from clicking links or submitting forms while previewing.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Inject a transparent full-page overlay that absorbs pointer events,
|
|
7
|
+
* and register capture-phase listeners for belt-and-suspenders blocking
|
|
8
|
+
* (covers keyboard-activated links/buttons the overlay doesn't intercept).
|
|
9
|
+
*/
|
|
10
|
+
export declare function injectInteractionBlocker(): void;
|
|
11
|
+
/**
|
|
12
|
+
* Remove interaction blocker and event listeners.
|
|
13
|
+
*/
|
|
14
|
+
export declare function removeInteractionBlocker(): void;
|
|
15
|
+
//# sourceMappingURL=interactions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interactions.d.ts","sourceRoot":"","sources":["../../../src/preview/internals/interactions.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAaH;;;;GAIG;AACH,wBAAgB,wBAAwB,IAAI,IAAI,CAU/C;AAED;;GAEG;AACH,wBAAgB,wBAAwB,IAAI,IAAI,CAK/C"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interaction blocking for preview mode.
|
|
3
|
+
* Prevents users from clicking links or submitting forms while previewing.
|
|
4
|
+
*/
|
|
5
|
+
import * as state from './state.js';
|
|
6
|
+
/**
|
|
7
|
+
* Capture-phase handler that swallows all clicks and form submits.
|
|
8
|
+
* Prevents links from navigating and buttons from firing actions.
|
|
9
|
+
*/
|
|
10
|
+
function blockInteraction(e) {
|
|
11
|
+
e.preventDefault();
|
|
12
|
+
e.stopPropagation();
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Inject a transparent full-page overlay that absorbs pointer events,
|
|
16
|
+
* and register capture-phase listeners for belt-and-suspenders blocking
|
|
17
|
+
* (covers keyboard-activated links/buttons the overlay doesn't intercept).
|
|
18
|
+
*/
|
|
19
|
+
export function injectInteractionBlocker() {
|
|
20
|
+
const overlay = document.createElement('div');
|
|
21
|
+
overlay.id = 'cms-preview-blocker';
|
|
22
|
+
overlay.style.cssText =
|
|
23
|
+
'position:fixed;inset:0;z-index:9997;pointer-events:all;cursor:default;';
|
|
24
|
+
document.body.appendChild(overlay);
|
|
25
|
+
state.setInteractionBlockerOverlay(overlay);
|
|
26
|
+
document.addEventListener('click', blockInteraction, true);
|
|
27
|
+
document.addEventListener('submit', blockInteraction, true);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Remove interaction blocker and event listeners.
|
|
31
|
+
*/
|
|
32
|
+
export function removeInteractionBlocker() {
|
|
33
|
+
document.removeEventListener('click', blockInteraction, true);
|
|
34
|
+
document.removeEventListener('submit', blockInteraction, true);
|
|
35
|
+
state.interactionBlockerOverlay?.remove();
|
|
36
|
+
state.setInteractionBlockerOverlay(null);
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=interactions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interactions.js","sourceRoot":"","sources":["../../../src/preview/internals/interactions.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,KAAK,MAAM,YAAY,CAAC;AAEpC;;;GAGG;AACH,SAAS,gBAAgB,CAAC,CAAQ;IAC9B,CAAC,CAAC,cAAc,EAAE,CAAC;IACnB,CAAC,CAAC,eAAe,EAAE,CAAC;AACxB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,wBAAwB;IACpC,MAAM,OAAO,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IAC9C,OAAO,CAAC,EAAE,GAAG,qBAAqB,CAAC;IACnC,OAAO,CAAC,KAAK,CAAC,OAAO;QACjB,wEAAwE,CAAC;IAC7E,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IACnC,KAAK,CAAC,4BAA4B,CAAC,OAAO,CAAC,CAAC;IAE5C,QAAQ,CAAC,gBAAgB,CAAC,OAAO,EAAE,gBAAgB,EAAE,IAAI,CAAC,CAAC;IAC3D,QAAQ,CAAC,gBAAgB,CAAC,QAAQ,EAAE,gBAAgB,EAAE,IAAI,CAAC,CAAC;AAChE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,wBAAwB;IACpC,QAAQ,CAAC,mBAAmB,CAAC,OAAO,EAAE,gBAAgB,EAAE,IAAI,CAAC,CAAC;IAC9D,QAAQ,CAAC,mBAAmB,CAAC,QAAQ,EAAE,gBAAgB,EAAE,IAAI,CAAC,CAAC;IAC/D,KAAK,CAAC,yBAAyB,EAAE,MAAM,EAAE,CAAC;IAC1C,KAAK,CAAC,4BAA4B,CAAC,IAAI,CAAC,CAAC;AAC7C,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Locale switching logic for preview listener.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Handle a locale switch request from the CMS.
|
|
6
|
+
* Tries the provided callback first, then falls back to window.__cmsSetLocale.
|
|
7
|
+
*/
|
|
8
|
+
export declare function handleLocaleSwitch(locale: string): void;
|
|
9
|
+
//# sourceMappingURL=locales.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"locales.d.ts","sourceRoot":"","sources":["../../../src/preview/internals/locales.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAmBvD"}
|