lib-e2e-cypress-for-dummys-ts 1.0.0 → 1.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.
- package/LICENSE +21 -21
- package/README.md +771 -767
- package/dist/chunk-PUZ6LLII.js +2279 -0
- package/dist/chunk-PUZ6LLII.js.map +1 -0
- package/dist/index.cjs +2587 -2131
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +430 -53
- package/dist/index.d.ts +430 -53
- package/dist/index.js +627 -2104
- package/dist/index.js.map +1 -1
- package/dist/runner.js +0 -0
- package/dist/selector-picker-RZGSSHX3.js +7 -0
- package/package.json +76 -74
- package/dist/chunk-24WFAT4W.js +0 -430
- package/dist/chunk-24WFAT4W.js.map +0 -1
- package/dist/selector-picker-KJUXPXHH.js +0 -7
- /package/dist/{selector-picker-KJUXPXHH.js.map → selector-picker-RZGSSHX3.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/code-format.utils.ts","../src/utils/selector-quality.utils.ts","../src/utils/theme.ts","../src/components/selector-picker/selector-picker.styles.ts","../src/utils/html.utils.ts","../src/components/selector-picker/selector-picker.template.ts","../src/models/lang.model.ts","../src/utils/subject.ts","../src/i18n/es.ts","../src/i18n/en.ts","../src/i18n/fr.ts","../src/i18n/it.ts","../src/i18n/de.ts","../src/services/translation.service.ts","../src/components/base.element.ts","../src/components/selector-picker/selector-picker.ts"],"sourcesContent":["function gcd(a: number, b: number): number {\r\n while (b) { const t = b; b = a % b; a = t; }\r\n return a;\r\n}\r\n\r\n/**\r\n * Escapes backslashes and single quotes so a value can be safely embedded inside\r\n * a single-quoted JavaScript string literal — e.g. an `it('…')` / `describe('…')`\r\n * name. Without this, a test named `User's login` produces broken generated JS.\r\n *\r\n * @param value - The raw string to escape.\r\n * @returns The string with backslashes and single quotes escaped.\r\n */\r\nexport function escapeSingleQuotes(value: string): string {\r\n return value.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\");\r\n}\r\n\r\n/**\r\n * Returns a quoted JavaScript string literal for use as the argument to `cy.get()`.\r\n * Uses single-quote wrapping by default; switches to double-quote wrapping when\r\n * the selector contains a single quote, so apostrophes never need backslash escaping\r\n * in the generated Cypress command.\r\n */\r\nexport function selectorLiteral(selector: string): string {\r\n if (selector.includes(\"'\")) {\r\n return `\"${selector.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"')}\"`;\r\n }\r\n return `'${escapeSingleQuotes(selector)}'`;\r\n}\r\n\r\n/**\r\n * Escapes double quotes so a value can be safely embedded inside a CSS\r\n * double-quoted attribute selector, e.g. `[data-cy=\"VALUE\"]`.\r\n * The result must subsequently pass through {@link escapeSingleQuotes} when it is\r\n * placed inside a single-quoted JS string literal (the JS layer doubles the\r\n * backslash introduced here).\r\n *\r\n * @param value - The raw attribute value to escape.\r\n * @returns The string with double quotes escaped.\r\n */\r\nexport function escapeCssAttrValue(value: string): string {\r\n return value.replace(/\"/g, '\\\\\"');\r\n}\r\n\r\n/**\r\n * Normalizes indentation in a code block and prefixes every line with `baseIndent`.\r\n *\r\n * Algorithm:\r\n * 1. Strip trailing whitespace from each line.\r\n * 2. Find the minimum leading-whitespace count of non-empty lines (dedent).\r\n * 3. Compute the indent step as the GCD of all non-zero relative indent values,\r\n * so the original indent unit (4-space, 8-space, etc.) maps to 2-space levels.\r\n * 4. Re-emit each line as: `baseIndent + ' '.repeat(level) + trimmedContent`.\r\n *\r\n * This handles multi-line interceptor/command blocks that were stored with\r\n * inconsistent or file-origin indentation.\r\n *\r\n * @param code - The source code block to normalize.\r\n * @param baseIndent - A string (typically spaces) prepended to every output line.\r\n * @returns The normalized code block, or an empty string if `code` has no non-empty lines.\r\n */\r\nexport function normalizeBlock(code: string, baseIndent: string): string {\r\n const lines = code.split('\\n').map(l => l.trimEnd());\r\n const nonEmpty = lines.filter(l => l.trim().length > 0);\r\n if (!nonEmpty.length) return '';\r\n\r\n const indents = nonEmpty.map(l => l.length - l.trimStart().length);\r\n const minIndent = Math.min(...indents);\r\n const relIndents = [...new Set(indents.map(n => n - minIndent).filter(n => n > 0))];\r\n const step = relIndents.length > 0 ? relIndents.reduce(gcd) : 2;\r\n\r\n return lines\r\n .map(l => {\r\n if (!l.trim()) return '';\r\n const level = Math.round((l.length - l.trimStart().length - minIndent) / step);\r\n return baseIndent + ' '.repeat(level) + l.trimStart();\r\n })\r\n .join('\\n');\r\n}\r\n","import { escapeCssAttrValue } from './code-format.utils';\r\n\r\nexport type SelectorQuality = 'excellent' | 'good' | 'acceptable' | 'poor';\r\n\r\nexport const FORBIDDEN_ID_PREFIXES = [\r\n 'cdk-', 'mat-', 'p-', 'ng-', 'mdc-',\r\n 'primeng-', 'auto-', 'field-', 'input-', 'select-',\r\n];\r\n\r\nexport function getSelectorQuality(el: HTMLElement): SelectorQuality {\r\n if (\r\n el.hasAttribute('data-cy') ||\r\n el.hasAttribute('data-testid') ||\r\n el.hasAttribute('aria-label')\r\n ) {\r\n return 'excellent';\r\n }\r\n\r\n const rawId = el.id;\r\n if (\r\n rawId &&\r\n rawId.length < 25 &&\r\n /^[a-zA-Z][\\w-]*$/.test(rawId) &&\r\n !FORBIDDEN_ID_PREFIXES.some((p) => rawId.startsWith(p)) &&\r\n !/^\\d+$/.test(rawId)\r\n ) {\r\n return 'good';\r\n }\r\n\r\n if (typeof el.className === 'string' && el.className.trim().length > 0) {\r\n return 'acceptable';\r\n }\r\n\r\n return 'poor';\r\n}\r\n\r\n/** Returns the best cy.get() selector string for a given element. */\r\nexport function buildPickerSelector(el: HTMLElement): string {\r\n const dataCy = el.getAttribute('data-cy');\r\n if (dataCy) return `[data-cy=\"${escapeCssAttrValue(dataCy)}\"]`;\r\n\r\n const dataTestid = el.getAttribute('data-testid');\r\n if (dataTestid) return `[data-testid=\"${escapeCssAttrValue(dataTestid)}\"]`;\r\n\r\n const ariaLabel = el.getAttribute('aria-label');\r\n if (ariaLabel) return `[aria-label=\"${escapeCssAttrValue(ariaLabel)}\"]`;\r\n\r\n const rawId = el.id;\r\n if (\r\n rawId &&\r\n rawId.length < 25 &&\r\n /^[a-zA-Z][\\w-]*$/.test(rawId) &&\r\n !FORBIDDEN_ID_PREFIXES.some((p) => rawId.startsWith(p)) &&\r\n !/^\\d+$/.test(rawId)\r\n ) {\r\n return `#${rawId}`;\r\n }\r\n\r\n if (typeof el.className === 'string' && el.className.trim().length > 0) {\r\n const classes = el.className.trim().split(/\\s+/);\r\n return classes.map((c) => `.${c}`).join('');\r\n }\r\n\r\n return el.tagName.toLowerCase();\r\n}\r\n\r\n/** Human-readable key attribute/selector preview for a picker row (raw, unescaped). */\r\nexport function keyAttrDisplay(el: HTMLElement): string {\r\n for (const attr of ['data-cy', 'data-testid', 'aria-label']) {\r\n const v = el.getAttribute(attr);\r\n if (v) return `${attr}=\"${v}\"`;\r\n }\r\n if (el.id) return `id=\"${el.id}\"`;\r\n if (el.className && el.className.trim()) {\r\n return el.className.trim().split(/\\s+/).map((c) => `.${c}`).join('');\r\n }\r\n return '';\r\n}\r\n\r\n/** Plain, serializable view-model for one picker row — no DOM held. */\r\nexport interface PickerRow {\r\n quality: SelectorQuality;\r\n selector: string;\r\n tag: string;\r\n attr: string;\r\n}\r\n\r\n/** Reads an element once and returns the plain data a picker row needs to render. */\r\nexport function describePickerRow(el: HTMLElement): PickerRow {\r\n return {\r\n quality: getSelectorQuality(el),\r\n selector: buildPickerSelector(el),\r\n tag: el.tagName.toLowerCase(),\r\n attr: keyAttrDisplay(el),\r\n };\r\n}\r\n","/**\r\n * Design tokens for the lib-e2e recorder widget.\r\n *\r\n * Import from here instead of hard-coding hex values in *.styles.ts files.\r\n * A single change here propagates to every component automatically.\r\n */\r\n\r\n/** GitHub dark-mode colour palette. */\r\nexport const THEME = {\r\n color: {\r\n // ── Backgrounds ─────────────────────────────────────────────────────────\r\n /** Darkest surface: inputs, code blocks, sidebar. */\r\n bgInput: '#0d1117',\r\n /** Panel / card surface. */\r\n bgCard: '#161b22',\r\n\r\n // ── Borders ─────────────────────────────────────────────────────────────\r\n /** Subtle border (default, non-interactive). */\r\n border: '#21262d',\r\n /** Muted border on hover, also used as scrollbar thumb colour. */\r\n borderHover: '#30363d',\r\n\r\n // ── Text ────────────────────────────────────────────────────────────────\r\n /** Dimmed text: placeholders, empty states, timestamps. */\r\n textMuted: '#484f58',\r\n /** Secondary labels, icon buttons, helper text. */\r\n textSecondary: '#8b949e',\r\n /** Body text, code. */\r\n textBody: '#c9d1d9',\r\n /** Primary headings and prominent text. */\r\n textPrimary: '#e6edf3',\r\n\r\n // ── Accents — blue ──────────────────────────────────────────────────────\r\n /** Primary interactive accent. */\r\n blue: '#2f81f7',\r\n /** Darker blue for hover / gradient end. */\r\n blueDark: '#1f6feb',\r\n /** Lighter blue for selection outlines. */\r\n blueLight: '#388bfd',\r\n\r\n // ── Accents — green ─────────────────────────────────────────────────────\r\n /** Success / \"new file\" button. */\r\n green: '#238636',\r\n /** Green hover state. */\r\n greenHover: '#2ea043',\r\n /** Lighter green for save buttons and diff additions. */\r\n greenLight: '#3fb950',\r\n\r\n // ── Accents — red ───────────────────────────────────────────────────────\r\n /** Danger / error. */\r\n red: '#f85149',\r\n /** Darker red for gradient end (recording button). */\r\n redDark: '#da3633',\r\n\r\n // ── Accents — yellow / amber ────────────────────────────────────────────\r\n /** Ticket badges, paused state. */\r\n yellow: '#d29922',\r\n /** Lighter amber (paused badge, launch button). */\r\n yellowLight: '#e3b341',\r\n /** Darker amber (folder-button border/hover). */\r\n yellowDark: '#9e6a03',\r\n\r\n // ── Accents — purple ────────────────────────────────────────────────────\r\n /** Insert / special action button. */\r\n purple: '#a371f7',\r\n\r\n // ── Syntax highlighting ─────────────────────────────────────────────────\r\n shKeyword: '#ff7b72',\r\n shBuiltin: '#d2a8ff',\r\n shString: '#a5d6ff',\r\n /** Alternate string colour (interceptor code blocks). */\r\n shStringAlt: '#85e89d',\r\n shNumber: '#79c0ff',\r\n /** Selector preview in the picker. */\r\n shSelector: '#58a6ff',\r\n },\r\n\r\n zIndex: {\r\n /** Full-viewport overlay: selector-picker host, recorder FAB, REC badge. */\r\n overlay: 2147483647,\r\n /** In-widget modal (export panel, login-setup panel). */\r\n modal: 100000,\r\n /** SweetAlert2 container override. */\r\n swal2: 99999,\r\n },\r\n} as const;\r\n\r\n/**\r\n * Generates CSS rules that apply the standard thin scrollbar style to a selector.\r\n * Use this as a tagged-template interpolation inside any Shadow DOM stylesheet.\r\n *\r\n * @param selector - CSS selector to apply scrollbar styles to (e.g. `'.list'`).\r\n * @param size - Track width/height in pixels (default `4`).\r\n * @returns Multi-line CSS string with both standard and WebKit rules.\r\n *\r\n * @example\r\n * ```ts\r\n * const STYLES = `\r\n * .list { overflow-y: auto; }\r\n * ${scrollbar('.list')}\r\n * `;\r\n * ```\r\n */\r\nexport function scrollbar(selector: string, size = 4): string {\r\n const c = THEME.color.borderHover;\r\n return `\r\n ${selector} { scrollbar-width: thin; scrollbar-color: ${c} transparent; }\r\n ${selector}::-webkit-scrollbar { width: ${size}px; height: ${size}px; }\r\n ${selector}::-webkit-scrollbar-thumb { background: ${c}; border-radius: 2px; }`;\r\n}\r\n\r\n/**\r\n * Inline scrollbar CSS properties (no selector wrapper).\r\n * Embed inside an existing rule when only the standard (non-WebKit) scrollbar\r\n * properties are needed or when the WebKit rule is authored separately.\r\n *\r\n * @example\r\n * ```ts\r\n * const STYLES = `\r\n * :host { overflow-y: auto; ${SCROLLBAR_INLINE} }\r\n * `;\r\n * ```\r\n */\r\nexport const SCROLLBAR_INLINE = `scrollbar-width: thin; scrollbar-color: ${THEME.color.borderHover} transparent;` as const;\r\n","import { THEME } from '../../utils/theme';\r\n\r\nexport const SELECTOR_PICKER_STYLES = `\r\n :host {\r\n position: fixed;\r\n z-index: ${THEME.zIndex.overlay};\r\n top: 0;\r\n left: 0;\r\n width: 100vw;\r\n height: 100vh;\r\n pointer-events: none;\r\n }\r\n\r\n .overlay {\r\n position: absolute;\r\n top: 50%;\r\n left: 50%;\r\n transform: translate(-50%, -50%);\r\n pointer-events: all;\r\n background: ${THEME.color.bgCard};\r\n border: 1px solid ${THEME.color.borderHover};\r\n border-radius: 10px;\r\n box-shadow: 0 8px 32px rgba(0,0,0,0.6);\r\n min-width: 420px;\r\n max-width: 600px;\r\n font-family: 'Segoe UI', system-ui, sans-serif;\r\n color: ${THEME.color.textPrimary};\r\n font-size: 13px;\r\n }\r\n\r\n .header {\r\n padding: 12px 16px 8px;\r\n border-bottom: 1px solid ${THEME.color.border};\r\n font-weight: 600;\r\n font-size: 13px;\r\n color: ${THEME.color.textSecondary};\r\n letter-spacing: 0.04em;\r\n text-transform: uppercase;\r\n }\r\n\r\n .list {\r\n max-height: 320px;\r\n overflow-y: auto;\r\n padding: 6px 0;\r\n }\r\n\r\n .row {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n padding: 7px 14px;\r\n cursor: pointer;\r\n border-radius: 6px;\r\n margin: 1px 6px;\r\n transition: background 0.1s;\r\n }\r\n\r\n .row:hover,\r\n .row.selected {\r\n background: ${THEME.color.border};\r\n }\r\n\r\n .row.selected {\r\n outline: 2px solid ${THEME.color.blueLight};\r\n outline-offset: -2px;\r\n }\r\n\r\n .quality-badge {\r\n width: 18px;\r\n height: 18px;\r\n border-radius: 50%;\r\n flex-shrink: 0;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n font-size: 10px;\r\n }\r\n\r\n .badge-excellent { background: ${THEME.color.green}; }\r\n .badge-good { background: ${THEME.color.blueDark}; }\r\n .badge-acceptable{ background: ${THEME.color.yellowDark}; }\r\n .badge-poor { background: ${THEME.color.redDark}; }\r\n\r\n .tag-name {\r\n font-family: monospace;\r\n font-size: 12px;\r\n color: ${THEME.color.textSecondary};\r\n flex-shrink: 0;\r\n }\r\n\r\n .attr-value {\r\n font-family: monospace;\r\n font-size: 12px;\r\n color: ${THEME.color.textBody};\r\n flex: 1;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n }\r\n\r\n .selector-preview {\r\n font-family: monospace;\r\n font-size: 11px;\r\n color: ${THEME.color.shSelector};\r\n flex-shrink: 0;\r\n max-width: 180px;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n }\r\n\r\n .poor-warning {\r\n font-size: 10px;\r\n color: ${THEME.color.red};\r\n margin-left: auto;\r\n }\r\n\r\n .footer {\r\n padding: 8px 14px 10px;\r\n border-top: 1px solid ${THEME.color.border};\r\n display: flex;\r\n gap: 16px;\r\n font-size: 11px;\r\n color: ${THEME.color.textMuted};\r\n }\r\n\r\n .hint kbd {\r\n background: ${THEME.color.border};\r\n border: 1px solid ${THEME.color.borderHover};\r\n border-radius: 3px;\r\n padding: 1px 5px;\r\n font-size: 10px;\r\n color: ${THEME.color.textSecondary};\r\n }\r\n`;\r\n","/**\r\n * Escapes `&`, `<`, and `>` so a string is safe to embed as text content inside\r\n * an HTML document.\r\n *\r\n * @param s - The raw string to escape.\r\n * @returns The HTML-escaped string.\r\n */\r\nexport function escHtml(s: string): string {\r\n return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');\r\n}\r\n\r\n/**\r\n * Escapes `\"` and `<` so a string is safe to embed inside a double-quoted HTML\r\n * attribute value (e.g. `data-cy=\"…\"`).\r\n *\r\n * @param s - The raw string to escape.\r\n * @returns The attribute-safe escaped string.\r\n */\r\nexport function escAttr(s: string): string {\r\n return s.replace(/\"/g, '"').replace(/</g, '<');\r\n}\r\n","import type { PickerRow, SelectorQuality } from '../../utils/selector-quality.utils';\r\nimport { escHtml } from '../../utils/html.utils';\r\n\r\nconst QUALITY_EMOJI: Record<SelectorQuality, string> = {\r\n excellent: '🟢',\r\n good: '🔵',\r\n acceptable: '🟡',\r\n poor: '🔴',\r\n};\r\n\r\nconst QUALITY_CLASS: Record<SelectorQuality, string> = {\r\n excellent: 'badge-excellent',\r\n good: 'badge-good',\r\n acceptable: 'badge-acceptable',\r\n poor: 'badge-poor',\r\n};\r\n\r\nexport function renderPickerRows(\r\n rows: PickerRow[],\r\n selectedIndex: number,\r\n t: (key: string) => string,\r\n): string {\r\n return rows.map((row, i) => {\r\n const isSelected = i === selectedIndex;\r\n const isPoor = row.quality === 'poor';\r\n\r\n return `\r\n <div class=\"row${isSelected ? ' selected' : ''}\" data-idx=\"${i}\" role=\"option\" aria-selected=\"${isSelected}\">\r\n <span class=\"quality-badge ${QUALITY_CLASS[row.quality]}\" title=\"${escHtml(t(`SELECTOR_PICKER.QUALITY_${row.quality.toUpperCase()}`))}\">\r\n ${QUALITY_EMOJI[row.quality]}\r\n </span>\r\n <span class=\"tag-name\"><${escHtml(row.tag)}></span>\r\n ${row.attr ? `<span class=\"attr-value\">${escHtml(row.attr)}</span>` : '<span class=\"attr-value\"></span>'}\r\n <span class=\"selector-preview\">${escHtml(row.selector)}</span>\r\n ${isPoor ? `<span class=\"poor-warning\" title=\"${escHtml(t('SELECTOR_PICKER.QUALITY_POOR'))}\">⚠</span>` : ''}\r\n </div>`;\r\n }).join('');\r\n}\r\n\r\nexport function renderPicker(\r\n rows: PickerRow[],\r\n selectedIndex: number,\r\n t: (key: string) => string,\r\n): string {\r\n return `\r\n <div class=\"overlay\" role=\"listbox\">\r\n <div class=\"header\">${escHtml(t('SELECTOR_PICKER.TITLE'))}</div>\r\n <div class=\"list\">\r\n ${renderPickerRows(rows, selectedIndex, t)}\r\n </div>\r\n <div class=\"footer\">\r\n <span class=\"hint\"><kbd>↑↓</kbd> ${escHtml(t('SELECTOR_PICKER.PREVIEW_LABEL'))}</span>\r\n <span class=\"hint\"><kbd>Enter</kbd> ${escHtml(t('SELECTOR_PICKER.CONFIRM_HINT'))}</span>\r\n <span class=\"hint\"><kbd>Esc</kbd> ${escHtml(t('SELECTOR_PICKER.CANCEL_HINT'))}</span>\r\n </div>\r\n </div>`;\r\n}\r\n","export type Lang = 'es' | 'en' | 'fr' | 'it' | 'de';\r\n\r\nexport const SUPPORTED_LANGS: Lang[] = ['es', 'en', 'fr', 'it', 'de'];\r\n\r\nexport function isLang(value: string): value is Lang {\r\n return SUPPORTED_LANGS.includes(value as Lang);\r\n}\r\n\r\n/** BCP-47 locale used for date/number formatting per UI language. */\r\nexport const LOCALE_BY_LANG: Record<Lang, string> = {\r\n es: 'es-ES',\r\n en: 'en-GB',\r\n fr: 'fr-FR',\r\n it: 'it-IT',\r\n de: 'de-DE',\r\n};\r\n\r\n/** Returns the formatting locale for a UI language (falls back to es-ES). */\r\nexport function localeForLang(lang: string): string {\r\n return isLang(lang) ? LOCALE_BY_LANG[lang] : 'es-ES';\r\n}\r\n","export class Subject<T> {\r\n private _value: T;\r\n private listeners = new Set<(v: T) => void>();\r\n\r\n constructor(initialValue: T) {\r\n this._value = initialValue;\r\n }\r\n\r\n next(value: T): void {\r\n this._value = value;\r\n this.listeners.forEach((l) => l(value));\r\n }\r\n\r\n getValue(): T {\r\n return this._value;\r\n }\r\n\r\n subscribe(fn: (v: T) => void): () => void {\r\n this.listeners.add(fn);\r\n return () => this.listeners.delete(fn);\r\n }\r\n}\r\n","export const I18N_ES = {\r\n MAIN_FRAME: {\r\n SETTINGS: 'Configuración',\r\n SHOW_ADVANCED_EDITOR: 'Editor avanzado',\r\n DIALOG_SAVED_TESTS: 'Pruebas guardadas',\r\n DIALOG_COMMANDS: 'Previsualizador de comandos Cypress',\r\n DIALOG_SAVE: '¿Guardar la grabación?',\r\n },\r\n SAVE_TEST: {\r\n DESC_LABEL: 'Descripción de la prueba',\r\n CANCEL: 'Cancelar',\r\n ASK: '¿Guardar el test grabado?',\r\n YES_CONTINUE: 'Sí, continuar',\r\n NO_DISCARD: 'No, descartar',\r\n DESC_PLACEHOLDER: 'Ej: Login correcto con credenciales válidas',\r\n TAGS_LABEL: 'Etiquetas (opcional, para filtrar después):',\r\n TAGS_PLACEHOLDER: 'smoke, login, regresión…',\r\n ADD_TAG: '+ Añadir',\r\n NO_TAGS: 'Sin etiquetas',\r\n SAVE_BTN: '💾 Guardar',\r\n SAVE_AND_EDIT: '📝 Guardar y editar',\r\n REMOVE_TAG_TITLE: 'Quitar',\r\n NOTES_LABEL: 'Descripción / Notas (opcional):',\r\n NOTES_PLACEHOLDER: 'Qué valida este test, condiciones previas, etc.',\r\n TICKET_LABEL: 'Ticket / Issue (opcional):',\r\n TICKET_PLACEHOLDER: 'Ej: PROJ-123, #42',\r\n TICKET_WARN: 'ID no válido para el proveedor configurado (se guardará igualmente)',\r\n CONFIRM_DISCARD: '¿Seguro que quieres descartar el test grabado? Se perderán todos los pasos registrados.',\r\n CONFIRM_DISCARD_BTN: 'Sí, descartar',\r\n BACK_BTN: 'Volver',\r\n CONTINUE_RECORDING_BTN: '⏺ Continuar grabando',\r\n },\r\n TEST_EDITOR: {\r\n NO_TAGS: 'Sin etiquetas',\r\n SELECTED_SINGULAR: 'seleccionado',\r\n SELECTED_PLURAL: 'seleccionados',\r\n DESCRIBE_PLACEHOLDER: 'Nombre del describe (opcional)',\r\n COPY_DESCRIBE: '🗂 Copiar describe()',\r\n MULTI_SELECT: '🗂 Multi-select',\r\n CANCEL_SELECT: '✕ Cancelar',\r\n COPY_CMDS_BTN: '📋 Copiar comandos',\r\n COPY_ICPS_BTN: '📋 Copiar interceptores',\r\n DEFAULT_DESCRIBE: 'Suite de tests',\r\n NO_TESTS: 'No hay tests guardados',\r\n DELETE_TITLE: 'Eliminar',\r\n GROUP_BY_TICKET: '🎫 Agrupar por ticket',\r\n UNGROUP_TICKET: '🎫 Desagrupar',\r\n NO_TICKET: 'Sin ticket',\r\n TICKET_LINK_TITLE: 'Abrir ticket',\r\n },\r\n CONFIG: {\r\n LANG_SECTION: '🌐 Idioma',\r\n LANG_FIELD: 'Interfaz',\r\n HTTP_SECTION: '⚡ HTTP Avanzado',\r\n HTTP_TITLE: 'Validaciones de body',\r\n HTTP_SUB: 'GET → response · POST/PUT → request',\r\n FIXTURE_SECTION: '🧪 Fixtures HTTP',\r\n FIXTURE_TITLE: 'Grabar respuestas como fixtures',\r\n FIXTURE_SUB: 'Las GET se guardan en cypress/fixtures y se stubean con cy.intercept({ fixture }).',\r\n SELECTOR_SECTION: '🎯 Estrategia de selector',\r\n SELECTOR_LABEL: 'Atributo preferido para cy.get()',\r\n SELECTOR_OPT_DATACY: 'data-cy (por defecto)',\r\n SELECTOR_OPT_TESTID: 'data-testid',\r\n SELECTOR_OPT_ARIA: 'aria-label',\r\n SELECTOR_OPT_ID: 'id (#elemento)',\r\n SELECTOR_HINT: 'El grabador buscará este atributo primero. Si no existe, intentará los demás.',\r\n FOLDER_SECTION: '📁 Carpeta Cypress',\r\n FOLDER_CONNECTED: 'conectado —',\r\n FOLDER_NOT_SET: 'sin configurar',\r\n FOLDER_CHANGE_BTN: '📁 Cambiar carpeta',\r\n FOLDER_SELECT_BTN: '📁 Seleccionar carpeta',\r\n FOLDER_REVOKE_BTN: '✕ Quitar acceso',\r\n DATA_SECTION: '💾 Datos',\r\n DATA_DESC: 'Exporta todos tus tests a JSON o importa una copia de seguridad.',\r\n EXPORT_BTN: '⬆️ Exportar tests',\r\n EXPORT_DIALOG_TITLE: '⬆️ Exportar tests',\r\n EXPORT_MODE_ALL: 'Todo',\r\n EXPORT_MODE_MANUAL: 'Selección manual',\r\n EXPORT_MODE_TAGS: 'Por tags',\r\n EXPORT_ALL_DESC: 'Se exportarán todos los tests guardados.',\r\n EXPORT_COUNT: 'A exportar:',\r\n EXPORT_CONFIRM: '⬆️ Exportar',\r\n EXPORT_CANCEL: 'Cancelar',\r\n EXPORT_EMPTY: 'No hay tests para exportar.',\r\n EXPORT_NO_TAGS: 'No hay tags disponibles.',\r\n EXPORT_TAGS_HINT: 'Selecciona uno o más tags para ver qué pruebas se exportarán.',\r\n EXPORT_RESULT_LABEL: 'Pruebas que se exportarán:',\r\n IMPORT_BTN: '⬇️ Importar tests',\r\n FOLDER_UPDATED_TOAST: '✓ Carpeta de Cypress actualizada',\r\n FOLDER_ERROR_TOAST: 'Error al acceder a la carpeta',\r\n IMPORT_SUCCESS: 'Datos importados correctamente.',\r\n IMPORT_ERROR: 'Error al importar.',\r\n JSON_INVALID: 'El archivo no es un JSON válido.',\r\n JSON_BAD_FORMAT: 'El archivo no tiene el formato esperado.',\r\n SMART_SELECTOR_SECTION: '🔍 Selector inteligente',\r\n SMART_SELECTOR_TITLE: 'Selector inteligente',\r\n SMART_SELECTOR_SUB: 'Muestra un picker al hacer click en elementos sin selector válido.',\r\n START_HIDDEN_SECTION: '👁 Visibilidad del widget',\r\n START_HIDDEN_TITLE: 'Iniciar oculto',\r\n START_HIDDEN_SUB: 'El widget arranca invisible. Usa Ctrl+Shift+E para mostrarlo u ocultarlo.',\r\n RESUME_TTL_SECTION: '⏱ Continuidad de grabación',\r\n RESUME_TTL_LABEL: 'Reanudar sin preguntar (minutos)',\r\n RESUME_TTL_HINT: 'Si recargas o cambias de proyecto, una grabación activa se reanuda sin preguntar dentro de este margen. Pasado ese tiempo, te preguntará si continuar o descartar.',\r\n WIDGET_POSITION_SECTION: '🧲 Posición del widget',\r\n WIDGET_POSITION_HINT: 'Arrastra el botón de grabar para moverlo donde no estorbe. Se recuerda su posición.',\r\n WIDGET_POSITION_RESET_BTN: '↺ Restablecer posición',\r\n WIDGET_POSITION_RESET_DONE: '✓ Posición restablecida',\r\n ISSUE_TRACKER_SECTION: '🎫 Issue tracker',\r\n ISSUE_TRACKER_TITLE: 'Vincular tests a tickets',\r\n ISSUE_TRACKER_SUB: 'Añade un ID de ticket al guardar y genera un enlace clickable en el listado.',\r\n ISSUE_TRACKER_PROVIDER: 'Proveedor',\r\n ISSUE_TRACKER_BASE_URL: 'URL base',\r\n ISSUE_TRACKER_BASE_URL_PH: 'Ej: https://miproyecto.atlassian.net',\r\n LOGIN_SETUP_SECTION: '🔐 Login setup',\r\n LOGIN_SETUP_NOT_CONFIGURED: 'No configurado',\r\n LOGIN_SETUP_SET_UP_BTN: 'Configurar',\r\n LOGIN_SETUP_TITLE: 'Configuración de login',\r\n LOGIN_SETUP_CREATE_SCAFFOLD: 'Crear scaffold',\r\n LOGIN_SETUP_SELECT_EXISTING: 'Seleccionar fichero existente',\r\n LOGIN_SETUP_FILE_NAME_LABEL: 'Nombre del fichero',\r\n LOGIN_SETUP_FILE_NAME_PH: 'Ej: cypress/common-services/login.service.ts',\r\n LOGIN_SETUP_RESCAN: '🔄 Re-escanear',\r\n LOGIN_SETUP_FUNCTIONS_DETECTED: 'Funciones detectadas',\r\n LOGIN_SETUP_BLOCK_ASSIGN: 'Asignación de bloques',\r\n LOGIN_SETUP_NO_FUNCTIONS: 'No se encontraron funciones exportadas. Rellena el scaffold y re-escanea.',\r\n LOGIN_SETUP_BEFORE_LABEL: 'Función before() (una vez por suite)',\r\n LOGIN_SETUP_BEFORE_EACH_LABEL: 'Función beforeEach() (antes de cada test)',\r\n LOGIN_SETUP_NONE_OPTION: '— Ninguna —',\r\n LOGIN_SETUP_SUMMARY: 'Fichero: {file} · before: {before} · beforeEach: {beforeEach}',\r\n LOGIN_SETUP_SAVE_BTN: '💾 Guardar',\r\n LOGIN_SETUP_CLEAR_BTN: 'Eliminar configuración',\r\n LOGIN_SETUP_CANCEL_BTN: 'Cancelar',\r\n LOGIN_SETUP_SOURCE_LABEL: 'Origen del fichero de login',\r\n LOGIN_SETUP_CREATE_SUB: 'Genera un scaffold con funciones de ejemplo',\r\n LOGIN_SETUP_SELECT_SUB: 'Apunta a un servicio de login existente',\r\n LOGIN_SETUP_INJECT_TITLE: '¿Añadir bloques de login?',\r\n LOGIN_SETUP_INJECT_TEXT: 'Este fichero no tiene los bloques de login configurados. ¿Quieres añadir el import y los bloques before/beforeEach ahora?',\r\n LOGIN_SETUP_INJECT_CONFIRM: 'Sí, añadir',\r\n },\r\n SELECTOR_PICKER: {\r\n TITLE: 'Selecciona un elemento del DOM',\r\n PREVIEW_LABEL: 'navegar',\r\n CONFIRM_HINT: 'confirmar',\r\n CANCEL_HINT: 'cancelar',\r\n QUALITY_EXCELLENT: 'Excelente — tiene atributo de prueba (data-cy / data-testid / aria-label)',\r\n QUALITY_GOOD: 'Bueno — tiene un id válido',\r\n QUALITY_ACCEPTABLE: 'Aceptable — solo tiene clases CSS',\r\n QUALITY_POOR: 'No recomendado — solo tag o estilo inline',\r\n },\r\n TEST_PREVISUALIZER: {\r\n INTERCEPTORS: 'Interceptores',\r\n COPY_CMDS_BTN: '📋 Copiar comandos',\r\n SHOW_INTERCEPTORS: '▼ Ver interceptores',\r\n HIDE_INTERCEPTORS: '▲ Ocultar interceptores',\r\n SECTION_COMMANDS: 'Comandos',\r\n NO_CMDS_YET: 'Sin comandos aún',\r\n NO_ICP_SHORT: 'Sin interceptores',\r\n COPY_ICP_BTN: '📋 Copiar interceptores',\r\n UP_TITLE: 'Subir',\r\n DOWN_TITLE: 'Bajar',\r\n DEL_TITLE: 'Eliminar',\r\n },\r\n ADVANCED_EDITOR: {\r\n REAUTH_BTN: '🔓 Reactivar acceso',\r\n PERMISSION_EXPIRED: '🔑 El permiso ha caducado',\r\n PERMISSION_EXPIRED_HINT: 'Haz clic para reactivar el acceso a tu carpeta de Cypress.',\r\n NO_ACCESS: '🔒 Sin acceso a archivos locales',\r\n NO_ACCESS_HINT: 'Configura el acceso en ⚙️ Config.',\r\n NO_FILES: 'Sin archivos',\r\n SELECT_FILE: '← Selecciona un archivo del árbol',\r\n IT_LABEL: '🧪 it() a insertar:',\r\n COPY_IT_BTN: '📋 Copiar it()',\r\n BEFORE_EACH_LABEL: '🔀 beforeEach() interceptores:',\r\n COPY_ICP_BTN: '📋 Copiar interceptores',\r\n INSERT_BTN: '💾 Insertar en archivo',\r\n EDIT_MANUAL_BTN: '✏️ Editar manualmente',\r\n CLOSE_BTN: '✕ Cerrar',\r\n NEW_FILE_BTN: '+ Nuevo archivo',\r\n NEW_FOLDER_BTN: '+ Nueva carpeta',\r\n REFRESH_BTN: '↻ Actualizar',\r\n NEW_FILE_PLACEHOLDER: 'nombre-del-test',\r\n NEW_FOLDER_PLACEHOLDER: 'nombre-de-carpeta',\r\n NEW_FILE_CONFIRM: 'Crear',\r\n NEW_FILE_CANCEL: 'Cancelar',\r\n },\r\n FILE_PREVIEW: {\r\n NO_FILE: 'Sin archivo',\r\n COPY_TITLE: 'Copiar contenido del editor',\r\n BLOCK_IT: '🧪 it()',\r\n COPY_BTN: '📋 Copiar',\r\n BLOCK_BEFORE_EACH: '🔀 beforeEach()',\r\n NO_CHANGES: 'Sin cambios respecto al original',\r\n NO_CHANGES_SHORT: 'Sin cambios',\r\n LAUNCH_BTN: '▶ Lanzar test',\r\n LAUNCH_LOCAL_ONLY: 'Muévelo a local para poder probar',\r\n LAUNCH_RUNNING: '⏳ Ejecutando…',\r\n LAUNCH_PASSED: '✓ Prueba superada',\r\n LAUNCH_FAILED: '✗ Prueba fallida',\r\n LAUNCH_NO_RUNNER: 'No se detectó el runner local (¿lo has arrancado?)',\r\n DIFF_BTN: '📊 Diff',\r\n SAVE_BTN: '💾 Guardar',\r\n CLOSE_BTN: '✕ Cerrar',\r\n BACK_TO_EDITOR: '← Volver al editor',\r\n INSERT_BTN: '🪄 Insertar bloques',\r\n INSERT_TITLE: 'Insertar it() y beforeEach() en el contenido del editor',\r\n INSERT_DONE: 'Bloques insertados en el editor',\r\n INSERT_ERROR: 'No se encontró un bloque describe() válido en el archivo',\r\n },\r\n RECORDER: {\r\n FS_TITLE: '📁 Acceso a ficheros',\r\n FS_LATER_BTN: 'Ahora no',\r\n FS_SELECT_BTN: '📁 Seleccionar carpeta',\r\n FS_SUCCESS_TOAST: '✓ Carpeta de Cypress configurada',\r\n FS_ERROR_TOAST: 'Error al acceder a la carpeta',\r\n FS_INTRO_HTML: 'El <strong style=\"color:#e6edf3\">editor avanzado</strong> puede insertar tus tests directamente en los archivos <code style=\"background:#0d1117;padding:1px 6px;border-radius:4px;font-size:11px;color:#c9d1d9\">.cy.ts</code> de Cypress.',\r\n FS_STRUCTURE_HINT_HTML: 'Selecciona la carpeta que contiene la subcarpeta <code style=\"background:#0d1117;padding:1px 5px;border-radius:4px;font-size:10px;color:#c9d1d9\">e2e/</code>. La extensión espera esta estructura:',\r\n FS_TREE_PICK_HINT: '← selecciona esta carpeta',\r\n FS_TREE_READ_HINT: '← la extensión leerá aquí',\r\n FS_PERMISSION_NOTE: 'El permiso se guarda en el navegador y no se vuelve a solicitar.',\r\n ASSERTION_SECTION: '➕ Añadir aserción',\r\n ASSERT_SELECTOR_PH: 'selector, ej: [data-cy=\"btn\"]',\r\n ASSERT_VALUE_PH: 'valor esperado',\r\n ASSERT_ADD_BTN: '➕ Añadir',\r\n FILE_EDITOR_TITLE: '✏️ Editor de archivo',\r\n FILE_SAVED_TOAST: '✓ Archivo guardado',\r\n FILE_SAVE_ERROR_TOAST: 'Error al guardar el archivo',\r\n FIXTURES_WRITTEN_TOAST: '✓ Fixtures escritos en cypress/fixtures',\r\n FIXTURES_NO_FOLDER_TOAST: 'No se pudieron escribir los fixtures (configura la carpeta Cypress)',\r\n FILE_UPLOAD_MANUAL_TOAST: 'Añade {files} a cypress/fixtures/ antes de ejecutar el test.',\r\n FILE_UPLOAD_COPIED_TOAST: '{files} copiado/s a cypress/fixtures/.',\r\n FILE_UPLOAD_COPY_ERROR_TOAST: 'No se pudo copiar {files} a cypress/fixtures/. Añádelo manualmente.',\r\n BTN_CONFIG: 'Config',\r\n BTN_FILES: 'Ficheros',\r\n BTN_COMMANDS: 'Comandos',\r\n BTN_TESTS: 'Tests',\r\n PAUSE_TITLE: 'Pausar (Ctrl+P)',\r\n RESUME_TITLE: 'Reanudar (Ctrl+P)',\r\n BADGE_PAUSED: '⏸ PAUSA',\r\n BADGE_REC: '● REC',\r\n STOP_TITLE: 'Detener (Ctrl+R)',\r\n START_TITLE: 'Grabar (Ctrl+R)',\r\n SESSION_RESUME_TITLE: '⏺ Grabación en curso',\r\n SESSION_RESUME_TEXT: 'Hay una grabación activa sin terminar.',\r\n SESSION_RESUME_COUNT: 'comandos capturados',\r\n SESSION_CONTINUE_BTN: 'Continuar grabando',\r\n SESSION_DISCARD_BTN: 'Descartar',\r\n BTN_HELP: 'Ayuda',\r\n RECOVER_BTN: 'Recuperar',\r\n RECOVER_TITLE: 'Recuperar la última grabación detenida: {count} comandos ({time})',\r\n RECOVER_TIME_NOW: 'justo ahora',\r\n RECOVER_TIME_MINUTES: 'hace {m} min',\r\n },\r\n HELP: {\r\n TITLE: '❓ Ayuda — Guía rápida',\r\n INTRO: 'Todo lo que puede hacer el grabador.',\r\n SEC_RECORDING: '⏺ Grabar',\r\n RECORDING_1: 'Pulsa ⏺ (o Ctrl+R) para empezar; ⏹ para parar y guardar.',\r\n RECORDING_2: 'Pausa / reanuda con ⏸ (o Ctrl+P).',\r\n SEC_SHORTCUTS: '⌨️ Atajos de teclado',\r\n SC_RECORD: 'Ctrl+R — Grabar / detener',\r\n SC_PAUSE: 'Ctrl+P — Pausar / reanudar',\r\n SC_TESTS: 'Ctrl+1 — Panel de tests guardados',\r\n SC_COMMANDS: 'Ctrl+2 — Panel de comandos',\r\n SC_CONFIG: 'Ctrl+3 — Configuración',\r\n SC_VISIBILITY: 'Ctrl+Shift+E — Mostrar / ocultar el widget',\r\n SC_HELP: 'Ctrl+Shift+H — Esta ayuda',\r\n SEC_CAPTURED: '🎯 Qué se graba',\r\n CAP_CLICK: 'Click → .click()',\r\n CAP_DBLCLICK: 'Doble-click → .dblclick()',\r\n CAP_RIGHTCLICK: 'Click derecho → .rightclick()',\r\n CAP_TYPE: 'Escribir en un campo → .clear().type(...)',\r\n CAP_CHECK: 'Checkbox / radio → .check() / .uncheck()',\r\n CAP_SELECT: '<select> → .select(...)',\r\n CAP_KEYS: 'Enter / Escape → .type(\"{enter}\") / (\"{esc}\")',\r\n CAP_ROUTE: 'Cambio de ruta (SPA) → cy.url().should(...)',\r\n CAP_HTTP: 'fetch / XHR → cy.intercept + cy.wait',\r\n SEC_ASSERT: '✅ Aserciones',\r\n ASSERT_1: 'Alt+click sobre un elemento para verificarlo sin ejecutar su acción (texto, valor, checked o visible).',\r\n ASSERT_2: 'O usa el constructor de aserciones en el panel de Comandos.',\r\n SEC_PANELS: '🗂 Paneles',\r\n PANEL_TESTS: '📋 Tests — guardados: filtrar por tag, copiar, combinar, exportar.',\r\n PANEL_COMMANDS: '⌨️ Comandos — de la grabación actual: reordenar, borrar, añadir aserciones.',\r\n PANEL_CONFIG: '⚙️ Config — idioma, selector, HTTP, carpeta Cypress, login setup, datos, visibilidad, posición.',\r\n PANEL_FILES: '📁 Ficheros — inserta tests en tus .cy.ts y lanza el runner.',\r\n SEC_SELECTOR: '🔎 Selectores',\r\n SELECTOR_1: 'Elige el atributo preferido (data-cy, data-testid, aria-label, id) en Config.',\r\n SELECTOR_2: 'Si un click no tiene selector fiable, aparece un picker para elegir el mejor ancestro.',\r\n SEC_DATA: '💾 Datos',\r\n DATA_1: 'Exporta tests a JSON (todo / selección / por tags).',\r\n DATA_2: 'Importa un JSON: se fusiona con lo existente (no se borra nada).',\r\n SEC_ADVANCED: '🚀 Avanzado',\r\n ADV_INVISIBLE: 'Modo invisible: start-hidden + Ctrl+Shift+E para grabar en producción sin molestar.',\r\n ADV_RUNNER: 'Runner local: npx lib-e2e-cypress-runner para lanzar un spec headless desde el editor.',\r\n ADV_CROSSAPP: 'Cross-app: la grabación sobrevive al cambiar de micro-frontend (mismo origen).',\r\n ADV_DRAG: 'Arrastra el botón ⏺ para mover el widget; recuerda su posición.',\r\n ADV_LOGIN: 'Login Setup (Ctrl+3): apunta a tu servicio de login; el grabador inyecta before()/beforeEach() automáticamente en cada test nuevo.',\r\n CLOSE: 'Cerrar',\r\n TAB_REFERENCE: 'Referencia rápida',\r\n TAB_GUIDE: 'Guía de uso',\r\n GUIDE_INTRO: 'Cómo sacarle partido al grabador, qué cubre y qué no.',\r\n G_SEC_WORKFLOW: '🧭 Flujo de trabajo',\r\n G_WF_1: '1. Pulsa ⏺ (o Ctrl+R) para empezar a grabar.',\r\n G_WF_2: '2. Usa tu app como un usuario: clicks, formularios, navegación. Cada acción se convierte en un comando Cypress.',\r\n G_WF_3: '3. Añade verificaciones con Alt+click sobre lo que quieras comprobar.',\r\n G_WF_4: '4. Pulsa ⏹ para parar; ponle nombre y tags, y guárdalo.',\r\n G_WF_5: '5. En 📁 Ficheros, inserta el test en un .cy.ts o lánzalo con el runner local.',\r\n G_SEC_COVERED: '✅ Qué cubre',\r\n G_COV_1: 'Clicks, doble-click, click derecho, inputs de texto, checkbox/radio, select y teclas Enter/Escape.',\r\n G_COV_2: 'Navegación SPA (pushState/replaceState/popstate) → cy.url().should(...).',\r\n G_COV_3: 'Llamadas fetch/XHR (GET/POST/PUT) → cy.intercept + cy.wait, con validación de body opcional.',\r\n G_COV_4: 'Selector fiable (data-cy/testid/aria/id) y picker cuando no hay uno claro.',\r\n G_COV_5: 'Aserciones automáticas (Alt+click) y constructor manual.',\r\n G_COV_6: 'Continuidad al cambiar de micro-frontend (mismo origen), modo invisible e i18n.',\r\n G_COV_7: 'Login Setup: configura tu función de login en Ctrl+3 → Login Setup y el grabador añade los bloques before()/beforeEach() a cada test nuevo.',\r\n G_SEC_NOTCOVERED: '🚫 Qué NO cubre (por ahora)',\r\n G_NC_1: 'Orígenes distintos / subdominios (solo mismo origen).',\r\n G_NC_2: 'Subida de ficheros (selectFile), arrastrar y soltar, y hover.',\r\n G_NC_3: 'La tecla Tab (Cypress no la soporta en .type()).',\r\n G_NC_4: 'Peticiones DELETE (se ignoran a propósito).',\r\n G_NC_5: 'iframes y Shadow DOM de terceros pueden no capturarse.',\r\n },\r\n};\r\n","export const I18N_EN = {\r\n MAIN_FRAME: {\r\n SETTINGS: 'Settings',\r\n SHOW_ADVANCED_EDITOR: 'Advanced editor',\r\n DIALOG_SAVED_TESTS: 'Saved tests',\r\n DIALOG_COMMANDS: 'Cypress commands previewer',\r\n DIALOG_SAVE: 'Save recording?',\r\n },\r\n SAVE_TEST: {\r\n DESC_LABEL: 'Test description',\r\n CANCEL: 'Cancel',\r\n ASK: 'Save the recorded test?',\r\n YES_CONTINUE: 'Yes, continue',\r\n NO_DISCARD: 'No, discard',\r\n DESC_PLACEHOLDER: 'E.g.: Successful login with valid credentials',\r\n TAGS_LABEL: 'Tags (optional, for later filtering):',\r\n TAGS_PLACEHOLDER: 'smoke, login, regression…',\r\n ADD_TAG: '+ Add',\r\n NO_TAGS: 'No tags',\r\n SAVE_BTN: '💾 Save',\r\n SAVE_AND_EDIT: '📝 Save and edit',\r\n REMOVE_TAG_TITLE: 'Remove',\r\n NOTES_LABEL: 'Description / Notes (optional):',\r\n NOTES_PLACEHOLDER: 'What this test validates, preconditions, etc.',\r\n TICKET_LABEL: 'Ticket / Issue (optional):',\r\n TICKET_PLACEHOLDER: 'E.g.: PROJ-123, #42',\r\n TICKET_WARN: 'Invalid ID for the configured provider (will be saved anyway)',\r\n CONFIRM_DISCARD: 'Are you sure you want to discard this recording? All recorded steps will be lost.',\r\n CONFIRM_DISCARD_BTN: 'Yes, discard',\r\n BACK_BTN: 'Go back',\r\n CONTINUE_RECORDING_BTN: '⏺ Continue recording',\r\n },\r\n TEST_EDITOR: {\r\n NO_TAGS: 'No tags',\r\n SELECTED_SINGULAR: 'selected',\r\n SELECTED_PLURAL: 'selected',\r\n DESCRIBE_PLACEHOLDER: 'describe name (optional)',\r\n COPY_DESCRIBE: '🗂 Copy describe()',\r\n MULTI_SELECT: '🗂 Multi-select',\r\n CANCEL_SELECT: '✕ Cancel',\r\n COPY_CMDS_BTN: '📋 Copy commands',\r\n COPY_ICPS_BTN: '📋 Copy interceptors',\r\n DEFAULT_DESCRIBE: 'Test suite',\r\n NO_TESTS: 'No saved tests',\r\n DELETE_TITLE: 'Delete',\r\n GROUP_BY_TICKET: '🎫 Group by ticket',\r\n UNGROUP_TICKET: '🎫 Ungroup',\r\n NO_TICKET: 'No ticket',\r\n TICKET_LINK_TITLE: 'Open ticket',\r\n },\r\n CONFIG: {\r\n LANG_SECTION: '🌐 Language',\r\n LANG_FIELD: 'Interface',\r\n HTTP_SECTION: '⚡ Advanced HTTP',\r\n HTTP_TITLE: 'Body validations',\r\n HTTP_SUB: 'GET → response · POST/PUT → request',\r\n FIXTURE_SECTION: '🧪 HTTP Fixtures',\r\n FIXTURE_TITLE: 'Record responses as fixtures',\r\n FIXTURE_SUB: 'GET responses are saved to cypress/fixtures and stubbed via cy.intercept({ fixture }).',\r\n SELECTOR_SECTION: '🎯 Selector strategy',\r\n SELECTOR_LABEL: 'Preferred attribute for cy.get()',\r\n SELECTOR_OPT_DATACY: 'data-cy (default)',\r\n SELECTOR_OPT_TESTID: 'data-testid',\r\n SELECTOR_OPT_ARIA: 'aria-label',\r\n SELECTOR_OPT_ID: 'id (#element)',\r\n SELECTOR_HINT: 'The recorder will look for this attribute first. If not found, it will try the others.',\r\n FOLDER_SECTION: '📁 Cypress Folder',\r\n FOLDER_CONNECTED: 'connected —',\r\n FOLDER_NOT_SET: 'not configured',\r\n FOLDER_CHANGE_BTN: '📁 Change folder',\r\n FOLDER_SELECT_BTN: '📁 Select folder',\r\n FOLDER_REVOKE_BTN: '✕ Revoke access',\r\n DATA_SECTION: '💾 Data',\r\n DATA_DESC: 'Export all your tests to JSON or import a backup.',\r\n EXPORT_BTN: '⬆️ Export tests',\r\n EXPORT_DIALOG_TITLE: '⬆️ Export tests',\r\n EXPORT_MODE_ALL: 'All',\r\n EXPORT_MODE_MANUAL: 'Manual selection',\r\n EXPORT_MODE_TAGS: 'By tags',\r\n EXPORT_ALL_DESC: 'All saved tests will be exported.',\r\n EXPORT_COUNT: 'To export:',\r\n EXPORT_CONFIRM: '⬆️ Export',\r\n EXPORT_CANCEL: 'Cancel',\r\n EXPORT_EMPTY: 'No tests to export.',\r\n EXPORT_NO_TAGS: 'No tags available.',\r\n EXPORT_TAGS_HINT: 'Select one or more tags to preview which tests will be exported.',\r\n EXPORT_RESULT_LABEL: 'Tests that will be exported:',\r\n IMPORT_BTN: '⬇️ Import tests',\r\n FOLDER_UPDATED_TOAST: '✓ Cypress folder updated',\r\n FOLDER_ERROR_TOAST: 'Error accessing the folder',\r\n IMPORT_SUCCESS: 'Data imported successfully.',\r\n IMPORT_ERROR: 'Error importing.',\r\n JSON_INVALID: 'The file is not valid JSON.',\r\n JSON_BAD_FORMAT: 'The file does not have the expected format.',\r\n SMART_SELECTOR_SECTION: '🔍 Smart selector',\r\n SMART_SELECTOR_TITLE: 'Smart selector',\r\n SMART_SELECTOR_SUB: 'Shows a picker when clicking elements with no valid selector.',\r\n START_HIDDEN_SECTION: '👁 Widget visibility',\r\n START_HIDDEN_TITLE: 'Start hidden',\r\n START_HIDDEN_SUB: 'The widget starts invisible. Use Ctrl+Shift+E to show or hide it.',\r\n RESUME_TTL_SECTION: '⏱ Recording continuity',\r\n RESUME_TTL_LABEL: 'Resume without asking (minutes)',\r\n RESUME_TTL_HINT: 'If you reload or switch projects, an active recording resumes without asking within this window. After that, you will be asked to continue or discard.',\r\n WIDGET_POSITION_SECTION: '🧲 Widget position',\r\n WIDGET_POSITION_HINT: 'Drag the record button to move it out of the way. Its position is remembered.',\r\n WIDGET_POSITION_RESET_BTN: '↺ Reset position',\r\n WIDGET_POSITION_RESET_DONE: '✓ Position reset',\r\n ISSUE_TRACKER_SECTION: '🎫 Issue tracker',\r\n ISSUE_TRACKER_TITLE: 'Link tests to tickets',\r\n ISSUE_TRACKER_SUB: 'Add a ticket ID when saving and generate a clickable link in the test list.',\r\n ISSUE_TRACKER_PROVIDER: 'Provider',\r\n ISSUE_TRACKER_BASE_URL: 'Base URL',\r\n ISSUE_TRACKER_BASE_URL_PH: 'E.g.: https://myproject.atlassian.net',\r\n LOGIN_SETUP_SECTION: '🔐 Login setup',\r\n LOGIN_SETUP_NOT_CONFIGURED: 'Not configured',\r\n LOGIN_SETUP_SET_UP_BTN: 'Set up',\r\n LOGIN_SETUP_TITLE: 'Login setup',\r\n LOGIN_SETUP_CREATE_SCAFFOLD: 'Create scaffold',\r\n LOGIN_SETUP_SELECT_EXISTING: 'Select existing file',\r\n LOGIN_SETUP_FILE_NAME_LABEL: 'File name',\r\n LOGIN_SETUP_FILE_NAME_PH: 'E.g.: cypress/common-services/login.service.ts',\r\n LOGIN_SETUP_RESCAN: '🔄 Re-scan',\r\n LOGIN_SETUP_FUNCTIONS_DETECTED: 'Detected functions',\r\n LOGIN_SETUP_BLOCK_ASSIGN: 'Block assignment',\r\n LOGIN_SETUP_NO_FUNCTIONS: 'No exported functions found. Fill in the scaffold and re-scan.',\r\n LOGIN_SETUP_BEFORE_LABEL: 'before() function (once per suite)',\r\n LOGIN_SETUP_BEFORE_EACH_LABEL: 'beforeEach() function (before every test)',\r\n LOGIN_SETUP_NONE_OPTION: '— None —',\r\n LOGIN_SETUP_SUMMARY: 'File: {file} · before: {before} · beforeEach: {beforeEach}',\r\n LOGIN_SETUP_SAVE_BTN: '💾 Save',\r\n LOGIN_SETUP_CLEAR_BTN: 'Remove configuration',\r\n LOGIN_SETUP_CANCEL_BTN: 'Cancel',\r\n LOGIN_SETUP_SOURCE_LABEL: 'Login file source',\r\n LOGIN_SETUP_CREATE_SUB: 'Generate a scaffold with sample functions',\r\n LOGIN_SETUP_SELECT_SUB: 'Point to an existing login service file',\r\n LOGIN_SETUP_INJECT_TITLE: 'Add login blocks?',\r\n LOGIN_SETUP_INJECT_TEXT: 'This file does not have the configured login blocks. Do you want to add the import and before/beforeEach blocks now?',\r\n LOGIN_SETUP_INJECT_CONFIRM: 'Yes, add them',\r\n },\r\n SELECTOR_PICKER: {\r\n TITLE: 'Select a DOM element',\r\n PREVIEW_LABEL: 'navigate',\r\n CONFIRM_HINT: 'confirm',\r\n CANCEL_HINT: 'cancel',\r\n QUALITY_EXCELLENT: 'Excellent — has a testing attribute (data-cy / data-testid / aria-label)',\r\n QUALITY_GOOD: 'Good — has a valid id',\r\n QUALITY_ACCEPTABLE: 'Acceptable — CSS classes only',\r\n QUALITY_POOR: 'Not recommended — tag name or inline style only',\r\n },\r\n TEST_PREVISUALIZER: {\r\n INTERCEPTORS: 'Interceptors',\r\n COPY_CMDS_BTN: '📋 Copy commands',\r\n SHOW_INTERCEPTORS: '▼ Show interceptors',\r\n HIDE_INTERCEPTORS: '▲ Hide interceptors',\r\n SECTION_COMMANDS: 'Commands',\r\n NO_CMDS_YET: 'No commands yet',\r\n NO_ICP_SHORT: 'No interceptors',\r\n COPY_ICP_BTN: '📋 Copy interceptors',\r\n UP_TITLE: 'Move up',\r\n DOWN_TITLE: 'Move down',\r\n DEL_TITLE: 'Delete',\r\n },\r\n ADVANCED_EDITOR: {\r\n REAUTH_BTN: '🔓 Reactivate access',\r\n PERMISSION_EXPIRED: '🔑 Permission expired',\r\n PERMISSION_EXPIRED_HINT: 'Click to reactivate access to your Cypress folder.',\r\n NO_ACCESS: '🔒 No access to local files',\r\n NO_ACCESS_HINT: 'Configure access in ⚙️ Config.',\r\n NO_FILES: 'No files',\r\n SELECT_FILE: '← Select a file from the tree',\r\n IT_LABEL: '🧪 it() to insert:',\r\n COPY_IT_BTN: '📋 Copy it()',\r\n BEFORE_EACH_LABEL: '🔀 beforeEach() interceptors:',\r\n COPY_ICP_BTN: '📋 Copy interceptors',\r\n INSERT_BTN: '💾 Insert into file',\r\n EDIT_MANUAL_BTN: '✏️ Edit manually',\r\n CLOSE_BTN: '✕ Close',\r\n NEW_FILE_BTN: '+ New file',\r\n NEW_FOLDER_BTN: '+ New folder',\r\n REFRESH_BTN: '↻ Refresh',\r\n NEW_FILE_PLACEHOLDER: 'test-name',\r\n NEW_FOLDER_PLACEHOLDER: 'folder-name',\r\n NEW_FILE_CONFIRM: 'Create',\r\n NEW_FILE_CANCEL: 'Cancel',\r\n },\r\n FILE_PREVIEW: {\r\n NO_FILE: 'No file',\r\n COPY_TITLE: 'Copy editor content',\r\n BLOCK_IT: '🧪 it()',\r\n COPY_BTN: '📋 Copy',\r\n BLOCK_BEFORE_EACH: '🔀 beforeEach()',\r\n NO_CHANGES: 'No changes from original',\r\n NO_CHANGES_SHORT: 'No changes',\r\n LAUNCH_BTN: '▶ Run test',\r\n LAUNCH_LOCAL_ONLY: 'Move it to localhost to run tests',\r\n LAUNCH_RUNNING: '⏳ Running…',\r\n LAUNCH_PASSED: '✓ Test passed',\r\n LAUNCH_FAILED: '✗ Test failed',\r\n LAUNCH_NO_RUNNER: 'No local runner detected (did you start it?)',\r\n DIFF_BTN: '📊 Diff',\r\n SAVE_BTN: '💾 Save',\r\n CLOSE_BTN: '✕ Close',\r\n BACK_TO_EDITOR: '← Back to editor',\r\n INSERT_BTN: '🪄 Insert blocks',\r\n INSERT_TITLE: 'Insert it() and beforeEach() into the editor content',\r\n INSERT_DONE: 'Blocks inserted into the editor',\r\n INSERT_ERROR: 'No valid describe() block found in the file',\r\n },\r\n RECORDER: {\r\n FS_TITLE: '📁 File access',\r\n FS_LATER_BTN: 'Not now',\r\n FS_SELECT_BTN: '📁 Select folder',\r\n FS_SUCCESS_TOAST: '✓ Cypress folder configured',\r\n FS_ERROR_TOAST: 'Error accessing the folder',\r\n FS_INTRO_HTML: 'The <strong style=\"color:#e6edf3\">advanced editor</strong> can insert your tests directly into the Cypress <code style=\"background:#0d1117;padding:1px 6px;border-radius:4px;font-size:11px;color:#c9d1d9\">.cy.ts</code> files.',\r\n FS_STRUCTURE_HINT_HTML: 'Select the folder that contains the <code style=\"background:#0d1117;padding:1px 5px;border-radius:4px;font-size:10px;color:#c9d1d9\">e2e/</code> subfolder. The extension expects this structure:',\r\n FS_TREE_PICK_HINT: '← select this folder',\r\n FS_TREE_READ_HINT: '← the extension will read here',\r\n FS_PERMISSION_NOTE: 'The permission is stored in the browser and will not be requested again.',\r\n ASSERTION_SECTION: '➕ Add assertion',\r\n ASSERT_SELECTOR_PH: 'selector, e.g.: [data-cy=\"btn\"]',\r\n ASSERT_VALUE_PH: 'expected value',\r\n ASSERT_ADD_BTN: '➕ Add',\r\n FILE_EDITOR_TITLE: '✏️ File editor',\r\n FILE_SAVED_TOAST: '✓ File saved',\r\n FILE_SAVE_ERROR_TOAST: 'Error saving the file',\r\n FIXTURES_WRITTEN_TOAST: '✓ Fixtures written to cypress/fixtures',\r\n FIXTURES_NO_FOLDER_TOAST: 'Could not write fixtures (configure the Cypress folder)',\r\n FILE_UPLOAD_MANUAL_TOAST: 'Add {files} to cypress/fixtures/ before running the test.',\r\n FILE_UPLOAD_COPIED_TOAST: '{files} copied to cypress/fixtures/.',\r\n FILE_UPLOAD_COPY_ERROR_TOAST: 'Could not copy {files} to cypress/fixtures/. Add it manually.',\r\n BTN_CONFIG: 'Config',\r\n BTN_FILES: 'Files',\r\n BTN_COMMANDS: 'Commands',\r\n BTN_TESTS: 'Tests',\r\n PAUSE_TITLE: 'Pause (Ctrl+P)',\r\n RESUME_TITLE: 'Resume (Ctrl+P)',\r\n BADGE_PAUSED: '⏸ PAUSED',\r\n BADGE_REC: '● REC',\r\n STOP_TITLE: 'Stop (Ctrl+R)',\r\n START_TITLE: 'Record (Ctrl+R)',\r\n SESSION_RESUME_TITLE: '⏺ Recording in progress',\r\n SESSION_RESUME_TEXT: 'There is an unfinished active recording.',\r\n SESSION_RESUME_COUNT: 'commands captured',\r\n SESSION_CONTINUE_BTN: 'Keep recording',\r\n SESSION_DISCARD_BTN: 'Discard',\r\n BTN_HELP: 'Help',\r\n RECOVER_BTN: 'Recover',\r\n RECOVER_TITLE: 'Recover the last stopped recording: {count} commands ({time})',\r\n RECOVER_TIME_NOW: 'just now',\r\n RECOVER_TIME_MINUTES: '{m} min ago',\r\n },\r\n HELP: {\r\n TITLE: '❓ Help — Quick guide',\r\n INTRO: 'Everything the recorder can do.',\r\n SEC_RECORDING: '⏺ Recording',\r\n RECORDING_1: 'Press ⏺ (or Ctrl+R) to start; ⏹ to stop and save.',\r\n RECORDING_2: 'Pause / resume with ⏸ (or Ctrl+P).',\r\n SEC_SHORTCUTS: '⌨️ Keyboard shortcuts',\r\n SC_RECORD: 'Ctrl+R — Record / stop',\r\n SC_PAUSE: 'Ctrl+P — Pause / resume',\r\n SC_TESTS: 'Ctrl+1 — Saved tests panel',\r\n SC_COMMANDS: 'Ctrl+2 — Commands panel',\r\n SC_CONFIG: 'Ctrl+3 — Settings',\r\n SC_VISIBILITY: 'Ctrl+Shift+E — Show / hide the widget',\r\n SC_HELP: 'Ctrl+Shift+H — This help',\r\n SEC_CAPTURED: '🎯 What gets recorded',\r\n CAP_CLICK: 'Click → .click()',\r\n CAP_DBLCLICK: 'Double-click → .dblclick()',\r\n CAP_RIGHTCLICK: 'Right-click → .rightclick()',\r\n CAP_TYPE: 'Type into a field → .clear().type(...)',\r\n CAP_CHECK: 'Checkbox / radio → .check() / .uncheck()',\r\n CAP_SELECT: '<select> → .select(...)',\r\n CAP_KEYS: 'Enter / Escape → .type(\"{enter}\") / (\"{esc}\")',\r\n CAP_ROUTE: 'Route change (SPA) → cy.url().should(...)',\r\n CAP_HTTP: 'fetch / XHR → cy.intercept + cy.wait',\r\n SEC_ASSERT: '✅ Assertions',\r\n ASSERT_1: 'Alt+click an element to verify it without running its action (text, value, checked or visible).',\r\n ASSERT_2: 'Or use the assertion builder in the Commands panel.',\r\n SEC_PANELS: '🗂 Panels',\r\n PANEL_TESTS: '📋 Tests — saved tests: filter by tag, copy, combine, export.',\r\n PANEL_COMMANDS: '⌨️ Commands — current recording: reorder, delete, add assertions.',\r\n PANEL_CONFIG: '⚙️ Config — language, selector, HTTP, Cypress folder, login setup, data, visibility, position.',\r\n PANEL_FILES: '📁 Files — insert tests into your .cy.ts and launch the runner.',\r\n SEC_SELECTOR: '🔎 Selectors',\r\n SELECTOR_1: 'Choose the preferred attribute (data-cy, data-testid, aria-label, id) in Config.',\r\n SELECTOR_2: 'If a click has no reliable selector, a picker appears to choose the best ancestor.',\r\n SEC_DATA: '💾 Data',\r\n DATA_1: 'Export tests to JSON (all / selection / by tags).',\r\n DATA_2: 'Import a JSON: it merges into your data (nothing is wiped).',\r\n SEC_ADVANCED: '🚀 Advanced',\r\n ADV_INVISIBLE: 'Invisible mode: start-hidden + Ctrl+Shift+E to record in production unobtrusively.',\r\n ADV_RUNNER: 'Local runner: npx lib-e2e-cypress-runner to run a spec headless from the editor.',\r\n ADV_CROSSAPP: 'Cross-app: the recording survives switching micro-frontend (same origin).',\r\n ADV_DRAG: 'Drag the ⏺ button to move the widget; its position is remembered.',\r\n ADV_LOGIN: 'Login Setup (Ctrl+3): point to your login service; the recorder automatically injects before()/beforeEach() blocks into each new test.',\r\n CLOSE: 'Close',\r\n TAB_REFERENCE: 'Quick reference',\r\n TAB_GUIDE: 'Usage guide',\r\n GUIDE_INTRO: 'How to get the most out of the recorder, and what it does / doesn\\'t cover.',\r\n G_SEC_WORKFLOW: '🧭 Workflow',\r\n G_WF_1: '1. Press ⏺ (or Ctrl+R) to start recording.',\r\n G_WF_2: '2. Use your app like a user: clicks, forms, navigation. Each action becomes a Cypress command.',\r\n G_WF_3: '3. Add checks with Alt+click on whatever you want to verify.',\r\n G_WF_4: '4. Press ⏹ to stop; give it a name and tags, and save it.',\r\n G_WF_5: '5. In 📁 Files, insert the test into a .cy.ts or run it with the local runner.',\r\n G_SEC_COVERED: '✅ What it covers',\r\n G_COV_1: 'Clicks, double-click, right-click, text inputs, checkbox/radio, select and Enter/Escape keys.',\r\n G_COV_2: 'SPA navigation (pushState/replaceState/popstate) → cy.url().should(...).',\r\n G_COV_3: 'fetch/XHR calls (GET/POST/PUT) → cy.intercept + cy.wait, with optional body validation.',\r\n G_COV_4: 'Reliable selector (data-cy/testid/aria/id) and a picker when none is obvious.',\r\n G_COV_5: 'Automatic assertions (Alt+click) and the manual builder.',\r\n G_COV_6: 'Continuity when switching micro-frontend (same origin), invisible mode and i18n.',\r\n G_COV_7: 'Login Setup: configure your login function under Ctrl+3 → Login Setup; the recorder adds before()/beforeEach() blocks to every new test.',\r\n G_SEC_NOTCOVERED: '🚫 What it does NOT cover (yet)',\r\n G_NC_1: 'Different origins / subdomains (same origin only).',\r\n G_NC_2: 'File upload (selectFile), drag & drop, and hover.',\r\n G_NC_3: 'The Tab key (Cypress can\\'t .type() it).',\r\n G_NC_4: 'DELETE requests (intentionally ignored).',\r\n G_NC_5: 'Third-party iframes and Shadow DOM may not be captured.',\r\n },\r\n};\r\n","export const I18N_FR = {\r\n MAIN_FRAME: {\r\n SETTINGS: 'Paramètres',\r\n SHOW_ADVANCED_EDITOR: 'Éditeur avancé',\r\n DIALOG_SAVED_TESTS: 'Tests enregistrés',\r\n DIALOG_COMMANDS: 'Aperçu des commandes Cypress',\r\n DIALOG_SAVE: \"Enregistrer l'enregistrement ?\",\r\n },\r\n SAVE_TEST: {\r\n DESC_LABEL: 'Description du test',\r\n CANCEL: 'Annuler',\r\n ASK: 'Enregistrer le test ?',\r\n YES_CONTINUE: 'Oui, continuer',\r\n NO_DISCARD: 'Non, ignorer',\r\n DESC_PLACEHOLDER: 'Ex : Connexion réussie avec identifiants valides',\r\n TAGS_LABEL: 'Étiquettes (optionnel, pour filtrer ensuite) :',\r\n TAGS_PLACEHOLDER: 'smoke, login, régression…',\r\n ADD_TAG: '+ Ajouter',\r\n NO_TAGS: 'Sans étiquettes',\r\n SAVE_BTN: '💾 Enregistrer',\r\n SAVE_AND_EDIT: '📝 Enregistrer et éditer',\r\n REMOVE_TAG_TITLE: 'Retirer',\r\n NOTES_LABEL: 'Description / Notes (optionnel) :',\r\n NOTES_PLACEHOLDER: 'Ce que ce test valide, conditions préalables, etc.',\r\n TICKET_LABEL: 'Ticket / Issue (optionnel) :',\r\n TICKET_PLACEHOLDER: 'Ex : PROJ-123, #42',\r\n TICKET_WARN: 'ID non valide pour le fournisseur configuré (sera enregistré quand même)', // TODO: translate\r\n CONFIRM_DISCARD: 'Êtes-vous sûr de vouloir abandonner cet enregistrement ? Toutes les étapes enregistrées seront perdues.',\r\n CONFIRM_DISCARD_BTN: 'Oui, abandonner',\r\n BACK_BTN: 'Retour',\r\n CONTINUE_RECORDING_BTN: '⏺ Continuer l’enregistrement',\r\n },\r\n TEST_EDITOR: {\r\n NO_TAGS: 'Sans étiquettes',\r\n SELECTED_SINGULAR: 'sélectionné',\r\n SELECTED_PLURAL: 'sélectionnés',\r\n DESCRIBE_PLACEHOLDER: 'Nom du describe (optionnel)',\r\n COPY_DESCRIBE: '🗂 Copier describe()',\r\n MULTI_SELECT: '🗂 Multi-sélection',\r\n CANCEL_SELECT: '✕ Annuler',\r\n COPY_CMDS_BTN: '📋 Copier les commandes',\r\n COPY_ICPS_BTN: '📋 Copier les intercepteurs',\r\n DEFAULT_DESCRIBE: 'Suite de tests',\r\n NO_TESTS: 'Aucun test enregistré',\r\n DELETE_TITLE: 'Supprimer',\r\n GROUP_BY_TICKET: '🎫 Grouper par ticket',\r\n UNGROUP_TICKET: '🎫 Dégrouper',\r\n NO_TICKET: 'Sans ticket',\r\n TICKET_LINK_TITLE: 'Ouvrir le ticket',\r\n },\r\n CONFIG: {\r\n LANG_SECTION: '🌐 Langue',\r\n LANG_FIELD: 'Interface',\r\n HTTP_SECTION: '⚡ HTTP Avancé',\r\n HTTP_TITLE: 'Validations du corps',\r\n HTTP_SUB: 'GET → réponse · POST/PUT → requête',\r\n FIXTURE_SECTION: '🧪 Fixtures HTTP',\r\n FIXTURE_TITLE: 'Enregistrer les réponses comme fixtures',\r\n FIXTURE_SUB: 'Les GET sont enregistrées dans cypress/fixtures et stubées via cy.intercept({ fixture }).',\r\n SELECTOR_SECTION: '🎯 Stratégie de sélecteur',\r\n SELECTOR_LABEL: 'Attribut préféré pour cy.get()',\r\n SELECTOR_OPT_DATACY: 'data-cy (par défaut)',\r\n SELECTOR_OPT_TESTID: 'data-testid',\r\n SELECTOR_OPT_ARIA: 'aria-label',\r\n SELECTOR_OPT_ID: 'id (#élément)',\r\n SELECTOR_HINT: \"L'enregistreur cherchera d'abord cet attribut. Si absent, il essaiera les autres.\",\r\n FOLDER_SECTION: '📁 Dossier Cypress',\r\n FOLDER_CONNECTED: 'connecté —',\r\n FOLDER_NOT_SET: 'non configuré',\r\n FOLDER_CHANGE_BTN: '📁 Changer de dossier',\r\n FOLDER_SELECT_BTN: '📁 Sélectionner un dossier',\r\n FOLDER_REVOKE_BTN: \"✕ Révoquer l'accès\",\r\n DATA_SECTION: '💾 Données',\r\n DATA_DESC: 'Exportez tous vos tests en JSON ou importez une sauvegarde.',\r\n EXPORT_BTN: '⬆️ Exporter les tests',\r\n EXPORT_DIALOG_TITLE: '⬆️ Exporter les tests',\r\n EXPORT_MODE_ALL: 'Tout',\r\n EXPORT_MODE_MANUAL: 'Sélection manuelle',\r\n EXPORT_MODE_TAGS: 'Par tags',\r\n EXPORT_ALL_DESC: 'Tous les tests enregistrés seront exportés.',\r\n EXPORT_COUNT: 'À exporter :',\r\n EXPORT_CONFIRM: '⬆️ Exporter',\r\n EXPORT_CANCEL: 'Annuler',\r\n EXPORT_EMPTY: 'Aucun test à exporter.',\r\n EXPORT_NO_TAGS: 'Aucun tag disponible.',\r\n EXPORT_TAGS_HINT: 'Sélectionnez un ou plusieurs tags pour voir les tests qui seront exportés.',\r\n EXPORT_RESULT_LABEL: 'Tests qui seront exportés :',\r\n IMPORT_BTN: '⬇️ Importer les tests',\r\n FOLDER_UPDATED_TOAST: '✓ Dossier Cypress mis à jour',\r\n FOLDER_ERROR_TOAST: \"Erreur lors de l'accès au dossier\",\r\n IMPORT_SUCCESS: 'Données importées avec succès.',\r\n IMPORT_ERROR: \"Erreur lors de l'importation.\",\r\n JSON_INVALID: \"Le fichier n'est pas un JSON valide.\",\r\n JSON_BAD_FORMAT: \"Le fichier n'a pas le format attendu.\",\r\n SMART_SELECTOR_SECTION: '🔍 Sélecteur intelligent',\r\n SMART_SELECTOR_TITLE: 'Sélecteur intelligent',\r\n SMART_SELECTOR_SUB: 'Affiche un sélecteur lors du clic sur des éléments sans sélecteur valide.',\r\n START_HIDDEN_SECTION: '👁 Visibilité du widget',\r\n START_HIDDEN_TITLE: 'Démarrer masqué',\r\n START_HIDDEN_SUB: 'Le widget démarre invisible. Utilisez Ctrl+Shift+E pour l\\'afficher ou le masquer.',\r\n RESUME_TTL_SECTION: '⏱ Continuité d\\'enregistrement',\r\n RESUME_TTL_LABEL: 'Reprendre sans demander (minutes)',\r\n RESUME_TTL_HINT: 'Si vous rechargez ou changez de projet, un enregistrement actif reprend sans demander dans ce délai. Au-delà, il vous demandera de continuer ou d\\'ignorer.',\r\n WIDGET_POSITION_SECTION: '🧲 Position du widget',\r\n WIDGET_POSITION_HINT: 'Fais glisser le bouton d\\'enregistrement pour le déplacer. Sa position est mémorisée.',\r\n WIDGET_POSITION_RESET_BTN: '↺ Réinitialiser la position',\r\n WIDGET_POSITION_RESET_DONE: '✓ Position réinitialisée',\r\n ISSUE_TRACKER_SECTION: '🎫 Gestionnaire de tickets',\r\n ISSUE_TRACKER_TITLE: 'Lier les tests aux tickets',\r\n ISSUE_TRACKER_SUB: \"Ajoutez un ID de ticket lors de l'enregistrement et générez un lien cliquable.\",\r\n ISSUE_TRACKER_PROVIDER: 'Fournisseur',\r\n ISSUE_TRACKER_BASE_URL: 'URL de base',\r\n ISSUE_TRACKER_BASE_URL_PH: 'Ex : https://monprojet.atlassian.net',\r\n LOGIN_SETUP_SECTION: '🔐 Login setup',\r\n LOGIN_SETUP_NOT_CONFIGURED: 'Non configuré',\r\n LOGIN_SETUP_SET_UP_BTN: 'Configurer',\r\n LOGIN_SETUP_TITLE: 'Configuration du login',\r\n LOGIN_SETUP_CREATE_SCAFFOLD: 'Créer un scaffold',\r\n LOGIN_SETUP_SELECT_EXISTING: 'Sélectionner un fichier existant',\r\n LOGIN_SETUP_FILE_NAME_LABEL: 'Nom du fichier',\r\n LOGIN_SETUP_FILE_NAME_PH: 'Ex : cypress/common-services/login.service.ts',\r\n LOGIN_SETUP_RESCAN: '🔄 Re-scanner',\r\n LOGIN_SETUP_FUNCTIONS_DETECTED: 'Fonctions détectées',\r\n LOGIN_SETUP_BLOCK_ASSIGN: 'Affectation des blocs',\r\n LOGIN_SETUP_NO_FUNCTIONS: 'Aucune fonction exportée trouvée. Remplissez le scaffold et re-scannez.',\r\n LOGIN_SETUP_BEFORE_LABEL: 'Fonction before() (une fois par suite)',\r\n LOGIN_SETUP_BEFORE_EACH_LABEL: 'Fonction beforeEach() (avant chaque test)',\r\n LOGIN_SETUP_NONE_OPTION: '— Aucune —',\r\n LOGIN_SETUP_SUMMARY: 'Fichier : {file} · before : {before} · beforeEach : {beforeEach}',\r\n LOGIN_SETUP_SAVE_BTN: '💾 Enregistrer',\r\n LOGIN_SETUP_CLEAR_BTN: 'Supprimer la configuration',\r\n LOGIN_SETUP_CANCEL_BTN: 'Annuler',\r\n LOGIN_SETUP_SOURCE_LABEL: 'Source du fichier de login',\r\n LOGIN_SETUP_CREATE_SUB: 'Générer un scaffold avec des fonctions exemples',\r\n LOGIN_SETUP_SELECT_SUB: 'Pointer vers un fichier de service de login existant',\r\n LOGIN_SETUP_INJECT_TITLE: 'Ajouter les blocs de login ?',\r\n LOGIN_SETUP_INJECT_TEXT: 'Ce fichier ne contient pas les blocs de login configurés. Voulez-vous ajouter l\\'import et les blocs before/beforeEach maintenant ?',\r\n LOGIN_SETUP_INJECT_CONFIRM: 'Oui, ajouter',\r\n },\r\n SELECTOR_PICKER: {\r\n TITLE: 'Sélectionnez un élément du DOM',\r\n PREVIEW_LABEL: 'naviguer',\r\n CONFIRM_HINT: 'confirmer',\r\n CANCEL_HINT: 'annuler',\r\n QUALITY_EXCELLENT: 'Excellent — attribut de test présent (data-cy / data-testid / aria-label)',\r\n QUALITY_GOOD: 'Bon — id valide',\r\n QUALITY_ACCEPTABLE: 'Acceptable — classes CSS uniquement',\r\n QUALITY_POOR: 'Déconseillé — seulement le nom de balise ou style inline',\r\n },\r\n TEST_PREVISUALIZER: {\r\n INTERCEPTORS: 'Intercepteurs',\r\n COPY_CMDS_BTN: '📋 Copier les commandes',\r\n SHOW_INTERCEPTORS: '▼ Voir les intercepteurs',\r\n HIDE_INTERCEPTORS: '▲ Masquer les intercepteurs',\r\n SECTION_COMMANDS: 'Commandes',\r\n NO_CMDS_YET: 'Aucune commande encore',\r\n NO_ICP_SHORT: 'Aucun intercepteur',\r\n COPY_ICP_BTN: '📋 Copier les intercepteurs',\r\n UP_TITLE: 'Monter',\r\n DOWN_TITLE: 'Descendre',\r\n DEL_TITLE: 'Supprimer',\r\n },\r\n ADVANCED_EDITOR: {\r\n REAUTH_BTN: \"🔓 Réactiver l'accès\",\r\n PERMISSION_EXPIRED: '🔑 Autorisation expirée',\r\n PERMISSION_EXPIRED_HINT: \"Cliquez pour réactiver l'accès à votre dossier Cypress.\",\r\n NO_ACCESS: '🔒 Pas d\\'accès aux fichiers locaux',\r\n NO_ACCESS_HINT: \"Configurez l'accès dans ⚙️ Config.\",\r\n NO_FILES: 'Aucun fichier',\r\n SELECT_FILE: \"← Sélectionnez un fichier dans l'arborescence\",\r\n IT_LABEL: '🧪 it() à insérer :',\r\n COPY_IT_BTN: '📋 Copier it()',\r\n BEFORE_EACH_LABEL: '🔀 beforeEach() intercepteurs :',\r\n COPY_ICP_BTN: '📋 Copier les intercepteurs',\r\n INSERT_BTN: '💾 Insérer dans le fichier',\r\n EDIT_MANUAL_BTN: '✏️ Éditer manuellement',\r\n CLOSE_BTN: '✕ Fermer',\r\n NEW_FILE_BTN: '+ Nouveau fichier',\r\n NEW_FOLDER_BTN: '+ Nouveau dossier',\r\n REFRESH_BTN: '↻ Actualiser',\r\n NEW_FILE_PLACEHOLDER: 'nom-du-test',\r\n NEW_FOLDER_PLACEHOLDER: 'nom-du-dossier',\r\n NEW_FILE_CONFIRM: 'Créer',\r\n NEW_FILE_CANCEL: 'Annuler',\r\n },\r\n FILE_PREVIEW: {\r\n NO_FILE: 'Sans fichier',\r\n COPY_TITLE: \"Copier le contenu de l'éditeur\",\r\n BLOCK_IT: '🧪 it()',\r\n COPY_BTN: '📋 Copier',\r\n BLOCK_BEFORE_EACH: '🔀 beforeEach()',\r\n NO_CHANGES: \"Aucun changement par rapport à l'original\",\r\n NO_CHANGES_SHORT: 'Aucun changement',\r\n LAUNCH_BTN: '▶ Lancer le test',\r\n LAUNCH_LOCAL_ONLY: 'Passe en local pour pouvoir tester',\r\n LAUNCH_RUNNING: '⏳ Exécution…',\r\n LAUNCH_PASSED: '✓ Test réussi',\r\n LAUNCH_FAILED: '✗ Test échoué',\r\n LAUNCH_NO_RUNNER: \"Aucun runner local détecté (l'avez-vous démarré ?)\",\r\n DIFF_BTN: '📊 Diff',\r\n SAVE_BTN: '💾 Enregistrer',\r\n CLOSE_BTN: '✕ Fermer',\r\n BACK_TO_EDITOR: \"← Retour à l'éditeur\",\r\n INSERT_BTN: '🪄 Insérer les blocs',\r\n INSERT_TITLE: \"Insérer it() et beforeEach() dans le contenu de l'éditeur\",\r\n INSERT_DONE: \"Blocs insérés dans l'éditeur\",\r\n INSERT_ERROR: 'Aucun bloc describe() valide trouvé dans le fichier',\r\n },\r\n RECORDER: {\r\n FS_TITLE: '📁 Accès aux fichiers',\r\n FS_LATER_BTN: 'Pas maintenant',\r\n FS_SELECT_BTN: '📁 Sélectionner un dossier',\r\n FS_SUCCESS_TOAST: '✓ Dossier Cypress configuré',\r\n FS_ERROR_TOAST: \"Erreur lors de l'accès au dossier\",\r\n FS_INTRO_HTML: 'L\\'<strong style=\"color:#e6edf3\">éditeur avancé</strong> peut insérer vos tests directement dans les fichiers <code style=\"background:#0d1117;padding:1px 6px;border-radius:4px;font-size:11px;color:#c9d1d9\">.cy.ts</code> de Cypress.',\r\n FS_STRUCTURE_HINT_HTML: 'Sélectionnez le dossier qui contient le sous-dossier <code style=\"background:#0d1117;padding:1px 5px;border-radius:4px;font-size:10px;color:#c9d1d9\">e2e/</code>. L\\'extension attend cette structure :',\r\n FS_TREE_PICK_HINT: '← sélectionnez ce dossier',\r\n FS_TREE_READ_HINT: '← l\\'extension lira ici',\r\n FS_PERMISSION_NOTE: 'L\\'autorisation est enregistrée dans le navigateur et ne sera plus demandée.',\r\n ASSERTION_SECTION: '➕ Ajouter une assertion',\r\n ASSERT_SELECTOR_PH: 'sélecteur, ex : [data-cy=\"btn\"]',\r\n ASSERT_VALUE_PH: 'valeur attendue',\r\n ASSERT_ADD_BTN: '➕ Ajouter',\r\n FILE_EDITOR_TITLE: '✏️ Éditeur de fichier',\r\n FILE_SAVED_TOAST: '✓ Fichier enregistré',\r\n FILE_SAVE_ERROR_TOAST: \"Erreur lors de l'enregistrement\",\r\n FIXTURES_WRITTEN_TOAST: '✓ Fixtures écrites dans cypress/fixtures',\r\n FIXTURES_NO_FOLDER_TOAST: 'Impossible d\\'écrire les fixtures (configure le dossier Cypress)',\r\n FILE_UPLOAD_MANUAL_TOAST: 'Ajoutez {files} à cypress/fixtures/ avant d\\'exécuter le test.', // TODO: translate\r\n FILE_UPLOAD_COPIED_TOAST: '{files} copié(s) dans cypress/fixtures/.', // TODO: translate\r\n FILE_UPLOAD_COPY_ERROR_TOAST: 'Impossible de copier {files} vers cypress/fixtures/. Ajoutez-le manuellement.', // TODO: translate\r\n BTN_CONFIG: 'Config',\r\n BTN_FILES: 'Fichiers',\r\n BTN_COMMANDS: 'Commandes',\r\n BTN_TESTS: 'Tests',\r\n PAUSE_TITLE: 'Pause (Ctrl+P)',\r\n RESUME_TITLE: 'Reprendre (Ctrl+P)',\r\n BADGE_PAUSED: '⏸ PAUSE',\r\n BADGE_REC: '● REC',\r\n STOP_TITLE: 'Arrêter (Ctrl+R)',\r\n START_TITLE: 'Enregistrer (Ctrl+R)',\r\n SESSION_RESUME_TITLE: '⏺ Enregistrement en cours',\r\n SESSION_RESUME_TEXT: 'Un enregistrement actif est inachevé.',\r\n SESSION_RESUME_COUNT: 'commandes capturées',\r\n SESSION_CONTINUE_BTN: 'Continuer l\\'enregistrement',\r\n SESSION_DISCARD_BTN: 'Ignorer',\r\n BTN_HELP: 'Aide',\r\n RECOVER_BTN: 'Récupérer',\r\n RECOVER_TITLE: 'Récupérer le dernier enregistrement arrêté : {count} commandes ({time})',\r\n RECOVER_TIME_NOW: 'à l’instant',\r\n RECOVER_TIME_MINUTES: 'il y a {m} min',\r\n },\r\n HELP: {\r\n TITLE: '❓ Aide — Guide rapide',\r\n INTRO: 'Tout ce que l\\'enregistreur sait faire.',\r\n SEC_RECORDING: '⏺ Enregistrer',\r\n RECORDING_1: 'Appuie sur ⏺ (ou Ctrl+R) pour commencer ; ⏹ pour arrêter et enregistrer.',\r\n RECORDING_2: 'Pause / reprise avec ⏸ (ou Ctrl+P).',\r\n SEC_SHORTCUTS: '⌨️ Raccourcis clavier',\r\n SC_RECORD: 'Ctrl+R — Enregistrer / arrêter',\r\n SC_PAUSE: 'Ctrl+P — Pause / reprise',\r\n SC_TESTS: 'Ctrl+1 — Panneau des tests enregistrés',\r\n SC_COMMANDS: 'Ctrl+2 — Panneau des commandes',\r\n SC_CONFIG: 'Ctrl+3 — Paramètres',\r\n SC_VISIBILITY: 'Ctrl+Shift+E — Afficher / masquer le widget',\r\n SC_HELP: 'Ctrl+Shift+H — Cette aide',\r\n SEC_CAPTURED: '🎯 Ce qui est enregistré',\r\n CAP_CLICK: 'Clic → .click()',\r\n CAP_DBLCLICK: 'Double-clic → .dblclick()',\r\n CAP_RIGHTCLICK: 'Clic droit → .rightclick()',\r\n CAP_TYPE: 'Saisie dans un champ → .clear().type(...)',\r\n CAP_CHECK: 'Case à cocher / radio → .check() / .uncheck()',\r\n CAP_SELECT: '<select> → .select(...)',\r\n CAP_KEYS: 'Entrée / Échap → .type(\"{enter}\") / (\"{esc}\")',\r\n CAP_ROUTE: 'Changement de route (SPA) → cy.url().should(...)',\r\n CAP_HTTP: 'fetch / XHR → cy.intercept + cy.wait',\r\n SEC_ASSERT: '✅ Assertions',\r\n ASSERT_1: 'Alt+clic sur un élément pour le vérifier sans exécuter son action (texte, valeur, coché ou visible).',\r\n ASSERT_2: 'Ou utilise le constructeur d\\'assertions dans le panneau Commandes.',\r\n SEC_PANELS: '🗂 Panneaux',\r\n PANEL_TESTS: '📋 Tests — enregistrés : filtrer par tag, copier, combiner, exporter.',\r\n PANEL_COMMANDS: '⌨️ Commandes — enregistrement en cours : réordonner, supprimer, ajouter des assertions.',\r\n PANEL_CONFIG: '⚙️ Config — langue, sélecteur, HTTP, dossier Cypress, login setup, données, visibilité, position.',\r\n PANEL_FILES: '📁 Fichiers — insère des tests dans tes .cy.ts et lance le runner.',\r\n SEC_SELECTOR: '🔎 Sélecteurs',\r\n SELECTOR_1: 'Choisis l\\'attribut préféré (data-cy, data-testid, aria-label, id) dans Config.',\r\n SELECTOR_2: 'Si un clic n\\'a pas de sélecteur fiable, un sélecteur apparaît pour choisir le meilleur ancêtre.',\r\n SEC_DATA: '💾 Données',\r\n DATA_1: 'Exporte les tests en JSON (tout / sélection / par tags).',\r\n DATA_2: 'Importe un JSON : il fusionne avec tes données (rien n\\'est effacé).',\r\n SEC_ADVANCED: '🚀 Avancé',\r\n ADV_INVISIBLE: 'Mode invisible : start-hidden + Ctrl+Shift+E pour enregistrer en production discrètement.',\r\n ADV_RUNNER: 'Runner local : npx lib-e2e-cypress-runner pour lancer un spec headless depuis l\\'éditeur.',\r\n ADV_CROSSAPP: 'Cross-app : l\\'enregistrement survit au changement de micro-frontend (même origine).',\r\n ADV_DRAG: 'Fais glisser le bouton ⏺ pour déplacer le widget ; sa position est mémorisée.',\r\n ADV_LOGIN: 'Login Setup (Ctrl+3): apunta a tu servicio de login; el grabador inyecta before()/beforeEach() automáticamente en cada test nuevo.', // TODO: translate (fr)\r\n CLOSE: 'Fermer',\r\n TAB_REFERENCE: 'Référence rapide',\r\n TAB_GUIDE: 'Guide d\\'utilisation',\r\n // TODO: translate (fr) — usage guide body kept in Spanish for now.\r\n GUIDE_INTRO: 'Cómo sacarle partido al grabador, qué cubre y qué no.',\r\n G_SEC_WORKFLOW: '🧭 Flujo de trabajo',\r\n G_WF_1: '1. Pulsa ⏺ (o Ctrl+R) para empezar a grabar.',\r\n G_WF_2: '2. Usa tu app como un usuario: clicks, formularios, navegación. Cada acción se convierte en un comando Cypress.',\r\n G_WF_3: '3. Añade verificaciones con Alt+click sobre lo que quieras comprobar.',\r\n G_WF_4: '4. Pulsa ⏹ para parar; ponle nombre y tags, y guárdalo.',\r\n G_WF_5: '5. En 📁 Ficheros, inserta el test en un .cy.ts o lánzalo con el runner local.',\r\n G_SEC_COVERED: '✅ Qué cubre',\r\n G_COV_1: 'Clicks, doble-click, click derecho, inputs de texto, checkbox/radio, select y teclas Enter/Escape.',\r\n G_COV_2: 'Navegación SPA (pushState/replaceState/popstate) → cy.url().should(...).',\r\n G_COV_3: 'Llamadas fetch/XHR (GET/POST/PUT) → cy.intercept + cy.wait, con validación de body opcional.',\r\n G_COV_4: 'Selector fiable (data-cy/testid/aria/id) y picker cuando no hay uno claro.',\r\n G_COV_5: 'Aserciones automáticas (Alt+click) y constructor manual.',\r\n G_COV_6: 'Continuidad al cambiar de micro-frontend (mismo origen), modo invisible e i18n.',\r\n G_COV_7: 'Login Setup: configura tu función de login en Ctrl+3 → Login Setup y el grabador añade los bloques before()/beforeEach() a cada test nuevo.', // TODO: translate (fr)\r\n G_SEC_NOTCOVERED: '🚫 Qué NO cubre (por ahora)',\r\n G_NC_1: 'Orígenes distintos / subdominios (solo mismo origen).',\r\n G_NC_2: 'Subida de ficheros (selectFile), arrastrar y soltar, y hover.',\r\n G_NC_3: 'La tecla Tab (Cypress no la soporta en .type()).',\r\n G_NC_4: 'Peticiones DELETE (se ignoran a propósito).',\r\n G_NC_5: 'iframes y Shadow DOM de terceros pueden no capturarse.',\r\n },\r\n};\r\n","export const I18N_IT = {\r\n MAIN_FRAME: {\r\n SETTINGS: 'Impostazioni',\r\n SHOW_ADVANCED_EDITOR: 'Editor avanzato',\r\n DIALOG_SAVED_TESTS: 'Test salvati',\r\n DIALOG_COMMANDS: 'Anteprima comandi Cypress',\r\n DIALOG_SAVE: 'Salvare la registrazione?',\r\n },\r\n SAVE_TEST: {\r\n DESC_LABEL: 'Descrizione del test',\r\n CANCEL: 'Annulla',\r\n ASK: 'Salvare il test registrato?',\r\n YES_CONTINUE: 'Sì, continua',\r\n NO_DISCARD: 'No, annulla',\r\n DESC_PLACEHOLDER: 'Es: Login riuscito con credenziali valide',\r\n TAGS_LABEL: 'Etichette (opzionale, per filtrare dopo):',\r\n TAGS_PLACEHOLDER: 'smoke, login, regressione…',\r\n ADD_TAG: '+ Aggiungi',\r\n NO_TAGS: 'Nessuna etichetta',\r\n SAVE_BTN: '💾 Salva',\r\n SAVE_AND_EDIT: '📝 Salva e modifica',\r\n REMOVE_TAG_TITLE: 'Rimuovi',\r\n NOTES_LABEL: 'Descrizione / Note (opzionale):',\r\n NOTES_PLACEHOLDER: 'Cosa valida questo test, condizioni preliminari, ecc.',\r\n TICKET_LABEL: 'Ticket / Issue (opzionale):',\r\n TICKET_PLACEHOLDER: 'Es: PROJ-123, #42',\r\n TICKET_WARN: 'ID non valido per il provider configurato (verrà salvato comunque)', // TODO: translate\r\n CONFIRM_DISCARD: 'Sei sicuro di voler scartare questa registrazione? Tutti i passi registrati andranno persi.',\r\n CONFIRM_DISCARD_BTN: 'Sì, scarta',\r\n BACK_BTN: 'Indietro',\r\n CONTINUE_RECORDING_BTN: '⏺ Continua a registrare',\r\n },\r\n TEST_EDITOR: {\r\n NO_TAGS: 'Nessuna etichetta',\r\n SELECTED_SINGULAR: 'selezionato',\r\n SELECTED_PLURAL: 'selezionati',\r\n DESCRIBE_PLACEHOLDER: 'Nome del describe (opzionale)',\r\n COPY_DESCRIBE: '🗂 Copia describe()',\r\n MULTI_SELECT: '🗂 Multi-selezione',\r\n CANCEL_SELECT: '✕ Annulla',\r\n COPY_CMDS_BTN: '📋 Copia comandi',\r\n COPY_ICPS_BTN: '📋 Copia interceptor',\r\n DEFAULT_DESCRIBE: 'Suite di test',\r\n NO_TESTS: 'Nessun test salvato',\r\n DELETE_TITLE: 'Elimina',\r\n GROUP_BY_TICKET: '🎫 Raggruppa per ticket',\r\n UNGROUP_TICKET: '🎫 Separa',\r\n NO_TICKET: 'Senza ticket',\r\n TICKET_LINK_TITLE: 'Apri ticket',\r\n },\r\n CONFIG: {\r\n LANG_SECTION: '🌐 Lingua',\r\n LANG_FIELD: 'Interfaccia',\r\n HTTP_SECTION: '⚡ HTTP Avanzato',\r\n HTTP_TITLE: 'Validazioni del body',\r\n HTTP_SUB: 'GET → risposta · POST/PUT → richiesta',\r\n FIXTURE_SECTION: '🧪 Fixture HTTP',\r\n FIXTURE_TITLE: 'Registra le risposte come fixture',\r\n FIXTURE_SUB: 'Le GET vengono salvate in cypress/fixtures e stubbate con cy.intercept({ fixture }).',\r\n SELECTOR_SECTION: '🎯 Strategia selettore',\r\n SELECTOR_LABEL: 'Attributo preferito per cy.get()',\r\n SELECTOR_OPT_DATACY: 'data-cy (predefinito)',\r\n SELECTOR_OPT_TESTID: 'data-testid',\r\n SELECTOR_OPT_ARIA: 'aria-label',\r\n SELECTOR_OPT_ID: 'id (#elemento)',\r\n SELECTOR_HINT: 'Il registratore cercherà prima questo attributo. Se assente, proverà gli altri.',\r\n FOLDER_SECTION: '📁 Cartella Cypress',\r\n FOLDER_CONNECTED: 'connesso —',\r\n FOLDER_NOT_SET: 'non configurato',\r\n FOLDER_CHANGE_BTN: '📁 Cambia cartella',\r\n FOLDER_SELECT_BTN: '📁 Seleziona cartella',\r\n FOLDER_REVOKE_BTN: '✕ Revoca accesso',\r\n DATA_SECTION: '💾 Dati',\r\n DATA_DESC: 'Esporta tutti i tuoi test in JSON o importa un backup.',\r\n EXPORT_BTN: '⬆️ Esporta test',\r\n EXPORT_DIALOG_TITLE: '⬆️ Esporta test',\r\n EXPORT_MODE_ALL: 'Tutto',\r\n EXPORT_MODE_MANUAL: 'Selezione manuale',\r\n EXPORT_MODE_TAGS: 'Per tag',\r\n EXPORT_ALL_DESC: 'Verranno esportati tutti i test salvati.',\r\n EXPORT_COUNT: 'Da esportare:',\r\n EXPORT_CONFIRM: '⬆️ Esporta',\r\n EXPORT_CANCEL: 'Annulla',\r\n EXPORT_EMPTY: 'Nessun test da esportare.',\r\n EXPORT_NO_TAGS: 'Nessun tag disponibile.',\r\n EXPORT_TAGS_HINT: 'Seleziona uno o più tag per vedere quali test verranno esportati.',\r\n EXPORT_RESULT_LABEL: 'Test che verranno esportati:',\r\n IMPORT_BTN: '⬇️ Importa test',\r\n FOLDER_UPDATED_TOAST: '✓ Cartella Cypress aggiornata',\r\n FOLDER_ERROR_TOAST: \"Errore durante l'accesso alla cartella\",\r\n IMPORT_SUCCESS: 'Dati importati correttamente.',\r\n IMPORT_ERROR: \"Errore durante l'importazione.\",\r\n JSON_INVALID: 'Il file non è un JSON valido.',\r\n JSON_BAD_FORMAT: 'Il file non ha il formato previsto.',\r\n SMART_SELECTOR_SECTION: '🔍 Selettore intelligente',\r\n SMART_SELECTOR_TITLE: 'Selettore intelligente',\r\n SMART_SELECTOR_SUB: 'Mostra un selettore quando si fa clic su elementi senza selettore valido.',\r\n START_HIDDEN_SECTION: '👁 Visibilità del widget',\r\n START_HIDDEN_TITLE: 'Avvia nascosto',\r\n START_HIDDEN_SUB: 'Il widget si avvia invisibile. Usa Ctrl+Shift+E per mostrarlo o nasconderlo.',\r\n RESUME_TTL_SECTION: '⏱ Continuità di registrazione',\r\n RESUME_TTL_LABEL: 'Riprendi senza chiedere (minuti)',\r\n RESUME_TTL_HINT: 'Se ricarichi o cambi progetto, una registrazione attiva riprende senza chiedere entro questo intervallo. Trascorso, ti chiederà se continuare o annullare.',\r\n WIDGET_POSITION_SECTION: '🧲 Posizione del widget',\r\n WIDGET_POSITION_HINT: 'Trascina il pulsante di registrazione per spostarlo. La posizione viene ricordata.',\r\n WIDGET_POSITION_RESET_BTN: '↺ Reimposta posizione',\r\n WIDGET_POSITION_RESET_DONE: '✓ Posizione reimpostata',\r\n ISSUE_TRACKER_SECTION: '🎫 Issue tracker',\r\n ISSUE_TRACKER_TITLE: 'Collega i test ai ticket',\r\n ISSUE_TRACKER_SUB: \"Aggiungi un ID ticket al salvataggio e genera un link cliccabile nell'elenco.\",\r\n ISSUE_TRACKER_PROVIDER: 'Provider',\r\n ISSUE_TRACKER_BASE_URL: 'URL base',\r\n ISSUE_TRACKER_BASE_URL_PH: 'Es: https://mioprogetto.atlassian.net',\r\n LOGIN_SETUP_SECTION: '🔐 Login setup',\r\n LOGIN_SETUP_NOT_CONFIGURED: 'Non configurato',\r\n LOGIN_SETUP_SET_UP_BTN: 'Configura',\r\n LOGIN_SETUP_TITLE: 'Configurazione del login',\r\n LOGIN_SETUP_CREATE_SCAFFOLD: 'Crea scaffold',\r\n LOGIN_SETUP_SELECT_EXISTING: 'Seleziona file esistente',\r\n LOGIN_SETUP_FILE_NAME_LABEL: 'Nome del file',\r\n LOGIN_SETUP_FILE_NAME_PH: 'Es: cypress/common-services/login.service.ts',\r\n LOGIN_SETUP_RESCAN: '🔄 Re-scansiona',\r\n LOGIN_SETUP_FUNCTIONS_DETECTED: 'Funzioni rilevate',\r\n LOGIN_SETUP_BLOCK_ASSIGN: 'Assegnazione dei blocchi',\r\n LOGIN_SETUP_NO_FUNCTIONS: 'Nessuna funzione esportata trovata. Compila lo scaffold e ri-scansiona.',\r\n LOGIN_SETUP_BEFORE_LABEL: 'Funzione before() (una volta per suite)',\r\n LOGIN_SETUP_BEFORE_EACH_LABEL: 'Funzione beforeEach() (prima di ogni test)',\r\n LOGIN_SETUP_NONE_OPTION: '— Nessuna —',\r\n LOGIN_SETUP_SUMMARY: 'File: {file} · before: {before} · beforeEach: {beforeEach}',\r\n LOGIN_SETUP_SAVE_BTN: '💾 Salva',\r\n LOGIN_SETUP_CLEAR_BTN: 'Rimuovi configurazione',\r\n LOGIN_SETUP_CANCEL_BTN: 'Annulla',\r\n LOGIN_SETUP_SOURCE_LABEL: 'Sorgente del file di login',\r\n LOGIN_SETUP_CREATE_SUB: 'Genera uno scaffold con funzioni di esempio',\r\n LOGIN_SETUP_SELECT_SUB: 'Punta a un file di servizio di login esistente',\r\n LOGIN_SETUP_INJECT_TITLE: 'Aggiungere i blocchi di login?',\r\n LOGIN_SETUP_INJECT_TEXT: 'Questo file non contiene i blocchi di login configurati. Vuoi aggiungere l\\'import e i blocchi before/beforeEach ora?',\r\n LOGIN_SETUP_INJECT_CONFIRM: 'Sì, aggiungi',\r\n },\r\n SELECTOR_PICKER: {\r\n TITLE: 'Seleziona un elemento DOM',\r\n PREVIEW_LABEL: 'navigare',\r\n CONFIRM_HINT: 'confermare',\r\n CANCEL_HINT: 'annullare',\r\n QUALITY_EXCELLENT: 'Eccellente — attributo di test presente (data-cy / data-testid / aria-label)',\r\n QUALITY_GOOD: 'Buono — id valido',\r\n QUALITY_ACCEPTABLE: 'Accettabile — solo classi CSS',\r\n QUALITY_POOR: 'Sconsigliato — solo tag o stile inline',\r\n },\r\n TEST_PREVISUALIZER: {\r\n INTERCEPTORS: 'Interceptor',\r\n COPY_CMDS_BTN: '📋 Copia comandi',\r\n SHOW_INTERCEPTORS: '▼ Vedi interceptor',\r\n HIDE_INTERCEPTORS: '▲ Nascondi interceptor',\r\n SECTION_COMMANDS: 'Comandi',\r\n NO_CMDS_YET: 'Ancora nessun comando',\r\n NO_ICP_SHORT: 'Nessun interceptor',\r\n COPY_ICP_BTN: '📋 Copia interceptor',\r\n UP_TITLE: 'Su',\r\n DOWN_TITLE: 'Giù',\r\n DEL_TITLE: 'Elimina',\r\n },\r\n ADVANCED_EDITOR: {\r\n REAUTH_BTN: '🔓 Riattiva accesso',\r\n PERMISSION_EXPIRED: '🔑 Autorizzazione scaduta',\r\n PERMISSION_EXPIRED_HINT: \"Clicca per riattivare l'accesso alla cartella Cypress.\",\r\n NO_ACCESS: '🔒 Nessun accesso ai file locali',\r\n NO_ACCESS_HINT: \"Configura l'accesso in ⚙️ Config.\",\r\n NO_FILES: 'Nessun file',\r\n SELECT_FILE: \"← Seleziona un file dall'albero\",\r\n IT_LABEL: '🧪 it() da inserire:',\r\n COPY_IT_BTN: '📋 Copia it()',\r\n BEFORE_EACH_LABEL: '🔀 beforeEach() interceptor:',\r\n COPY_ICP_BTN: '📋 Copia interceptor',\r\n INSERT_BTN: '💾 Inserisci nel file',\r\n EDIT_MANUAL_BTN: '✏️ Modifica manualmente',\r\n CLOSE_BTN: '✕ Chiudi',\r\n NEW_FILE_BTN: '+ Nuovo file',\r\n NEW_FOLDER_BTN: '+ Nuova cartella',\r\n REFRESH_BTN: '↻ Aggiorna',\r\n NEW_FILE_PLACEHOLDER: 'nome-del-test',\r\n NEW_FOLDER_PLACEHOLDER: 'nome-cartella',\r\n NEW_FILE_CONFIRM: 'Crea',\r\n NEW_FILE_CANCEL: 'Annulla',\r\n },\r\n FILE_PREVIEW: {\r\n NO_FILE: 'Nessun file',\r\n COPY_TITLE: \"Copia il contenuto dell'editor\",\r\n BLOCK_IT: '🧪 it()',\r\n COPY_BTN: '📋 Copia',\r\n BLOCK_BEFORE_EACH: '🔀 beforeEach()',\r\n NO_CHANGES: \"Nessuna modifica rispetto all'originale\",\r\n NO_CHANGES_SHORT: 'Nessuna modifica',\r\n LAUNCH_BTN: '▶ Esegui test',\r\n LAUNCH_LOCAL_ONLY: 'Spostati in locale per poter testare',\r\n LAUNCH_RUNNING: '⏳ Esecuzione…',\r\n LAUNCH_PASSED: '✓ Test superato',\r\n LAUNCH_FAILED: '✗ Test fallito',\r\n LAUNCH_NO_RUNNER: \"Nessun runner locale rilevato (l'hai avviato?)\",\r\n DIFF_BTN: '📊 Diff',\r\n SAVE_BTN: '💾 Salva',\r\n CLOSE_BTN: '✕ Chiudi',\r\n BACK_TO_EDITOR: \"← Torna all'editor\",\r\n INSERT_BTN: '🪄 Inserisci blocchi',\r\n INSERT_TITLE: \"Inserisci it() e beforeEach() nel contenuto dell'editor\",\r\n INSERT_DONE: \"Blocchi inseriti nell'editor\",\r\n INSERT_ERROR: 'Nessun blocco describe() valido trovato nel file',\r\n },\r\n RECORDER: {\r\n FS_TITLE: '📁 Accesso ai file',\r\n FS_LATER_BTN: 'Non ora',\r\n FS_SELECT_BTN: '📁 Seleziona cartella',\r\n FS_SUCCESS_TOAST: '✓ Cartella Cypress configurata',\r\n FS_ERROR_TOAST: \"Errore durante l'accesso alla cartella\",\r\n FS_INTRO_HTML: 'L\\'<strong style=\"color:#e6edf3\">editor avanzato</strong> può inserire i tuoi test direttamente nei file <code style=\"background:#0d1117;padding:1px 6px;border-radius:4px;font-size:11px;color:#c9d1d9\">.cy.ts</code> di Cypress.',\r\n FS_STRUCTURE_HINT_HTML: 'Seleziona la cartella che contiene la sottocartella <code style=\"background:#0d1117;padding:1px 5px;border-radius:4px;font-size:10px;color:#c9d1d9\">e2e/</code>. L\\'estensione si aspetta questa struttura:',\r\n FS_TREE_PICK_HINT: '← seleziona questa cartella',\r\n FS_TREE_READ_HINT: '← l\\'estensione leggerà qui',\r\n FS_PERMISSION_NOTE: 'Il permesso viene salvato nel browser e non sarà richiesto di nuovo.',\r\n ASSERTION_SECTION: '➕ Aggiungi asserzione',\r\n ASSERT_SELECTOR_PH: 'selettore, es: [data-cy=\"btn\"]',\r\n ASSERT_VALUE_PH: 'valore atteso',\r\n ASSERT_ADD_BTN: '➕ Aggiungi',\r\n FILE_EDITOR_TITLE: '✏️ Editor di file',\r\n FILE_SAVED_TOAST: '✓ File salvato',\r\n FILE_SAVE_ERROR_TOAST: 'Errore durante il salvataggio',\r\n FIXTURES_WRITTEN_TOAST: '✓ Fixture scritte in cypress/fixtures',\r\n FIXTURES_NO_FOLDER_TOAST: 'Impossibile scrivere le fixture (configura la cartella Cypress)',\r\n FILE_UPLOAD_MANUAL_TOAST: 'Aggiungi {files} a cypress/fixtures/ prima di eseguire il test.', // TODO: translate\r\n FILE_UPLOAD_COPIED_TOAST: '{files} copiato/i in cypress/fixtures/.', // TODO: translate\r\n FILE_UPLOAD_COPY_ERROR_TOAST: 'Impossibile copiare {files} in cypress/fixtures/. Aggiungilo manualmente.', // TODO: translate\r\n BTN_CONFIG: 'Config',\r\n BTN_FILES: 'File',\r\n BTN_COMMANDS: 'Comandi',\r\n BTN_TESTS: 'Test',\r\n PAUSE_TITLE: 'Pausa (Ctrl+P)',\r\n RESUME_TITLE: 'Riprendi (Ctrl+P)',\r\n BADGE_PAUSED: '⏸ PAUSA',\r\n BADGE_REC: '● REC',\r\n STOP_TITLE: 'Ferma (Ctrl+R)',\r\n START_TITLE: 'Registra (Ctrl+R)',\r\n SESSION_RESUME_TITLE: '⏺ Registrazione in corso',\r\n SESSION_RESUME_TEXT: 'C\\'è una registrazione attiva non terminata.',\r\n SESSION_RESUME_COUNT: 'comandi catturati',\r\n SESSION_CONTINUE_BTN: 'Continua a registrare',\r\n SESSION_DISCARD_BTN: 'Annulla',\r\n BTN_HELP: 'Aiuto',\r\n RECOVER_BTN: 'Recupera',\r\n RECOVER_TITLE: 'Recupera l’ultima registrazione interrotta: {count} comandi ({time})',\r\n RECOVER_TIME_NOW: 'proprio ora',\r\n RECOVER_TIME_MINUTES: '{m} min fa',\r\n },\r\n HELP: {\r\n TITLE: '❓ Aiuto — Guida rapida',\r\n INTRO: 'Tutto ciò che il registratore sa fare.',\r\n SEC_RECORDING: '⏺ Registrare',\r\n RECORDING_1: 'Premi ⏺ (o Ctrl+R) per iniziare; ⏹ per fermare e salvare.',\r\n RECORDING_2: 'Pausa / ripresa con ⏸ (o Ctrl+P).',\r\n SEC_SHORTCUTS: '⌨️ Scorciatoie da tastiera',\r\n SC_RECORD: 'Ctrl+R — Registra / ferma',\r\n SC_PAUSE: 'Ctrl+P — Pausa / ripresa',\r\n SC_TESTS: 'Ctrl+1 — Pannello test salvati',\r\n SC_COMMANDS: 'Ctrl+2 — Pannello comandi',\r\n SC_CONFIG: 'Ctrl+3 — Impostazioni',\r\n SC_VISIBILITY: 'Ctrl+Shift+E — Mostra / nascondi il widget',\r\n SC_HELP: 'Ctrl+Shift+H — Questo aiuto',\r\n SEC_CAPTURED: '🎯 Cosa viene registrato',\r\n CAP_CLICK: 'Click → .click()',\r\n CAP_DBLCLICK: 'Doppio click → .dblclick()',\r\n CAP_RIGHTCLICK: 'Click destro → .rightclick()',\r\n CAP_TYPE: 'Digitare in un campo → .clear().type(...)',\r\n CAP_CHECK: 'Checkbox / radio → .check() / .uncheck()',\r\n CAP_SELECT: '<select> → .select(...)',\r\n CAP_KEYS: 'Invio / Esc → .type(\"{enter}\") / (\"{esc}\")',\r\n CAP_ROUTE: 'Cambio di rotta (SPA) → cy.url().should(...)',\r\n CAP_HTTP: 'fetch / XHR → cy.intercept + cy.wait',\r\n SEC_ASSERT: '✅ Asserzioni',\r\n ASSERT_1: 'Alt+click su un elemento per verificarlo senza eseguire la sua azione (testo, valore, checked o visibile).',\r\n ASSERT_2: 'Oppure usa il costruttore di asserzioni nel pannello Comandi.',\r\n SEC_PANELS: '🗂 Pannelli',\r\n PANEL_TESTS: '📋 Test — salvati: filtra per tag, copia, combina, esporta.',\r\n PANEL_COMMANDS: '⌨️ Comandi — registrazione corrente: riordina, elimina, aggiungi asserzioni.',\r\n PANEL_CONFIG: '⚙️ Config — lingua, selettore, HTTP, cartella Cypress, login setup, dati, visibilità, posizione.',\r\n PANEL_FILES: '📁 File — inserisci test nei tuoi .cy.ts e avvia il runner.',\r\n SEC_SELECTOR: '🔎 Selettori',\r\n SELECTOR_1: 'Scegli l\\'attributo preferito (data-cy, data-testid, aria-label, id) in Config.',\r\n SELECTOR_2: 'Se un click non ha un selettore affidabile, appare un picker per scegliere l\\'antenato migliore.',\r\n SEC_DATA: '💾 Dati',\r\n DATA_1: 'Esporta i test in JSON (tutto / selezione / per tag).',\r\n DATA_2: 'Importa un JSON: si fonde con i tuoi dati (non si cancella nulla).',\r\n SEC_ADVANCED: '🚀 Avanzato',\r\n ADV_INVISIBLE: 'Modalità invisibile: start-hidden + Ctrl+Shift+E per registrare in produzione senza disturbare.',\r\n ADV_RUNNER: 'Runner locale: npx lib-e2e-cypress-runner per eseguire uno spec headless dall\\'editor.',\r\n ADV_CROSSAPP: 'Cross-app: la registrazione sopravvive al cambio di micro-frontend (stessa origine).',\r\n ADV_DRAG: 'Trascina il pulsante ⏺ per spostare il widget; la posizione viene ricordata.',\r\n ADV_LOGIN: 'Login Setup (Ctrl+3): apunta a tu servicio de login; el grabador inyecta before()/beforeEach() automáticamente en cada test nuevo.', // TODO: translate (it)\r\n CLOSE: 'Chiudi',\r\n TAB_REFERENCE: 'Riferimento rapido',\r\n TAB_GUIDE: 'Guida all\\'uso',\r\n // TODO: translate (it) — usage guide body kept in Spanish for now.\r\n GUIDE_INTRO: 'Cómo sacarle partido al grabador, qué cubre y qué no.',\r\n G_SEC_WORKFLOW: '🧭 Flujo de trabajo',\r\n G_WF_1: '1. Pulsa ⏺ (o Ctrl+R) para empezar a grabar.',\r\n G_WF_2: '2. Usa tu app como un usuario: clicks, formularios, navegación. Cada acción se convierte en un comando Cypress.',\r\n G_WF_3: '3. Añade verificaciones con Alt+click sobre lo que quieras comprobar.',\r\n G_WF_4: '4. Pulsa ⏹ para parar; ponle nombre y tags, y guárdalo.',\r\n G_WF_5: '5. En 📁 Ficheros, inserta el test en un .cy.ts o lánzalo con el runner local.',\r\n G_SEC_COVERED: '✅ Qué cubre',\r\n G_COV_1: 'Clicks, doble-click, click derecho, inputs de texto, checkbox/radio, select y teclas Enter/Escape.',\r\n G_COV_2: 'Navegación SPA (pushState/replaceState/popstate) → cy.url().should(...).',\r\n G_COV_3: 'Llamadas fetch/XHR (GET/POST/PUT) → cy.intercept + cy.wait, con validación de body opcional.',\r\n G_COV_4: 'Selector fiable (data-cy/testid/aria/id) y picker cuando no hay uno claro.',\r\n G_COV_5: 'Aserciones automáticas (Alt+click) y constructor manual.',\r\n G_COV_6: 'Continuidad al cambiar de micro-frontend (mismo origen), modo invisible e i18n.',\r\n G_COV_7: 'Login Setup: configura tu función de login en Ctrl+3 → Login Setup y el grabador añade los bloques before()/beforeEach() a cada test nuevo.', // TODO: translate (it)\r\n G_SEC_NOTCOVERED: '🚫 Qué NO cubre (por ahora)',\r\n G_NC_1: 'Orígenes distintos / subdominios (solo mismo origen).',\r\n G_NC_2: 'Subida de ficheros (selectFile), arrastrar y soltar, y hover.',\r\n G_NC_3: 'La tecla Tab (Cypress no la soporta en .type()).',\r\n G_NC_4: 'Peticiones DELETE (se ignoran a propósito).',\r\n G_NC_5: 'iframes y Shadow DOM de terceros pueden no capturarse.',\r\n },\r\n};\r\n","export const I18N_DE = {\r\n MAIN_FRAME: {\r\n SETTINGS: 'Einstellungen',\r\n SHOW_ADVANCED_EDITOR: 'Erweiterter Editor',\r\n DIALOG_SAVED_TESTS: 'Gespeicherte Tests',\r\n DIALOG_COMMANDS: 'Cypress-Befehle Vorschau',\r\n DIALOG_SAVE: 'Aufzeichnung speichern?',\r\n },\r\n SAVE_TEST: {\r\n DESC_LABEL: 'Testbeschreibung',\r\n CANCEL: 'Abbrechen',\r\n ASK: 'Aufgezeichneten Test speichern?',\r\n YES_CONTINUE: 'Ja, weiter',\r\n NO_DISCARD: 'Nein, verwerfen',\r\n DESC_PLACEHOLDER: 'Z. B.: Erfolgreiche Anmeldung mit gültigen Zugangsdaten',\r\n TAGS_LABEL: 'Tags (optional, zum späteren Filtern):',\r\n TAGS_PLACEHOLDER: 'smoke, login, regression…',\r\n ADD_TAG: '+ Hinzufügen',\r\n NO_TAGS: 'Keine Tags',\r\n SAVE_BTN: '💾 Speichern',\r\n SAVE_AND_EDIT: '📝 Speichern und bearbeiten',\r\n REMOVE_TAG_TITLE: 'Entfernen',\r\n NOTES_LABEL: 'Beschreibung / Notizen (optional):',\r\n NOTES_PLACEHOLDER: 'Was dieser Test validiert, Voraussetzungen usw.',\r\n TICKET_LABEL: 'Ticket / Issue (optional):',\r\n TICKET_PLACEHOLDER: 'Z. B.: PROJ-123, #42',\r\n TICKET_WARN: 'Ungültige ID für den konfigurierten Anbieter (wird trotzdem gespeichert)', // TODO: translate\r\n CONFIRM_DISCARD: 'Sind Sie sicher, dass Sie diese Aufzeichnung verwerfen möchten? Alle aufgezeichneten Schritte gehen verloren.',\r\n CONFIRM_DISCARD_BTN: 'Ja, verwerfen',\r\n BACK_BTN: 'Zurück',\r\n CONTINUE_RECORDING_BTN: '⏺ Aufnahme fortsetzen',\r\n },\r\n TEST_EDITOR: {\r\n NO_TAGS: 'Keine Tags',\r\n SELECTED_SINGULAR: 'ausgewählt',\r\n SELECTED_PLURAL: 'ausgewählt',\r\n DESCRIBE_PLACEHOLDER: 'describe-Name (optional)',\r\n COPY_DESCRIBE: '🗂 describe() kopieren',\r\n MULTI_SELECT: '🗂 Mehrfachauswahl',\r\n CANCEL_SELECT: '✕ Abbrechen',\r\n COPY_CMDS_BTN: '📋 Befehle kopieren',\r\n COPY_ICPS_BTN: '📋 Interceptors kopieren',\r\n DEFAULT_DESCRIBE: 'Test-Suite',\r\n NO_TESTS: 'Keine gespeicherten Tests',\r\n DELETE_TITLE: 'Löschen',\r\n GROUP_BY_TICKET: '🎫 Nach Ticket gruppieren',\r\n UNGROUP_TICKET: '🎫 Gruppierung aufheben',\r\n NO_TICKET: 'Kein Ticket',\r\n TICKET_LINK_TITLE: 'Ticket öffnen',\r\n },\r\n CONFIG: {\r\n LANG_SECTION: '🌐 Sprache',\r\n LANG_FIELD: 'Oberfläche',\r\n HTTP_SECTION: '⚡ Erweitertes HTTP',\r\n HTTP_TITLE: 'Body-Validierungen',\r\n HTTP_SUB: 'GET → Antwort · POST/PUT → Anfrage',\r\n FIXTURE_SECTION: '🧪 HTTP-Fixtures',\r\n FIXTURE_TITLE: 'Antworten als Fixtures aufzeichnen',\r\n FIXTURE_SUB: 'GET-Antworten werden in cypress/fixtures gespeichert und mit cy.intercept({ fixture }) gestubbt.',\r\n SELECTOR_SECTION: '🎯 Selector-Strategie',\r\n SELECTOR_LABEL: 'Bevorzugtes Attribut für cy.get()',\r\n SELECTOR_OPT_DATACY: 'data-cy (Standard)',\r\n SELECTOR_OPT_TESTID: 'data-testid',\r\n SELECTOR_OPT_ARIA: 'aria-label',\r\n SELECTOR_OPT_ID: 'id (#element)',\r\n SELECTOR_HINT: 'Der Recorder sucht zuerst nach diesem Attribut. Falls nicht gefunden, versucht er die anderen.',\r\n FOLDER_SECTION: '📁 Cypress-Ordner',\r\n FOLDER_CONNECTED: 'verbunden —',\r\n FOLDER_NOT_SET: 'nicht konfiguriert',\r\n FOLDER_CHANGE_BTN: '📁 Ordner wechseln',\r\n FOLDER_SELECT_BTN: '📁 Ordner auswählen',\r\n FOLDER_REVOKE_BTN: '✕ Zugriff widerrufen',\r\n DATA_SECTION: '💾 Daten',\r\n DATA_DESC: 'Exportieren Sie alle Tests als JSON oder importieren Sie ein Backup.',\r\n EXPORT_BTN: '⬆️ Tests exportieren',\r\n EXPORT_DIALOG_TITLE: '⬆️ Tests exportieren',\r\n EXPORT_MODE_ALL: 'Alle',\r\n EXPORT_MODE_MANUAL: 'Manuelle Auswahl',\r\n EXPORT_MODE_TAGS: 'Nach Tags',\r\n EXPORT_ALL_DESC: 'Alle gespeicherten Tests werden exportiert.',\r\n EXPORT_COUNT: 'Zu exportieren:',\r\n EXPORT_CONFIRM: '⬆️ Exportieren',\r\n EXPORT_CANCEL: 'Abbrechen',\r\n EXPORT_EMPTY: 'Keine Tests zum Exportieren.',\r\n EXPORT_NO_TAGS: 'Keine Tags verfügbar.',\r\n EXPORT_TAGS_HINT: 'Wähle ein oder mehrere Tags, um zu sehen, welche Tests exportiert werden.',\r\n EXPORT_RESULT_LABEL: 'Diese Tests werden exportiert:',\r\n IMPORT_BTN: '⬇️ Tests importieren',\r\n FOLDER_UPDATED_TOAST: '✓ Cypress-Ordner aktualisiert',\r\n FOLDER_ERROR_TOAST: 'Fehler beim Zugriff auf den Ordner',\r\n IMPORT_SUCCESS: 'Daten erfolgreich importiert.',\r\n IMPORT_ERROR: 'Fehler beim Importieren.',\r\n JSON_INVALID: 'Die Datei ist kein gültiges JSON.',\r\n JSON_BAD_FORMAT: 'Die Datei hat nicht das erwartete Format.',\r\n SMART_SELECTOR_SECTION: '🔍 Intelligenter Selektor',\r\n SMART_SELECTOR_TITLE: 'Intelligenter Selektor',\r\n SMART_SELECTOR_SUB: 'Zeigt ein Auswahlfeld, wenn auf Elemente ohne gültigen Selektor geklickt wird.',\r\n START_HIDDEN_SECTION: '👁 Widget-Sichtbarkeit',\r\n START_HIDDEN_TITLE: 'Versteckt starten',\r\n START_HIDDEN_SUB: 'Das Widget startet unsichtbar. Verwenden Sie Ctrl+Shift+E zum Ein-/Ausblenden.',\r\n RESUME_TTL_SECTION: '⏱ Aufzeichnungskontinuität',\r\n RESUME_TTL_LABEL: 'Ohne Nachfrage fortsetzen (Minuten)',\r\n RESUME_TTL_HINT: 'Wenn Sie neu laden oder das Projekt wechseln, wird eine aktive Aufzeichnung innerhalb dieses Zeitfensters ohne Nachfrage fortgesetzt. Danach werden Sie gefragt, ob fortsetzen oder verwerfen.',\r\n WIDGET_POSITION_SECTION: '🧲 Widget-Position',\r\n WIDGET_POSITION_HINT: 'Ziehe den Aufnahme-Button, um ihn aus dem Weg zu schieben. Die Position wird gespeichert.',\r\n WIDGET_POSITION_RESET_BTN: '↺ Position zurücksetzen',\r\n WIDGET_POSITION_RESET_DONE: '✓ Position zurückgesetzt',\r\n ISSUE_TRACKER_SECTION: '🎫 Issue-Tracker',\r\n ISSUE_TRACKER_TITLE: 'Tests mit Tickets verknüpfen',\r\n ISSUE_TRACKER_SUB: 'Füge beim Speichern eine Ticket-ID hinzu und erstelle einen klickbaren Link.',\r\n ISSUE_TRACKER_PROVIDER: 'Anbieter',\r\n ISSUE_TRACKER_BASE_URL: 'Basis-URL',\r\n ISSUE_TRACKER_BASE_URL_PH: 'Z. B.: https://meinprojekt.atlassian.net',\r\n LOGIN_SETUP_SECTION: '🔐 Login setup',\r\n LOGIN_SETUP_NOT_CONFIGURED: 'Nicht konfiguriert',\r\n LOGIN_SETUP_SET_UP_BTN: 'Einrichten',\r\n LOGIN_SETUP_TITLE: 'Login-Konfiguration',\r\n LOGIN_SETUP_CREATE_SCAFFOLD: 'Scaffold erstellen',\r\n LOGIN_SETUP_SELECT_EXISTING: 'Vorhandene Datei auswählen',\r\n LOGIN_SETUP_FILE_NAME_LABEL: 'Dateiname',\r\n LOGIN_SETUP_FILE_NAME_PH: 'Z. B.: cypress/common-services/login.service.ts',\r\n LOGIN_SETUP_RESCAN: '🔄 Erneut scannen',\r\n LOGIN_SETUP_FUNCTIONS_DETECTED: 'Erkannte Funktionen',\r\n LOGIN_SETUP_BLOCK_ASSIGN: 'Blockzuweisung',\r\n LOGIN_SETUP_NO_FUNCTIONS: 'Keine exportierten Funktionen gefunden. Scaffold ausfüllen und erneut scannen.',\r\n LOGIN_SETUP_BEFORE_LABEL: 'before()-Funktion (einmal pro Suite)',\r\n LOGIN_SETUP_BEFORE_EACH_LABEL: 'beforeEach()-Funktion (vor jedem Test)',\r\n LOGIN_SETUP_NONE_OPTION: '— Keine —',\r\n LOGIN_SETUP_SUMMARY: 'Datei: {file} · before: {before} · beforeEach: {beforeEach}',\r\n LOGIN_SETUP_SAVE_BTN: '💾 Speichern',\r\n LOGIN_SETUP_CLEAR_BTN: 'Konfiguration entfernen',\r\n LOGIN_SETUP_CANCEL_BTN: 'Abbrechen',\r\n LOGIN_SETUP_SOURCE_LABEL: 'Quelle der Login-Datei',\r\n LOGIN_SETUP_CREATE_SUB: 'Scaffold mit Beispielfunktionen erstellen',\r\n LOGIN_SETUP_SELECT_SUB: 'Auf eine vorhandene Login-Service-Datei verweisen',\r\n LOGIN_SETUP_INJECT_TITLE: 'Login-Blöcke hinzufügen?',\r\n LOGIN_SETUP_INJECT_TEXT: 'Diese Datei enthält die konfigurierten Login-Blöcke nicht. Möchten Sie jetzt den Import und die before/beforeEach-Blöcke hinzufügen?',\r\n LOGIN_SETUP_INJECT_CONFIRM: 'Ja, hinzufügen',\r\n },\r\n SELECTOR_PICKER: {\r\n TITLE: 'DOM-Element auswählen',\r\n PREVIEW_LABEL: 'navigieren',\r\n CONFIRM_HINT: 'bestätigen',\r\n CANCEL_HINT: 'abbrechen',\r\n QUALITY_EXCELLENT: 'Ausgezeichnet — Test-Attribut vorhanden (data-cy / data-testid / aria-label)',\r\n QUALITY_GOOD: 'Gut — gültige ID',\r\n QUALITY_ACCEPTABLE: 'Akzeptabel — nur CSS-Klassen',\r\n QUALITY_POOR: 'Nicht empfohlen — nur Tag oder Inline-Style',\r\n },\r\n TEST_PREVISUALIZER: {\r\n INTERCEPTORS: 'Interceptors',\r\n COPY_CMDS_BTN: '📋 Befehle kopieren',\r\n SHOW_INTERCEPTORS: '▼ Interceptors anzeigen',\r\n HIDE_INTERCEPTORS: '▲ Interceptors ausblenden',\r\n SECTION_COMMANDS: 'Befehle',\r\n NO_CMDS_YET: 'Noch keine Befehle',\r\n NO_ICP_SHORT: 'Keine Interceptors',\r\n COPY_ICP_BTN: '📋 Interceptors kopieren',\r\n UP_TITLE: 'Nach oben',\r\n DOWN_TITLE: 'Nach unten',\r\n DEL_TITLE: 'Löschen',\r\n },\r\n ADVANCED_EDITOR: {\r\n REAUTH_BTN: '🔓 Zugriff reaktivieren',\r\n PERMISSION_EXPIRED: '🔑 Berechtigung abgelaufen',\r\n PERMISSION_EXPIRED_HINT: 'Klicken Sie, um den Zugriff auf Ihren Cypress-Ordner zu reaktivieren.',\r\n NO_ACCESS: '🔒 Kein Zugriff auf lokale Dateien',\r\n NO_ACCESS_HINT: 'Konfigurieren Sie den Zugriff unter ⚙️ Config.',\r\n NO_FILES: 'Keine Dateien',\r\n SELECT_FILE: '← Wählen Sie eine Datei aus dem Baum',\r\n IT_LABEL: '🧪 it() zum Einfügen:',\r\n COPY_IT_BTN: '📋 it() kopieren',\r\n BEFORE_EACH_LABEL: '🔀 beforeEach() Interceptors:',\r\n COPY_ICP_BTN: '📋 Interceptors kopieren',\r\n INSERT_BTN: '💾 In Datei einfügen',\r\n EDIT_MANUAL_BTN: '✏️ Manuell bearbeiten',\r\n CLOSE_BTN: '✕ Schließen',\r\n NEW_FILE_BTN: '+ Neue Datei',\r\n NEW_FOLDER_BTN: '+ Neuer Ordner',\r\n REFRESH_BTN: '↻ Aktualisieren',\r\n NEW_FILE_PLACEHOLDER: 'test-name',\r\n NEW_FOLDER_PLACEHOLDER: 'ordnername',\r\n NEW_FILE_CONFIRM: 'Erstellen',\r\n NEW_FILE_CANCEL: 'Abbrechen',\r\n },\r\n FILE_PREVIEW: {\r\n NO_FILE: 'Keine Datei',\r\n COPY_TITLE: 'Editor-Inhalt kopieren',\r\n BLOCK_IT: '🧪 it()',\r\n COPY_BTN: '📋 Kopieren',\r\n BLOCK_BEFORE_EACH: '🔀 beforeEach()',\r\n NO_CHANGES: 'Keine Änderungen gegenüber dem Original',\r\n NO_CHANGES_SHORT: 'Keine Änderungen',\r\n LAUNCH_BTN: '▶ Test starten',\r\n LAUNCH_LOCAL_ONLY: 'Wechsle zu localhost, um Tests auszuführen',\r\n LAUNCH_RUNNING: '⏳ Läuft…',\r\n LAUNCH_PASSED: '✓ Test bestanden',\r\n LAUNCH_FAILED: '✗ Test fehlgeschlagen',\r\n LAUNCH_NO_RUNNER: 'Kein lokaler Runner erkannt (gestartet?)',\r\n DIFF_BTN: '📊 Diff',\r\n SAVE_BTN: '💾 Speichern',\r\n CLOSE_BTN: '✕ Schließen',\r\n BACK_TO_EDITOR: '← Zurück zum Editor',\r\n INSERT_BTN: '🪄 Blöcke einfügen',\r\n INSERT_TITLE: 'it() und beforeEach() in den Editor-Inhalt einfügen',\r\n INSERT_DONE: 'Blöcke in den Editor eingefügt',\r\n INSERT_ERROR: 'Kein gültiger describe()-Block in der Datei gefunden',\r\n },\r\n RECORDER: {\r\n FS_TITLE: '📁 Dateizugriff',\r\n FS_LATER_BTN: 'Nicht jetzt',\r\n FS_SELECT_BTN: '📁 Ordner auswählen',\r\n FS_SUCCESS_TOAST: '✓ Cypress-Ordner konfiguriert',\r\n FS_ERROR_TOAST: 'Fehler beim Zugriff auf den Ordner',\r\n FS_INTRO_HTML: 'Der <strong style=\"color:#e6edf3\">erweiterte Editor</strong> kann Ihre Tests direkt in die Cypress-Dateien <code style=\"background:#0d1117;padding:1px 6px;border-radius:4px;font-size:11px;color:#c9d1d9\">.cy.ts</code> einfügen.',\r\n FS_STRUCTURE_HINT_HTML: 'Wählen Sie den Ordner, der den Unterordner <code style=\"background:#0d1117;padding:1px 5px;border-radius:4px;font-size:10px;color:#c9d1d9\">e2e/</code> enthält. Die Erweiterung erwartet diese Struktur:',\r\n FS_TREE_PICK_HINT: '← diesen Ordner auswählen',\r\n FS_TREE_READ_HINT: '← die Erweiterung liest hier',\r\n FS_PERMISSION_NOTE: 'Die Berechtigung wird im Browser gespeichert und nicht erneut angefordert.',\r\n ASSERTION_SECTION: '➕ Assertion hinzufügen',\r\n ASSERT_SELECTOR_PH: 'Selektor, z. B.: [data-cy=\"btn\"]',\r\n ASSERT_VALUE_PH: 'erwarteter Wert',\r\n ASSERT_ADD_BTN: '➕ Hinzufügen',\r\n FILE_EDITOR_TITLE: '✏️ Datei-Editor',\r\n FILE_SAVED_TOAST: '✓ Datei gespeichert',\r\n FILE_SAVE_ERROR_TOAST: 'Fehler beim Speichern',\r\n FIXTURES_WRITTEN_TOAST: '✓ Fixtures in cypress/fixtures geschrieben',\r\n FIXTURES_NO_FOLDER_TOAST: 'Fixtures konnten nicht geschrieben werden (Cypress-Ordner konfigurieren)',\r\n FILE_UPLOAD_MANUAL_TOAST: 'Füge {files} zu cypress/fixtures/ hinzu, bevor du den Test ausführst.', // TODO: translate\r\n FILE_UPLOAD_COPIED_TOAST: '{files} nach cypress/fixtures/ kopiert.', // TODO: translate\r\n FILE_UPLOAD_COPY_ERROR_TOAST: '{files} konnte nicht nach cypress/fixtures/ kopiert werden. Füge es manuell hinzu.', // TODO: translate\r\n BTN_CONFIG: 'Config',\r\n BTN_FILES: 'Dateien',\r\n BTN_COMMANDS: 'Befehle',\r\n BTN_TESTS: 'Tests',\r\n PAUSE_TITLE: 'Pausieren (Ctrl+P)',\r\n RESUME_TITLE: 'Fortsetzen (Ctrl+P)',\r\n BADGE_PAUSED: '⏸ PAUSE',\r\n BADGE_REC: '● REC',\r\n STOP_TITLE: 'Stopp (Ctrl+R)',\r\n START_TITLE: 'Aufzeichnen (Ctrl+R)',\r\n SESSION_RESUME_TITLE: '⏺ Aufzeichnung läuft',\r\n SESSION_RESUME_TEXT: 'Es gibt eine nicht abgeschlossene aktive Aufzeichnung.',\r\n SESSION_RESUME_COUNT: 'erfasste Befehle',\r\n SESSION_CONTINUE_BTN: 'Weiter aufzeichnen',\r\n SESSION_DISCARD_BTN: 'Verwerfen',\r\n BTN_HELP: 'Hilfe',\r\n RECOVER_BTN: 'Wiederherstellen',\r\n RECOVER_TITLE: 'Letzte gestoppte Aufnahme wiederherstellen: {count} Befehle ({time})',\r\n RECOVER_TIME_NOW: 'gerade eben',\r\n RECOVER_TIME_MINUTES: 'vor {m} Min.',\r\n },\r\n HELP: {\r\n TITLE: '❓ Hilfe — Kurzanleitung',\r\n INTRO: 'Alles, was der Recorder kann.',\r\n SEC_RECORDING: '⏺ Aufzeichnen',\r\n RECORDING_1: 'Drücke ⏺ (oder Ctrl+R) zum Starten; ⏹ zum Stoppen und Speichern.',\r\n RECORDING_2: 'Pause / Fortsetzen mit ⏸ (oder Ctrl+P).',\r\n SEC_SHORTCUTS: '⌨️ Tastenkürzel',\r\n SC_RECORD: 'Ctrl+R — Aufzeichnen / stoppen',\r\n SC_PAUSE: 'Ctrl+P — Pausieren / fortsetzen',\r\n SC_TESTS: 'Ctrl+1 — Panel gespeicherte Tests',\r\n SC_COMMANDS: 'Ctrl+2 — Befehle-Panel',\r\n SC_CONFIG: 'Ctrl+3 — Einstellungen',\r\n SC_VISIBILITY: 'Ctrl+Shift+E — Widget ein-/ausblenden',\r\n SC_HELP: 'Ctrl+Shift+H — Diese Hilfe',\r\n SEC_CAPTURED: '🎯 Was aufgezeichnet wird',\r\n CAP_CLICK: 'Klick → .click()',\r\n CAP_DBLCLICK: 'Doppelklick → .dblclick()',\r\n CAP_RIGHTCLICK: 'Rechtsklick → .rightclick()',\r\n CAP_TYPE: 'In ein Feld tippen → .clear().type(...)',\r\n CAP_CHECK: 'Checkbox / Radio → .check() / .uncheck()',\r\n CAP_SELECT: '<select> → .select(...)',\r\n CAP_KEYS: 'Enter / Escape → .type(\"{enter}\") / (\"{esc}\")',\r\n CAP_ROUTE: 'Routenwechsel (SPA) → cy.url().should(...)',\r\n CAP_HTTP: 'fetch / XHR → cy.intercept + cy.wait',\r\n SEC_ASSERT: '✅ Assertions',\r\n ASSERT_1: 'Alt+Klick auf ein Element, um es zu prüfen, ohne seine Aktion auszulösen (Text, Wert, checked oder sichtbar).',\r\n ASSERT_2: 'Oder nutze den Assertion-Builder im Befehle-Panel.',\r\n SEC_PANELS: '🗂 Panels',\r\n PANEL_TESTS: '📋 Tests — gespeichert: nach Tag filtern, kopieren, kombinieren, exportieren.',\r\n PANEL_COMMANDS: '⌨️ Befehle — aktuelle Aufzeichnung: umsortieren, löschen, Assertions hinzufügen.',\r\n PANEL_CONFIG: '⚙️ Config — Sprache, Selektor, HTTP, Cypress-Ordner, Login-Setup, Daten, Sichtbarkeit, Position.',\r\n PANEL_FILES: '📁 Dateien — Tests in deine .cy.ts einfügen und den Runner starten.',\r\n SEC_SELECTOR: '🔎 Selektoren',\r\n SELECTOR_1: 'Wähle das bevorzugte Attribut (data-cy, data-testid, aria-label, id) unter Config.',\r\n SELECTOR_2: 'Hat ein Klick keinen zuverlässigen Selektor, erscheint ein Picker zur Wahl des besten Vorfahren.',\r\n SEC_DATA: '💾 Daten',\r\n DATA_1: 'Tests als JSON exportieren (alle / Auswahl / nach Tags).',\r\n DATA_2: 'JSON importieren: wird zu deinen Daten hinzugefügt (nichts wird gelöscht).',\r\n SEC_ADVANCED: '🚀 Erweitert',\r\n ADV_INVISIBLE: 'Unsichtbarer Modus: start-hidden + Ctrl+Shift+E, um in Produktion unauffällig aufzuzeichnen.',\r\n ADV_RUNNER: 'Lokaler Runner: npx lib-e2e-cypress-runner, um einen Spec headless aus dem Editor zu starten.',\r\n ADV_CROSSAPP: 'Cross-App: die Aufzeichnung übersteht den Wechsel des Micro-Frontends (gleicher Origin).',\r\n ADV_DRAG: 'Ziehe den ⏺-Button, um das Widget zu verschieben; die Position wird gemerkt.',\r\n ADV_LOGIN: 'Login Setup (Ctrl+3): apunta a tu servicio de login; el grabador inyecta before()/beforeEach() automáticamente en cada test nuevo.', // TODO: translate (de)\r\n CLOSE: 'Schließen',\r\n TAB_REFERENCE: 'Kurzreferenz',\r\n TAB_GUIDE: 'Nutzungsleitfaden',\r\n // TODO: translate (de) — usage guide body kept in Spanish for now.\r\n GUIDE_INTRO: 'Cómo sacarle partido al grabador, qué cubre y qué no.',\r\n G_SEC_WORKFLOW: '🧭 Flujo de trabajo',\r\n G_WF_1: '1. Pulsa ⏺ (o Ctrl+R) para empezar a grabar.',\r\n G_WF_2: '2. Usa tu app como un usuario: clicks, formularios, navegación. Cada acción se convierte en un comando Cypress.',\r\n G_WF_3: '3. Añade verificaciones con Alt+click sobre lo que quieras comprobar.',\r\n G_WF_4: '4. Pulsa ⏹ para parar; ponle nombre y tags, y guárdalo.',\r\n G_WF_5: '5. En 📁 Ficheros, inserta el test en un .cy.ts o lánzalo con el runner local.',\r\n G_SEC_COVERED: '✅ Qué cubre',\r\n G_COV_1: 'Clicks, doble-click, click derecho, inputs de texto, checkbox/radio, select y teclas Enter/Escape.',\r\n G_COV_2: 'Navegación SPA (pushState/replaceState/popstate) → cy.url().should(...).',\r\n G_COV_3: 'Llamadas fetch/XHR (GET/POST/PUT) → cy.intercept + cy.wait, con validación de body opcional.',\r\n G_COV_4: 'Selector fiable (data-cy/testid/aria/id) y picker cuando no hay uno claro.',\r\n G_COV_5: 'Aserciones automáticas (Alt+click) y constructor manual.',\r\n G_COV_6: 'Continuidad al cambiar de micro-frontend (mismo origen), modo invisible e i18n.',\r\n G_COV_7: 'Login Setup: configura tu función de login en Ctrl+3 → Login Setup y el grabador añade los bloques before()/beforeEach() a cada test nuevo.', // TODO: translate (de)\r\n G_SEC_NOTCOVERED: '🚫 Qué NO cubre (por ahora)',\r\n G_NC_1: 'Orígenes distintos / subdominios (solo mismo origen).',\r\n G_NC_2: 'Subida de ficheros (selectFile), arrastrar y soltar, y hover.',\r\n G_NC_3: 'La tecla Tab (Cypress no la soporta en .type()).',\r\n G_NC_4: 'Peticiones DELETE (se ignoran a propósito).',\r\n G_NC_5: 'iframes y Shadow DOM de terceros pueden no capturarse.',\r\n },\r\n};\r\n","import { type Lang, isLang } from '../models/lang.model';\r\nimport { Subject } from '../utils/subject';\r\nimport { I18N_ES } from '../i18n/es';\r\nimport { I18N_EN } from '../i18n/en';\r\nimport { I18N_FR } from '../i18n/fr';\r\nimport { I18N_IT } from '../i18n/it';\r\nimport { I18N_DE } from '../i18n/de';\r\n\r\ntype Translations = typeof I18N_ES;\r\n\r\n/**\r\n * Manages the active UI language and resolves i18n translation keys for all\r\n * components in the library.\r\n *\r\n * Supports five languages: Spanish (`es`), English (`en`), French (`fr`),\r\n * Italian (`it`), and German (`de`). The active language is stored in a\r\n * reactive {@link Subject} so components can subscribe and re-render on change.\r\n */\r\nexport class TranslationService {\r\n private readonly lang$: Subject<Lang>;\r\n\r\n private readonly translations: Record<Lang, Translations> = {\r\n es: I18N_ES,\r\n en: I18N_EN,\r\n fr: I18N_FR,\r\n it: I18N_IT,\r\n de: I18N_DE,\r\n };\r\n\r\n constructor() {\r\n this.lang$ = new Subject<Lang>(this.detectLang());\r\n }\r\n\r\n /**\r\n * Sets the active language, notifying all subscribers.\r\n *\r\n * @param lang - One of the supported language codes (`'es'`, `'en'`, `'fr'`, `'it'`, `'de'`).\r\n */\r\n setLang(lang: Lang): void {\r\n this.lang$.next(lang);\r\n }\r\n\r\n /** Returns the currently active language code. */\r\n getLang(): Lang {\r\n return this.lang$.getValue();\r\n }\r\n\r\n /** Subscribe to language changes; returns an unsubscribe function. */\r\n onLangChange(fn: (lang: Lang) => void): () => void {\r\n return this.lang$.subscribe(fn);\r\n }\r\n\r\n /**\r\n * Resolves a dot-separated translation key against the current language's\r\n * translation map. Returns the key itself when the path is not found, so\r\n * missing translations are visible rather than silent.\r\n *\r\n * @param key - A dot-separated path into the translation object\r\n * (e.g. `'RECORDER.START_BTN'`).\r\n * @returns The translated string, or `key` if the path does not exist.\r\n */\r\n translate(key: string): string {\r\n const keys = key.split('.');\r\n let value: unknown = this.translations[this.lang$.getValue()];\r\n for (const k of keys) {\r\n value = (value as Record<string, unknown>)?.[k];\r\n if (value === undefined) return key;\r\n }\r\n return value as string;\r\n }\r\n\r\n /**\r\n * Detects the best initial language from `navigator.language`. Falls back to\r\n * `'es'` when the browser language is not one of the supported codes.\r\n *\r\n * @returns The detected or default {@link Lang} code.\r\n */\r\n detectLang(): Lang {\r\n const browserLang = navigator.language.split('-')[0];\r\n return isLang(browserLang) ? browserLang : 'es';\r\n }\r\n}\r\n\r\n/** Shared singleton instance of {@link TranslationService}. */\r\nexport const translationService = new TranslationService();\r\n","import { translationService, type TranslationService } from '../services/translation.service';\r\n\r\n/**\r\n * Abstract base class for all lib-e2e custom elements.\r\n *\r\n * Centralises the three pieces of boilerplate that every component repeats:\r\n * - Shadow DOM attachment (open mode).\r\n * - The `translation` property (defaults to the global singleton; injectable for tests).\r\n * - The `t()` shorthand for translating i18n keys.\r\n *\r\n * @example\r\n * ```ts\r\n * export class MyElement extends BaseElement {\r\n * connectedCallback() {\r\n * this.shadow.innerHTML = `<p>${this.t('MY.KEY')}</p>`;\r\n * }\r\n * }\r\n * ```\r\n */\r\nexport abstract class BaseElement extends HTMLElement {\r\n /** Attached shadow root (open mode). Available from the constructor onwards. */\r\n protected shadow: ShadowRoot;\r\n\r\n /**\r\n * Translation service instance.\r\n * Defaults to the global singleton; override for isolated unit tests.\r\n */\r\n translation: TranslationService = translationService;\r\n\r\n constructor() {\r\n super();\r\n this.shadow = this.attachShadow({ mode: 'open' });\r\n }\r\n\r\n /**\r\n * Returns the localised string for an i18n key.\r\n * Falls back to the raw key when the service is unavailable (e.g. in tests).\r\n *\r\n * @param key - Dot-separated translation key (e.g. `'PICKER.TITLE'`).\r\n * @returns Translated string, or the key itself if no translation is found.\r\n */\r\n protected t(key: string): string {\r\n return this.translation?.translate(key) ?? key;\r\n }\r\n}\r\n","import type { RecordingService } from '../../services/recording.service';\r\nimport { describePickerRow, type PickerRow } from '../../utils/selector-quality.utils';\r\nimport { escapeSingleQuotes } from '../../utils/code-format.utils';\r\nimport { SELECTOR_PICKER_STYLES } from './selector-picker.styles';\r\nimport { renderPicker } from './selector-picker.template';\r\nimport { BaseElement } from '../base.element';\r\n\r\nconst OWN_DATA_CY = 'lib-e2e-cypress-for-dummys';\r\nconst MAX_ANCESTORS = 10;\r\n\r\n/**\r\n * `<lib-e2e-selector-picker>` custom element — floating overlay that lets the\r\n * user choose the best CSS selector for an element the recorder could not\r\n * resolve automatically.\r\n *\r\n * Displays a ranked list of ancestor elements with their available selector\r\n * attributes and lets the user confirm or dismiss with keyboard or mouse.\r\n */\r\nexport class SelectorPickerElement extends BaseElement {\r\n targetElement: HTMLElement | null = null;\r\n recording!: RecordingService;\r\n\r\n private ancestors: HTMLElement[] = [];\r\n private rows: PickerRow[] = [];\r\n private selectedIndex = 0;\r\n private keyHandler: ((e: KeyboardEvent) => void) | null = null;\r\n private unsubRecording: (() => void) | null = null;\r\n private unsubPause: (() => void) | null = null;\r\n\r\n connectedCallback(): void {\r\n this.setAttribute('data-cy', 'lib-e2e-cypress-for-dummys');\r\n this.ancestors = this.buildAncestors();\r\n this.rows = this.ancestors.map(describePickerRow);\r\n this.selectedIndex = this.findBestIndex();\r\n this.render();\r\n this.attachKeyListener();\r\n this.attachRowClickListeners();\r\n this.subscribeToRecordingChanges();\r\n }\r\n\r\n disconnectedCallback(): void {\r\n this.detachKeyListener();\r\n this.unsubRecording?.();\r\n this.unsubPause?.();\r\n }\r\n\r\n // ── Ancestor chain ──────────────────────────────────────────────────────────\r\n\r\n private buildAncestors(): HTMLElement[] {\r\n const chain: HTMLElement[] = [];\r\n let current: HTMLElement | null = this.targetElement;\r\n\r\n while (current && current.tagName.toLowerCase() !== 'html' && chain.length < MAX_ANCESTORS) {\r\n if (current.getAttribute('data-cy') === OWN_DATA_CY) {\r\n current = current.parentElement;\r\n continue;\r\n }\r\n chain.push(current);\r\n current = current.parentElement;\r\n }\r\n\r\n return chain;\r\n }\r\n\r\n private findBestIndex(): number {\r\n for (let i = 0; i < this.rows.length; i++) {\r\n const q = this.rows[i].quality;\r\n if (q === 'excellent' || q === 'good' || q === 'acceptable') return i;\r\n }\r\n return 0;\r\n }\r\n\r\n // ── Rendering ───────────────────────────────────────────────────────────────\r\n\r\n private render(): void {\r\n this.shadow.innerHTML = `<style>${SELECTOR_PICKER_STYLES}</style>${renderPicker(\r\n this.rows,\r\n this.selectedIndex,\r\n this.t.bind(this),\r\n )}`;\r\n }\r\n\r\n // ── Keyboard ────────────────────────────────────────────────────────────────\r\n\r\n private attachKeyListener(): void {\r\n this.keyHandler = (e: KeyboardEvent) => {\r\n if (e.key === 'ArrowDown') {\r\n e.stopPropagation();\r\n e.preventDefault();\r\n this.selectedIndex = (this.selectedIndex + 1) % this.ancestors.length;\r\n this.render();\r\n this.attachRowClickListeners();\r\n } else if (e.key === 'ArrowUp') {\r\n e.stopPropagation();\r\n e.preventDefault();\r\n this.selectedIndex = (this.selectedIndex - 1 + this.ancestors.length) % this.ancestors.length;\r\n this.render();\r\n this.attachRowClickListeners();\r\n } else if (e.key === 'Enter') {\r\n e.stopPropagation();\r\n this.confirm(this.selectedIndex);\r\n } else if (e.key === 'Escape') {\r\n e.stopPropagation();\r\n this.cancel();\r\n }\r\n };\r\n window.addEventListener('keydown', this.keyHandler, { capture: true });\r\n }\r\n\r\n private detachKeyListener(): void {\r\n if (this.keyHandler) {\r\n window.removeEventListener('keydown', this.keyHandler, { capture: true });\r\n this.keyHandler = null;\r\n }\r\n }\r\n\r\n // ── Row click listeners ─────────────────────────────────────────────────────\r\n\r\n private attachRowClickListeners(): void {\r\n this.shadow.querySelectorAll('[data-idx]').forEach((row) => {\r\n (row as HTMLElement).addEventListener('click', () => {\r\n const idx = parseInt((row as HTMLElement).dataset['idx'] ?? '0', 10);\r\n this.confirm(idx);\r\n });\r\n });\r\n }\r\n\r\n // ── Recording auto-close ────────────────────────────────────────────────────\r\n\r\n private subscribeToRecordingChanges(): void {\r\n this.unsubRecording = this.recording.onRecordingChange((isRecording) => {\r\n if (!isRecording) this.closeSilently();\r\n });\r\n this.unsubPause = this.recording.onPauseChange((isPaused) => {\r\n if (isPaused) this.closeSilently();\r\n });\r\n }\r\n\r\n // ── Actions ─────────────────────────────────────────────────────────────────\r\n\r\n private confirm(index: number): void {\r\n const row = this.rows[index];\r\n if (!row) return;\r\n const command = `cy.get('${escapeSingleQuotes(row.selector)}').click()`;\r\n this.recording.appendCommand(command);\r\n this.dispatchEvent(new CustomEvent('selectorchosen', { detail: command, bubbles: true, composed: true }));\r\n this.closeSilently();\r\n }\r\n\r\n private cancel(): void {\r\n this.dispatchEvent(new CustomEvent('pickercancelled', { bubbles: true, composed: true }));\r\n this.closeSilently();\r\n }\r\n\r\n private closeSilently(): void {\r\n this.detachKeyListener();\r\n this.unsubRecording?.();\r\n this.unsubPause?.();\r\n this.unsubRecording = null;\r\n this.unsubPause = null;\r\n this.remove();\r\n }\r\n}\r\n\r\nif (!customElements.get('lib-e2e-selector-picker')) {\r\n customElements.define('lib-e2e-selector-picker', SelectorPickerElement);\r\n}\r\n"],"mappings":"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","names":[]}
|