# i18n Tickets / Máquina Usada / Dashboard Staff — Inventario de archivos

> ## ✅ TAREA CERRADA / COMPLETA (2026-07-20) — Bloques 1–37, checklist 185/185, 0 pendientes.
> Todo el texto de usuario de UI (§1–§11) migrado a `__()` (Sentence case, key inglés + 6 JSON válidos).
> Correos (§12) quedaron en inglés por decisión de negocio de **esta** tarea.
>
> **👉 TAREA SIGUIENTE (correos multi-idioma):** `docs/I18N-CORREOS-IDIOMA-USUARIO.md` — hacer que los correos
> lleguen en el idioma preferido del usuario (campo nuevo en `users` + editable en perfil). Esa tarea **revierte**
> la decisión de dejar los correos en inglés. Es independiente y tiene su propia lógica.

> **Objetivo:** migrar a `__()` TODO el texto de usuario del módulo de **tickets** (Sale /
> Purchase), **máquina usada** (Sale Used Machine + Used Machine Request) y el **dashboard de
> staff** (navbars, sidebars, tablas, shows, kanbans, profiles, customers, users), para **guest,
> customer, staff/admin y cualquier vista del módulo sin traducción**. Luego agregar las keys
> faltantes en los 6 JSON: `lang/en.json`, `lang/es.json`, `lang/fr.json`, `lang/it.json`,
> `lang/pt.json`, `lang/zh_CN.json`.
>
> Tarea larga (NO en un día). Ir archivo por archivo marcando `[x]` al terminar.

---

## ⭐ REGLAS DEL MÓDULO DE TRADUCCIONES (acordadas con el usuario)

1. **Trabajar de 5 en 5.** Se toman **5 archivos** del checklist, se traducen los 5, se **cierra el
   bloque** (se registran abajo) y recién ahí se empieza el siguiente bloque de 5. Así llevamos
   control exacto de cuáles están hechos y cuáles no.
2. **Registrar cada bloque cerrado** en la sección *REGISTRO DE PROGRESO* de este mismo archivo y en
   la **memoria** (`i18n-tickets-inventory`), para saber qué quedó hecho y en qué bloque seguimos.
3. **Formato y flujo de traducción:**
   - Usar el helper de Laravel **`__('...')`**. La **clave va en INGLÉS** (idioma por defecto).
   - Tras poner la key en inglés en el archivo, **agregar el valor traducido en los 6 JSON de
     `lang/`**: `en.json`, `es.json`, `fr.json`, `it.json`, `pt.json`, `zh_CN.json`.
   - Por cada archivo del checklist se tocan: **(a) el archivo en cuestión** + **(b) los 6 JSON**.
4. **No replicar traducciones.** Si una key **ya existe** en los JSON (agregada por otro archivo),
   **no** volver a agregarla al catálogo — reutilizar la existente.
5. **Deduplicar.** Si se detectan keys **duplicadas** en los JSON, **borrar las repetidas** para no
   ocupar espacio en los catálogos.
6. **Continuidad entre chats.** Estas reglas + checklist + progreso viven TODO en este archivo. El
   `CLAUDE.md` raíz solo tiene un puntero. → Ver *CÓMO CONTINUAR*.

## Glosario de maquinaria (movido desde `CLAUDE.md`)

Los términos son de taller del cliente, no traducción literal, y viven en DOS sitios que hay que
mantener sincronizados: `lang/*.json` y `lang/*/used_machine.php`. Tocar un término en uno implica
tocarlo en el otro **y en los 6 idiomas**, o la misma máquina dice una cosa en el detalle y otra en
la ficha PDF (ya pasó con `ganci`/`uncini`, `pórtico`/`estructura`).

- **Glosario ES aprobado por el cliente (2026-08):** Dobby=Maquinilla, Crank=Crank (en inglés a
  propósito), Cams=Excéntrico, levers=levas, gantry=estructura, healds=mallas, flange=balona,
  rollers=enrollatejidos, droppers=Laminillas.
- **Correcciones IT aprobadas por el cliente (2026-09, Guido Consonni):** healds=maglie (NO licci),
  cloth roller="avvolgitore del tessuto con subbielli", big batcher="grande rotolo",
  knitting="Macchine per maglieria" (sin "Warp"), hooks=uncini, harness=arcata, gantry=struttura.

## 🔄 CÓMO CONTINUAR (chat nuevo)

Al abrir un chat nuevo para esta tarea:
1. `CLAUDE.md` (auto-cargado) ya apunta aquí. **Leer este archivo completo** (`docs/I18N-TICKETS-ARCHIVOS.md`).
2. Mirar *REGISTRO DE PROGRESO* → identificar el **último bloque cerrado** y el **siguiente bloque de 5**.
3. Seguir las *REGLAS DEL MÓDULO* (5 en 5, key inglés + 6 JSON, no duplicar, deduplicar).
4. Al cerrar un bloque: marcar `[x]` en el checklist, anotar el bloque en *REGISTRO DE PROGRESO* y
   actualizar la memoria.

## 📋 REGISTRO DE PROGRESO (bloques de 5)

> Formato por bloque: `Bloque N [ESTADO] — archivos + keys nuevas/reutilizadas + notas`.
> ESTADO: `EN CURSO` / `CERRADO`.

- **Bloque 1 [CERRADO]** — 2026-07-17 · Shell staff + layouts de formularios
  1. `resources/views/layouts/users/main.blade.php` — sin texto de usuario (shell). Sin cambios.
  2. `resources/views/layouts/users/nav-bar-app.blade.php` — normalizado a Sentence case:
     `my profile→My profile`, `home→Home`, `create sale tickets→Create sale tickets`,
     `create purchase tickets→Create purchase tickets`.
  3. `resources/views/layouts/users/nav-sidebar.blade.php` — ya usaba `__()`; etiquetas vienen de
     **`app/Services/SidebarService.php`** (agregado al checklist §1). 13 labels → keys en los 6 JSON.
  4. `resources/views/layouts/purchase-and-sale/form-navbar.blade.php` — `Sale Form→Sale form`,
     `Purchase Form→Purchase form`; resto ya con `__()`.
  5. `resources/views/layouts/purchase-and-sale/general-form-tickets.blade.php` — sin texto (shell).
  · **Keys nuevas (22)** en los 6 JSON: My profile, Home, Login, Log Out, Toggle navigation,
    Sale form, Purchase form, Create sale tickets, Create purchase tickets, Dashboard, Users,
    My sales tickets, Sales ticket, Sales ticket kanban, Sales ticket list, Sales ticket archived,
    Sale used machine, My purchase tickets, Purchase ticket, Purchase ticket kanban,
    Purchase ticket list, Purchase ticket archived.
  · **Dedup/borradas:** key vieja `my profile` (minúscula) eliminada de los 6 JSON.
  · **Correcciones de valor:** `Home` estaba mal traducido (fr "Maison", it "Casa", pt "Lar",
    zh "家" = "casa") → corregido a nav real (Accueil/Home/Início/首页). zh `My profile` 我的简介→我的资料.
  · **Touch fuera de bloque (solo dedup):** `resources/views/livewire/guest/auth-nav-link.blade.php`
    (Bloque 11) — `my profile→My profile`, `login→Login`. El archivo SIGUE en §11 para revisión completa.
  · Verificado clave por clave en los 6 idiomas: correcto.

- **Bloque 2 [CERRADO]** — 2026-07-17 · Dashboard staff + Profile
  1. `resources/views/dashboard/dashboard-admin.blade.php` — normalizado a Sentence case:
     `Total Tickets→Total tickets`, `Sales Tickets→Sales tickets`, `Purchase Tickets→Purchase tickets`,
     `Sales Tickets Progress→Sales tickets progress`, `Purchase Tickets Progress→Purchase tickets progress`.
  2. `resources/views/dashboard/welcome-dashboard.blade.php` — `Edit Profile→Edit profile`.
  3. `app/Http/Controllers/Dashboards/DashboardAdminController.php` — SEO `Admin Dashboard→Admin dashboard`.
  4. `app/Http/Controllers/Dashboards/WelComeDashboardController.php` — SEO `Welcome Dashboard→Welcome dashboard`,
     `Welcome to the Dashboard Page→Welcome to the dashboard page`.
  5. `resources/views/profile/profile.blade.php` — sin texto propio; delega en 3 componentes de perfil
     (`user-profile-layout`, `update-profile-information-form`, `update-password-form`) → **agregados al
     checklist §3** para un bloque dedicado.
  · **Keys nuevas (19)** en los 6 JSON: Welcome back, Here is what is happening today., Total tickets,
    Global overview, Sales tickets, Active sales, Purchase tickets, Active purchases,
    Sales tickets progress, Purchase tickets progress, Machines for sale published,
    Global inventory of used machines currently listed., Welcome, We're glad to see you again…,
    Edit profile, All rights reserved. (solo en/es; fr/it/pt/zh ya existían), Admin dashboard,
    Welcome dashboard, Welcome to the dashboard page.
  · **Reutilizadas:** `Dashboard` (Bloque 1), `All rights reserved.` (defaults fr/it/pt/zh).
  · Verificado clave por clave en los 6 idiomas: correcto.
  · ⚠️ **Pendiente para Bloques 4/5:** normalizar las variantes Title Case aún presentes en
    `purchase-ticket/admin/kanban.blade.php` (`Purchase Tickets`), `SaleTicketController` (`Sales Tickets`),
    `PurchaseTicketController` (`Purchase Tickets`), `PurchaseTicketKanbanController` (`Purchase Tickets Kanban`)
    → reusar `Purchase tickets` / `Sales tickets` / `Purchase tickets kanban` (evitar duplicar).

- **Bloque 3 [CERRADO]** — 2026-07-17 · Perfil (componentes) + UserController + ProfileController
  1. `resources/views/components/user-profile-layout.blade.php` — `user details→User details`,
     `fullname→Full name`, `Account Settings→Account settings`.
  2. `resources/views/livewire/profile/update-profile-information-form.blade.php` (Volt) — normalizado
     Sentence case (Profile information, Full name, Email address, Phone number, Company position,
     Company information, Company name, Save changes, Profile updated successfully…).
  3. `resources/views/livewire/profile/update-password-form.blade.php` (Volt) — normalizado +
     **envueltos 2 mensajes de validación** (`password.regex`, `password.not_regex`) que estaban sin `__()`.
  4. `app/Http/Controllers/UserController.php` — SEO + breadcrumb (`User management`, `User details`,
     `User detail`, `Manage users in the system`, `View details of the user`).
  5. `app/Http/Controllers/ProfileController.php` — SEO (`User profile`, `View and edit your profile
     information`). El `abort(403, 'Unauthorized to edit profile.')` **queda en inglés** (guard técnico).
  · **Keys nuevas (40)** en los 6 JSON. Reutilizada: `Users` (Bloque 1).
  · **Keys compartidas creadas en Sentence case** que otros bloques deben reusar (NO recrear en Title Case):
    `Country`, `City` (ya se usan en users/register/owner/used-machine → esos archivos quedan traducidos ya),
    `Full name`, `Save changes`, `Company name`, `New password`, `User details`.
  · ⚠️ **Pendiente otros bloques:** normalizar a estas keys las variantes Title Case aún presentes en
    `livewire/user/*`, `pages/auth/register.blade.php`, `ticket/create/steps/register-step-form.blade.php`,
    `sale-used-machine/*edit*`, `users/user-detail.blade.php` (`Save Changes`, `Company Name`, `New Password`,
    `User Details`).
  · Verificado clave por clave en los 6 idiomas: correcto.

- **Bloque 4 [CERRADO]** — 2026-07-17 · Users/Tables (CRUD de usuarios completo, 7 archivos)
  1. `resources/views/users/user-table.blade.php` — `Users Table→Users table`.
  2. `resources/views/users/user-detail.blade.php` — Sentence case + reusa keys B3 (Role, Email,
     Company position/information/name, Country, City, User details); `phone→Phone`, `Created At→Created at`,
     `Last Updated→Last updated`; `x-print-button title` ahora con `__()`.
  3. `app/Livewire/Tables/UserTable.php` (PowerGrid) — envueltos slot header, títulos de columna,
     labels de filtro Active/Inactive y titles de acciones (`Edit user`, `View user`).
  4. `app/Livewire/User/CreateUser.php` (+ `create-user.blade.php`) — normalizado; envueltos 2 msgs de
     validación de password (reusan B3); alerts `User created successfully`/`User creation failed`.
  5. `app/Livewire/User/EditUser.php` (+ `edit-user.blade.php`) — íd.; alerts `User updated successfully`/
     `User update failed`. Reusa B3: New password, Confirm new password, Save changes, Password requirements.
  · **Keys nuevas (55)** en los 6 JSON. Reutilizadas: `Action`, `Admin`, `Cancel` (defaults fr/it/pt/zh →
    solo en/es); varias de B3 (New password, Save changes, Company name, Country, City, Email, Role…).
  · **Corrección de valor:** it `Admin` "Ammin" → "Amministratore".
  · **Dedup resuelto (pendiente de B3):** `livewire/user/*` ya normalizados (Save Changes/Company Name/
    New Password → keys sentence-case). `Country`/`City` compartidas.
  · **Dejado en inglés a propósito:** `validationAttributes()` (labels minúscula de validación) y
    `abort(403, 'Unauthorized to ...')` (guards técnicos, como logs).
  · Verificado clave por clave en los 6 idiomas: correcto.

- **Bloque 5 [CERRADO]** — 2026-07-20 · Purchase Ticket — Controllers (§4.4, 5 de 6)
  1. `PurchaseTicketController.php` — normalizado Title/lowercase → Sentence case; **reusa B1**
     (`Purchase tickets`, `Purchase ticket list`, `Purchase ticket kanban`); breadcrumbs
     `purchase ticket edit `→`Purchase ticket edit`, `purchase ticket details `→`Purchase ticket details`;
     `Ticket Details`→`Ticket details`; alerts stage/status/channels envueltas.
  2. `PurchaseTicketArchivedController.php` — `Archived Tickets`→`Archived tickets`; alerts con `:id`.
  3. `PurchaseTicketCustomerController.php` — `My Tickets`→`My tickets`, `Create Ticket`→`Create ticket`,
     `edit purchase ticket`→`Edit purchase ticket` (reusa key nueva), `My Purchase Requests`/`Edit Request`
     → Sentence case; alerts de corrección/observación.
  4. `PurchaseTicketDraftController.php` — `Edit Draft Ticket`→`Edit draft ticket`; alerts submit/delete draft.
  5. `PurchaseTicketKanbanController.php` — `Purchase Tickets Kanban`→`Purchase ticket kanban` (reusa B1).
  · **Keys nuevas (33)** en los 6 JSON. **Reutilizadas B1:** `Purchase tickets`, `Purchase ticket list`,
    `Purchase ticket kanban`. Sin duplicados (verificado: 0 skipped en los 6 idiomas).
  · **Dejado en inglés a propósito:** `Log::error(...)` (técnicos) y `$e->getMessage()` de `HttpException`
    (ya viene del service, se muestra tal cual). Comentarios de código no se tocan.
  · ⚠️ **Nota:** `Edit the details of the sales ticket.` aparece (copy-paste) en el edit de *purchase*
    customer; se dejó el texto tal cual (no es bug de i18n). Falta cerrar `PurchaseTicketObservationController`
    para completar §4.4 (irá en el próximo bloque junto a Tables/Service).
  · Verificado JSON válido en los 6 idiomas y keys presentes en los 6.

- **Bloque 6 [CERRADO]** — 2026-07-20 · Purchase Ticket — cierre backend (§4.4 obs + §4.5 tablas + §4.6 service)
  1. `PurchaseTicketObservationController.php` — alerts de `store`/`finishComment` (ya con `__()`);
     **reusa B5** (`Ticket marked as corrected successfully.`, `An error occurred while updating the observation status.`).
     Nuevas: `Observation added successfully.`, `An error occurred while saving the observation.`
  2. `PurchaseTicketTable.php` (PowerGrid) — envueltas columnas + `Column::action` (patrón B4:
     `Column::make(__('...'), 'field')`), `Not purchased` en el badge, `show details→Show details`.
     Alerts de archivar ya estaban con `__()`. `exportable('Purchase tickets')` **queda en inglés** (nombre de archivo, patrón B4).
  3. `PurchaseTicketCustomerTable.php` — columnas/action envueltas; `Ticket Id→Ticket ID`.
  4. `PurchaseTicketArchivedTable.php` — columnas/action envueltas; `show details→Show details`;
     alerts de cambio de estado ya con `__()`.
  5. `PurchaseTicketService.php` — todos los `abort(403/404, __())` ya estaban envueltos; solo se agregaron keys.
     Las 2 excepciones técnicas (`Error creating sale ticket:`, `Invalid status value:`) **quedan en inglés** (solo se loguean/técnicas).
  · **Keys nuevas (28)** en los 6 JSON (0 duplicados). **Reutilizadas:** `Name`, `Status`, `Created at`, `Action`,
    `Cancel`, `Success` (previas) + `Ticket #:id was archived successfully.` / `Ticket marked as corrected successfully.`
    / `An error occurred while updating the observation status.` (B5).
  · **Normalizaciones:** `User Name→User name`, `User Email→User email`, `Ticket Id→Ticket ID`, `show details→Show details`.
  · **§4 PURCHASE TICKET backend COMPLETO** (controllers §4.4 + tablas §4.5 + service §4.6). Falta §4.1/§4.2/§4.3
    (blades + Livewire) y §4.6 Policy/Model (🔍 revisar).
  · Verificado JSON válido en los 6 idiomas.

- **Bloque 7 [CERRADO]** — 2026-07-20 · Purchase Ticket — Blades admin (§4.1, 5 archivos)
  1. `admin/edit.blade.php` — normalizado Sentence case (Ticket setup, Control panel, Ticket status,
     Update current status, Social channels, Update channels, Return with comments, Activity timeline,
     Team hub, System actions, Archive ticket); confirms Swal (`Update status?`, `Update channels?`,
     `Are you sure you want to archive this ticket?`, `Yes, update`…) ya con `@js`/`__()`. Reusa B5 `Ticket details`,
     B6 `Yes, archive`/`Archive ticket`, `Cancel`.
  2. `admin/show.blade.php` — `Purchase Ticket Details`→`Purchase ticket details` (B5), `No User Assigned`→`No user assigned`,
     `Approved At`→`Approved at`, `Not Approved`→`Not approved`, `Created At`→`Created at` (B4), `Machine Information`→`Machine information`.
     Reusa B6 `Ticket ID`/`Stage`, `Status`, `Back`. `__(str_replace('_',' ',ucfirst($key)))` (labels dinámicos de máquina) se deja igual.
  3. `admin/index.blade.php` — `Purchase Ticket`→`Purchase ticket` (reusa B1).
  4. `admin/kanban.blade.php` — `Purchase Tickets`→`Purchase tickets` (reusa B1).
  5. `archived/index.blade.php` — `Purchase ticket archived`→`Archived tickets` (reusa B5, = SEO title del controller).
  · **Keys nuevas (34)** en los 6 JSON. `Update` y `User` ya existían en fr/it/pt/zh (defaults vendor) →
    solo se agregaron a en/es (0 duplicados, script skip). **Reutilizadas:** `Ticket details`, `Purchase ticket details`,
    `Ticket ID`, `Stage`, `Status`, `Created at`, `Back`, `Yes, archive`, `Archive ticket`, `Cancel`,
    `Purchase ticket`, `Purchase tickets`, `Archived tickets`.
  · Verificado JSON válido en los 6; leftovers de Title Case solo en comentarios blade `{{-- --}}` (no visibles).
  · Falta §4.1: blades de customer/drafts/observations/partials (create, edit, index, drafts/edit, observations/create, _observations-list).

- **Bloque 8 [CERRADO]** — 2026-07-20 · Purchase Ticket — Blades customer/drafts/observations (§4.1, 5 archivos)
  1. `customer/create.blade.php` — `Active Drafts→Active drafts`, `Untitled Machine→Untitled machine`,
     `alt="Empty Drafts"→__('Empty drafts')`; Swal borradores (`Yes, delete it`, `Submit all draft tickets?`…).
  2. `customer/edit.blade.php` — `Update Ticket Information→Update ticket information`,
     `Administrative Observations→Administrative observations`; Swal return corrected; reusa B7 `Ticket #:id`, `Cancel`.
  3. `customer/index.blade.php` — `Purchase Ticket→Purchase ticket` (reusa B1).
  4. `drafts/edit.blade.php` — `Back to Create Ticket`, `Continue your Request`, `Draft Mode`, `Draft Setup`
     → Sentence case; reusa B5 `Ticket details`, B7 `Control panel`, `Cancel`; Swal submit-one.
  5. `observations/create.blade.php` — ya con `__()` (`Add new observation`, `Add observation`); solo keys.
  · **Keys nuevas (33)** en los 6 JSON (0 duplicados). **Reutilizadas:** `Are you sure?` (B6), `Cancel`,
    `Ticket #:id` (B7), `Purchase ticket` (B1), `Control panel` (B7), `Ticket details` (B5).
  · `alt="..."` de imagen envuelto en `__()` (texto accesible = usuario).
  · **§4.1 PURCHASE Blades COMPLETO salvo `partials/_observations-list.blade.php`** (irá con Livewire §4.2/§4.3).
  · Verificado JSON válido en los 6; 0 leftovers Title Case (solo comentarios blade).

- **Bloque 9 [CERRADO]** — 2026-07-20 · Purchase Ticket — Team comment (§4.2/§4.3) + observations partial (§4.1)
  1. `team-comment/purchase-ticket-comment-list.blade.php` — empty state (`No comments recorded yet`,
     `Be the first to leave a team note on this ticket.`).
  2. `team-comment/purchase-ticket-create-comment-form.blade.php` — `Add Comment→Add comment` + `Add team comment`,
     `Write your comment here...`, `Sending...`.
  3. `PurchaseTicketCommentList.php` — sin texto de usuario (nada que envolver).
  4. `PurchaseTicketCreateCommentForm.php` — alerts save/error (`Comment saved successfully`,
     `An error occurred while saving the comment. Please try again.`); reusa `Success`/`Error`.
     `abort_unless(403, __('Unauthorized to create purchase team comment.'))` **traducido** (ver *Corrección aborts*).
  5. `partials/_observations-list.blade.php` — Swal (`Mark as answered?`, `Confirm`, `Cancel`), botón `Mark as answered`,
     metadata `Created`/`Answered`, empty `No purchase observations found`.
  · **Keys nuevas (15)** en los 6 JSON. `Confirm`/`Created` ya existían en fr/it/pt/zh (defaults) → solo en/es.
    **Reutilizadas:** `Success`, `Error`, `Cancel`. 0 duplicados.
  · **§4 PURCHASE COMPLETO** (controllers §4.4, tablas §4.5, service §4.6, blades §4.1, Livewire team-comment §4.2/§4.3).
    Falta en §4.2/§4.3: wizard create (step-form) + edit-form + kanban (blades y clases), y §4.6 Policy/Model (🔍).
  · Verificado JSON válido en los 6.

- **Bloque 10 [CERRADO]** — 2026-07-20 · Purchase Ticket — Wizard create + edit-form + kanban (§4.2/§4.3, 5 archivos)
  1. `create/steps/purchase-ticket-step-form.blade.php` — wizard: type selection, specs, movement types
     (`Dobby`, `Crank`, `Cams`, `Jacquard`, `E-sheet`), acciones save/finish; Sentence case.
  2. `edit/purchase-ticket-edit-form.blade.php` — mismos campos; `Machine Request Details→Machine request details`,
     `Save Changes→Save changes` (reusa B3).
  3. `kanban/purchase-ticket-kanban.blade.php` — `View/Edit/Delete Ticket→...ticket` (reusa B6 View/Edit ticket),
     `Reject`, `Confirm` (reusa), `No type`, `No model`, `No tickets in this stage.`
  4. `PurchaseTicketStepForm.php` — `Purchase Form→Purchase form` (B1) + flashes (`Machine added to draft...`,
     `Purchase request submitted successfully!`).
  5. `PurchaseTicketKanban.php` — Swal reject/confirm/archive/move (`Reject this ticket?`, `Yes, reject it`,
     `Ticket #:id was moved successfully.`, `Invalid Action→Invalid action`, `Invalid Stage Change→Invalid stage change`);
     abort permiso ya traducido en *Corrección aborts*; reusa `Cancel`, `Ticket archived`, `Ticket #:id was archived successfully.`
  · **Keys nuevas (55)** en los 6 JSON (0 duplicados). **Reutilizadas:** Selected, Click to select, Brand, Model,
    Year, Saving..., Sending... (B9), Save changes (B3), View ticket/Edit ticket (B6), Confirm, Purchase form (B1),
    Ticket archived (B6), Ticket #:id was archived successfully. (B5), Cancel.
  · Movement types (`Dobby`/`Crank`/`Cams`/`Jacquard`/`E-sheet`) traducidos como términos textiles; `E-sheet` se deja igual.
  · **§4 PURCHASE TICKET COMPLETO** (blades §4.1, Livewire §4.2/§4.3, controllers §4.4, tablas §4.5, service §4.6).
    Solo queda §4.3 `PurchaseTicketCreateForm.php`(0)/`EditForm.php` y §4.6 Policy/Model (🔍 revisar si emiten texto).
  · Verificado JSON válido en los 6; 0 leftovers Title Case.

- **Bloque 11 [CERRADO]** — 2026-07-20 · Cierre §4 (cabos §4.3/§4.6) + arranque Sale Ticket (§5.4)
  1. `PurchaseTicketCreateForm.php` — wizard shell, sin texto de usuario (solo slugs/vistas). Sin cambios.
  2. `PurchaseTicketEditForm.php` — `abort_unless(update, __('You are not allowed to update this ticket.'))` +
     alert `Purchase ticket information updated successfully` (ambos ya con `__()`); solo se agregaron keys.
  3. `PurchaseTicketPolicy.php` — solo retornos bool, sin `deny()`/mensajes → nada que traducir.
  4. `PurchaseTicket.php` (model) — casts/relaciones, sin texto de usuario.
  5. `SaleTicketController.php` (§5.4) — `Sales Tickets→Sales tickets` (reusa B2); `Ticket not found!→Ticket not found.`
     (dedup, reusa B6, 2x); reusa `Ticket status updated successfully` (B5). Nueva: `List of sales tickets that are currently active.`
  · **Keys nuevas (3)** en los 6 JSON (0 duplicados): `You are not allowed to update this ticket.`,
    `Purchase ticket information updated successfully`, `List of sales tickets that are currently active.`
  · **§4 PURCHASE TICKET 100% COMPLETO.** Empieza §5 SALE TICKET.
  · Verificado JSON válido en los 6.

- **Bloque 12 [CERRADO]** — 2026-07-20 · Sale Ticket — Controllers §5.4 restantes (5 archivos)
  1. `SaleTicketArchivedController.php` — `Archived Tickets→Archived tickets`; todo lo demás reusa B5
     (list archived, `Ticket #:id was archived successfully.`, `Ticket #:id cannot be archived...`).
  2. `SaleTicketCustomerController.php` — `My Tickets→My tickets`, `Create Ticket→Create ticket`,
     `Edit Request→Edit request` (reusa B5); nuevas `Create a new ticket for sale.`, `Edit sale ticket`, `My sale requests`.
     Reusa `Edit the details of the sales ticket.` (B5), `This ticket cannot be edited.`, alerts observación.
  3. `SaleTicketDraftController.php` — `Edit Draft Ticket→Edit draft ticket` (B5); nueva
     `Edit the details of your draft ticket before submitting it for review.`; reusa deleted/submitted (B5).
  4. `SaleTicketKanbanController.php` — `Kanban Tickets→Sales ticket kanban` (reusa B1); nueva desc kanban.
  5. `SaleTicketObservationController.php` — ya con `__()`; reusa B9 (`Observation added successfully.`,
     `An error occurred while saving the observation.`), B5 (`Ticket marked as corrected successfully.`),
     y `You cannot return this ticket in its current status.` (ya existía).
  · **Keys nuevas (5)** en los 6 JSON (0 duplicados): `Create a new ticket for sale.`, `Edit sale ticket`,
    `My sale requests`, `Edit the details of your draft ticket before submitting it for review.`,
    `Manage your sales tickets using the Kanban view for better organization and tracking.`
  · Sale reutilizó MUCHÍSIMO de Purchase (espejo). Verificado JSON válido en los 6.

- **Bloque 13 [CERRADO]** — 2026-07-20 · Sale Ticket — Tablas §5.5 + Services §5.6 (5 archivos)
  1. `SaleTicketTable.php` — columnas/`Column::action` envueltas (patrón B4), `Not approved` en badge; `Owner Name→Owner name`.
     `exportable('Sale tickets')` en inglés (filename). Alerts archivar ya con `__()`.
  2. `SaleTicketCustomerTable.php` — columnas/action envueltas; actions View/Edit ticket ya con `__()`.
  3. `SaleTicketArchivedTable.php` — columnas/action envueltas (`User Name→User name`); alerts cambio estado ya con `__()`.
  4. `SaleTicketService.php` — aborts permiso ya con `__()`; nuevas `You do not have permission to create a sales ticket.`,
     `You do not have permission to edit this sales ticket.`, `The stage :stage is not allowed for update.`;
     reusa `You are not allowed to archive/confirm/reject this ticket.` (B6), `Invalid draft ticket.` (B6),
     `Ticket not found.` (B6). Excepción técnica `Error creating sale ticket:` en inglés.
  5. `SaleFormService.php` — abort permiso reusa `You do not have permission to create a sales ticket.`
  · **Keys nuevas (4)** en los 6 JSON (0 duplicados): `Owner name`, `You do not have permission to create a sales ticket.`,
    `You do not have permission to edit this sales ticket.`, `The stage :stage is not allowed for update.`
  · Enorme reutilización de Purchase (columnas, alerts, permisos). **§5.4 controllers + §5.5 tablas + §5.6 services COMPLETO.**
  · Verificado JSON válido en los 6; 0 leftovers.

- **Bloque 14 [CERRADO]** — 2026-07-20 · Sale Ticket — Blades §5.1 (admin/index, kanban, archived, customer create/edit)
  1. `admin/index.blade.php` — `Sales Ticket→Sales ticket` (reusa B1).
  2. `admin/kanban.blade.php` — ya usaba `Sales tickets` (B2); sin cambios.
  3. `archived/index.blade.php` — `Sales ticket archived→Archived tickets` (reusa B5, como Purchase).
  4. `customer/create.blade.php` — espejo de B8: `Active Drafts→Active drafts`, `alt="Empty Drafts"→__('Empty drafts')`;
     todo el resto (Swal borradores, Draft, Edit/Delete draft, submit) reusa B5/B8.
  5. `customer/edit.blade.php` — espejo de B8 (Update ticket information, Administrative observations, Swal return
     corrected) + sección **Multimedia** nueva. Reusa B7 `Ticket #:id`.
  · **Keys nuevas (2)** en los 6 JSON (0 duplicados): `Multimedia assets`,
    `Review and manage your high-quality media content for this machine listing.`
  · Reutilización masiva de Purchase B5/B7/B8. **§5.1 blades COMPLETO salvo customer/index, drafts/edit,
    observations/create, partials/_observations_list** (van en el próximo bloque con Livewire §5.2/§5.3).
  · Verificado JSON válido en los 6; 0 leftovers Title Case.

- **Bloque 15 [CERRADO]** — 2026-07-20 · Sale Ticket — resto §5.1 blades + kanban blade §5.2 (5 archivos)
  1. `customer/index.blade.php` — `Sales Ticket→Sales ticket` (B1).
  2. `drafts/edit.blade.php` — espejo B8 (`Back to create ticket`, `Continue your request`, `Draft mode`, Swal submit-one);
     usa flujo unificado Sale Used Machine (`used-machine-edit-form`).
  3. `observations/create.blade.php` — nueva `New observation`; reusa B9 (`Add new observation`, `Add observation`).
  4. `partials/_observations_list.blade.php` — Swal (`Mark as answered?`, `Confirm`, `Cancel`), botón `Mark as answered`,
     metadata `Created`/`Answered`; nuevas `This will notify the team that the observation has been addressed.` y
     `No observations found` (variantes propias de Sale).
  5. `livewire/sale-ticket/kanban/sale-ticket-kanban.blade.php` — reusa B6 `Edit ticket`, B10 `Delete ticket`/`No type`/
     `No model`/`Reject`/`Confirm`/`No tickets in this stage.`; nuevas `View machine ticket`, `Request table`.
  · **Keys nuevas (5)** en los 6 JSON (0 duplicados): `New observation`,
    `This will notify the team that the observation has been addressed.`, `No observations found`,
    `View machine ticket`, `Request table`.
  · **§5.1 blades COMPLETO.** Falta §5.2/§5.3 clases (SaleTicketKanban, team-comment, edit sections photo/video list)
    y §5.6 Policy/Model.
  · Verificado JSON válido en los 6; 0 leftovers Title Case.

- **Bloque 16 [CERRADO]** — 2026-07-20 · Sale Ticket — Team comment (§5.2/§5.3) + SaleTicketKanban (§5.3)
  1. `sale-ticket-comment-list.blade.php` — espejo B9 (empty state), todo reusado.
  2. `sale-ticket-create-comment-form.blade.php` — `Add Comment→Add comment`; resto reusa B9.
  3. `SaleTicketCommentList.php` — sin texto de usuario.
  4. `SaleTicketCreateCommentForm.php` — alerts save/error (reusa B9 Success/Error/Comment saved…);
     abort permiso ya traducido en *Corrección aborts*.
  5. `SaleTicketKanban.php` — Swal reject/confirm/archive/move; `Invalid Action→Invalid action`,
     `Invalid Stage Change→Invalid stage change`; reusa B10 (reject/archive/move/`Ticket #:id was moved...`),
     B6/B5 (archived). Nuevas propias de Sale: `This ticket cannot be moved to the selected stage due to its approval status.`,
     `Used machine created`, `Used machine for Ticket #:id was created successfully.`
  · **Keys nuevas (3)** en los 6 JSON (0 duplicados). Enorme reutilización de Purchase B9/B10.
  · **§5 SALE casi COMPLETO:** falta §5.2/§5.3 edit sections (photo-list/video-list blades+clases) y §5.6 Policy/Model.
  · Verificado JSON válido en los 6; 0 leftovers.

- **Bloque 17 [CERRADO]** — 2026-07-20 · Sale Ticket — Edit sections media (§5.2/§5.3) + Policy/Model (§5.6)
  1. `sale-ticket-photo-list.blade.php` — `alt="Ticket photo"` envuelto; empty `No photos uploaded yet.`; reusa `Delete`.
  2. `sale-ticket-video-list.blade.php` — fallback `Your browser does not support the video element.`; empty `No video uploaded yet.`
  3. `SaleTicketPhotoList.php` — Swal `Delete photo?` + `This will permanently delete the photo...`, `Yes, delete`;
     alerts `Media deleted successfully.`/`Could not delete the photo.` (reusa Success/Error/Cancel).
  4. `SaleTicketVideoList.php` — Swal `Delete this video?` + `...delete the video...`; `Could not delete the video.`
  5. `SaleTicketPolicy.php` + `SaleTicket.php` (model) — sin texto de usuario (verificación).
  · **Keys nuevas (12)** en los 6 JSON (0 duplicados). Reusa `Delete`, `Cancel`, `Success`, `Error`.
  · **✅ §5 SALE TICKET 100% COMPLETO.** Siguiente: §6 Sale Used Machine.
  · Verificado JSON válido en los 6.

- **Bloque 18 [CERRADO]** — 2026-07-20 · Sale Used Machine — Controllers §6.4 + Tablas §6.5 (5 archivos)
  1. `SaleUsedMachineController.php` — SEO/breadcrumbs a Sentence case; **concatenaciones → placeholders**
     (`Detail: :name`, `Edit used machine for sale - :name`, `Edit sales ticket #:id`); `Sale ticket kanban→Sales ticket kanban` (B1).
  2. `FrontendUsedMachineController.php` — SEO guest ya con `__()` (título marketing se deja con capitalización).
  3. `UsedMachineRequestController.php` — SEO/breadcrumbs Sentence case (`Used machine requests`, `Details`).
  4. `SaleUsedMachineTable.php` — columnas/`Column::action` envueltas, header slot `Add New Machine→__('Add new machine')`,
     `Unsold` (reusa), `Owner Name→Owner name` (B13); `exportable('Sale Used Machines')` en inglés (filename).
     Filtros `Weaving/Knitting/Other` y actions `Edit/View details/View request` ya con `__()`.
  5. `UsedMachineRequestTable.php` — columnas/action envueltas; `show details→Show details` (B6).
  · **Keys nuevas (28)** en los 6 JSON (0 duplicados). `Details` ya existía en fr/it/pt/zh → solo en/es.
    Reusa `Sales ticket kanban`, `Edit`, `Unsold`, `Owner name`, `Weaving/Knitting/Other`, `Phone`, `Show details`, etc.
  · ⚠️ **Pendiente dedup:** la key vieja `Used Machines` (Title) sigue usada por `customer/show.blade` (§6.1);
    al migrar ese blade → normalizar a `Used machines` y **borrar** `Used Machines`.
  · Verificado JSON válido en los 6.

- **Bloque 19 [CERRADO]** — 2026-07-20 · Sale Used Machine — Blades §6.1 admin + guest customer (5 archivos)
  1. `admin/edit.blade.php` — Sentence case masivo (Machine setup, Machine specs, Sales tracking,
     Media & promotional assets, Machine gallery/flyer, Ticket status management, Customer requests…);
     **concatenaciones→placeholders** (`Edit sales ticket #:id` reusa B18, `Edit machine for ticket #:id` nueva);
     `Yes, update it`→`Yes, update` (dedup B7). Reusa B7 Control panel/Return with comments/Activity timeline/
     Team hub/System actions, B6 Archive ticket/Yes, archive, `Are you sure?`, Cancel, Update.
  2. `admin/show.blade.php` — Sentence case (Used machine details reusa, Type of machine, Ticket status,
     Approved at, Not approved, Additional information); `alt` de imágenes envueltos (`Machine image`,
     `Promotional flyer`); `No user assigned` (B7). **Dedup video** (ver abajo).
  3. `admin/index.blade.php` — solo `Sale used machine` (reusa B1); sin cambios.
  4. `customer/index.blade.php` — **guest marketing** (reutilizado por `FrontendUsedMachineController`):
     Sentence case en headings (Buy, sell & trade machinery; Post a purchase request; List your machine for sale;
     New arrival; View complete details; Pre-owned; Industrial solutions) + párrafos largos ITG. SEO title marketing
     `Our Exclusive Products - ITG Group` se deja capitalizado (decisión B18).
  5. `customer/show.blade.php` — **guest detail**: Technical specifications, Video demonstration,
     Additional information; `Used machines` ya estaba en minúscula (reusa). **Dedup video**.
  · **Keys nuevas (49 en/en; 38 en es/fr/it/pt/zh)** en los 6 JSON. Los 11 restantes (Owner, Video, Images, ID,
    Multimedia, N/A, Pre-owned, etc.) ya existían en es/fr/it/pt/zh (defaults vendor) → solo se agregaron a en.
  · **Dedup borradas (2 keys en los 6 JSON):** `Used Machines` (Title, huérfana — usos reales eran
    strings distintos) y `Your browser does not support the video tag.` (normalizada a la existente B17
    `...video element.`). **Touch fuera de bloque (solo dedup):** `livewire/sale-used-machine/used-machine-edit-media-form.blade.php`
    (§6.2) — cambiado `video tag.`→`video element.` para poder borrar la key; SIGUE en §6.2 para revisión completa.
  · Verificado JSON válido en los 6; keys presentes en los 6; 0 leftovers Title Case visibles.

- **Bloque 20 [CERRADO]** — 2026-07-20 · Cierre §6.1 request + arranque §6.2 wizard create (5 archivos)
  1. `request/index.blade.php` — solo `Used machine requests` (reusa B18); sin cambios.
  2. `request/show.blade.php` — reusa `Name`/`Email`/`Phone`/`Country`/`Created at`/`Last updated`/`Back`,
     `Used machine request details` (existía); nuevas `Used machine request` (print title), `Division`,
     `Requested machine`, `Message`.
  3. `create/steps/machine-type-step-form.blade.php` — **normalizó Title Case a keys ya existentes**:
     `Machine Type Selection`→`Machine type selection`, `Weaving Machine`→`Weaving machine`,
     `Warp Knitting Machine`→`Warp knitting machine`, `Other Machines`→`Other machines`; reusa `Selected`/
     `Click to select` (B10); nueva `Next`.
  4. `create/steps/media-step-form.blade.php` — reusa `Save and add another machine`/`Send all loaded machines`/
     `Saving...`/`Sending...` (existentes); nuevas `Machine images`, `Maximum 5 images, each up to 3 MB.`,
     `Machine video (optional)`, `Maximum 1 video, up to 5 MB.`
  5. `create/steps/used-machine-intake-step-form.blade.php` — reusa `Please review the form`/`Back`/`Saving...`;
     nuevas `Unknown form type.`, `Continue`.
  · **Keys nuevas (11 en/es; 10 en fr/it/pt/zh)** en los 6 JSON. 1 (`Division`/`Message`/`Next`/`Continue` —
    una de ellas) ya existía en fr/it/pt/zh (default vendor) → solo en/es. **Enorme reutilización** (varios títulos
    del wizard ya estaban en el catálogo). 0 duplicados.
  · Verificado JSON válido en los 6; keys presentes en los 6; 0 leftovers Title Case.
  · Falta §6.2: partials wizard steps (customer/staff), used-machine-create-form, edit-form(-customer),
    edit-media-form, edit-promo-flyer-form, used-machine-filter. Luego §6.3 clases, §6.6 services, §6.7 Rules, §6.8.

- **Bloque 21 [CERRADO]** — 2026-07-20 · Sale Used Machine §6.2 wizard partials + create/edit forms (5 archivos)
  1. `partials/used-machine-customer-wizard-steps.blade.php` — steps stepper `General`/`Specifications`/`Pricing`/
     `Details`(existía)/`Media`; `Save All`→`Save all`; reusa `Back`/`Next`/`Saving...`/`Please review the form`/
     `Unknown form type.` (B20).
  2. `partials/used-machine-staff-wizard-steps.blade.php` — `Save Specs`→`Save specs`; reusa mismos steps +
     `This ticket is locked by its current status (:status)...` (ya existía con placeholder), `Back`/`Next`.
  3. `used-machine-create-form.blade.php` — `Create New Used Machine`→`Create new used machine`,
     `Create Machine`→`Create machine`; nueva `Register a new machine with all technical specifications and pricing.`;
     reusa `Cancel`/`Back`/`Next`/steps.
  4. `used-machine-edit-form.blade.php` — solo `@include` del staff-wizard-steps + `@push('styles')`; **sin texto propio.**
  5. `used-machine-edit-form-customer.blade.php` — Sentence case: `Draft Setup`→`Draft setup`(B15),
     `Control Panel`→`Control panel`(B7), `Ticket Details`→`Ticket details`(B5), `Machine Media`→`Machine media`,
     `Machine Photos & Video`→`Machine photos & video`, `Upload New Content`→`Upload new content`,
     `Gallery Images`→`Gallery images`, `Machine Video`→`Machine video`; nueva `Save media`.
  · **Keys nuevas (15 en los 6 JSON, 0 skipped/0 duplicados):** General, Specifications, Pricing, Media, Save all,
    Save specs, Create new used machine, Register a new machine…, Create machine, Machine media, Machine photos & video,
    Upload new content, Gallery images, Machine video, Save media.
  · **Reutilizadas:** Details, Please review the form, Unknown form type.(B20), Back, Saving..., Next, Cancel,
    Draft setup(B15), Control panel(B7), Ticket details(B5), This ticket is locked…(:status).
  · Verificado JSON válido en los 6; keys presentes en los 6; 0 leftovers Title Case.
  · Falta §6.2: `used-machine-edit-media-form`, `used-machine-edit-promo-flyer-form`, `used-machine-filter`.
    Luego §6.3 clases PHP, §6.6 services, §6.7 Rules, §6.8 Policy/Model.

- **Bloque 22 [CERRADO]** — 2026-07-20 · Cierre §6.2 (edit-media/promo-flyer/filter) + arranque §6.3 clases (5 archivos)
  1. `used-machine-edit-media-form.blade.php` — Sentence case (Machine gallery/Gallery images/Machine video/
     Upload new content/Save changes reusan); `alt` envueltos (`Primary machine image`, `Machine media`); nuevas
     `Primary image`, `Primary`, `Make primary`, `Set a primary image…`. Reusa `Delete`/`video element.`/`Cancel`/`Saving...`.
  2. `used-machine-edit-promo-flyer-form.blade.php` — Sentence case (`Promotional flyer` reusa, `Current flyer`,
     `Replace flyer`, `Upload flyer`); `alt` envuelto; nuevas `Upload or manage…`, `Delete flyer`, `Recommended: …3 MB.`
  3. `used-machine-filter.blade.php` — **guest filtro**; Sentence case (`Search brand or model`, `All brands`,
     `All types`, `View details` reusa B18); nuevas Check out our offer/of second-hand machinery/Manufacturer/Clear/
     Available/No machines found…/Show all machines/placeholder búsqueda. Reusa Technology/Sold/N/A/Discover…(B19).
  4. `MachineTypeStepForm.php` — stepInfo label `machine type`→`Machine type`; nueva `Select the type of machine you want to sale`.
  5. `MediaStepForm.php` — flashes (`All machine data has been…`, reusa `Machines submitted successfully!`),
     `abort(422, __('No valid draft data…'))`, alert `Warning`+`Please complete the machine information first.`,
     stepInfo (`Media` reusa, `Upload media files related to the sale ticket.`). **Excepciones `\Exception("Sale ticket #… no associated machine")` en inglés** (solo se lanzan/loguean).
  · **Keys nuevas (28 en; 23 en es/fr/it/pt/zh)** en los 6 JSON. 5 (`Manufacturer`/`Clear`/`Available`/`Machine type`/
    una más) ya existían en es/fr/it/pt/zh (defaults vendor) → solo en. 0 duplicados.
  · Verificado JSON válido en los 6; keys presentes en los 6; 0 leftovers Title Case.
  · **✅ §6.2 blades Livewire COMPLETO.** Falta §6.3: CreateUsedMachineWizard, UsedMachineIntakeStepForm,
    UsedMachineCreateForm, UsedMachineEditForm, UsedMachineEditMediaForm, UsedMachineEditPromoFlyerForm, UsedMachineFilter,
    Forms/UsedMachineForm. Luego §6.6 services, §6.7 Rules, §6.8 Policy/Model.

- **Bloque 23 [CERRADO]** — 2026-07-20 · §6.3 clases PHP (wizard + create/edit/media, 5 archivos)
  1. `CreateUsedMachineWizard.php` — shell del wizard (steps/slugs/showStep); **sin texto de usuario.** Sin cambios.
  2. `Create/Steps/UsedMachineIntakeStepForm.php` — title concatenado `__('Machine form').' - '.ucfirst(type)` →
     **placeholder** `__('Machine form - :type', ['type'=>...])`; stepInfo `Machine form` + `Enter the information…`;
     alert reusa `Success` + nueva `Machine information saved successfully`.
  3. `UsedMachineCreateForm.php` — alerts create; reusa `Error`; nuevas `Used machine created successfully.`,
     `The machine has been registered in the inventory.`, `An error occurred while creating the machine. Please try again.`
     `Log::error('Error creating used machine…')` **en inglés** (técnico).
  4. `UsedMachineEditForm.php` — `abort_if(locked,403,__('This machine can no longer be edited.'))` (nueva),
     `abort_unless(update,403,__('You are not allowed to update this ticket.'))` (reusa B11); alert reusa `Success`,
     nueva `Machine updated successfully.`
  5. `UsedMachineEditMediaForm.php` — alerts main-image/delete/save; reusa `Success`/`Error`/`Are you sure?`/`Yes, delete`/
     `Cancel`; **dedup:** `Media deleted successfully`→`Media deleted successfully.` (reusa B17, con punto) y
     `Media saved successfully`→`Media saved successfully.` (consistencia). Nuevas `Main image updated successfully`,
     `An error occurred while updating the main image.`, `This action cannot be undone.`,
     `An error occurred while deleting the media.`, `Media saved successfully.`, `An error occurred while processing media: `
     (prefijo con espacio final; se concatena `$e->getMessage()` técnico). `Log::error(...)` en inglés.
  · **Keys nuevas (15 en los 6 JSON, 0 skipped/0 duplicados).** Reutilizadas: Success, Error, Are you sure?, Yes, delete,
    Cancel, You are not allowed to update this ticket.(B11), Media/Warning/Machines submitted successfully!, Media deleted successfully.(B17).
  · Verificado JSON válido en los 6; keys presentes en los 6.
  · Falta §6.3: `UsedMachineEditPromoFlyerForm`, `UsedMachineFilter`(0), `Forms/UsedMachineForm`(0, attrs/validación).
    Luego §6.6 services, §6.7 Rules, §6.8 Policy/Model.

- **Bloque 24 [CERRADO]** — 2026-07-20 · Cierre §6.3 clases + §6.6 services (5 archivos)
  1. `UsedMachineEditPromoFlyerForm.php` — alerts delete/upload del flyer; reusa `Are you sure?`/`Yes, delete it`(B8)/
     `Cancel`/`Success`/`Error`; nuevas `This action will permanently delete the promotional flyer.`,
     `Promotional flyer deleted successfully`, `An error occurred while deleting the flyer.`,
     `Promotional flyer uploaded successfully`, `An error occurred while uploading the flyer: ` (prefijo con espacio +
     `$e->getMessage()` técnico). `Log::error(...)` en inglés.
  2. `UsedMachineFilter.php` — solo query/paginación/filtros; **sin texto de usuario.** Sin cambios.
  3. `Forms/UsedMachineForm.php` — Livewire Form object; `validationAttributes()` delega en `MachineValidationRules`
     (irá en §6.7 Rules); **sin texto propio.** Sin cambios.
  4. `CreateSaleUsedMachineryService.php` (§6.6) — `abort_unless(..., 403, __('You do not have permission to create used machinery.'))`
     (nueva); excepciones `\Exception("Ticket #… no associated machine")` y `"Error creating used machinery: …"` **en inglés** (técnicas/logueadas).
  5. `MachineMediaService.php` (§6.6) — helper saveImages/saveVideo; **sin texto de usuario.** Sin cambios.
  · **Keys nuevas (6 en los 6 JSON, 0 skipped/0 duplicados).** Reutilizadas: Are you sure?, Yes, delete it (B8), Cancel, Success, Error.
  · Verificado JSON válido en los 6; keys presentes en los 6.
  · **✅ §6.3 clases COMPLETO.** §6.6 services: falta `MachinePayloadBuilder`(0, 🔍) y `SaleUsedMachineService`(0, 🔍).
    Luego §6.7 Rules (MachineValidationRules 55 __, MaxTotalImagesRule), §6.8 Policy/Model.

- **Bloque 25 [CERRADO]** — 2026-07-20 · §6.6 services (cierre) + §6.7 Rule + §6.8 Policy/Model (5 archivos)
  1. `MachinePayloadBuilder.php` (§6.6) — build/parse de payload JSON (secciones conocidas + custom); **sin texto de usuario.**
  2. `SaleUsedMachineService.php` (§6.6) — saveMachine/processMedia (delega en MachineMediaService); **sin texto de usuario.**
  3. `MaxTotalImagesRule.php` (§6.7) — única regla con mensaje al usuario: `Limit exceeded. You have :existing saved photos
     and can only upload :available more. (Max :max)` (ya con `__()` + placeholders). 1 key nueva en los 6.
  4. `SaleUsedMachinePolicy.php` (§6.8) — solo `viewAny()`/`view()` bool (sin `deny()` con mensaje); **sin texto de usuario.**
  5. `SaleUsedMachine.php` model (§6.8) — casts/relaciones/helpers; **sin texto de usuario.**
  · **Keys nuevas (1 en los 6 JSON, 0 dups).** Verificado JSON válido en los 6; key presente en los 6.
  · **§6.6 services COMPLETO; §6.8 Policy + SaleUsedMachine model COMPLETO.** Falta §6.7 `MachineValidationRules` (el grande,
    ~55 mensajes/atributos de validación) y §6.8 `UsedMachineRequest` model (🔍). **Casi cierra §6** — solo queda ese Rule grande.

- **Bloque 26 [CERRADO]** — 2026-07-20 · §6.7 MachineValidationRules + §6.8 UsedMachineRequest model → **CIERRA §6** (2 archivos)
  1. `MachineValidationRules.php` (§6.7) — método `attributes()`: ~53 labels de validación (visibles en mensajes de error
     Laravel vía `:attribute`) **normalizados Title Case → Sentence case**. Las reglas (`base/weaving/knitting/cam/dobby/
     jacquard/other/multimedia`) son solo strings de reglas (required/string/max…), sin texto de usuario. **Reusadas:**
     `Brand`/`Model`/`Year`/`Width`/`Machine type`(B22)/`Quantity`/`Movement type`/`Additional information`(B19)/
     `Type of machine`(B18)/`Video`(B19). **42 keys nuevas** (términos textiles: RPM, Price range, Machine status,
     Cam/Dobby/Jacquard model, Total capacity hooks, Weft feeders, Droppers, Frames, Healds, beams/flange diameter,
     Fineness, Weaving type, etc.). Duplicados internos colapsan a 1 key (`Density` x2, `Total number of levers` x2,
     `Levers installed/in use` x2).
  2. `UsedMachineRequest.php` model (§6.8) — fillable/relaciones; **sin texto de usuario.**
  · **Keys nuevas (42 en los 6 JSON, 0 dups).** Verificado JSON válido en los 6; keys presentes en los 6; 0 leftovers
    Title Case en el Rule; las variantes Title Case viejas nunca estuvieron en JSON (solo fallback en código).
  · **✅✅ §6 SALE USED MACHINE + USED MACHINE REQUEST 100% COMPLETO** (§6.1 blades, §6.2 Livewire blades, §6.3 clases,
    §6.4 controllers, §6.5 tablas, §6.6 services, §6.7 Rules, §6.8 Policy/Model).
  · **Siguiente: §7** — componentes Blade compartidos. El grueso es **§7.2 sections** (16 componentes de campos dinámicos
    del wizard: general/specs/jacquard/dobby/cam/knitting/beams/loom/price/status/etc). Los labels de §7.2 deben **reusar
    las keys sentence-case recién creadas aquí** (Fabric type, Weft feeders, Total capacity hooks, etc.).

- **Bloque 27 [CERRADO]** — 2026-07-20 · Arranque §7: §7.1 components/tickets + §7.2 sections (3) (5 archivos)
  1. `components/tickets/activity-history.blade.php` (§7.1) — empty state `No activity recorded yet.`
  2. `components/tickets/introduction-create.blade.php` (§7.1) — form ITG Machinery: `ITG Machinery Request Form→
     ITG Machinery request form`; bullets + `If form is accepted, :email will contact you…` (placeholder :email con `<strong>`);
     alt `ITG Weaving Loom Machine`→envuelto `ITG weaving loom machine`. `Required` nueva.
  3. `sections/general-fields.blade.php` (§7.2) — `General Information→General information`, `Manufacturing Year→
     Manufacturing year`; reusa `Brand`/`Model`/`RPM`(B26)/`Quantity`(B26)/`Enter model`/`Enter quantity`; placeholders `e.g. …`.
  4. `sections/price-info-fields.blade.php` (§7.2) — `Pricing Details→Pricing details`, `Price Range→Price range`(B26),
     `Select Currency→Select currency`; reusa `Currency`(B26).
  5. `sections/machine-specs-fields.blade.php` (§7.2) — Sentence case; **reusa B26** `Machine status`/`Movement type`/
     `Stopped since` + B10 movement types `Dobby`/`Crank`/`Cams`/`Jacquard`/`E-sheet` + `Other`; nuevas Voltage (V)/
     Frequency (Hz)/Type of fabric produced/In working condition/Not connected/Off/etc.
  · **Keys nuevas (34 en los 6 JSON, 0 dups).** `e.g.` localizado por idioma (p. ej./p. ex./es./ex./例如). ⚠️ **Reuso B26
    confirmado** en §7.2 (labels de campos = keys sentence-case de validación). Reusadas: General information, Brand, Model,
    RPM, Quantity, Enter model, Enter quantity, Price range, Currency, Machine status, Movement type, Stopped since,
    Select movement type, Other, Dobby/Crank/Cams/Jacquard/E-sheet.
  · Verificado JSON válido en los 6; keys presentes en los 6; 0 leftovers Title Case.
  · **§7.1 COMPLETO.** Falta §7.2: 13 sections restantes (status-information, type-of-machine, additional-information,
    decription, media-information, owner-field, custom-sections, machine-specs subsecciones: cam/dobby/jacquard-details,
    core-knitting, loom-accessories, beams-rollers). Luego §7.3-7.5, §8, §9, §10, §11, cabos §1.

- **Bloque 28 [CERRADO]** — 2026-07-20 · §7.2 sections (5): status/type-of-machine/additional-info/description/owner
  1. `status-information.blade.php` — staff-only; `Publication & Category`→`Publication & category`, `Publication Status`→
     `Publication status`, `Publish Machine`→`Publish machine`, `Machine Type`→`Machine type`(B22); reusa Weaving/Knitting/
     Other; nueva `Visible to all site visitors.` + `Select machine type`.
  2. `type-of-machine.blade.php` — `Core Specifications`→`Core specifications`, `Type of Machine`→`Type of machine`(B18);
     reusa desc(B27); nueva `Enter machine type`.
  3. `additional-information.blade.php` — `Additional Information`→`Additional information`(B19); nuevas
     `Technical info / included materials`, `Enter technical details...`.
  4. `decription.blade.php` (sic) — `Marketing & Web Content`→`Marketing & web content`, `Additional Information (Marketing/Web)`→
     `Additional information (marketing/web)`; nueva desc marketing. (Quill inline sin texto traducible.)
  5. `owner-field.blade.php` — reusa `Owner`(B19)/`New`; nuevas `Select owner` (`@js(__())` dentro de x-data select2),
     `No owner assigned`, desc interna del propietario.
  · **Keys nuevas (15 en los 6 JSON, 0 dups).** Reusadas: Machine type(B22), Weaving/Knitting/Other, Type of machine(B18),
    Basic operational details…(B27), Additional information(B19), Owner(B19), New.
  · Verificado JSON válido en los 6; keys presentes en los 6; 0 leftovers Title Case.
  · Falta §7.2: 8 sections (media-information, custom-sections, cam/dobby/jacquard-details, core-knitting, loom-accessories,
    beams-rollers). Luego §7.3-7.5, §8, §9, §10, §11, cabos §1.

- **Bloque 29 [CERRADO]** — 2026-07-20 · §7.2 sections detalles textiles (5): media/custom/cam/dobby/jacquard
  1. `media-information.blade.php` — **sin cambios**: reusa B20 `Machine images`/`Machine video (optional)`/`Maximum 5 images…`/`Maximum 1 video…`.
  2. `custom-sections.blade.php` — `Additional Sections→Additional sections`, `Section Title→Section title`,
     `Technical Details→Technical details`, `Add Field→Add field`, `Create New Section→Create new section`;
     nuevas `Feature`, `Value`, `Delete section`, `Delete field`, `Create custom sections…`.
  3. `cam-details-fields.blade.php` — `CAM Specifications→CAM specifications`, `Cam Model→Cam model`(B26);
     nuevas `Total number of levers on the loom`, `Levers installed/in use on the loom` (labels más largos que los attrs B26).
  4. `dobby-details-fields.blade.php` — `Dobby Specifications→Dobby specifications`, `Dobby Model→Dobby model`(B26);
     reusa las 2 nuevas de cam (espejo).
  5. `jacquard-details-fields.blade.php` — Sentence case; **reusa B26** Jacquard brand/model, Controller brand/model,
     Total capacity hooks, Density, Gantry type; nuevas `Jacquard specifications`, `Year of model`, `Select number of hooks`,
     `Qty. installed hooks`, `Jacquard accessories & structures`, `Include harness?`, `Number of strings (Pavilion)`,
     `Include gantry?`, `Select gantry`, `Double`/`Single`/`Quadruple`.
  · **Keys nuevas (36 en los 6 JSON, 0 dups).** `e.g. …` localizado por idioma. Reuso B26 masivo en cam/dobby/jacquard.
  · Verificado JSON válido en los 6; keys presentes en los 6; 0 leftovers Title Case.
  · Falta §7.2: **3 sections** (core-knitting, loom-accessories-fields, beams-rollers-fields). Luego §7.3-7.5, §8, §9, §10, §11, cabos §1.

- **Bloque 30 [CERRADO]** — 2026-07-20 · Cierra §7.2 (core-knitting/loom-accessories/beams-rollers) + §7.3 types (2)
  1. `sections/core-knitting.blade.php` — Sentence case; reusa `Core specifications`(B28)/`Basic operational…`(B27)/
     `Weaving type`(B26); nuevas `N. bars`/`N. fineness`/`Fabric winder`/`Machine movement`/`Double front`/`Mono front`/
     `Tangencial`/`Loom`/`Elastane`/`Hard` + selects/placeholders.
  2. `sections/loom-accessories-fields.blade.php` — Sentence case (`Loom accessories & feeders`, `Quantity frames/healds/
     of colors/weft-feeders/droppers`); nueva `Only for CAM and Dobby movements`.
  3. `sections/beams-rollers-fields.blade.php` — Sentence case (`Beams, flanges & rollers`, `Includes cloth roller?`,
     `Quantity rollers`, `Big batcher included?`, `Qty. lower/upper beams`, `Lower/Upper flange diam.`).
  4. `types/knitting-form.blade.php` — solo `@include`/`<x-…>` de sections; **sin texto propio.**
  5. `types/weaving-form.blade.php` — íd; **sin texto propio.**
  · **Keys nuevas (36 en los 6 JSON, 0 dups).** `e.g. …` localizado. Labels cortos/abreviados propios de estos sections
    (N. bars, Qty. lower beams) → keys nuevas distintas de los attrs largos B26. Reuso B26/B27/B28 donde el texto coincide.
  · Verificado JSON válido en los 6; keys presentes en los 6; 0 leftovers Title Case.
  · **✅ §7.2 sections COMPLETO (16/16).** §7.3: falta `other-form`(0) e `image`(0,🔍). Luego §7.4 (form-wizard, carousel),
    §7.5 traits, §8, §9, §10, §11, cabos §1.

- **Bloque 31 [CERRADO]** — 2026-07-20 · §7.3 types/image + §7.4 form-wizard/carousel + §7.5 trait (5 archivos)
  1. `types/other-form.blade.php` — solo `<x-…>` de sections; **sin texto propio.**
  2. `used-machine/image.blade.php` — componente imagen; `alt` viene de prop (no literal); **sin texto propio.**
  3. `components/form-wizard.blade.php` — stepper base; `$step->label`/`$step->icon` dinámicos; **sin texto propio.**
  4. `components/used-machines-carousel.blade.php` — carrusel guest; reusa B22 `Check out our offer`+`of second-hand machinery`,
     B19 subtitle/`Sold`/`Available`, `N/A`; `View Details→View details`(B18); nueva `No used machines available at the moment.`
  5. `Traits/HandlesServiceExceptions.php` (§7.5) — alerts de `guard()` (ya con `__()`): nuevas `Permission denied`,
     `You do not have permission to perform this action.`, `Notice`, `An error occurred. Please try again.`; reusa `Error`.
  · **Keys nuevas (5 en los 6 JSON, 0 dups).** Verificado JSON válido en los 6; keys presentes en los 6.
  · **§7.3 COMPLETO, §7.4 COMPLETO.** Falta §7.5: `WithDynamicSections`(6), `WithRecaptcha`(🔍). Luego §8, §9, §10, §11, cabos §1.

- **Bloque 32 [CERRADO]** — 2026-07-20 · Cierra §7.5 traits + arranque §8 (register/select) (5 archivos)
  1. `Traits/UsedMachine/WithDynamicSections.php` (§7.5) — confirms Swal (`Do you really want to delete this field?`,
     `Do you want to delete this entire section?`); reusa `Are you sure?`/`Yes, delete`/`Cancel`.
  2. `Traits/Captcha/WithRecaptcha.php` (§7.5) — **sin cambios**: `abort(403,'captcha required'/'invalid captcha')` FUERA DE
     SCOPE (quedan en inglés, decisión abort correction) + `Log::debug` técnicos.
  3. `ticket/create/steps/register-step-form.blade.php` (§8) — Sentence case (`User Information→User information`,
     `Confirm Password→Confirm password`, `Company Information/Name→` reusa B3); reusa Name/Email/Phone/Company position/
     Password/Country/City/Enter company name/Enter country/Continue; nuevas labels/placeholders/req password/Processing…
  4. `ticket/create/steps/select-action-step-form.blade.php` (§8) — `Choose Your Action→Choose your action`; cards
     `Purchase`/`Sale`/`Option`/`Select` + descripciones (typo "sale" se deja).
  5. `Ticket/Create/Steps/RegisterStepForm.php` (§8) — alerts crear cuenta (reusa Success/Error + msgs password.regex/
     not_regex B3); stepInfo `Register`; nuevas `Your account has been created successfully.`/`There was an error…`/
     `Create a new account and company information`. `Log::error` en inglés.
  · **Keys nuevas (28 en; 26-27 en es/fr/it/pt/zh)** en los 6 JSON. Algunas (Register/Select/Sale/Purchase) ya existían como
    defaults vendor en es/fr/it/pt/zh → solo en/es. 0 duplicados. (Los JSON no-EN pasaron de 1000 keys.)
  · Verificado JSON válido en los 6; keys presentes en los 6; 0 leftovers Title Case.
  · **✅ §7 COMPLETO (7.1-7.5).** Falta §8: `SelectActionStepForm.php`(2). Luego §9 (owner), §10 (notificaciones 12), §11, cabos §1.

- **Bloque 33 [CERRADO]** — 2026-07-20 · Cierra §8 + §9 + arranque §10 bell (5 archivos)
  1. `SelectActionStepForm.php` (§8) — stepInfo `select action→Select action`; nueva `Selection the action`. **✅ §8 COMPLETO.**
  2. `owner/owner-quick-create-form.blade.php` (§9) — `New Owner→New owner`, `Save Owner→Save owner`,
     `Additional Information→Additional information` (**dedup: borrada key Title huérfana** de los 6 JSON); reusa Name/Country/
     Phone/Email/Saving...; `@js(__('Select owner'))` ya en B28.
  3. `Owner/OwnerQuickCreateForm.php` (§9) — abort permiso `You do not have permission to perform this action.`(B31);
     alert `Owner Created Successfully→Owner created successfully` + `The owner has been added and selected.`. **✅ §9 COMPLETO.**
  4. `notifications/notification-bell.blade.php` (§10) — **sin cambios**: todo ya con `__()` y keys existentes
     (Notifications, New, Mark all as read, Delete all notifications?…, Delete all, Notification, Unread, Delete, No notifications).
  5. `Notifications/NotificationBell.php` (§10) — **sin cambios**: alerts ya con `__()` y keys existentes
     (Could not mark/delete notification(s)…); `Log::error` en inglés.
  · **Keys nuevas (6 en los 6 JSON) + 1 dedup borrada (`Additional Information` Title).** Verificado JSON válido en los 6.
  · **✅ §8 + §9 COMPLETOS; §10 bell (2/12) hecho.** Falta §10: `BaseTicketNotification` + 9 notifs (New*/Approved/Corrected/
    Returned Purchase/Sale/UsedMachineRequest). Luego §11 (guest auth-nav + contacto máquina), cabos §1 (guest/auth/captcha).

- **Bloque 34 [CERRADO]** — 2026-07-20 · §10 Notificaciones (base + 4 notifs)
  1. `BaseTicketNotification.php` — clase abstracta (via/toDatabase, métodos abstractos title/message/url/icon); **sin texto de usuario.**
  2. `NewPurchaseTicketNotification.php` — `New purchase ticket` + `:name submitted a new purchase ticket.` (nuevas).
  3. `NewSaleTicketNotification.php` — `New sale ticket` + `:name submitted a new sale ticket.` (nuevas).
  4. `NewUsedMachineRequestNotification.php` — `New machine request` + msg :name; **keys ya existían, sin cambios.**
  5. `PurchaseTicketApprovedNotification.php` — `Purchase ticket approved` + msg #:id; **keys ya existían, sin cambios.**
  · **Keys nuevas (4 en los 6 JSON, 0 dups).** Todo el texto ya venía con `__()` + placeholders. Verificado JSON válido en los 6.
  · Falta §10: `PurchaseTicketCorrected/Returned`, `SaleTicketApproved/Corrected/Returned` (5 notifs). Luego §11, cabos §1.

- **Bloque 35 [CERRADO]** — 2026-07-20 · §10 notifs restantes (5) → **CIERRA §10**
  1. `PurchaseTicketCorrectedNotification.php` — `Purchase ticket corrected` + `Purchase ticket #:id was corrected…` (nuevas).
  2. `PurchaseTicketReturnedNotification.php` — `Ticket returned for correction` + `Your purchase ticket #:id was returned…`; **keys ya existían.**
  3. `SaleTicketApprovedNotification.php` — `Sale ticket approved` + msg #:id; **keys ya existían, sin cambios.**
  4. `SaleTicketCorrectedNotification.php` — `Sale ticket corrected` + `Sale ticket #:id was corrected…` (nuevas).
  5. `SaleTicketReturnedNotification.php` — `Ticket returned for correction` (compartida con Purchase) + `Your sale ticket #:id was returned…`; **keys ya existían.**
  · **Keys nuevas (4 en los 6 JSON, 0 dups).** `Ticket returned for correction` compartida Purchase/Sale (1 key, reutilizada).
  · Verificado JSON válido en los 6.
  · **✅✅ §10 NOTIFICACIONES CAMPANITA 100% COMPLETO** (bell + base + 9 notifs). Falta: §11 (guest auth-nav + contacto máquina),
    cabos §1 (guest/general/navbar/footer/preview-admin, auth, captcha). Y §3 CustomerController (🔍 verificar).

- **Bloque 36 [CERRADO]** — 2026-07-20 · §11 guest COMPLETO + arranque cabos §1 (guest/general) (5 archivos)
  1. `Guest/AuthNavLink.php` — solo re-render por evento `user-logged-in`; **sin texto de usuario.**
  2. `guest/auth-nav-link.blade.php` — `My profile`/`Login` ya normalizados en B1; **sin cambios.**
  3. `ContactForm/ContactUsedMachinePost.php` — alerts `Success`/`Error` (existen) + `messages.success-email`/`error-email`
     (namespace `messages.*` preexistente, NO se migra); `Log::error` en inglés. **Sin keys nuevas.**
  4. `contact-form/contact-used-machine-post.blade.php` — placeholders/botón usan `messages.*` (preexistente). **Sin cambios.**
  5. `layouts/guest/general.blade.php` (§1) — shell guest; TODO el contenido ya con `messages.*`/`nationality.*` (preexistente);
     único texto suelto: alts de logo `Image Logo`/`Image Logo White` → envueltos como `Company logo` (1 key nueva, mejora a11y).
  · **Keys nuevas (1 en los 6 JSON: `Company logo`).** Verificado JSON válido en los 6.
  · **✅✅ §11 GUEST COMPLETO.** Nota: guest de máquinas usadas ya cubierto por §6.1 (customer/index+show) reutilizado por
    `FrontendUsedMachineController`. Falta §1 cabos: `guest/navbar`, `guest/footer`, `guest/preview-admin`, `auth/auth`, `partials/captcha`.
    Y §3 `CustomerController` (🔍). **Casi cierra TODO el checklist.**

- **Bloque 37 [CERRADO]** — 2026-07-20 · Cabos §1 guest/auth/captcha + §3 CustomerController → **CIERRA EL CHECKLIST**
  1. `layouts/guest/navbar.blade.php` — todo `messages.*` + nombres dinámicos de categorías; **sin texto suelto.**
  2. `layouts/guest/footer.blade.php` — `messages.*`/`nationality.*`; alt `Image Catalogue`→`Catalogue` (1 key).
  3. `layouts/guest/preview-admin.blade.php` — banner `SANDBOX / PREVIEW MODE…` envuelto (1 key); resto `messages.*`/includes.
  4. `layouts/auth/auth.blade.php` — solo `<title>ITG Group - Auth`/alt de marca; **sin texto de usuario a traducir.**
  5. `layouts/partials/captcha.blade.php` — solo `<script>` reCAPTCHA (JS); **sin texto de usuario.**
  · `app/Http/Controllers/CustomerController.php` — **stub vacío**, sin texto (verificado, 6º archivo del cierre).
  · **Keys nuevas (2 en los 6 JSON: `Catalogue`, `SANDBOX / PREVIEW MODE - This record is NOT necessarily published`).**
  · **Nota:** los guest layouts (§1) usan el namespace `messages.*` (`lang/*/messages.php`), NO JSON `__()`; su contenido ya
    estaba traducido ahí. Solo se envolvieron los textos sueltos en inglés.
  · Barrido final: 0 leftovers Title Case (2+ palabras) en todo el módulo. JSON válido en los 6 (en:801, es:820, fr/it/pt/zh:~1018).

═══════════════════════════════════════════════════════════════════════════════════════════════════════
## ✅✅✅ CHECKLIST COMPLETO — 185/185 archivos (§1–§11), 0 pendientes.
Todos los módulos migrados a `__()` (Sentence case, key inglés + 6 JSON): §1 layouts/shell, §2 dashboard, §3 users/profile,
§4 Purchase, §5 Sale, §6 Sale Used Machine, §7 componentes compartidos, §8 flujo genérico, §9 owner, §10 notificaciones,
§11 guest. **Correos §12 quedan en inglés por decisión de negocio (NO migrar).**
═══════════════════════════════════════════════════════════════════════════════════════════════════════

<!-- Ejemplo de cómo se irá registrando:
- **Bloque N [CERRADO]** — fecha · tema
  1. ... 2. ... 3. ... 4. ... 5. ...
  Keys nuevas: X · Reutilizadas: Y · Duplicadas borradas: Z
-->

---

## Convenciones de estado

- `❌ PENDIENTE (0)` — sin ninguna traducción, hay que hacerlo entero.
- `🔶 COMPLETAR (N)` — ya tiene N `__()`; **revisar** que no queden cadenas hardcodeadas.
- `🔍 VERIFICAR` — archivo de lógica; confirmar si realmente emite texto de usuario.
- `🚫 NO TRADUCIR` — queda en inglés por decisión de negocio (correos EmailTicket/Mailable) o
  por regla (mensajes de `Log::*` y excepciones solo logueadas → siempre en inglés).

> El número `(N)` es el conteo actual de `__(` / `@lang(` / `trans(` — es orientativo, NO garantiza
> que el archivo esté 100% cubierto. Siempre revisar el archivo completo.

---

## 0. Reglas clave (recordatorio de CLAUDE.md)

- Todo texto que ve el usuario → `__('...')` (labels, placeholders, botones, títulos, tooltips,
  options de select, sweet alerts `$this->alert()`/`notify()`, flash, validaciones, notificaciones
  campanita, excepciones que se muestran).
- **`abort(403/404, ...)` y `abort_unless(...)` de PERMISOS SÍ se traducen** → su `getMessage()` se muestra
  al usuario (flash/alert vía guard/try-catch `HttpException`, o página de error). Ej.:
  `abort_unless($can, 403, __('Unauthorized to ...'))`. **Solo quedan en inglés los `Log::*` y las
  excepciones puramente técnicas que NO se muestran** (p.ej. `throw new Exception("Invalid status value: ...")`
  que el controller solo loguea).
- **NO traducir:** `Log::info/warning/error/debug`, excepciones solo logueadas, y **correos**
  (`Mail`/`Mailable` + `app/Services/EmailTicket/**`) → quedan EN INGLÉS.

> **⚙️ Corrección aborts (2026-07-20):** durante B3/B4/B9 se dejaron algunos `abort(403,'Unauthorized...')`
> en inglés por una nota vieja ("guard técnico"). **Regla corregida por el usuario:** los aborts de permisos
> los ve el usuario → traducir. Ya envueltos + 5 keys en los 6 JSON:
> `PurchaseTicketCreateCommentForm`, `PurchaseTicketKanban`, `EditUser`, `SaleTicketCreateCommentForm`,
> `SaleTicketKanban`. (Fuera de scope: `abort(404)` de Product/Home guest y captcha `WithRecaptcha` §7.5.)
- Blade: `{{ __('...') }}`; en `<script>` inline: `@js(__('...'))`; interpolar con placeholders
  `__('Ticket #:id', ['id'=>$x])`, nunca concatenar. No doble-envolver, no tocar keys de
  arrays/enums/rutas/iconos/clases CSS/`wire:`/formatos de fecha/IDs.

---

## 0.1 Verificación contra `routes/web.php` (cross-check)

Todos los controllers referenciados por rutas del módulo están inventariados en este doc:

| Rutas (`web.php`) | Controller | Sección |
|---|---|---|
| `/dashboard-admin`, `/dashboard-welcome` | Dashboards\* | 2 |
| `/users`, `/users/{id}/detail` | UserController | 3 |
| `/profile` | ProfileController | 3 |
| `sale-tickets*`, kanban, archived, drafts, observations, customer | SaleTicket\* (6 controllers) | 5.4 |
| `purchase-tickets*`, kanban, archived, drafts, observations, customer | PurchaseTicket\* (6 controllers) | 4.4 |
| `/sale-used-machines*` (staff) | SaleUsedMachineController | 6.4 |
| `/used-machines-for-sale*` (**guest, en scope**) | FrontendUsedMachineController → reusa blades `sale-used-machine/customer/*` | 6.1 / 6.4 |
| `/used-machine-request/*` | UsedMachineRequestController | 6.4 |
| `/machinery*` (**guest preexistente**) | MachineryController | ⛔ FUERA DE SCOPE (§11) |
| `/`, `/about`, `/contact`, `/partners`, `/sitemap`, `/products`, `/blogs`, `auth.php` | Guest\*/Product/Blog/Auth | ⛔ FUERA DE SCOPE (ya traducidos) |

## 1. LAYOUTS / NAVBAR / SIDEBAR / SHELL (staff + guest + tickets)

- [x] ✅ `resources/views/layouts/users/main.blade.php` — shell admin (sin texto de usuario) · **Bloque 1**
- [x] ✅ `resources/views/layouts/users/nav-bar-app.blade.php` — navbar top staff · **Bloque 1**
- [x] ✅ `resources/views/layouts/users/nav-sidebar.blade.php` — sidebar staff (usa `__()` sobre labels de SidebarService) · **Bloque 1**
- [x] ✅ `app/Services/SidebarService.php` — **fuente de las 13 etiquetas del sidebar** (keys en inglés) · **Bloque 1**
- [x] ✅ `resources/views/layouts/purchase-and-sale/form-navbar.blade.php` — navbar de formularios ticket · **Bloque 1**
- [x] ✅ `resources/views/layouts/purchase-and-sale/general-form-tickets.blade.php` — layout forms ticket (sin texto) · **Bloque 1**
- [x] ✅ `resources/views/layouts/guest/general.blade.php` — contenido con `messages.*`/`nationality.*` (preexistente); alts de logo→`Company logo` (1 key) · **Bloque 36**
- [x] ✅ `resources/views/layouts/guest/navbar.blade.php` — todo `messages.*` + nombres dinámicos; sin texto suelto · **Bloque 37**
- [x] ✅ `resources/views/layouts/guest/footer.blade.php` — `messages.*`/`nationality.*`; alt catálogo→`Catalogue` · **Bloque 37**
- [x] ✅ `resources/views/layouts/guest/preview-admin.blade.php` — banner SANDBOX envuelto; resto `messages.*`/includes · **Bloque 37**
- [x] ✅ `resources/views/layouts/auth/auth.blade.php` — solo `<title>`/alt de marca (ITG Group); sin texto de usuario a traducir · **Bloque 37**
- [x] ✅ `resources/views/layouts/partials/captcha.blade.php` — solo `<script>` de reCAPTCHA (JS); sin texto de usuario · **Bloque 37**

## 2. DASHBOARD STAFF

- [x] ✅ `resources/views/dashboard/dashboard-admin.blade.php` — normalizado Sentence case · **Bloque 2**
- [x] ✅ `resources/views/dashboard/welcome-dashboard.blade.php` · **Bloque 2**
- [x] ✅ `app/Http/Controllers/Dashboards/DashboardAdminController.php` (SEO) · **Bloque 2**
- [x] ✅ `app/Http/Controllers/Dashboards/WelComeDashboardController.php` (SEO) · **Bloque 2**

## 3. USERS / PROFILE / CUSTOMERS (staff dashboard)

- [x] ✅ `resources/views/users/user-detail.blade.php` — Sentence case + reusa keys B3 · **Bloque 4**
- [x] ✅ `resources/views/users/user-table.blade.php` — `Users Table→Users table` · **Bloque 4**
- [x] ✅ `resources/views/profile/profile.blade.php` — sin texto propio (delega en componentes) · **Bloque 2**
- [x] ✅ `resources/views/components/user-profile-layout.blade.php` — Sentence case · **Bloque 3**
- [x] ✅ `resources/views/livewire/profile/update-profile-information-form.blade.php` (Volt) · **Bloque 3**
- [x] ✅ `resources/views/livewire/profile/update-password-form.blade.php` (Volt; +2 msgs validación envueltos) · **Bloque 3**
- [x] ✅ `app/Http/Controllers/UserController.php` (SEO + breadcrumb) · **Bloque 3**
- [x] ✅ `app/Http/Controllers/ProfileController.php` (SEO; abort 403 queda en inglés) · **Bloque 3**
- [x] ✅ `app/Http/Controllers/CustomerController.php` — stub vacío (`//`); sin texto de usuario · **Bloque 37**
- [x] ✅ `app/Livewire/Tables/UserTable.php` — columnas/filtros/acciones PowerGrid envueltos · **Bloque 4**
- [x] ✅ `app/Livewire/User/CreateUser.php` (+ `livewire/user/create-user.blade.php`) · **Bloque 4**
- [x] ✅ `app/Livewire/User/EditUser.php` (+ `livewire/user/edit-user.blade.php`) · **Bloque 4**
  - _Nota:_ `validationAttributes()` (labels minúscula) y `abort(403,...)` quedan **en inglés** (attrs de validación + guard técnico).

---

## 4. PURCHASE TICKET

### 4.1 Blades — admin / customer / drafts / archived / observations
- [x] ✅ `resources/views/purchase-ticket/admin/edit.blade.php` — Sentence case + Swal confirms · **Bloque 7**
- [x] ✅ `resources/views/purchase-ticket/admin/show.blade.php` — Sentence case; reusa B4/B5/B6 · **Bloque 7**
- [x] ✅ `resources/views/purchase-ticket/admin/index.blade.php` — `Purchase Ticket→Purchase ticket` (reusa B1) · **Bloque 7**
- [x] ✅ `resources/views/purchase-ticket/admin/kanban.blade.php` — `Purchase Tickets→Purchase tickets` (reusa B1) · **Bloque 7**
- [x] ✅ `resources/views/purchase-ticket/archived/index.blade.php` — `Purchase ticket archived→Archived tickets` (reusa B5) · **Bloque 7**
- [x] ✅ `resources/views/purchase-ticket/customer/create.blade.php` — Sentence case + Swal (drafts) · **Bloque 8**
- [x] ✅ `resources/views/purchase-ticket/customer/edit.blade.php` — Sentence case + Swal (return corrected); reusa B7 `Ticket #:id` · **Bloque 8**
- [x] ✅ `resources/views/purchase-ticket/customer/index.blade.php` — `Purchase Ticket→Purchase ticket` (reusa B1) · **Bloque 8**
- [x] ✅ `resources/views/purchase-ticket/drafts/edit.blade.php` — Sentence case + Swal; reusa B5/B7 · **Bloque 8**
- [x] ✅ `resources/views/purchase-ticket/observations/create.blade.php` — ya con `__()`; solo keys · **Bloque 8**
- [x] ✅ `resources/views/purchase-ticket/partials/_observations-list.blade.php` — Swal mark-as-answered + metadata · **Bloque 9**

### 4.2 Blades Livewire
- [x] ✅ `resources/views/livewire/purchase-ticket/create/steps/purchase-ticket-step-form.blade.php` — wizard create · **Bloque 10**
- [x] ✅ `resources/views/livewire/purchase-ticket/edit/purchase-ticket-edit-form.blade.php` — edit form; reusa B3 `Save changes` · **Bloque 10**
- [x] ✅ `resources/views/livewire/purchase-ticket/kanban/purchase-ticket-kanban.blade.php` — reusa B6 `View/Edit ticket`, `Confirm` · **Bloque 10**
- [x] ✅ `resources/views/livewire/purchase-ticket/team-comment/purchase-ticket-comment-list.blade.php` — empty state · **Bloque 9**
- [x] ✅ `resources/views/livewire/purchase-ticket/team-comment/purchase-ticket-create-comment-form.blade.php` — `Add Comment→Add comment` + labels · **Bloque 9**

### 4.3 Livewire (clases PHP)
- [x] ✅ `app/Livewire/PurchaseTicket/Create/PurchaseTicketCreateForm.php` — sin texto de usuario (wizard shell) · **Bloque 11**
- [x] ✅ `app/Livewire/PurchaseTicket/Create/Steps/PurchaseTicketStepForm.php` — `Purchase Form→Purchase form` (B1) + flashes · **Bloque 10**
- [x] ✅ `app/Livewire/PurchaseTicket/Edit/PurchaseTicketEditForm.php` — abort update + alert (ya con `__()`); solo keys · **Bloque 11**
- [x] ✅ `app/Livewire/PurchaseTicket/Kanban/PurchaseTicketKanban.php` — Swal reject/confirm/archive + abort permiso · **Bloque 10**
- [x] ✅ `app/Livewire/PurchaseTicket/TeamComment/PurchaseTicketCommentList.php` — sin texto de usuario · **Bloque 9**
- [x] ✅ `app/Livewire/PurchaseTicket/TeamComment/PurchaseTicketCreateCommentForm.php` — alerts save/error (abort 403 en inglés) · **Bloque 9**

### 4.4 Controllers
- [x] ✅ `app/Http/Controllers/PurchaseTicket/PurchaseTicketController.php` — Sentence case + reusa keys B1 (Purchase tickets/list/kanban) · **Bloque 5**
- [x] ✅ `app/Http/Controllers/PurchaseTicket/PurchaseTicketArchivedController.php` · **Bloque 5**
- [x] ✅ `app/Http/Controllers/PurchaseTicket/PurchaseTicketCustomerController.php` · **Bloque 5**
- [x] ✅ `app/Http/Controllers/PurchaseTicket/PurchaseTicketDraftController.php` · **Bloque 5**
- [x] ✅ `app/Http/Controllers/PurchaseTicket/PurchaseTicketKanbanController.php` — `Purchase Tickets Kanban→Purchase ticket kanban` (reusa B1) · **Bloque 5**
- [x] ✅ `app/Http/Controllers/PurchaseTicket/PurchaseTicketObservationController.php` — alerts store/finish; reusa B5 · **Bloque 6**

### 4.5 Tablas PowerGrid
- [x] ✅ `app/Livewire/Tables/PurchaseTicketTable.php` — columnas/action envueltas + `Not purchased` + `show details→Show details` · **Bloque 6**
- [x] ✅ `app/Livewire/Tables/PurchaseTicketCustomerTable.php` — columnas/action envueltas (`Ticket Id→Ticket ID`) · **Bloque 6**
- [x] ✅ `app/Livewire/Tables/PurchaseTicketArchivedTable.php` — columnas/action envueltas + `show details→Show details` · **Bloque 6**

### 4.6 Service / Policy / Model
- [x] ✅ `app/Services/PurchaseTicket/PurchaseTicketService.php` — aborts 403/404 (ya con `__()`); solo keys en JSON · **Bloque 6**
- [x] ✅ `app/Policies/PurchaseTicketPolicy.php` — sin texto de usuario (solo bool, sin `deny()` con mensaje) · **Bloque 11**
- [x] ✅ `app/Models/PurchaseTicket.php` — sin texto de usuario (casts/relaciones) · **Bloque 11**

---

## 5. SALE TICKET

### 5.1 Blades — admin / customer / drafts / archived / observations
- [x] ✅ `resources/views/sale-ticket/admin/index.blade.php` — `Sales Ticket→Sales ticket` (B1) · **Bloque 14**
- [x] ✅ `resources/views/sale-ticket/admin/kanban.blade.php` — ya usaba `Sales tickets` (B2) · **Bloque 14**
- [x] ✅ `resources/views/sale-ticket/archived/index.blade.php` — `Sales ticket archived→Archived tickets` (B5) · **Bloque 14**
- [x] ✅ `resources/views/sale-ticket/customer/create.blade.php` — espejo B8; solo normalizó Active/Empty drafts · **Bloque 14**
- [x] ✅ `resources/views/sale-ticket/customer/edit.blade.php` — espejo B8 + sección Multimedia (2 keys nuevas) · **Bloque 14**
- [x] ✅ `resources/views/sale-ticket/customer/index.blade.php` — `Sales Ticket→Sales ticket` (B1) · **Bloque 15**
- [x] ✅ `resources/views/sale-ticket/drafts/edit.blade.php` — espejo B8; usa flujo unificado Sale Used Machine edit-form · **Bloque 15**
- [x] ✅ `resources/views/sale-ticket/observations/create.blade.php` — `New observation` + reusa B9 · **Bloque 15**
- [x] ✅ `resources/views/sale-ticket/partials/_observations_list.blade.php` — Swal + metadata; reusa B9 · **Bloque 15**

> Nota: `sale-ticket` NO tiene `admin/edit.blade.php` ni `admin/show.blade.php` propios: usa el
> flujo unificado de **Sale Used Machine** (ver memoria `sale-machine-single-source-refactor`).

### 5.2 Blades Livewire
- [x] ✅ `resources/views/livewire/sale-ticket/edit/sections/sale-ticket-photo-list.blade.php` — `alt` + empty state · **Bloque 17**
- [x] ✅ `resources/views/livewire/sale-ticket/edit/sections/sale-ticket-video-list.blade.php` — empty state + fallback video · **Bloque 17**
- [x] ✅ `resources/views/livewire/sale-ticket/kanban/sale-ticket-kanban.blade.php` — reusa B6/B10; nuevas View machine ticket/Request table · **Bloque 15**
- [x] ✅ `resources/views/livewire/sale-ticket/team-comment/sale-ticket-comment-list.blade.php` — espejo B9, todo reusado · **Bloque 16**
- [x] ✅ `resources/views/livewire/sale-ticket/team-comment/sale-ticket-create-comment-form.blade.php` — `Add Comment→Add comment` (B9) · **Bloque 16**

### 5.3 Livewire (clases PHP)
- [x] ✅ `app/Livewire/SaleTicket/Edit/Sections/SaleTicketPhotoList.php` — Swal delete photo + alerts · **Bloque 17**
- [x] ✅ `app/Livewire/SaleTicket/Edit/Sections/SaleTicketVideoList.php` — Swal delete video + alerts · **Bloque 17**
- [x] ✅ `app/Livewire/SaleTicket/Kanban/SaleTicketKanban.php` — Swal reject/confirm/archive/move; nuevas `This ticket cannot be moved...`/`Used machine created`/`Used machine for Ticket #:id...` · **Bloque 16**
- [x] ✅ `app/Livewire/SaleTicket/TeamComment/SaleTicketCommentList.php` — sin texto de usuario · **Bloque 16**
- [x] ✅ `app/Livewire/SaleTicket/TeamComment/SaleTicketCreateCommentForm.php` — alerts (ya con `__()`); abort permiso traducido · **Bloque 16**

### 5.4 Controllers
- [x] ✅ `app/Http/Controllers/SaleTicket/SaleTicketController.php` — `Sales Tickets→Sales tickets`(B2), `Ticket not found!→Ticket not found.`(B6, dedup) · **Bloque 11**
- [x] ✅ `app/Http/Controllers/SaleTicket/SaleTicketArchivedController.php` — `Archived Tickets→Archived tickets` (reusa B5) · **Bloque 12**
- [x] ✅ `app/Http/Controllers/SaleTicket/SaleTicketCustomerController.php` — Sentence case; reusa B5; nuevas `Create a new ticket for sale.`/`Edit sale ticket`/`My sale requests` · **Bloque 12**
- [x] ✅ `app/Http/Controllers/SaleTicket/SaleTicketDraftController.php` — `Edit Draft Ticket→Edit draft ticket` (reusa B5); nueva desc draft · **Bloque 12**
- [x] ✅ `app/Http/Controllers/SaleTicket/SaleTicketKanbanController.php` — `Kanban Tickets→Sales ticket kanban` (reusa B1) · **Bloque 12**
- [x] ✅ `app/Http/Controllers/SaleTicket/SaleTicketObservationController.php` — ya con `__()`; reusa B5/B9 · **Bloque 12**

### 5.5 Tablas PowerGrid
- [x] ✅ `app/Livewire/Tables/SaleTicketTable.php` — columnas/action envueltas + `Not approved` + `Owner name` · **Bloque 13**
- [x] ✅ `app/Livewire/Tables/SaleTicketCustomerTable.php` — columnas/action envueltas · **Bloque 13**
- [x] ✅ `app/Livewire/Tables/SaleTicketArchivedTable.php` — columnas/action envueltas (`User Name→User name`) · **Bloque 13**

### 5.6 Services / Policy / Model
- [x] ✅ `app/Services/SaleTicket/SaleTicketService.php` — aborts permiso (ya con `__()`); nuevas create/edit sales + stage · **Bloque 13**
- [x] ✅ `app/Services/SaleTicket/SaleFormService.php` — abort permiso (reusa key create sales) · **Bloque 13**
- [x] ✅ `app/Policies/SaleTicketPolicy.php` — sin texto de usuario (solo bool) · **Bloque 17**
- [x] ✅ `app/Models/SaleTicket.php` — sin texto de usuario (casts/relaciones/helpers) · **Bloque 17**

---

## 6. SALE USED MACHINE (staff/customer) + USED MACHINE REQUEST

### 6.1 Blades — admin / customer / request
- [x] ✅ `resources/views/sale-used-machine/admin/edit.blade.php` — Sentence case + Swal; concatenaciones→placeholders · **Bloque 19**
- [x] ✅ `resources/views/sale-used-machine/admin/show.blade.php` — Sentence case; alts envueltos; dedup video · **Bloque 19**
- [x] ✅ `resources/views/sale-used-machine/admin/index.blade.php` — `Sale used machine` (reusa B1); sin cambios · **Bloque 19**
- [x] ✅ `resources/views/sale-used-machine/customer/index.blade.php` — guest marketing Sentence case + keys · **Bloque 19**
- [x] ✅ `resources/views/sale-used-machine/customer/show.blade.php` — guest detail Sentence case; dedup video · **Bloque 19**
- [x] ✅ `resources/views/sale-used-machine/request/index.blade.php` — `Used machine requests` (reusa B18); sin cambios · **Bloque 20**
- [x] ✅ `resources/views/sale-used-machine/request/show.blade.php` — reusa Name/Email/Phone/Country/Created at/Last updated; nuevas Division/Requested machine/Message/Used machine request · **Bloque 20**

### 6.2 Blades Livewire (wizard create / edit / media / filter)
- [x] ✅ `resources/views/livewire/sale-used-machine/create/steps/machine-type-step-form.blade.php` — normalizó a keys existentes (Machine type selection, Weaving/Warp knitting/Other machine); nueva `Next` · **Bloque 20**
- [x] ✅ `resources/views/livewire/sale-used-machine/create/steps/media-step-form.blade.php` — reusa Save and add another machine/Send all loaded machines/Saving.../Sending...; nuevas Machine images/video + límites · **Bloque 20**
- [x] ✅ `resources/views/livewire/sale-used-machine/create/steps/used-machine-intake-step-form.blade.php` — reusa Please review the form/Back/Saving...; nuevas `Unknown form type.`/`Continue` · **Bloque 20**
- [x] ✅ `resources/views/livewire/sale-used-machine/partials/used-machine-customer-wizard-steps.blade.php` — steps General/Specifications/Pricing/Media; `Save All→Save all`; reusa Back/Next/Saving.../Please review the form/Unknown form type. · **Bloque 21**
- [x] ✅ `resources/views/livewire/sale-used-machine/partials/used-machine-staff-wizard-steps.blade.php` — `Save Specs→Save specs`; reusa lock-status(:status)/Back/Next · **Bloque 21**
- [x] ✅ `resources/views/livewire/sale-used-machine/used-machine-create-form.blade.php` — `Create New Used Machine→Create new used machine`, `Create Machine→Create machine`; reusa Cancel/Back/Next · **Bloque 21**
- [x] ✅ `resources/views/livewire/sale-used-machine/used-machine-edit-form.blade.php` — solo `@include` staff-wizard-steps; sin texto propio · **Bloque 21**
- [x] ✅ `resources/views/livewire/sale-used-machine/used-machine-edit-form-customer.blade.php` — Sentence case (Draft setup/Control panel/Ticket details/Machine media/Machine photos & video/Upload new content/Gallery images/Machine video); nueva `Save media` · **Bloque 21**
- [x] ✅ `resources/views/livewire/sale-used-machine/used-machine-edit-media-form.blade.php` — Sentence case + alts envueltos; reusa Machine gallery/Gallery images/Machine media/Machine video/Save changes/Cancel · **Bloque 22**
- [x] ✅ `resources/views/livewire/sale-used-machine/used-machine-edit-promo-flyer-form.blade.php` — Sentence case + alt; reusa Promotional flyer/Save changes/Cancel · **Bloque 22**
- [x] ✅ `resources/views/livewire/sale-used-machine/used-machine-filter.blade.php` — guest filtro; Sentence case (Search brand or model/All brands/All types/View details) + keys · **Bloque 22**

### 6.3 Livewire (clases PHP)
- [x] ✅ `app/Livewire/SaleUsedMachine/Create/CreateUsedMachineWizard.php` — wizard shell (steps/slugs); sin texto de usuario · **Bloque 23**
- [x] ✅ `app/Livewire/SaleUsedMachine/Create/Steps/MachineTypeStepForm.php` — stepInfo label `machine type→Machine type`; nueva desc select · **Bloque 22**
- [x] ✅ `app/Livewire/SaleUsedMachine/Create/Steps/MediaStepForm.php` — flashes/abort/alerts + stepInfo (reusa Media/Warning/Machines submitted successfully!); excepciones técnicas en inglés · **Bloque 22**
- [x] ✅ `app/Livewire/SaleUsedMachine/Create/Steps/UsedMachineIntakeStepForm.php` — title concat→placeholder `Machine form - :type`; stepInfo `Machine form` + desc; alert (reusa Success) · **Bloque 23**
- [x] ✅ `app/Livewire/SaleUsedMachine/UsedMachineCreateForm.php` — alerts create (reusa Error); nuevas `Used machine created successfully.`/`The machine has been registered…`/error crear · **Bloque 23**
- [x] ✅ `app/Livewire/SaleUsedMachine/UsedMachineEditForm.php` — abort locked/update (reusa B11); alert (reusa Success); nuevas `This machine can no longer be edited.`/`Machine updated successfully.` · **Bloque 23**
- [x] ✅ `app/Livewire/SaleUsedMachine/UsedMachineEditMediaForm.php` — alerts main/delete/save (reusa Success/Error/Are you sure?/Yes, delete/Cancel); dedup `Media deleted successfully.` (B17) · **Bloque 23**
- [x] ✅ `app/Livewire/SaleUsedMachine/UsedMachineEditPromoFlyerForm.php` — alerts delete/upload flyer (reusa Are you sure?/Yes, delete it/Cancel/Success/Error); 5 keys nuevas · **Bloque 24**
- [x] ✅ `app/Livewire/SaleUsedMachine/UsedMachineFilter.php` — solo query/paginación; sin texto de usuario · **Bloque 24**
- [x] ✅ `app/Livewire/Forms/UsedMachineForm.php` — Form object; `validationAttributes()` delega en `MachineValidationRules` (§6.7); sin texto propio · **Bloque 24**

### 6.4 Controllers
- [x] ✅ `app/Http/Controllers/SaleUsedMachine/SaleUsedMachineController.php` — SEO/breadcrumbs Sentence case + concatenaciones→placeholders · **Bloque 18**
- [x] ✅ `app/Http/Controllers/SaleUsedMachine/FrontendUsedMachineController.php` — SEO guest (ya con `__()`) · **Bloque 18**
- [x] ✅ `app/Http/Controllers/UsedMachineRequestController.php` — SEO/breadcrumbs Sentence case · **Bloque 18**

### 6.5 Tablas PowerGrid
- [x] ✅ `app/Livewire/Tables/SaleUsedMachineTable.php` — columnas/action + header slot `Add new machine` + `Unsold` · **Bloque 18**
- [x] ✅ `app/Livewire/Tables/UsedMachineRequestTable.php` — columnas/action + `show details→Show details` · **Bloque 18**

### 6.6 Services
- [x] ✅ `app/Services/SaleUsedMachinery/CreateSaleUsedMachineryService.php` — abort permiso `You do not have permission to create used machinery.` (nueva); excepciones técnicas en inglés · **Bloque 24**
- [x] ✅ `app/Services/SaleUsedMachinery/MachineMediaService.php` — helper de media (save images/video); sin texto de usuario · **Bloque 24**
- [x] ✅ `app/Services/SaleUsedMachinery/MachinePayloadBuilder.php` — build/parse de payload JSON; sin texto de usuario · **Bloque 25**
- [x] ✅ `app/Services/SaleUsedMachinery/SaleUsedMachineService.php` — saveMachine/processMedia; sin texto de usuario · **Bloque 25**

### 6.7 Rules (validación máquina usada — texto de usuario)
- [x] ✅ `app/Rules/UsedMachine/MachineValidationRules.php` — `attributes()` (~53 labels de validación) normalizados Title→Sentence case; reglas sin texto · **Bloque 26**
- [x] ✅ `app/Rules/UsedMachine/MaxTotalImagesRule.php` — mensaje `Limit exceeded…(:existing/:available/:max)` con placeholders · **Bloque 25**

### 6.8 Policy / Model
- [x] ✅ `app/Policies/SaleUsedMachinePolicy.php` — solo retornos bool (viewAny/view); sin texto de usuario · **Bloque 25**
- [x] ✅ `app/Models/SaleUsedMachine.php` — casts/relaciones/helpers; sin texto de usuario · **Bloque 25**
- [x] ✅ `app/Models/UsedMachineRequest.php` — fillable/relaciones; sin texto de usuario · **Bloque 26**

---

## 7. COMPONENTES BLADE COMPARTIDOS (tickets + máquina usada)

### 7.1 `components/tickets`
- [x] ✅ `resources/views/components/tickets/activity-history.blade.php` — empty state `No activity recorded yet.` · **Bloque 27**
- [x] ✅ `resources/views/components/tickets/introduction-create.blade.php` — form ITG Machinery (título/bullets/:email placeholder); alt envuelto · **Bloque 27**

### 7.2 `components/used-machine/sections` (campos dinámicos del wizard)
- [x] ✅ `resources/views/components/used-machine/sections/additional-information.blade.php` — `Additional information`(B19) + Technical info/placeholder · **Bloque 28**
- [x] ✅ `resources/views/components/used-machine/sections/beams-rollers-fields.blade.php` — Sentence case (Beams, flanges & rollers/Qty. lower-upper beams/flange diam./Includes cloth roller?) · **Bloque 30**
- [x] ✅ `resources/views/components/used-machine/sections/cam-details-fields.blade.php` — `CAM specifications`; reusa Cam model(B26); nuevas levers on the loom · **Bloque 29**
- [x] ✅ `resources/views/components/used-machine/sections/core-knitting.blade.php` — Sentence case; reusa Core specifications(B28)/Weaving type(B26); nuevas N. bars/fineness/fabric winder/machine movement · **Bloque 30**
- [x] ✅ `resources/views/components/used-machine/sections/custom-sections.blade.php` — Sentence case (Additional sections/Section title/Add field/Create new section); nuevas Feature/Value/Delete field · **Bloque 29**
- [x] ✅ `resources/views/components/used-machine/sections/decription.blade.php` — `Marketing & web content` + desc + `Additional information (marketing/web)` · **Bloque 28**
- [x] ✅ `resources/views/components/used-machine/sections/dobby-details-fields.blade.php` — `Dobby specifications`; reusa Dobby model(B26); reusa levers on the loom · **Bloque 29**
- [x] ✅ `resources/views/components/used-machine/sections/general-fields.blade.php` — Sentence case (General information/Manufacturing year); reusa Brand/Model/RPM/Quantity + placeholders · **Bloque 27**
- [x] ✅ `resources/views/components/used-machine/sections/jacquard-details-fields.blade.php` — Sentence case; reusa B26 (Jacquard brand/model, Controller brand/model, Total capacity hooks, Density, Gantry type); nuevas harness/gantry/hooks · **Bloque 29**
- [x] ✅ `resources/views/components/used-machine/sections/loom-accessories-fields.blade.php` — Sentence case (Loom accessories & feeders/Quantity frames/colors/weft-feeders/droppers) · **Bloque 30**
- [x] ✅ `resources/views/components/used-machine/sections/machine-specs-fields.blade.php` — Sentence case; **reusa B26** (Machine status/Movement type/Stopped since) + B10 movement types (Dobby/Crank/Cams/Jacquard/E-sheet) · **Bloque 27**
- [x] ✅ `resources/views/components/used-machine/sections/media-information.blade.php` — reusa B20 (Machine images/Machine video (optional)/límites); sin cambios · **Bloque 29**
- [x] ✅ `resources/views/components/used-machine/sections/owner-field.blade.php` — `Owner`(B19)/`New`; nuevas Select owner/No owner assigned/desc interna (`@js(__())` en x-data) · **Bloque 28**
- [x] ✅ `resources/views/components/used-machine/sections/price-info-fields.blade.php` — Sentence case (Pricing details); **reusa B26** Price range/Currency + Select currency · **Bloque 27**
- [x] ✅ `resources/views/components/used-machine/sections/status-information.blade.php` — staff-only; Sentence case (Publication & category/Publication status/Publish machine); reusa Machine type(B22)/Weaving/Knitting/Other · **Bloque 28**
- [x] ✅ `resources/views/components/used-machine/sections/type-of-machine.blade.php` — `Core specifications`; reusa Type of machine(B18)/desc(B27); nueva Enter machine type · **Bloque 28**

### 7.3 `components/used-machine/types` + image
- [x] ✅ `resources/views/components/used-machine/types/knitting-form.blade.php` — solo incluye sections; sin texto propio · **Bloque 30**
- [x] ✅ `resources/views/components/used-machine/types/other-form.blade.php` — solo incluye sections; sin texto propio · **Bloque 31**
- [x] ✅ `resources/views/components/used-machine/types/weaving-form.blade.php` — solo incluye sections; sin texto propio · **Bloque 30**
- [x] ✅ `resources/views/components/used-machine/image.blade.php` — `alt` viene de prop; sin texto propio · **Bloque 31**

### 7.4 Otros componentes usados por el módulo
- [x] ✅ `resources/views/components/form-wizard.blade.php` — stepper base; labels/icons dinámicos ($step->label); sin texto propio · **Bloque 31**
- [x] ✅ `resources/views/components/used-machines-carousel.blade.php` — reusa B19/B22 (title/subtitle/Sold/Available); `View Details→View details`(B18); nueva empty state · **Bloque 31**

### 7.5 Traits Livewire
- [x] ✅ `app/Livewire/Traits/HandlesServiceExceptions.php` — alerts guard() (Permission denied/Notice/genérico); 4 keys nuevas · **Bloque 31**
- [x] ✅ `app/Livewire/Traits/UsedMachine/WithDynamicSections.php` — confirms Swal borrar campo/sección (reusa Are you sure?/Yes, delete/Cancel); 2 keys nuevas · **Bloque 32**
- [x] ✅ `app/Livewire/Traits/Captcha/WithRecaptcha.php` — `abort(403,'captcha required/invalid captcha')` FUERA DE SCOPE (quedan en inglés) + Log::debug; sin cambios · **Bloque 32**

---

## 8. FLUJO DE CREACIÓN GENÉRICO DE TICKET (guest → register → select action)

- [x] ✅ `resources/views/livewire/ticket/create/steps/register-step-form.blade.php` — Sentence case (User/Company information, Confirm/Company name reusa B3); labels/placeholders/req password · **Bloque 32**
- [x] ✅ `resources/views/livewire/ticket/create/steps/select-action-step-form.blade.php` — `Choose your action` + cards Purchase/Sale/Option/Select · **Bloque 32**
- [x] ✅ `app/Livewire/Ticket/Create/Steps/RegisterStepForm.php` — alerts crear cuenta + stepInfo Register (reusa msgs password B3/Success/Error); Log::error inglés · **Bloque 32**
- [x] ✅ `app/Livewire/Ticket/Create/Steps/SelectActionStepForm.php` — stepInfo `select action→Select action` + `Selection the action` · **Bloque 33**

## 9. OWNER (quick create dentro del wizard de máquina)

- [x] ✅ `resources/views/livewire/owner/owner-quick-create-form.blade.php` — `New owner`/`Save owner`; `Additional Information→Additional information` (dedup, borrada Title); reusa Name/Country/Phone/Email/Saving... · **Bloque 33**
- [x] ✅ `app/Livewire/Owner/OwnerQuickCreateForm.php` — abort permiso(B31) + alert `Owner created successfully`/`The owner has been added and selected.` · **Bloque 33**

## 10. NOTIFICACIONES CAMPANITA (staff) + BELL

- [x] ✅ `resources/views/livewire/notifications/notification-bell.blade.php` — TODO ya con `__()` y keys existentes (Notifications/New/Mark all as read/No notifications/etc.); sin cambios · **Bloque 33**
- [x] ✅ `app/Livewire/Notifications/NotificationBell.php` — alerts ya con `__()` y keys existentes (Could not mark/delete…); Log::error inglés; sin cambios · **Bloque 33**
- [x] ✅ `app/Notifications/Tickets/BaseTicketNotification.php` — clase abstracta (via/toDatabase); sin texto de usuario · **Bloque 34**
- [x] ✅ `app/Notifications/Tickets/NewPurchaseTicketNotification.php` — `New purchase ticket` + msg con :name · **Bloque 34**
- [x] ✅ `app/Notifications/Tickets/NewSaleTicketNotification.php` — `New sale ticket` + msg con :name · **Bloque 34**
- [x] ✅ `app/Notifications/Tickets/NewUsedMachineRequestNotification.php` — keys ya existían; sin cambios · **Bloque 34**
- [x] ✅ `app/Notifications/Tickets/PurchaseTicketApprovedNotification.php` — keys ya existían; sin cambios · **Bloque 34**
- [x] ✅ `app/Notifications/Tickets/PurchaseTicketCorrectedNotification.php` — `Purchase ticket corrected` + msg #:id · **Bloque 35**
- [x] ✅ `app/Notifications/Tickets/PurchaseTicketReturnedNotification.php` — `Ticket returned for correction`/msg; keys ya existían · **Bloque 35**
- [x] ✅ `app/Notifications/Tickets/SaleTicketApprovedNotification.php` — keys ya existían; sin cambios · **Bloque 35**
- [x] ✅ `app/Notifications/Tickets/SaleTicketCorrectedNotification.php` — `Sale ticket corrected` + msg #:id · **Bloque 35**
- [x] ✅ `app/Notifications/Tickets/SaleTicketReturnedNotification.php` — `Ticket returned for correction`/msg; keys ya existían · **Bloque 35**

## 11. GUEST — SOLO máquinas usadas (única vista guest en scope)

> **Regla del usuario:** las vistas guest que YA EXISTÍAN (home, about, contact, partners, sitemap,
> products, blogs, **catálogo `machinery/*` de maquinaria nueva**, login/register de `auth.php`)
> **quedan FUERA de scope** (ya tienen traducción). La **ÚNICA excepción guest en scope** es el
> **guest de máquinas usadas** (`/used-machines-for-sale`, `FrontendUsedMachineController`).

**IMPORTANTE:** el guest de máquinas usadas **reutiliza los mismos blades del customer** →
`resources/views/sale-used-machine/customer/index.blade.php` y `.../show.blade.php`
(ya listados en la **sección 6.1**). No hay blades guest adicionales: al traducir la sección 6.1
queda cubierto también el guest. `FrontendUsedMachineController` ya está en **6.4**.

- [x] ✅ `app/Livewire/Guest/AuthNavLink.php` — solo re-render por evento; sin texto de usuario · **Bloque 36**
- [x] ✅ `resources/views/livewire/guest/auth-nav-link.blade.php` — `My profile`/`Login` (ya normalizados en B1); sin cambios · **Bloque 36**
- [x] ✅ `app/Livewire/ContactForm/ContactUsedMachinePost.php` — alerts Success/Error + `messages.*` (namespace preexistente); Log::error inglés; sin keys nuevas · **Bloque 36**
- [x] ✅ `resources/views/livewire/contact-form/contact-used-machine-post.blade.php` — placeholders/botón usan `messages.*` (preexistente); sin cambios · **Bloque 36**

> ⛔ **FUERA DE SCOPE (guest preexistente — NO tocar):** `resources/views/machinery/*`
> (`machinery.blade.php`, `machinery-show.blade.php`, `new-machinery.blade.php`,
> `braiding-complementary.blade.php`, `machinery-video.blade.php`), `MachineryController`,
> y demás vistas guest ya existentes (home/about/contact/partners/sitemap/products/blogs/auth).

---

## 12. 🚫 CORREOS — NO TRADUCIR (quedan en INGLÉS por decisión de negocio)

> `app/Services/EmailTicket/**` y `Mail`/`Mailable`. Listados solo para referencia; **NO migrar**.

- [—] 🚫 `app/Services/EmailTicket/PurchaseTicket/PurchaseNotificationService.php`
- [—] 🚫 `app/Services/EmailTicket/PurchaseTicket/PurchaseObservationFinishNotificationService.php`
- [—] 🚫 `app/Services/EmailTicket/PurchaseTicket/PurchaseTicketApprovedNotificationService.php`
- [—] 🚫 `app/Services/EmailTicket/PurchaseTicket/PurchaseTicketReturnNotificationService.php`
- [—] 🚫 `app/Services/EmailTicket/PurchaseTicket/PurchaseTicketSoldNotificationService.php`
- [—] 🚫 `app/Services/EmailTicket/SaleTicket/SaleNotificationService.php`
- [—] 🚫 `app/Services/EmailTicket/SaleTicket/SaleMachinePublishedNotificationService.php`
- [—] 🚫 `app/Services/EmailTicket/SaleTicket/SaleMachineSoldNotificationService.php`
- [—] 🚫 `app/Services/EmailTicket/SaleTicket/SaleObservationFinishNotificationService.php`
- [—] 🚫 `app/Services/EmailTicket/SaleTicket/SaleTicketReturnNotificationService.php`
- [—] 🚫 `app/Services/EmailTicket/SaleTicket/UsedMachineRequestMailService.php`
- [—] 🚫 `app/Mail/ContactMailable.php` + `resources/views/emails/contact-email.blade.php`
- [—] 🚫 Blades de correo (si existen bajo `resources/views/emails/**` o vendor mail markdown)

---

## 13. DESTINO DE LAS TRADUCCIONES (agregar keys faltantes)

- `lang/en.json`  (key = cadena en inglés)
- `lang/es.json`
- `lang/fr.json`
- `lang/it.json`
- `lang/pt.json`
- `lang/zh_CN.json`

---

## Resumen de conteo

- Blades del módulo: **95** (+ carousel/form-wizard compartidos)
- Livewire, Controllers, Services, Tables, Notifications, Rules, Policies, Models, Traits: **~90** PHP
- Correos EmailTicket (NO traducir): **11 servicios** + 1 Mailable + blades de correo

> Al terminar cada archivo marca `[x]`. Cuando TODO el checklist esté cerrado y las keys estén en
> los 6 JSON, cerrar con: **LISTO TAREA TERMINADA**.
