Finalish MVP
This commit is contained in:
333
lib/i18n/en.json
Normal file
333
lib/i18n/en.json
Normal file
@@ -0,0 +1,333 @@
|
||||
{
|
||||
"---": "---",
|
||||
"common.loading": "Loading...",
|
||||
"common.loadingShort": "Loading",
|
||||
"common.never": "never",
|
||||
"common.na": "--",
|
||||
"common.back": "Back",
|
||||
"common.cancel": "Cancel",
|
||||
"common.close": "Close",
|
||||
"common.save": "Save",
|
||||
"common.copy": "Copy",
|
||||
"nav.overview": "Overview",
|
||||
"nav.machines": "Machines",
|
||||
"nav.reports": "Reports",
|
||||
"nav.settings": "Settings",
|
||||
"sidebar.productTitle": "MIS",
|
||||
"sidebar.productSubtitle": "Control Tower",
|
||||
"sidebar.userFallback": "User",
|
||||
"sidebar.loadingOrg": "Loading...",
|
||||
"sidebar.themeTooltip": "Theme and language settings",
|
||||
"sidebar.switchToDark": "Switch to dark mode",
|
||||
"sidebar.switchToLight": "Switch to light mode",
|
||||
"sidebar.logout": "Logout",
|
||||
"sidebar.role.member": "MEMBER",
|
||||
"sidebar.role.admin": "ADMIN",
|
||||
"sidebar.role.owner": "OWNER",
|
||||
"login.title": "Control Tower",
|
||||
"login.subtitle": "Sign in to your organization",
|
||||
"login.email": "Email",
|
||||
"login.password": "Password",
|
||||
"login.error.default": "Login failed",
|
||||
"login.error.network": "Network error",
|
||||
"login.submit.loading": "Signing in...",
|
||||
"login.submit.default": "Login",
|
||||
"login.newHere": "New here?",
|
||||
"login.createAccount": "Create an account",
|
||||
"signup.verify.title": "Verify your email",
|
||||
"signup.verify.sent": "We sent a verification link to {email}.",
|
||||
"signup.verify.failed": "Verification email failed to send. Please contact support.",
|
||||
"signup.verify.notice": "Once verified, you can sign in and invite your team.",
|
||||
"signup.verify.back": "Back to login",
|
||||
"signup.title": "Create your Control Tower",
|
||||
"signup.subtitle": "Set up your organization and invite the team.",
|
||||
"signup.orgName": "Organization name",
|
||||
"signup.yourName": "Your name",
|
||||
"signup.email": "Email",
|
||||
"signup.password": "Password",
|
||||
"signup.error.default": "Signup failed",
|
||||
"signup.error.network": "Network error",
|
||||
"signup.submit.loading": "Creating account...",
|
||||
"signup.submit.default": "Create account",
|
||||
"signup.alreadyHave": "Already have access?",
|
||||
"signup.signIn": "Sign in",
|
||||
"invite.loading": "Loading invite...",
|
||||
"invite.notFound": "Invite not found.",
|
||||
"invite.joinTitle": "Join {org}",
|
||||
"invite.acceptCopy": "Accept the invite for {email} as {role}.",
|
||||
"invite.yourName": "Your name",
|
||||
"invite.password": "Password",
|
||||
"invite.error.notFound": "Invite not found",
|
||||
"invite.error.acceptFailed": "Invite acceptance failed",
|
||||
"invite.submit.loading": "Joining...",
|
||||
"invite.submit.default": "Join organization",
|
||||
"overview.title": "Overview",
|
||||
"overview.subtitle": "Fleet pulse, alerts, and top attention items.",
|
||||
"overview.viewMachines": "View Machines",
|
||||
"overview.loading": "Loading overview...",
|
||||
"overview.fleetHealth": "Fleet Health",
|
||||
"overview.machinesTotal": "Machines total",
|
||||
"overview.online": "Online",
|
||||
"overview.offline": "Offline",
|
||||
"overview.run": "Run",
|
||||
"overview.idle": "Idle",
|
||||
"overview.stop": "Stop",
|
||||
"overview.productionTotals": "Production Totals",
|
||||
"overview.good": "Good",
|
||||
"overview.scrap": "Scrap",
|
||||
"overview.target": "Target",
|
||||
"overview.kpiSumNote": "Sum of latest KPIs across machines.",
|
||||
"overview.activityFeed": "Activity Feed",
|
||||
"overview.eventsRefreshing": "Refreshing recent events...",
|
||||
"overview.eventsLast30": "Last 30 merged events",
|
||||
"overview.eventsNone": "No recent events.",
|
||||
"overview.oeeAvg": "OEE (avg)",
|
||||
"overview.availabilityAvg": "Availability (avg)",
|
||||
"overview.performanceAvg": "Performance (avg)",
|
||||
"overview.qualityAvg": "Quality (avg)",
|
||||
"overview.attentionList": "Attention List",
|
||||
"overview.shown": "shown",
|
||||
"overview.noUrgent": "No urgent issues detected.",
|
||||
"overview.timeline": "Unified Timeline",
|
||||
"overview.items": "items",
|
||||
"overview.noEvents": "No events yet.",
|
||||
"overview.ack": "ACK",
|
||||
"overview.severity.critical": "CRITICAL",
|
||||
"overview.severity.warning": "WARNING",
|
||||
"overview.severity.info": "INFO",
|
||||
"overview.source.ingested": "ingested",
|
||||
"overview.source.derived": "derived",
|
||||
"overview.event.macrostop": "macrostop",
|
||||
"overview.event.microstop": "microstop",
|
||||
"overview.event.slow-cycle": "slow-cycle",
|
||||
"overview.status.offline": "OFFLINE",
|
||||
"overview.status.online": "ONLINE",
|
||||
"machines.title": "Machines",
|
||||
"machines.subtitle": "Select a machine to view live KPIs.",
|
||||
"machines.cancel": "Cancel",
|
||||
"machines.addMachine": "Add Machine",
|
||||
"machines.backOverview": "Back to Overview",
|
||||
"machines.addCardTitle": "Add a machine",
|
||||
"machines.addCardSubtitle": "Generate the machine ID and API key for your Node-RED edge.",
|
||||
"machines.field.name": "Machine Name",
|
||||
"machines.field.code": "Code (optional)",
|
||||
"machines.field.location": "Location (optional)",
|
||||
"machines.create.loading": "Creating...",
|
||||
"machines.create.default": "Create Machine",
|
||||
"machines.create.error.nameRequired": "Machine name is required",
|
||||
"machines.create.error.failed": "Failed to create machine",
|
||||
"machines.pairing.title": "Edge pairing code",
|
||||
"machines.pairing.machine": "Machine:",
|
||||
"machines.pairing.codeLabel": "Pairing code",
|
||||
"machines.pairing.expires": "Expires",
|
||||
"machines.pairing.soon": "soon",
|
||||
"machines.pairing.instructions": "Enter this code on the Node-RED Control Tower settings screen to link the edge device.",
|
||||
"machines.pairing.copy": "Copy Code",
|
||||
"machines.pairing.copied": "Copied",
|
||||
"machines.pairing.copyUnsupported": "Copy not supported",
|
||||
"machines.pairing.copyFailed": "Copy failed",
|
||||
"machines.loading": "Loading machines...",
|
||||
"machines.empty": "No machines found for this org.",
|
||||
"machines.status": "Status",
|
||||
"machines.status.noHeartbeat": "No heartbeat",
|
||||
"machines.status.ok": "OK",
|
||||
"machines.status.offline": "OFFLINE",
|
||||
"machines.status.unknown": "UNKNOWN",
|
||||
"machines.lastSeen": "Last seen {time}",
|
||||
"machine.detail.titleFallback": "Machine",
|
||||
"machine.detail.lastSeen": "Last seen {time}",
|
||||
"machine.detail.loading": "Loading...",
|
||||
"machine.detail.error.failed": "Failed to load machine",
|
||||
"machine.detail.error.network": "Network error",
|
||||
"machine.detail.back": "Back",
|
||||
"machine.detail.status.offline": "OFFLINE",
|
||||
"machine.detail.status.unknown": "UNKNOWN",
|
||||
"machine.detail.status.run": "RUN",
|
||||
"machine.detail.status.idle": "IDLE",
|
||||
"machine.detail.status.stop": "STOP",
|
||||
"machine.detail.status.down": "DOWN",
|
||||
"machine.detail.bucket.normal": "Normal Cycle",
|
||||
"machine.detail.bucket.slow": "Slow Cycle",
|
||||
"machine.detail.bucket.microstop": "Microstop",
|
||||
"machine.detail.bucket.macrostop": "Macrostop",
|
||||
"machine.detail.bucket.unknown": "Unknown",
|
||||
"machine.detail.activity.title": "Machine Activity Timeline",
|
||||
"machine.detail.activity.subtitle": "Real-time analysis of production cycles",
|
||||
"machine.detail.activity.noData": "No timeline data yet.",
|
||||
"machine.detail.tooltip.cycle": "Cycle: {label}",
|
||||
"machine.detail.tooltip.duration": "Duration",
|
||||
"machine.detail.tooltip.ideal": "Ideal",
|
||||
"machine.detail.tooltip.deviation": "Deviation",
|
||||
"machine.detail.kpi.updated": "Updated {time}",
|
||||
"machine.detail.currentWorkOrder": "Current Work Order",
|
||||
"machine.detail.recentEvents": "Recent Events",
|
||||
"machine.detail.noEvents": "No events yet.",
|
||||
"machine.detail.cycleTarget": "Cycle target",
|
||||
"machine.detail.mini.events": "Detected Events",
|
||||
"machine.detail.mini.events.subtitle": "Count by type (cycles)",
|
||||
"machine.detail.mini.deviation": "Actual vs Standard Cycle",
|
||||
"machine.detail.mini.deviation.subtitle": "Average deviation",
|
||||
"machine.detail.mini.impact": "Production Impact",
|
||||
"machine.detail.mini.impact.subtitle": "Extra time vs ideal",
|
||||
"machine.detail.modal.events": "Detected Events",
|
||||
"machine.detail.modal.deviation": "Actual vs Standard Cycle",
|
||||
"machine.detail.modal.impact": "Production Impact",
|
||||
"machine.detail.modal.standardCycle": "Standard cycle (ideal)",
|
||||
"machine.detail.modal.avgDeviation": "Average deviation",
|
||||
"machine.detail.modal.sample": "Sample",
|
||||
"machine.detail.modal.cycles": "cycles",
|
||||
"machine.detail.modal.tip": "Tip: the faint line is the ideal. Each point is a real cycle.",
|
||||
"machine.detail.modal.totalExtra": "Total extra time",
|
||||
"machine.detail.modal.microstops": "Microstops",
|
||||
"machine.detail.modal.macroStops": "Macro stops",
|
||||
"machine.detail.modal.extraTimeLabel": "Extra time",
|
||||
"machine.detail.modal.extraTimeNote": "This is \"lost time\" vs ideal, distributed by event type.",
|
||||
"reports.title": "Reports",
|
||||
"reports.subtitle": "Trends, downtime, and quality analytics across machines.",
|
||||
"reports.exportCsv": "Export CSV",
|
||||
"reports.exportPdf": "Export PDF",
|
||||
"reports.filters": "Filters",
|
||||
"reports.rangeLabel.last24": "Last 24 hours",
|
||||
"reports.rangeLabel.last7": "Last 7 days",
|
||||
"reports.rangeLabel.last30": "Last 30 days",
|
||||
"reports.rangeLabel.custom": "Custom range",
|
||||
"reports.filter.range": "Range",
|
||||
"reports.filter.machine": "Machine",
|
||||
"reports.filter.workOrder": "Work Order",
|
||||
"reports.filter.sku": "SKU",
|
||||
"reports.filter.allMachines": "All machines",
|
||||
"reports.filter.allWorkOrders": "All work orders",
|
||||
"reports.filter.allSkus": "All SKUs",
|
||||
"reports.loading": "Loading reports...",
|
||||
"reports.error.failed": "Failed to load reports",
|
||||
"reports.error.network": "Network error",
|
||||
"reports.kpi.note.withData": "Computed from KPI snapshots.",
|
||||
"reports.kpi.note.noData": "No data in selected range.",
|
||||
"reports.oeeTrend": "OEE Trend",
|
||||
"reports.downtimePareto": "Downtime Pareto",
|
||||
"reports.cycleDistribution": "Cycle Time Distribution",
|
||||
"reports.scrapTrend": "Scrap Trend",
|
||||
"reports.topLossDrivers": "Top Loss Drivers",
|
||||
"reports.qualitySummary": "Quality Summary",
|
||||
"reports.notes": "Notes for Ops",
|
||||
"reports.notes.suggested": "Suggested actions",
|
||||
"reports.notes.none": "No insights yet. Generate reports after data collection.",
|
||||
"reports.noTrend": "No trend data yet.",
|
||||
"reports.noDowntime": "No downtime data yet.",
|
||||
"reports.noCycle": "No cycle data yet.",
|
||||
"reports.scrapRate": "Scrap Rate",
|
||||
"reports.topScrapSku": "Top Scrap SKU",
|
||||
"reports.topScrapWorkOrder": "Top Scrap Work Order",
|
||||
"reports.loss.macrostop": "Macrostop",
|
||||
"reports.loss.microstop": "Microstop",
|
||||
"reports.loss.slowCycle": "Slow Cycle",
|
||||
"reports.loss.qualitySpike": "Quality Spike",
|
||||
"reports.loss.oeeDrop": "OEE Drop",
|
||||
"reports.loss.perfDegradation": "Perf Degradation",
|
||||
"reports.tooltip.cycles": "Cycles",
|
||||
"reports.tooltip.range": "Range",
|
||||
"reports.tooltip.below": "Below",
|
||||
"reports.tooltip.above": "Above",
|
||||
"reports.tooltip.extremes": "Extremes",
|
||||
"reports.tooltip.downtime": "Downtime",
|
||||
"reports.tooltip.extraTime": "Extra time",
|
||||
"reports.csv.section": "section",
|
||||
"reports.csv.key": "key",
|
||||
"reports.csv.value": "value",
|
||||
"reports.pdf.title": "Report Export",
|
||||
"reports.pdf.range": "Range",
|
||||
"reports.pdf.machine": "Machine",
|
||||
"reports.pdf.workOrder": "Work Order",
|
||||
"reports.pdf.sku": "SKU",
|
||||
"reports.pdf.metric": "Metric",
|
||||
"reports.pdf.value": "Value",
|
||||
"reports.pdf.topLoss": "Top Loss Drivers",
|
||||
"reports.pdf.qualitySummary": "Quality Summary",
|
||||
"reports.pdf.cycleDistribution": "Cycle Time Distribution",
|
||||
"reports.pdf.notes": "Notes for Ops",
|
||||
"reports.pdf.none": "None",
|
||||
"settings.title": "Settings",
|
||||
"settings.subtitle": "Live configuration for shifts, alerts, and defaults.",
|
||||
"settings.loading": "Loading settings...",
|
||||
"settings.loadingTeam": "Loading team...",
|
||||
"settings.refresh": "Refresh",
|
||||
"settings.save": "Save changes",
|
||||
"settings.saving": "Saving...",
|
||||
"settings.saved": "Settings saved",
|
||||
"settings.failedLoad": "Failed to load settings",
|
||||
"settings.failedTeam": "Failed to load team",
|
||||
"settings.failedSave": "Failed to save settings",
|
||||
"settings.unavailable": "Settings are unavailable.",
|
||||
"settings.conflict": "Settings changed elsewhere. Refresh and try again.",
|
||||
"settings.org.title": "Organization",
|
||||
"settings.org.plantName": "Plant Name",
|
||||
"settings.org.slug": "Slug",
|
||||
"settings.org.timeZone": "Time Zone",
|
||||
"settings.shiftSchedule": "Shift Schedule",
|
||||
"settings.shiftSubtitle": "Define active shifts and downtime compensation.",
|
||||
"settings.shiftName": "Shift name",
|
||||
"settings.shiftStart": "Start",
|
||||
"settings.shiftEnd": "End",
|
||||
"settings.shiftEnabled": "Enabled",
|
||||
"settings.shiftAdd": "Add shift",
|
||||
"settings.shiftRemove": "Remove",
|
||||
"settings.shiftComp": "Shift change compensation",
|
||||
"settings.lunchBreak": "Lunch break",
|
||||
"settings.minutes": "minutes",
|
||||
"settings.shiftHint": "Max 3 shifts, HH:mm",
|
||||
"settings.shiftTo": "to",
|
||||
"settings.shiftCompLabel": "Shift change compensation (min)",
|
||||
"settings.lunchBreakLabel": "Lunch break (min)",
|
||||
"settings.shift.defaultName": "Shift {index}",
|
||||
"settings.thresholds": "Alert thresholds",
|
||||
"settings.thresholdsSubtitle": "Tune production health alerts.",
|
||||
"settings.thresholds.appliesAll": "Applies to all machines",
|
||||
"settings.thresholds.oee": "OEE alert threshold",
|
||||
"settings.thresholds.performance": "Performance threshold",
|
||||
"settings.thresholds.qualitySpike": "Quality spike delta",
|
||||
"settings.thresholds.stoppage": "Stoppage multiplier",
|
||||
"settings.alerts": "Alerts",
|
||||
"settings.alertsSubtitle": "Choose which alerts to notify.",
|
||||
"settings.alerts.oeeDrop": "OEE drop alerts",
|
||||
"settings.alerts.oeeDropHelper": "Notify when OEE falls below threshold",
|
||||
"settings.alerts.performanceDegradation": "Performance degradation alerts",
|
||||
"settings.alerts.performanceDegradationHelper": "Flag prolonged slow cycles",
|
||||
"settings.alerts.qualitySpike": "Quality spike alerts",
|
||||
"settings.alerts.qualitySpikeHelper": "Alert on scrap spikes",
|
||||
"settings.alerts.predictive": "Predictive OEE decline alerts",
|
||||
"settings.alerts.predictiveHelper": "Warn before OEE drops",
|
||||
"settings.defaults": "Mold Defaults",
|
||||
"settings.defaults.moldTotal": "Total molds",
|
||||
"settings.defaults.moldActive": "Active molds",
|
||||
"settings.updated": "Updated",
|
||||
"settings.updatedBy": "Updated by",
|
||||
"settings.team": "Team Members",
|
||||
"settings.teamTotal": "{count} total",
|
||||
"settings.teamNone": "No team members yet.",
|
||||
"settings.invites": "Invitations",
|
||||
"settings.inviteEmail": "Invite email",
|
||||
"settings.inviteRole": "Role",
|
||||
"settings.inviteSend": "Create invite",
|
||||
"settings.inviteSending": "Creating...",
|
||||
"settings.inviteStatus.copied": "Invite link copied",
|
||||
"settings.inviteStatus.emailRequired": "Email is required",
|
||||
"settings.inviteStatus.failed": "Failed to revoke invite",
|
||||
"settings.inviteStatus.sent": "Invite email sent",
|
||||
"settings.inviteStatus.createFailed": "Failed to create invite",
|
||||
"settings.inviteStatus.emailFailed": "Invite created, email failed: {url}",
|
||||
"settings.inviteNone": "No pending invites.",
|
||||
"settings.inviteExpires": "Expires {date}",
|
||||
"settings.inviteRole.member": "Member",
|
||||
"settings.inviteRole.admin": "Admin",
|
||||
"settings.inviteRole.owner": "Owner",
|
||||
"settings.inviteCopy": "Copy link",
|
||||
"settings.inviteRevoke": "Revoke",
|
||||
"settings.role.owner": "Owner",
|
||||
"settings.role.admin": "Admin",
|
||||
"settings.role.member": "Member",
|
||||
"settings.role.inactive": "Inactive",
|
||||
"settings.integrations": "Integrations",
|
||||
"settings.integrations.webhook": "Webhook URL",
|
||||
"settings.integrations.erp": "ERP Sync",
|
||||
"settings.integrations.erpNotConfigured": "Not configured"
|
||||
}
|
||||
333
lib/i18n/es-MX.json
Normal file
333
lib/i18n/es-MX.json
Normal file
@@ -0,0 +1,333 @@
|
||||
{
|
||||
"---": "---",
|
||||
"common.loading": "Cargando...",
|
||||
"common.loadingShort": "Cargando",
|
||||
"common.never": "nunca",
|
||||
"common.na": "--",
|
||||
"common.back": "Volver",
|
||||
"common.cancel": "Cancelar",
|
||||
"common.close": "Cerrar",
|
||||
"common.save": "Guardar",
|
||||
"common.copy": "Copiar",
|
||||
"nav.overview": "Resumen",
|
||||
"nav.machines": "Máquinas",
|
||||
"nav.reports": "Reportes",
|
||||
"nav.settings": "Configuración",
|
||||
"sidebar.productTitle": "MIS",
|
||||
"sidebar.productSubtitle": "Control Tower",
|
||||
"sidebar.userFallback": "Usuario",
|
||||
"sidebar.loadingOrg": "Cargando...",
|
||||
"sidebar.themeTooltip": "Tema e idioma",
|
||||
"sidebar.switchToDark": "Cambiar a modo oscuro",
|
||||
"sidebar.switchToLight": "Cambiar a modo claro",
|
||||
"sidebar.logout": "Cerrar sesión",
|
||||
"sidebar.role.member": "MIEMBRO",
|
||||
"sidebar.role.admin": "ADMIN",
|
||||
"sidebar.role.owner": "PROPIETARIO",
|
||||
"login.title": "Control Tower",
|
||||
"login.subtitle": "Inicia sesión en tu organización",
|
||||
"login.email": "Correo electrónico",
|
||||
"login.password": "Contraseña",
|
||||
"login.error.default": "Inicio de sesión fallido",
|
||||
"login.error.network": "Error de red",
|
||||
"login.submit.loading": "Iniciando sesión...",
|
||||
"login.submit.default": "Iniciar sesión",
|
||||
"login.newHere": "¿Nuevo aquí?",
|
||||
"login.createAccount": "Crear cuenta",
|
||||
"signup.verify.title": "Verifica tu correo",
|
||||
"signup.verify.sent": "Enviamos un enlace de verificación a {email}.",
|
||||
"signup.verify.failed": "No se pudo enviar el correo de verificación. Contacta a soporte.",
|
||||
"signup.verify.notice": "Después de verificar, puedes iniciar sesión e invitar a tu equipo.",
|
||||
"signup.verify.back": "Volver al inicio de sesión",
|
||||
"signup.title": "Crea tu Control Tower",
|
||||
"signup.subtitle": "Configura tu organización e invita al equipo.",
|
||||
"signup.orgName": "Nombre de la organización",
|
||||
"signup.yourName": "Tu nombre",
|
||||
"signup.email": "Correo electrónico",
|
||||
"signup.password": "Contraseña",
|
||||
"signup.error.default": "Registro fallido",
|
||||
"signup.error.network": "Error de red",
|
||||
"signup.submit.loading": "Creando cuenta...",
|
||||
"signup.submit.default": "Crear cuenta",
|
||||
"signup.alreadyHave": "¿Ya tienes acceso?",
|
||||
"signup.signIn": "Iniciar sesión",
|
||||
"invite.loading": "Cargando invitación...",
|
||||
"invite.notFound": "Invitación no encontrada.",
|
||||
"invite.joinTitle": "Únete a {org}",
|
||||
"invite.acceptCopy": "Acepta la invitación para {email} como {role}.",
|
||||
"invite.yourName": "Tu nombre",
|
||||
"invite.password": "Contraseña",
|
||||
"invite.error.notFound": "Invitación no encontrada",
|
||||
"invite.error.acceptFailed": "No se pudo aceptar la invitación",
|
||||
"invite.submit.loading": "Uniéndote...",
|
||||
"invite.submit.default": "Unirse a la organización",
|
||||
"overview.title": "Resumen",
|
||||
"overview.subtitle": "Pulso de flota, alertas y elementos prioritarios.",
|
||||
"overview.viewMachines": "Ver Máquinas",
|
||||
"overview.loading": "Cargando resumen...",
|
||||
"overview.fleetHealth": "Salud de flota",
|
||||
"overview.machinesTotal": "Máquinas totales",
|
||||
"overview.online": "En línea",
|
||||
"overview.offline": "Fuera de línea",
|
||||
"overview.run": "En marcha",
|
||||
"overview.idle": "En espera",
|
||||
"overview.stop": "Paro",
|
||||
"overview.productionTotals": "Totales de producción",
|
||||
"overview.good": "Buenas",
|
||||
"overview.scrap": "Scrap",
|
||||
"overview.target": "Meta",
|
||||
"overview.kpiSumNote": "Suma de los últimos KPIs por máquina.",
|
||||
"overview.activityFeed": "Actividad",
|
||||
"overview.eventsRefreshing": "Actualizando eventos recientes...",
|
||||
"overview.eventsLast30": "Últimos 30 eventos combinados",
|
||||
"overview.eventsNone": "Sin eventos recientes.",
|
||||
"overview.oeeAvg": "OEE (avg)",
|
||||
"overview.availabilityAvg": "Availability (avg)",
|
||||
"overview.performanceAvg": "Performance (avg)",
|
||||
"overview.qualityAvg": "Quality (avg)",
|
||||
"overview.attentionList": "Lista de atención",
|
||||
"overview.shown": "mostrados",
|
||||
"overview.noUrgent": "No se detectaron problemas urgentes.",
|
||||
"overview.timeline": "Línea de tiempo unificada",
|
||||
"overview.items": "elementos",
|
||||
"overview.noEvents": "Sin eventos aún.",
|
||||
"overview.ack": "ACK",
|
||||
"overview.severity.critical": "CRÍTICO",
|
||||
"overview.severity.warning": "ADVERTENCIA",
|
||||
"overview.severity.info": "INFO",
|
||||
"overview.source.ingested": "ingestado",
|
||||
"overview.source.derived": "derivado",
|
||||
"overview.event.macrostop": "macroparo",
|
||||
"overview.event.microstop": "microparo",
|
||||
"overview.event.slow-cycle": "ciclo lento",
|
||||
"overview.status.offline": "FUERA DE LÍNEA",
|
||||
"overview.status.online": "EN LÍNEA",
|
||||
"machines.title": "Máquinas",
|
||||
"machines.subtitle": "Selecciona una máquina para ver KPIs en vivo.",
|
||||
"machines.cancel": "Cancelar",
|
||||
"machines.addMachine": "Agregar máquina",
|
||||
"machines.backOverview": "Volver al Resumen",
|
||||
"machines.addCardTitle": "Agregar máquina",
|
||||
"machines.addCardSubtitle": "Genera el ID de máquina y la API key para tu edge Node-RED.",
|
||||
"machines.field.name": "Nombre de la máquina",
|
||||
"machines.field.code": "Código (opcional)",
|
||||
"machines.field.location": "Ubicación (opcional)",
|
||||
"machines.create.loading": "Creando...",
|
||||
"machines.create.default": "Crear máquina",
|
||||
"machines.create.error.nameRequired": "El nombre de la máquina es obligatorio",
|
||||
"machines.create.error.failed": "No se pudo crear la máquina",
|
||||
"machines.pairing.title": "Código de emparejamiento",
|
||||
"machines.pairing.machine": "Máquina:",
|
||||
"machines.pairing.codeLabel": "Código de emparejamiento",
|
||||
"machines.pairing.expires": "Expira",
|
||||
"machines.pairing.soon": "pronto",
|
||||
"machines.pairing.instructions": "Ingresa este código en la pantalla de configuración de Node-RED Control Tower para vincular el dispositivo.",
|
||||
"machines.pairing.copy": "Copiar código",
|
||||
"machines.pairing.copied": "Copiado",
|
||||
"machines.pairing.copyUnsupported": "Copiar no disponible",
|
||||
"machines.pairing.copyFailed": "Falló la copia",
|
||||
"machines.loading": "Cargando máquinas...",
|
||||
"machines.empty": "No se encontraron máquinas para esta organización.",
|
||||
"machines.status": "Estado",
|
||||
"machines.status.noHeartbeat": "Sin heartbeat",
|
||||
"machines.status.ok": "OK",
|
||||
"machines.status.offline": "FUERA DE LÍNEA",
|
||||
"machines.status.unknown": "DESCONOCIDO",
|
||||
"machines.lastSeen": "Visto hace {time}",
|
||||
"machine.detail.titleFallback": "Máquina",
|
||||
"machine.detail.lastSeen": "Visto hace {time}",
|
||||
"machine.detail.loading": "Cargando...",
|
||||
"machine.detail.error.failed": "No se pudo cargar la máquina",
|
||||
"machine.detail.error.network": "Error de red",
|
||||
"machine.detail.back": "Volver",
|
||||
"machine.detail.status.offline": "FUERA DE LÍNEA",
|
||||
"machine.detail.status.unknown": "DESCONOCIDO",
|
||||
"machine.detail.status.run": "EN MARCHA",
|
||||
"machine.detail.status.idle": "EN ESPERA",
|
||||
"machine.detail.status.stop": "PARO",
|
||||
"machine.detail.status.down": "CAÍDA",
|
||||
"machine.detail.bucket.normal": "Ciclo normal",
|
||||
"machine.detail.bucket.slow": "Ciclo lento",
|
||||
"machine.detail.bucket.microstop": "Microparo",
|
||||
"machine.detail.bucket.macrostop": "Macroparo",
|
||||
"machine.detail.bucket.unknown": "Desconocido",
|
||||
"machine.detail.activity.title": "Línea de tiempo de actividad",
|
||||
"machine.detail.activity.subtitle": "Análisis en tiempo real de ciclos de producción",
|
||||
"machine.detail.activity.noData": "Sin datos de línea de tiempo.",
|
||||
"machine.detail.tooltip.cycle": "Ciclo: {label}",
|
||||
"machine.detail.tooltip.duration": "Duración",
|
||||
"machine.detail.tooltip.ideal": "Ideal",
|
||||
"machine.detail.tooltip.deviation": "Desviación",
|
||||
"machine.detail.kpi.updated": "Actualizado {time}",
|
||||
"machine.detail.currentWorkOrder": "Orden de trabajo actual",
|
||||
"machine.detail.recentEvents": "Eventos recientes",
|
||||
"machine.detail.noEvents": "Sin eventos aún.",
|
||||
"machine.detail.cycleTarget": "Ciclo objetivo",
|
||||
"machine.detail.mini.events": "Eventos detectados",
|
||||
"machine.detail.mini.events.subtitle": "Conteo por tipo (ciclos)",
|
||||
"machine.detail.mini.deviation": "Ciclo real vs estándar",
|
||||
"machine.detail.mini.deviation.subtitle": "Desviación promedio",
|
||||
"machine.detail.mini.impact": "Impacto en producción",
|
||||
"machine.detail.mini.impact.subtitle": "Tiempo extra vs ideal",
|
||||
"machine.detail.modal.events": "Eventos detectados",
|
||||
"machine.detail.modal.deviation": "Ciclo real vs estándar",
|
||||
"machine.detail.modal.impact": "Impacto en producción",
|
||||
"machine.detail.modal.standardCycle": "Ciclo estándar (ideal)",
|
||||
"machine.detail.modal.avgDeviation": "Desviación promedio",
|
||||
"machine.detail.modal.sample": "Muestra",
|
||||
"machine.detail.modal.cycles": "ciclos",
|
||||
"machine.detail.modal.tip": "Tip: la línea tenue es el ideal. Cada punto es un ciclo real.",
|
||||
"machine.detail.modal.totalExtra": "Tiempo extra total",
|
||||
"machine.detail.modal.microstops": "Microparos",
|
||||
"machine.detail.modal.macroStops": "Macroparos",
|
||||
"machine.detail.modal.extraTimeLabel": "Tiempo extra",
|
||||
"machine.detail.modal.extraTimeNote": "Esto es \"tiempo perdido\" vs ideal, distribuido por tipo de evento.",
|
||||
"reports.title": "Reportes",
|
||||
"reports.subtitle": "Tendencias, paros y analítica de calidad por máquina.",
|
||||
"reports.exportCsv": "Exportar CSV",
|
||||
"reports.exportPdf": "Exportar PDF",
|
||||
"reports.filters": "Filtros",
|
||||
"reports.rangeLabel.last24": "Últimas 24 horas",
|
||||
"reports.rangeLabel.last7": "Últimos 7 días",
|
||||
"reports.rangeLabel.last30": "Últimos 30 días",
|
||||
"reports.rangeLabel.custom": "Rango personalizado",
|
||||
"reports.filter.range": "Rango",
|
||||
"reports.filter.machine": "Máquina",
|
||||
"reports.filter.workOrder": "Orden de trabajo",
|
||||
"reports.filter.sku": "SKU",
|
||||
"reports.filter.allMachines": "Todas las máquinas",
|
||||
"reports.filter.allWorkOrders": "Todas las órdenes",
|
||||
"reports.filter.allSkus": "Todos los SKUs",
|
||||
"reports.loading": "Cargando reportes...",
|
||||
"reports.error.failed": "No se pudieron cargar los reportes",
|
||||
"reports.error.network": "Error de red",
|
||||
"reports.kpi.note.withData": "Calculado a partir de KPIs.",
|
||||
"reports.kpi.note.noData": "Sin datos en el rango seleccionado.",
|
||||
"reports.oeeTrend": "Tendencia de OEE",
|
||||
"reports.downtimePareto": "Pareto de paros",
|
||||
"reports.cycleDistribution": "Distribución de tiempos de ciclo",
|
||||
"reports.scrapTrend": "Tendencia de scrap",
|
||||
"reports.topLossDrivers": "Principales causas de pérdida",
|
||||
"reports.qualitySummary": "Resumen de calidad",
|
||||
"reports.notes": "Notas para operaciones",
|
||||
"reports.notes.suggested": "Acciones sugeridas",
|
||||
"reports.notes.none": "Sin insights todavía. Genera reportes tras recolectar datos.",
|
||||
"reports.noTrend": "Sin datos de tendencia.",
|
||||
"reports.noDowntime": "Sin datos de paros.",
|
||||
"reports.noCycle": "Sin datos de ciclo.",
|
||||
"reports.scrapRate": "Scrap Rate",
|
||||
"reports.topScrapSku": "SKU con más scrap",
|
||||
"reports.topScrapWorkOrder": "Orden con más scrap",
|
||||
"reports.loss.macrostop": "Macroparo",
|
||||
"reports.loss.microstop": "Microparo",
|
||||
"reports.loss.slowCycle": "Ciclo lento",
|
||||
"reports.loss.qualitySpike": "Pico de calidad",
|
||||
"reports.loss.oeeDrop": "Caída de OEE",
|
||||
"reports.loss.perfDegradation": "Baja de desempeño",
|
||||
"reports.tooltip.cycles": "Ciclos",
|
||||
"reports.tooltip.range": "Rango",
|
||||
"reports.tooltip.below": "Debajo de",
|
||||
"reports.tooltip.above": "Encima de",
|
||||
"reports.tooltip.extremes": "Extremos",
|
||||
"reports.tooltip.downtime": "Tiempo de paro",
|
||||
"reports.tooltip.extraTime": "Tiempo extra",
|
||||
"reports.csv.section": "sección",
|
||||
"reports.csv.key": "clave",
|
||||
"reports.csv.value": "valor",
|
||||
"reports.pdf.title": "Exportación de reporte",
|
||||
"reports.pdf.range": "Rango",
|
||||
"reports.pdf.machine": "Máquina",
|
||||
"reports.pdf.workOrder": "Orden de trabajo",
|
||||
"reports.pdf.sku": "SKU",
|
||||
"reports.pdf.metric": "Métrica",
|
||||
"reports.pdf.value": "Valor",
|
||||
"reports.pdf.topLoss": "Principales causas de pérdida",
|
||||
"reports.pdf.qualitySummary": "Resumen de calidad",
|
||||
"reports.pdf.cycleDistribution": "Distribución de tiempos de ciclo",
|
||||
"reports.pdf.notes": "Notas para operaciones",
|
||||
"reports.pdf.none": "Ninguna",
|
||||
"settings.title": "Configuración",
|
||||
"settings.subtitle": "Configuración en vivo para turnos, alertas y valores predeterminados.",
|
||||
"settings.loading": "Cargando configuración...",
|
||||
"settings.loadingTeam": "Cargando equipo...",
|
||||
"settings.refresh": "Actualizar",
|
||||
"settings.save": "Guardar cambios",
|
||||
"settings.saving": "Guardando...",
|
||||
"settings.saved": "Configuración guardada",
|
||||
"settings.failedLoad": "No se pudo cargar la configuración",
|
||||
"settings.failedTeam": "No se pudo cargar el equipo",
|
||||
"settings.failedSave": "No se pudo guardar la configuración",
|
||||
"settings.unavailable": "La configuración no está disponible.",
|
||||
"settings.conflict": "La configuración cambió en otro lugar. Actualiza e intenta de nuevo.",
|
||||
"settings.org.title": "Organización",
|
||||
"settings.org.plantName": "Nombre de planta",
|
||||
"settings.org.slug": "Slug",
|
||||
"settings.org.timeZone": "Zona horaria",
|
||||
"settings.shiftSchedule": "Turnos",
|
||||
"settings.shiftSubtitle": "Define turnos activos y compensación de paros.",
|
||||
"settings.shiftName": "Nombre del turno",
|
||||
"settings.shiftStart": "Inicio",
|
||||
"settings.shiftEnd": "Fin",
|
||||
"settings.shiftEnabled": "Activo",
|
||||
"settings.shiftAdd": "Agregar turno",
|
||||
"settings.shiftRemove": "Eliminar",
|
||||
"settings.shiftComp": "Compensación por cambio de turno",
|
||||
"settings.lunchBreak": "Comida",
|
||||
"settings.minutes": "minutos",
|
||||
"settings.shiftHint": "Máx 3 turnos, HH:mm",
|
||||
"settings.shiftTo": "a",
|
||||
"settings.shiftCompLabel": "Compensación por cambio de turno (min)",
|
||||
"settings.lunchBreakLabel": "Comida (min)",
|
||||
"settings.shift.defaultName": "Turno {index}",
|
||||
"settings.thresholds": "Umbrales de alertas",
|
||||
"settings.thresholdsSubtitle": "Ajusta alertas de salud de producción.",
|
||||
"settings.thresholds.appliesAll": "Aplica a todas las máquinas",
|
||||
"settings.thresholds.oee": "Umbral de alerta OEE",
|
||||
"settings.thresholds.performance": "Umbral de Performance",
|
||||
"settings.thresholds.qualitySpike": "Delta de pico de calidad",
|
||||
"settings.thresholds.stoppage": "Multiplicador de paro",
|
||||
"settings.alerts": "Alertas",
|
||||
"settings.alertsSubtitle": "Elige qué alertas notificar.",
|
||||
"settings.alerts.oeeDrop": "Alertas por caída de OEE",
|
||||
"settings.alerts.oeeDropHelper": "Notificar cuando OEE esté por debajo del umbral",
|
||||
"settings.alerts.performanceDegradation": "Alertas por baja de Performance",
|
||||
"settings.alerts.performanceDegradationHelper": "Marcar ciclos lentos prolongados",
|
||||
"settings.alerts.qualitySpike": "Alertas por picos de calidad",
|
||||
"settings.alerts.qualitySpikeHelper": "Alertar por picos de scrap",
|
||||
"settings.alerts.predictive": "Alertas predictivas de caída OEE",
|
||||
"settings.alerts.predictiveHelper": "Avisar antes de que OEE caiga",
|
||||
"settings.defaults": "Valores predeterminados de moldes",
|
||||
"settings.defaults.moldTotal": "Moldes totales",
|
||||
"settings.defaults.moldActive": "Moldes activos",
|
||||
"settings.updated": "Actualizado",
|
||||
"settings.updatedBy": "Actualizado por",
|
||||
"settings.team": "Miembros del equipo",
|
||||
"settings.teamTotal": "{count} total",
|
||||
"settings.teamNone": "Sin miembros del equipo.",
|
||||
"settings.invites": "Invitaciones",
|
||||
"settings.inviteEmail": "Correo de invitación",
|
||||
"settings.inviteRole": "Rol",
|
||||
"settings.inviteSend": "Crear invitación",
|
||||
"settings.inviteSending": "Creando...",
|
||||
"settings.inviteStatus.copied": "Enlace de invitación copiado",
|
||||
"settings.inviteStatus.emailRequired": "El correo es obligatorio",
|
||||
"settings.inviteStatus.failed": "No se pudo revocar la invitación",
|
||||
"settings.inviteStatus.sent": "Correo de invitación enviado",
|
||||
"settings.inviteStatus.createFailed": "No se pudo crear la invitación",
|
||||
"settings.inviteStatus.emailFailed": "Invitación creada, falló el correo: {url}",
|
||||
"settings.inviteNone": "Sin invitaciones pendientes.",
|
||||
"settings.inviteExpires": "Expira {date}",
|
||||
"settings.inviteRole.member": "Miembro",
|
||||
"settings.inviteRole.admin": "Admin",
|
||||
"settings.inviteRole.owner": "Propietario",
|
||||
"settings.inviteCopy": "Copiar enlace",
|
||||
"settings.inviteRevoke": "Revocar",
|
||||
"settings.role.owner": "Propietario",
|
||||
"settings.role.admin": "Admin",
|
||||
"settings.role.member": "Miembro",
|
||||
"settings.role.inactive": "Inactivo",
|
||||
"settings.integrations": "Integraciones",
|
||||
"settings.integrations.webhook": "Webhook URL",
|
||||
"settings.integrations.erp": "ERP Sync",
|
||||
"settings.integrations.erpNotConfigured": "No configurado"
|
||||
}
|
||||
30
lib/i18n/translations.ts
Normal file
30
lib/i18n/translations.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import en from "./en.json";
|
||||
import esMX from "./es-MX.json";
|
||||
|
||||
export type Locale = "en" | "es-MX";
|
||||
|
||||
type Dictionary = Record<string, string>;
|
||||
|
||||
export const translations: Record<Locale, Dictionary> = {
|
||||
en,
|
||||
"es-MX": esMX,
|
||||
};
|
||||
|
||||
export const defaultLocale: Locale = "en";
|
||||
|
||||
export function translate(
|
||||
locale: Locale,
|
||||
key: string,
|
||||
vars?: Record<string, string | number>
|
||||
): string {
|
||||
const table = translations[locale] ?? translations[defaultLocale];
|
||||
const fallback = translations[defaultLocale];
|
||||
let text = table[key] ?? fallback[key] ?? key;
|
||||
if (vars) {
|
||||
text = text.replace(/\{(\w+)\}/g, (match, token) => {
|
||||
const value = vars[token];
|
||||
return value == null ? match : String(value);
|
||||
});
|
||||
}
|
||||
return text;
|
||||
}
|
||||
60
lib/i18n/useI18n.ts
Normal file
60
lib/i18n/useI18n.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
"use client";
|
||||
|
||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { defaultLocale, Locale, translate } from "./translations";
|
||||
|
||||
const LOCALE_COOKIE = "mis_locale";
|
||||
const LOCALE_EVENT = "mis-locale-change";
|
||||
|
||||
function readCookieLocale(): Locale | null {
|
||||
const match = document.cookie
|
||||
.split(";")
|
||||
.map((part) => part.trim())
|
||||
.find((part) => part.startsWith(`${LOCALE_COOKIE}=`));
|
||||
if (!match) return null;
|
||||
const value = match.split("=")[1];
|
||||
if (value === "es-MX" || value === "en") return value;
|
||||
return null;
|
||||
}
|
||||
|
||||
function readLocale(): Locale {
|
||||
const docLang = document.documentElement.getAttribute("lang");
|
||||
if (docLang === "es-MX" || docLang === "en") return docLang;
|
||||
return readCookieLocale() ?? defaultLocale;
|
||||
}
|
||||
|
||||
export function useI18n() {
|
||||
const [locale, setLocale] = useState<Locale>(() => readLocale());
|
||||
|
||||
useEffect(() => {
|
||||
const handler = (event: Event) => {
|
||||
const detail = (event as CustomEvent).detail;
|
||||
if (detail === "es-MX" || detail === "en") {
|
||||
setLocale(detail);
|
||||
}
|
||||
};
|
||||
window.addEventListener(LOCALE_EVENT, handler);
|
||||
return () => window.removeEventListener(LOCALE_EVENT, handler);
|
||||
}, []);
|
||||
|
||||
const setLocaleAndPersist = useCallback((next: Locale) => {
|
||||
document.documentElement.setAttribute("lang", next);
|
||||
document.cookie = `${LOCALE_COOKIE}=${next}; Path=/; Max-Age=31536000; SameSite=Lax`;
|
||||
setLocale(next);
|
||||
window.dispatchEvent(new CustomEvent(LOCALE_EVENT, { detail: next }));
|
||||
}, [setLocale]);
|
||||
|
||||
const t = useCallback(
|
||||
(key: string, vars?: Record<string, string | number>) => translate(locale, key, vars),
|
||||
[locale]
|
||||
);
|
||||
|
||||
return useMemo(
|
||||
() => ({
|
||||
locale,
|
||||
setLocale: setLocaleAndPersist,
|
||||
t,
|
||||
}),
|
||||
[locale, setLocaleAndPersist, t]
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user