lingo-guardian 0.1.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 (38) hide show
  1. package/README.md +45 -0
  2. package/dist/bin/cli.d.ts +10 -0
  3. package/dist/bin/cli.d.ts.map +1 -0
  4. package/dist/bin/cli.js +36 -0
  5. package/dist/bin/cli.js.map +1 -0
  6. package/dist/commands/lint.d.ts +19 -0
  7. package/dist/commands/lint.d.ts.map +1 -0
  8. package/dist/commands/lint.js +166 -0
  9. package/dist/commands/lint.js.map +1 -0
  10. package/dist/constants.d.ts +110 -0
  11. package/dist/constants.d.ts.map +1 -0
  12. package/dist/constants.js +41 -0
  13. package/dist/constants.js.map +1 -0
  14. package/dist/core/auditor.d.ts +62 -0
  15. package/dist/core/auditor.d.ts.map +1 -0
  16. package/dist/core/auditor.js +261 -0
  17. package/dist/core/auditor.js.map +1 -0
  18. package/dist/core/lingo-integration.d.ts +109 -0
  19. package/dist/core/lingo-integration.d.ts.map +1 -0
  20. package/dist/core/lingo-integration.js +243 -0
  21. package/dist/core/lingo-integration.js.map +1 -0
  22. package/dist/index.d.ts +12 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +11 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/reporters/reporter.d.ts +35 -0
  27. package/dist/reporters/reporter.d.ts.map +1 -0
  28. package/dist/reporters/reporter.js +322 -0
  29. package/dist/reporters/reporter.js.map +1 -0
  30. package/dist/transforms/pseudo-locale.d.ts +22 -0
  31. package/dist/transforms/pseudo-locale.d.ts.map +1 -0
  32. package/dist/transforms/pseudo-locale.js +181 -0
  33. package/dist/transforms/pseudo-locale.js.map +1 -0
  34. package/dist/transforms/rtl.d.ts +26 -0
  35. package/dist/transforms/rtl.d.ts.map +1 -0
  36. package/dist/transforms/rtl.js +120 -0
  37. package/dist/transforms/rtl.js.map +1 -0
  38. package/package.json +70 -0
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Reporter - Formats and outputs audit results
3
+ *
4
+ * Supports multiple output formats:
5
+ * - Table (default): Pretty terminal output
6
+ * - JSON: Machine-readable format
7
+ * - HTML: Visual report with styling
8
+ */
9
+ import type { AuditResult } from '../constants.js';
10
+ export type OutputFormat = 'table' | 'json' | 'html';
11
+ export declare class Reporter {
12
+ private format;
13
+ constructor(format?: OutputFormat);
14
+ /**
15
+ * Generate report from audit results
16
+ */
17
+ report(results: AuditResult[]): Promise<string>;
18
+ /**
19
+ * Print report to console
20
+ */
21
+ print(results: AuditResult[]): void;
22
+ /**
23
+ * Save report to file
24
+ */
25
+ save(results: AuditResult[], outputPath: string): Promise<void>;
26
+ private formatTable;
27
+ private formatJSON;
28
+ private formatHTML;
29
+ private formatSeverity;
30
+ private formatOverflow;
31
+ private colorize;
32
+ private truncate;
33
+ private escapeHtml;
34
+ }
35
+ //# sourceMappingURL=reporter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reporter.d.ts","sourceRoot":"","sources":["../../src/reporters/reporter.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,WAAW,EAA2B,MAAM,iBAAiB,CAAC;AAI5E,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;AAErD,qBAAa,QAAQ;IACjB,OAAO,CAAC,MAAM,CAAe;gBAEjB,MAAM,GAAE,YAAsB;IAI1C;;OAEG;IACG,MAAM,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IAYrD;;OAEG;IACH,KAAK,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,IAAI;IAsFnC;;OAEG;IACG,IAAI,CAAC,OAAO,EAAE,WAAW,EAAE,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAYrE,OAAO,CAAC,WAAW;IAsBnB,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,UAAU;IAoJlB,OAAO,CAAC,cAAc;IAWtB,OAAO,CAAC,cAAc;IAatB,OAAO,CAAC,QAAQ;IAMhB,OAAO,CAAC,QAAQ;IAKhB,OAAO,CAAC,UAAU;CAOrB"}
@@ -0,0 +1,322 @@
1
+ /**
2
+ * Reporter - Formats and outputs audit results
3
+ *
4
+ * Supports multiple output formats:
5
+ * - Table (default): Pretty terminal output
6
+ * - JSON: Machine-readable format
7
+ * - HTML: Visual report with styling
8
+ */
9
+ import chalk from 'chalk';
10
+ import { table } from 'table';
11
+ import fs from 'fs/promises';
12
+ import path from 'path';
13
+ export class Reporter {
14
+ format;
15
+ constructor(format = 'table') {
16
+ this.format = format;
17
+ }
18
+ /**
19
+ * Generate report from audit results
20
+ */
21
+ async report(results) {
22
+ switch (this.format) {
23
+ case 'json':
24
+ return this.formatJSON(results);
25
+ case 'html':
26
+ return this.formatHTML(results);
27
+ case 'table':
28
+ default:
29
+ return this.formatTable(results);
30
+ }
31
+ }
32
+ /**
33
+ * Print report to console
34
+ */
35
+ print(results) {
36
+ const totalIssues = results.reduce((sum, r) => sum + r.issueCount, 0);
37
+ const errors = results.flatMap((r) => r.issues).filter((i) => i.severity === 'error').length;
38
+ const warnings = results.flatMap((r) => r.issues).filter((i) => i.severity === 'warning').length;
39
+ console.log('\n' + chalk.bold('═══ LINGO-GUARDIAN AUDIT RESULTS ═══') + '\n');
40
+ // Summary
41
+ console.log(chalk.bold('📊 Summary'));
42
+ console.log(` URL: ${chalk.cyan(results[0]?.url || 'N/A')}`);
43
+ console.log(` Locales tested: ${chalk.cyan(results.map((r) => r.locale).join(', '))}`);
44
+ console.log(` Total issues: ${this.colorize(totalIssues, 'count')}`);
45
+ console.log(` Errors: ${chalk.red(errors)}`);
46
+ console.log(` Warnings: ${chalk.yellow(warnings)}`);
47
+ console.log();
48
+ // Issues by locale
49
+ for (const result of results) {
50
+ if (result.issues.length === 0) {
51
+ console.log(chalk.green(`✓ ${result.locale.toUpperCase()}: No issues found`));
52
+ continue;
53
+ }
54
+ console.log(chalk.bold(`\n🔍 ${result.locale.toUpperCase()} (${result.issues.length} issues)`));
55
+ const tableData = [
56
+ [
57
+ chalk.bold('Severity'),
58
+ chalk.bold('Element'),
59
+ chalk.bold('Overflow'),
60
+ chalk.bold('Text'),
61
+ ],
62
+ ...result.issues.map((issue) => [
63
+ this.formatSeverity(issue.severity),
64
+ this.truncate(issue.selector, 40),
65
+ this.formatOverflow(issue),
66
+ this.truncate(issue.textContent, 25),
67
+ ]),
68
+ ];
69
+ console.log(table(tableData, {
70
+ border: {
71
+ topBody: '─',
72
+ topJoin: '┬',
73
+ topLeft: '┌',
74
+ topRight: '┐',
75
+ bottomBody: '─',
76
+ bottomJoin: '┴',
77
+ bottomLeft: '└',
78
+ bottomRight: '┘',
79
+ bodyLeft: '│',
80
+ bodyRight: '│',
81
+ bodyJoin: '│',
82
+ joinBody: '─',
83
+ joinLeft: '├',
84
+ joinRight: '┤',
85
+ joinJoin: '┼',
86
+ },
87
+ }));
88
+ }
89
+ // Overall status
90
+ console.log();
91
+ if (errors > 0) {
92
+ console.log(chalk.bgRed.white.bold(' FAIL ') +
93
+ ` Found ${errors} error(s) that will likely cause layout breaks.`);
94
+ }
95
+ else if (warnings > 0) {
96
+ console.log(chalk.bgYellow.black.bold(' WARN ') +
97
+ ` Found ${warnings} warning(s) that should be reviewed.`);
98
+ }
99
+ else if (totalIssues > 0) {
100
+ console.log(chalk.bgBlue.white.bold(' INFO ') +
101
+ ` Found ${totalIssues} minor issue(s).`);
102
+ }
103
+ else {
104
+ console.log(chalk.bgGreen.white.bold(' PASS ') + ' No i18n layout issues detected! 🎉');
105
+ }
106
+ console.log();
107
+ }
108
+ /**
109
+ * Save report to file
110
+ */
111
+ async save(results, outputPath) {
112
+ const content = await this.report(results);
113
+ const ext = this.format === 'json' ? 'json' : this.format === 'html' ? 'html' : 'txt';
114
+ const filename = `lingo-guardian-report-${Date.now()}.${ext}`;
115
+ const fullPath = path.join(outputPath, filename);
116
+ await fs.mkdir(outputPath, { recursive: true });
117
+ await fs.writeFile(fullPath, content, 'utf-8');
118
+ console.log(chalk.green(`\n📄 Report saved to: ${fullPath}`));
119
+ }
120
+ formatTable(results) {
121
+ // Return plain text version of the table
122
+ const lines = [];
123
+ for (const result of results) {
124
+ lines.push(`\n=== ${result.locale.toUpperCase()} ===`);
125
+ lines.push(`URL: ${result.url}`);
126
+ lines.push(`Issues: ${result.issueCount}`);
127
+ lines.push('');
128
+ for (const issue of result.issues) {
129
+ lines.push(`[${issue.severity.toUpperCase()}] ${issue.selector}` +
130
+ ` (${issue.scrollWidth}x${issue.scrollHeight} > ${issue.offsetWidth}x${issue.offsetHeight})` +
131
+ ` "${issue.textContent}"`);
132
+ }
133
+ }
134
+ return lines.join('\n');
135
+ }
136
+ formatJSON(results) {
137
+ return JSON.stringify(results, null, 2);
138
+ }
139
+ formatHTML(results) {
140
+ const totalIssues = results.reduce((sum, r) => sum + r.issueCount, 0);
141
+ const errors = results.flatMap((r) => r.issues).filter((i) => i.severity === 'error').length;
142
+ return `<!DOCTYPE html>
143
+ <html lang="en">
144
+ <head>
145
+ <meta charset="UTF-8">
146
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
147
+ <title>Lingo-Guardian Audit Report</title>
148
+ <style>
149
+ * { box-sizing: border-box; margin: 0; padding: 0; }
150
+ body {
151
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
152
+ background: #0f172a;
153
+ color: #e2e8f0;
154
+ padding: 2rem;
155
+ min-height: 100vh;
156
+ }
157
+ .container { max-width: 1200px; margin: 0 auto; }
158
+ h1 {
159
+ font-size: 2rem;
160
+ background: linear-gradient(135deg, #8B5CF6, #06B6D4);
161
+ -webkit-background-clip: text;
162
+ -webkit-text-fill-color: transparent;
163
+ margin-bottom: 1rem;
164
+ }
165
+ .summary {
166
+ display: grid;
167
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
168
+ gap: 1rem;
169
+ margin: 2rem 0;
170
+ }
171
+ .stat {
172
+ background: #1e293b;
173
+ border-radius: 12px;
174
+ padding: 1.5rem;
175
+ text-align: center;
176
+ }
177
+ .stat-value { font-size: 2.5rem; font-weight: bold; }
178
+ .stat-label { color: #94a3b8; margin-top: 0.5rem; }
179
+ .stat.error .stat-value { color: #f87171; }
180
+ .stat.warning .stat-value { color: #fbbf24; }
181
+ .stat.success .stat-value { color: #4ade80; }
182
+ .locale-section { margin: 2rem 0; }
183
+ .locale-header {
184
+ background: #1e293b;
185
+ padding: 1rem 1.5rem;
186
+ border-radius: 12px 12px 0 0;
187
+ font-weight: 600;
188
+ }
189
+ table { width: 100%; border-collapse: collapse; }
190
+ th, td { padding: 1rem; text-align: left; border-bottom: 1px solid #334155; }
191
+ th { background: #1e293b; color: #94a3b8; font-weight: 500; }
192
+ td { background: #0f172a; }
193
+ .severity {
194
+ display: inline-block;
195
+ padding: 0.25rem 0.75rem;
196
+ border-radius: 99px;
197
+ font-size: 0.75rem;
198
+ font-weight: 600;
199
+ text-transform: uppercase;
200
+ }
201
+ .severity.error { background: #7f1d1d; color: #fca5a5; }
202
+ .severity.warning { background: #78350f; color: #fcd34d; }
203
+ .severity.info { background: #1e3a5f; color: #7dd3fc; }
204
+ .selector { font-family: monospace; font-size: 0.85rem; color: #06B6D4; }
205
+ .overflow { color: #f472b6; font-family: monospace; }
206
+ .text { color: #94a3b8; max-width: 200px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
207
+ .pass-badge {
208
+ background: linear-gradient(135deg, #4ade80, #22d3ee);
209
+ color: #0f172a;
210
+ padding: 1rem 2rem;
211
+ border-radius: 12px;
212
+ font-size: 1.25rem;
213
+ font-weight: 600;
214
+ text-align: center;
215
+ margin: 2rem 0;
216
+ }
217
+ </style>
218
+ </head>
219
+ <body>
220
+ <div class="container">
221
+ <h1>🛡️ Lingo-Guardian Audit Report</h1>
222
+ <p>Generated: ${new Date().toLocaleString()}</p>
223
+
224
+ <div class="summary">
225
+ <div class="stat ${totalIssues === 0 ? 'success' : errors > 0 ? 'error' : 'warning'}">
226
+ <div class="stat-value">${totalIssues}</div>
227
+ <div class="stat-label">Total Issues</div>
228
+ </div>
229
+ <div class="stat">
230
+ <div class="stat-value">${results.length}</div>
231
+ <div class="stat-label">Locales Tested</div>
232
+ </div>
233
+ <div class="stat error">
234
+ <div class="stat-value">${errors}</div>
235
+ <div class="stat-label">Errors</div>
236
+ </div>
237
+ </div>
238
+
239
+ ${totalIssues === 0 ? '<div class="pass-badge">✓ No i18n layout issues detected! 🎉</div>' : ''}
240
+
241
+ ${results
242
+ .map((result) => `
243
+ <div class="locale-section">
244
+ <div class="locale-header">
245
+ ${result.locale.toUpperCase()} - ${result.issues.length} issues
246
+ </div>
247
+ ${result.issues.length > 0
248
+ ? `
249
+ <table>
250
+ <thead>
251
+ <tr>
252
+ <th>Severity</th>
253
+ <th>Element</th>
254
+ <th>Overflow</th>
255
+ <th>Text</th>
256
+ </tr>
257
+ </thead>
258
+ <tbody>
259
+ ${result.issues
260
+ .map((issue) => `
261
+ <tr>
262
+ <td><span class="severity ${issue.severity}">${issue.severity}</span></td>
263
+ <td class="selector">${this.escapeHtml(issue.selector)}</td>
264
+ <td class="overflow">${issue.overflowDirection}: ${issue.scrollWidth - issue.offsetWidth}px</td>
265
+ <td class="text">${this.escapeHtml(issue.textContent)}</td>
266
+ </tr>
267
+ `)
268
+ .join('')}
269
+ </tbody>
270
+ </table>
271
+ `
272
+ : '<p style="padding: 1rem; background: #1e293b; border-radius: 0 0 12px 12px;">✓ No issues</p>'}
273
+ </div>
274
+ `)
275
+ .join('')}
276
+ </div>
277
+ </body>
278
+ </html>`;
279
+ }
280
+ formatSeverity(severity) {
281
+ switch (severity) {
282
+ case 'error':
283
+ return chalk.red('● ERROR');
284
+ case 'warning':
285
+ return chalk.yellow('● WARN');
286
+ case 'info':
287
+ return chalk.blue('● INFO');
288
+ }
289
+ }
290
+ formatOverflow(issue) {
291
+ const direction = issue.overflowDirection === 'horizontal' ? '↔' : issue.overflowDirection === 'vertical' ? '↕' : '↔↕';
292
+ const widthDiff = issue.scrollWidth - issue.offsetWidth;
293
+ const heightDiff = issue.scrollHeight - issue.offsetHeight;
294
+ if (issue.overflowDirection === 'horizontal') {
295
+ return chalk.magenta(`${direction} +${widthDiff}px`);
296
+ }
297
+ else if (issue.overflowDirection === 'vertical') {
298
+ return chalk.magenta(`${direction} +${heightDiff}px`);
299
+ }
300
+ return chalk.magenta(`${direction} +${widthDiff}x${heightDiff}px`);
301
+ }
302
+ colorize(value, type) {
303
+ if (value === 0)
304
+ return chalk.green(value.toString());
305
+ if (value <= 3)
306
+ return chalk.yellow(value.toString());
307
+ return chalk.red(value.toString());
308
+ }
309
+ truncate(str, maxLength) {
310
+ if (str.length <= maxLength)
311
+ return str;
312
+ return str.slice(0, maxLength - 3) + '...';
313
+ }
314
+ escapeHtml(str) {
315
+ return str
316
+ .replace(/&/g, '&amp;')
317
+ .replace(/</g, '&lt;')
318
+ .replace(/>/g, '&gt;')
319
+ .replace(/"/g, '&quot;');
320
+ }
321
+ }
322
+ //# sourceMappingURL=reporter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reporter.js","sourceRoot":"","sources":["../../src/reporters/reporter.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AAE9B,OAAO,EAAE,MAAM,aAAa,CAAC;AAC7B,OAAO,IAAI,MAAM,MAAM,CAAC;AAIxB,MAAM,OAAO,QAAQ;IACT,MAAM,CAAe;IAE7B,YAAY,SAAuB,OAAO;QACtC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACzB,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,MAAM,CAAC,OAAsB;QAC/B,QAAQ,IAAI,CAAC,MAAM,EAAE,CAAC;YAClB,KAAK,MAAM;gBACP,OAAO,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;YACpC,KAAK,MAAM;gBACP,OAAO,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;YACpC,KAAK,OAAO,CAAC;YACb;gBACI,OAAO,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QACzC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,OAAsB;QACxB,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;QACtE,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,MAAM,CAAC;QAC7F,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,MAAM,CAAC;QAEjG,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,sCAAsC,CAAC,GAAG,IAAI,CAAC,CAAC;QAE9E,UAAU;QACV,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;QACtC,OAAO,CAAC,GAAG,CAAC,WAAW,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,KAAK,CAAC,EAAE,CAAC,CAAC;QAC/D,OAAO,CAAC,GAAG,CAAC,sBAAsB,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC;QACzF,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC;QACvE,OAAO,CAAC,GAAG,CAAC,cAAc,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAC/C,OAAO,CAAC,GAAG,CAAC,gBAAgB,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QACtD,OAAO,CAAC,GAAG,EAAE,CAAC;QAEd,mBAAmB;QACnB,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC3B,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC7B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,mBAAmB,CAAC,CAAC,CAAC;gBAC9E,SAAS;YACb,CAAC;YAED,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC,MAAM,CAAC,MAAM,UAAU,CAAC,CAAC,CAAC;YAEhG,MAAM,SAAS,GAAG;gBACd;oBACI,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC;oBACtB,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC;oBACrB,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC;oBACtB,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC;iBACrB;gBACD,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC;oBAC5B,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,QAAQ,CAAC;oBACnC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,EAAE,CAAC;oBACjC,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC;oBAC1B,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;iBACvC,CAAC;aACL,CAAC;YAEF,OAAO,CAAC,GAAG,CACP,KAAK,CAAC,SAAS,EAAE;gBACb,MAAM,EAAE;oBACJ,OAAO,EAAE,GAAG;oBACZ,OAAO,EAAE,GAAG;oBACZ,OAAO,EAAE,GAAG;oBACZ,QAAQ,EAAE,GAAG;oBACb,UAAU,EAAE,GAAG;oBACf,UAAU,EAAE,GAAG;oBACf,UAAU,EAAE,GAAG;oBACf,WAAW,EAAE,GAAG;oBAChB,QAAQ,EAAE,GAAG;oBACb,SAAS,EAAE,GAAG;oBACd,QAAQ,EAAE,GAAG;oBACb,QAAQ,EAAE,GAAG;oBACb,QAAQ,EAAE,GAAG;oBACb,SAAS,EAAE,GAAG;oBACd,QAAQ,EAAE,GAAG;iBAChB;aACJ,CAAC,CACL,CAAC;QACN,CAAC;QAED,iBAAiB;QACjB,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;YACb,OAAO,CAAC,GAAG,CACP,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC;gBAChC,UAAU,MAAM,iDAAiD,CACpE,CAAC;QACN,CAAC;aAAM,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;YACtB,OAAO,CAAC,GAAG,CACP,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC;gBACnC,UAAU,QAAQ,sCAAsC,CAC3D,CAAC;QACN,CAAC;aAAM,IAAI,WAAW,GAAG,CAAC,EAAE,CAAC;YACzB,OAAO,CAAC,GAAG,CACP,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC;gBACjC,UAAU,WAAW,kBAAkB,CAC1C,CAAC;QACN,CAAC;aAAM,CAAC;YACJ,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,qCAAqC,CAAC,CAAC;QAC5F,CAAC;QACD,OAAO,CAAC,GAAG,EAAE,CAAC;IAClB,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,IAAI,CAAC,OAAsB,EAAE,UAAkB;QACjD,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC3C,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC;QACtF,MAAM,QAAQ,GAAG,yBAAyB,IAAI,CAAC,GAAG,EAAE,IAAI,GAAG,EAAE,CAAC;QAC9D,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QAEjD,MAAM,EAAE,CAAC,KAAK,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAChD,MAAM,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QAE/C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,yBAAyB,QAAQ,EAAE,CAAC,CAAC,CAAC;IAClE,CAAC;IAEO,WAAW,CAAC,OAAsB;QACtC,yCAAyC;QACzC,MAAM,KAAK,GAAa,EAAE,CAAC;QAE3B,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC3B,KAAK,CAAC,IAAI,CAAC,SAAS,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;YACvD,KAAK,CAAC,IAAI,CAAC,QAAQ,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC;YACjC,KAAK,CAAC,IAAI,CAAC,WAAW,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;YAC3C,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAEf,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;gBAChC,KAAK,CAAC,IAAI,CACN,IAAI,KAAK,CAAC,QAAQ,CAAC,WAAW,EAAE,KAAK,KAAK,CAAC,QAAQ,EAAE;oBACrD,MAAM,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC,YAAY,MAAM,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC,YAAY,GAAG;oBAC7F,MAAM,KAAK,CAAC,WAAW,GAAG,CAC7B,CAAC;YACN,CAAC;QACL,CAAC;QAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IAEO,UAAU,CAAC,OAAsB;QACrC,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAC5C,CAAC;IAEO,UAAU,CAAC,OAAsB;QACrC,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;QACtE,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,MAAM,CAAC;QAE7F,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oBAgFK,IAAI,IAAI,EAAE,CAAC,cAAc,EAAE;;;yBAGtB,WAAW,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS;kCACvD,WAAW;;;;kCAIX,OAAO,CAAC,MAAM;;;;kCAId,MAAM;;;;;MAKlC,WAAW,KAAK,CAAC,CAAC,CAAC,CAAC,oEAAoE,CAAC,CAAC,CAAC,EAAE;;MAE7F,OAAO;aACI,GAAG,CACA,CAAC,MAAM,EAAE,EAAE,CAAC;;;UAGtB,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM;;QAEvD,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC;YACJ,CAAC,CAAC;;;;;;;;;;;YAWlB,MAAM,CAAC,MAAM;iBACQ,GAAG,CACA,CAAC,KAAK,EAAE,EAAE,CAAC;;wCAEP,KAAK,CAAC,QAAQ,KAAK,KAAK,CAAC,QAAQ;mCACtC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC;mCAC/B,KAAK,CAAC,iBAAiB,KAAK,KAAK,CAAC,WAAW,GAAG,KAAK,CAAC,WAAW;+BACrE,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,WAAW,CAAC;;WAEtD,CACsB;iBACA,IAAI,CAAC,EAAE,CAAC;;;OAGlC;YACqB,CAAC,CAAC,8FACN;;KAEnB,CACY;aACA,IAAI,CAAC,EAAE,CAAC;;;QAGjB,CAAC;IACL,CAAC;IAEO,cAAc,CAAC,QAAkB;QACrC,QAAQ,QAAQ,EAAE,CAAC;YACf,KAAK,OAAO;gBACR,OAAO,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YAChC,KAAK,SAAS;gBACV,OAAO,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YAClC,KAAK,MAAM;gBACP,OAAO,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACpC,CAAC;IACL,CAAC;IAEO,cAAc,CAAC,KAAoB;QACvC,MAAM,SAAS,GAAG,KAAK,CAAC,iBAAiB,KAAK,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,iBAAiB,KAAK,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;QACvH,MAAM,SAAS,GAAG,KAAK,CAAC,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC;QACxD,MAAM,UAAU,GAAG,KAAK,CAAC,YAAY,GAAG,KAAK,CAAC,YAAY,CAAC;QAE3D,IAAI,KAAK,CAAC,iBAAiB,KAAK,YAAY,EAAE,CAAC;YAC3C,OAAO,KAAK,CAAC,OAAO,CAAC,GAAG,SAAS,KAAK,SAAS,IAAI,CAAC,CAAC;QACzD,CAAC;aAAM,IAAI,KAAK,CAAC,iBAAiB,KAAK,UAAU,EAAE,CAAC;YAChD,OAAO,KAAK,CAAC,OAAO,CAAC,GAAG,SAAS,KAAK,UAAU,IAAI,CAAC,CAAC;QAC1D,CAAC;QACD,OAAO,KAAK,CAAC,OAAO,CAAC,GAAG,SAAS,KAAK,SAAS,IAAI,UAAU,IAAI,CAAC,CAAC;IACvE,CAAC;IAEO,QAAQ,CAAC,KAAa,EAAE,IAAa;QACzC,IAAI,KAAK,KAAK,CAAC;YAAE,OAAO,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;QACtD,IAAI,KAAK,IAAI,CAAC;YAAE,OAAO,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;QACtD,OAAO,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;IACvC,CAAC;IAEO,QAAQ,CAAC,GAAW,EAAE,SAAiB;QAC3C,IAAI,GAAG,CAAC,MAAM,IAAI,SAAS;YAAE,OAAO,GAAG,CAAC;QACxC,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC;IAC/C,CAAC;IAEO,UAAU,CAAC,GAAW;QAC1B,OAAO,GAAG;aACL,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;aACtB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;aACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;aACrB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACjC,CAAC;CACJ"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Pseudo-Locale Transformation
3
+ *
4
+ * Expands text content to simulate translations that are longer than English.
5
+ * German text is ~30% longer, some languages can be 40%+ longer.
6
+ *
7
+ * NOTE: This is a fallback when Lingo.dev integration is not used.
8
+ * The preferred approach is using Lingo.dev's built-in pseudo-locale.
9
+ */
10
+ import type { Page as PlaywrightPage } from 'playwright';
11
+ export declare class PseudoLocaleTransform {
12
+ /**
13
+ * Apply pseudo-locale transformation using Playwright
14
+ * Cross-platform compatible (Mac, Windows, Linux)
15
+ */
16
+ static applyPlaywright(page: PlaywrightPage, expansionFactor?: number): Promise<void>;
17
+ /**
18
+ * Transform a single string to pseudo-locale (for testing)
19
+ */
20
+ static transform(text: string, expansionFactor?: number): string;
21
+ }
22
+ //# sourceMappingURL=pseudo-locale.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pseudo-locale.d.ts","sourceRoot":"","sources":["../../src/transforms/pseudo-locale.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,IAAI,IAAI,cAAc,EAAE,MAAM,YAAY,CAAC;AAmEzD,qBAAa,qBAAqB;IAC9B;;;OAGG;WACU,eAAe,CACxB,IAAI,EAAE,cAAc,EACpB,eAAe,GAAE,MAAyC,GAC3D,OAAO,CAAC,IAAI,CAAC;IAoGhB;;OAEG;IACH,MAAM,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,eAAe,GAAE,MAAa,GAAG,MAAM;CAmBzE"}
@@ -0,0 +1,181 @@
1
+ /**
2
+ * Pseudo-Locale Transformation
3
+ *
4
+ * Expands text content to simulate translations that are longer than English.
5
+ * German text is ~30% longer, some languages can be 40%+ longer.
6
+ *
7
+ * NOTE: This is a fallback when Lingo.dev integration is not used.
8
+ * The preferred approach is using Lingo.dev's built-in pseudo-locale.
9
+ */
10
+ import { DEFAULTS } from '../constants.js';
11
+ /**
12
+ * Character mappings for pseudo-localization
13
+ * Maps ASCII to accented equivalents for visual distinction
14
+ */
15
+ const CHAR_MAP = {
16
+ a: 'à',
17
+ b: 'ƀ',
18
+ c: 'ç',
19
+ d: 'ð',
20
+ e: 'è',
21
+ f: 'ƒ',
22
+ g: 'ĝ',
23
+ h: 'ĥ',
24
+ i: 'ï',
25
+ j: 'ĵ',
26
+ k: 'ķ',
27
+ l: 'ĺ',
28
+ m: 'ɱ',
29
+ n: 'ñ',
30
+ o: 'ö',
31
+ p: 'þ',
32
+ q: 'ǫ',
33
+ r: 'ŕ',
34
+ s: 'š',
35
+ t: 'ţ',
36
+ u: 'ü',
37
+ v: 'ṿ',
38
+ w: 'ŵ',
39
+ x: 'ẋ',
40
+ y: 'ÿ',
41
+ z: 'ž',
42
+ A: 'À',
43
+ B: 'Ɓ',
44
+ C: 'Ç',
45
+ D: 'Ð',
46
+ E: 'È',
47
+ F: 'Ƒ',
48
+ G: 'Ĝ',
49
+ H: 'Ĥ',
50
+ I: 'Ï',
51
+ J: 'Ĵ',
52
+ K: 'Ķ',
53
+ L: 'Ĺ',
54
+ M: 'Ṃ',
55
+ N: 'Ñ',
56
+ O: 'Ö',
57
+ P: 'Þ',
58
+ Q: 'Ǫ',
59
+ R: 'Ŕ',
60
+ S: 'Š',
61
+ T: 'Ţ',
62
+ U: 'Ü',
63
+ V: 'Ṿ',
64
+ W: 'Ŵ',
65
+ X: 'Ẋ',
66
+ Y: 'Ÿ',
67
+ Z: 'Ž',
68
+ };
69
+ /**
70
+ * Padding characters added to expand text length
71
+ */
72
+ const PADDING_CHARS = ['ẍ', 'ỳ', 'ẑ', 'ẅ'];
73
+ export class PseudoLocaleTransform {
74
+ /**
75
+ * Apply pseudo-locale transformation using Playwright
76
+ * Cross-platform compatible (Mac, Windows, Linux)
77
+ */
78
+ static async applyPlaywright(page, expansionFactor = DEFAULTS.PSEUDO_EXPANSION_FACTOR) {
79
+ await page.evaluate(({ charMap, paddingChars, factor }) => {
80
+ function pseudoLocalize(text) {
81
+ if (!text || text.trim().length === 0)
82
+ return text;
83
+ if (text.includes('://') ||
84
+ text.includes('{') ||
85
+ text.includes('<') ||
86
+ /^[\d\s.,!?]+$/.test(text)) {
87
+ return text;
88
+ }
89
+ let result = '';
90
+ for (const char of text) {
91
+ result += charMap[char] || char;
92
+ }
93
+ const paddingLength = Math.ceil(text.length * factor);
94
+ if (paddingLength > 0) {
95
+ let padding = '';
96
+ for (let i = 0; i < paddingLength; i++) {
97
+ padding += paddingChars[i % paddingChars.length];
98
+ }
99
+ result = `[${result}${padding}]`;
100
+ }
101
+ return result;
102
+ }
103
+ function processTextNodes(node) {
104
+ if (node.nodeType === Node.TEXT_NODE) {
105
+ const text = node.textContent;
106
+ if (text && text.trim().length > 0) {
107
+ node.textContent = pseudoLocalize(text);
108
+ }
109
+ }
110
+ else if (node.nodeType === Node.ELEMENT_NODE) {
111
+ const element = node;
112
+ const tagName = element.tagName.toLowerCase();
113
+ if (tagName === 'script' ||
114
+ tagName === 'style' ||
115
+ tagName === 'noscript' ||
116
+ tagName === 'svg' ||
117
+ tagName === 'textarea' ||
118
+ tagName === 'input') {
119
+ return;
120
+ }
121
+ for (const child of Array.from(node.childNodes)) {
122
+ processTextNodes(child);
123
+ }
124
+ if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement) {
125
+ if (element.placeholder) {
126
+ element.placeholder = pseudoLocalize(element.placeholder);
127
+ }
128
+ }
129
+ const title = element.getAttribute('title');
130
+ if (title) {
131
+ element.setAttribute('title', pseudoLocalize(title));
132
+ }
133
+ const ariaLabel = element.getAttribute('aria-label');
134
+ if (ariaLabel) {
135
+ element.setAttribute('aria-label', pseudoLocalize(ariaLabel));
136
+ }
137
+ }
138
+ }
139
+ processTextNodes(document.body);
140
+ // Add visual indicator
141
+ const indicator = document.createElement('div');
142
+ indicator.id = 'lingo-guardian-pseudo-indicator';
143
+ indicator.style.cssText = `
144
+ position: fixed;
145
+ top: 4px;
146
+ right: 4px;
147
+ background: #8B5CF6;
148
+ color: white;
149
+ padding: 4px 8px;
150
+ border-radius: 4px;
151
+ font-size: 10px;
152
+ font-family: monospace;
153
+ z-index: 99999;
154
+ opacity: 0.9;
155
+ `;
156
+ indicator.textContent = '🔤 PSEUDO';
157
+ document.body.appendChild(indicator);
158
+ }, { charMap: CHAR_MAP, paddingChars: PADDING_CHARS, factor: expansionFactor });
159
+ }
160
+ /**
161
+ * Transform a single string to pseudo-locale (for testing)
162
+ */
163
+ static transform(text, expansionFactor = 0.35) {
164
+ if (!text || text.trim().length === 0)
165
+ return text;
166
+ let result = '';
167
+ for (const char of text) {
168
+ result += CHAR_MAP[char] || char;
169
+ }
170
+ const paddingLength = Math.ceil(text.length * expansionFactor);
171
+ if (paddingLength > 0) {
172
+ let padding = '';
173
+ for (let i = 0; i < paddingLength; i++) {
174
+ padding += PADDING_CHARS[i % PADDING_CHARS.length];
175
+ }
176
+ result = `[${result}${padding}]`;
177
+ }
178
+ return result;
179
+ }
180
+ }
181
+ //# sourceMappingURL=pseudo-locale.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pseudo-locale.js","sourceRoot":"","sources":["../../src/transforms/pseudo-locale.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE3C;;;GAGG;AACH,MAAM,QAAQ,GAA2B;IACrC,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;CACT,CAAC;AAEF;;GAEG;AACH,MAAM,aAAa,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AAE3C,MAAM,OAAO,qBAAqB;IAC9B;;;OAGG;IACH,MAAM,CAAC,KAAK,CAAC,eAAe,CACxB,IAAoB,EACpB,kBAA0B,QAAQ,CAAC,uBAAuB;QAE1D,MAAM,IAAI,CAAC,QAAQ,CACf,CAAC,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,EAAE,EAAE;YAClC,SAAS,cAAc,CAAC,IAAY;gBAChC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC;oBAAE,OAAO,IAAI,CAAC;gBAEnD,IACI,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;oBACpB,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;oBAClB,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;oBAClB,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,EAC5B,CAAC;oBACC,OAAO,IAAI,CAAC;gBAChB,CAAC;gBAED,IAAI,MAAM,GAAG,EAAE,CAAC;gBAChB,KAAK,MAAM,IAAI,IAAI,IAAI,EAAE,CAAC;oBACtB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC;gBACpC,CAAC;gBAED,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC;gBACtD,IAAI,aAAa,GAAG,CAAC,EAAE,CAAC;oBACpB,IAAI,OAAO,GAAG,EAAE,CAAC;oBACjB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,aAAa,EAAE,CAAC,EAAE,EAAE,CAAC;wBACrC,OAAO,IAAI,YAAY,CAAC,CAAC,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;oBACrD,CAAC;oBACD,MAAM,GAAG,IAAI,MAAM,GAAG,OAAO,GAAG,CAAC;gBACrC,CAAC;gBAED,OAAO,MAAM,CAAC;YAClB,CAAC;YAED,SAAS,gBAAgB,CAAC,IAAU;gBAChC,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI,CAAC,SAAS,EAAE,CAAC;oBACnC,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC;oBAC9B,IAAI,IAAI,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;wBACjC,IAAI,CAAC,WAAW,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;oBAC5C,CAAC;gBACL,CAAC;qBAAM,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI,CAAC,YAAY,EAAE,CAAC;oBAC7C,MAAM,OAAO,GAAG,IAAe,CAAC;oBAChC,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;oBAE9C,IACI,OAAO,KAAK,QAAQ;wBACpB,OAAO,KAAK,OAAO;wBACnB,OAAO,KAAK,UAAU;wBACtB,OAAO,KAAK,KAAK;wBACjB,OAAO,KAAK,UAAU;wBACtB,OAAO,KAAK,OAAO,EACrB,CAAC;wBACC,OAAO;oBACX,CAAC;oBAED,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;wBAC9C,gBAAgB,CAAC,KAAK,CAAC,CAAC;oBAC5B,CAAC;oBAED,IAAI,OAAO,YAAY,gBAAgB,IAAI,OAAO,YAAY,mBAAmB,EAAE,CAAC;wBAChF,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;4BACtB,OAAO,CAAC,WAAW,GAAG,cAAc,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;wBAC9D,CAAC;oBACL,CAAC;oBAED,MAAM,KAAK,GAAG,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;oBAC5C,IAAI,KAAK,EAAE,CAAC;wBACR,OAAO,CAAC,YAAY,CAAC,OAAO,EAAE,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC;oBACzD,CAAC;oBAED,MAAM,SAAS,GAAG,OAAO,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC;oBACrD,IAAI,SAAS,EAAE,CAAC;wBACZ,OAAO,CAAC,YAAY,CAAC,YAAY,EAAE,cAAc,CAAC,SAAS,CAAC,CAAC,CAAC;oBAClE,CAAC;gBACL,CAAC;YACL,CAAC;YAED,gBAAgB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YAEhC,uBAAuB;YACvB,MAAM,SAAS,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;YAChD,SAAS,CAAC,EAAE,GAAG,iCAAiC,CAAC;YACjD,SAAS,CAAC,KAAK,CAAC,OAAO,GAAG;;;;;;;;;;;;SAYjC,CAAC;YACM,SAAS,CAAC,WAAW,GAAG,WAAW,CAAC;YACpC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;QACzC,CAAC,EACD,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,EAAE,eAAe,EAAE,CAC9E,CAAC;IACN,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,SAAS,CAAC,IAAY,EAAE,kBAA0B,IAAI;QACzD,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QAEnD,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,KAAK,MAAM,IAAI,IAAI,IAAI,EAAE,CAAC;YACtB,MAAM,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC;QACrC,CAAC;QAED,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,eAAe,CAAC,CAAC;QAC/D,IAAI,aAAa,GAAG,CAAC,EAAE,CAAC;YACpB,IAAI,OAAO,GAAG,EAAE,CAAC;YACjB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,aAAa,EAAE,CAAC,EAAE,EAAE,CAAC;gBACrC,OAAO,IAAI,aAAa,CAAC,CAAC,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;YACvD,CAAC;YACD,MAAM,GAAG,IAAI,MAAM,GAAG,OAAO,GAAG,CAAC;QACrC,CAAC;QAED,OAAO,MAAM,CAAC;IAClB,CAAC;CACJ"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * RTL (Right-to-Left) Transformation
3
+ *
4
+ * Applies RTL layout transformation for testing Arabic, Hebrew,
5
+ * Farsi, and other RTL languages.
6
+ *
7
+ * Detects layout breaks from improper CSS that doesn't support
8
+ * bidirectional text properly.
9
+ */
10
+ import type { Page as PlaywrightPage } from 'playwright';
11
+ export declare class RTLTransform {
12
+ /**
13
+ * Check if a locale is RTL
14
+ */
15
+ static isRTL(locale: string): boolean;
16
+ /**
17
+ * Apply RTL transformation using Playwright
18
+ * Cross-platform compatible (Mac, Windows, Linux)
19
+ */
20
+ static applyPlaywright(page: PlaywrightPage, locale?: string): Promise<void>;
21
+ /**
22
+ * Get sample RTL text for testing
23
+ */
24
+ static getSampleText(locale?: string): string;
25
+ }
26
+ //# sourceMappingURL=rtl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rtl.d.ts","sourceRoot":"","sources":["../../src/transforms/rtl.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,IAAI,IAAI,cAAc,EAAE,MAAM,YAAY,CAAC;AAOzD,qBAAa,YAAY;IACrB;;OAEG;IACH,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAIrC;;;OAGG;WACU,eAAe,CAAC,IAAI,EAAE,cAAc,EAAE,MAAM,GAAE,MAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAwFxF;;OAEG;IACH,MAAM,CAAC,aAAa,CAAC,MAAM,GAAE,MAAa,GAAG,MAAM;CAStD"}