Files
stock-manager/tests/unit/i18n/dictionaries.test.ts
T

986 lines
30 KiB
TypeScript

import { describe, expect, it } from "vitest"
import { dictionaries, getDictionary } from "@/i18n/dictionaries"
import { SUPPORTED_LOCALES } from "@/i18n/locales"
describe("i18n dictionaries", () => {
it("provides dictionaries for every supported locale and no extra locales", () => {
expect(Object.keys(dictionaries).sort()).toEqual(
[...SUPPORTED_LOCALES].sort(),
)
})
it("returns localized login copy for English and Spanish", () => {
expect(getDictionary("en").login).toEqual({
title: "Sign In",
usernameLabel: "Username",
passwordLabel: "Password",
submitLabel: "Sign In",
})
expect(getDictionary("es").login).toEqual({
title: "Iniciar sesión",
usernameLabel: "Usuario",
passwordLabel: "Contraseña",
submitLabel: "Iniciar sesión",
})
})
it("provides localized language switcher copy for English and Spanish", () => {
expect(getDictionary("en").common.languageSwitcher).toEqual({
label: "Language",
options: {
en: "English",
es: "Spanish",
},
})
expect(getDictionary("es").common.languageSwitcher).toEqual({
label: "Idioma",
options: {
en: "Inglés",
es: "Español",
},
})
})
it("provides localized shell and common copy for English and Spanish", () => {
expect(getDictionary("en").layout).toEqual({
sidebar: {
home: "Home",
inventory: "Inventory",
items: "Items",
categories: "Categories",
assets: "Assets",
people: "People",
movements: "Movements",
assignments: "Assignments",
users: "Users",
},
navbar: {
accountLabel: "My Account",
},
addMenu: {
add: "Add",
import: "Import",
category: "Category",
item: "Item",
asset: "Asset",
person: "Person",
assignment: "Assignment",
},
resetDatabase: {
idle: "Reset Database",
loading: "Resetting...",
successToast: "Database reset successfully",
errorToast: "Error resetting database",
},
logout: {
label: "Sign Out",
},
})
expect(getDictionary("es").layout).toEqual({
sidebar: {
home: "Inicio",
inventory: "Inventario",
items: "Artículos",
categories: "Categorías",
assets: "Activos",
people: "Personas",
movements: "Movimientos",
assignments: "Asignaciones",
users: "Usuarios",
},
navbar: {
accountLabel: "Mi cuenta",
},
addMenu: {
add: "Añadir",
import: "Importar",
category: "Categoría",
item: "Artículo",
asset: "Activo",
person: "Persona",
assignment: "Asignación",
},
resetDatabase: {
idle: "Reiniciar base de datos",
loading: "Reiniciando...",
successToast: "Base de datos reiniciada correctamente",
errorToast: "Error al reiniciar la base de datos",
},
logout: {
label: "Cerrar sesión",
},
})
expect(getDictionary("en").common.search).toEqual({
placeholder: "Search...",
label: "Search",
clearLabel: "Clear search",
})
expect(getDictionary("es").common.search).toEqual({
placeholder: "Buscar...",
label: "Buscar",
clearLabel: "Limpiar búsqueda",
})
expect(getDictionary("en").common.pagination).toEqual({
summaryPrefix: "Showing page",
summarySeparator: "of",
previous: "Previous",
next: "Next",
})
expect(getDictionary("es").common.pagination).toEqual({
summaryPrefix: "Mostrando página",
summarySeparator: "de",
previous: "Anterior",
next: "Siguiente",
})
expect(getDictionary("en").common.submitButton).toEqual({
defaultLabel: "Submit",
processing: "Processing",
success: "Success",
})
expect(getDictionary("en").common.forbidden).toEqual({
title: "Access denied",
description: "You do not have permission to access this section.",
homeLink: "Back to home",
})
expect(getDictionary("es").common.submitButton).toEqual({
defaultLabel: "Enviar",
processing: "Procesando",
success: "Completado",
})
expect(getDictionary("es").common.forbidden).toEqual({
title: "Acceso denegado",
description: "No tienes permisos para acceder a esta sección.",
homeLink: "Volver al inicio",
})
})
it("provides localized inventory category copy for English and Spanish", () => {
expect(getDictionary("en").inventory.categories).toEqual({
list: {
title: "Categories",
addLabel: "Add Category",
empty: "No categories found.",
columns: {
name: "Name",
items: "Items",
actions: "Actions",
},
actions: {
edit: "Edit category",
delete: "Delete category",
},
},
new: {
title: "New Category",
},
edit: {
title: "Edit Category",
},
form: {
nameLabel: "Name",
namePlaceholder: "Category name",
createSubmit: "Create Category",
updateSubmit: "Update Category",
},
delete: {
label: "Delete category",
pending: "Deleting...",
unknownError: "Unknown error",
},
actions: {
createSuccess: "Category created successfully",
createFailure: "Failed to create category",
updateSuccess: "Category updated successfully",
updateFailure: "Failed to update category",
deleteSuccess: "Category deleted successfully",
deleteFailure: "Failed to delete category",
duplicateName: "Category already exists",
unchangedName: "Category name unchanged",
notFound: "Category not found",
hasItems: "Cannot delete category with items",
},
schema: {
nameRequired: "Name is required and must be at least 3 characters long",
idRequired: "ID is required",
},
})
expect(getDictionary("es").inventory.categories).toEqual({
list: {
title: "Categorías",
addLabel: "Agregar categoría",
empty: "No se encontraron categorías.",
columns: {
name: "Nombre",
items: "Artículos",
actions: "Acciones",
},
actions: {
edit: "Editar categoría",
delete: "Eliminar categoría",
},
},
new: {
title: "Nueva categoría",
},
edit: {
title: "Editar categoría",
},
form: {
nameLabel: "Nombre",
namePlaceholder: "Nombre de la categoría",
createSubmit: "Crear categoría",
updateSubmit: "Actualizar categoría",
},
delete: {
label: "Eliminar categoría",
pending: "Eliminando...",
unknownError: "Error desconocido",
},
actions: {
createSuccess: "Categoría creada correctamente",
createFailure: "Error al crear la categoría",
updateSuccess: "Categoría actualizada correctamente",
updateFailure: "Error al actualizar la categoría",
deleteSuccess: "Categoría eliminada correctamente",
deleteFailure: "Error al eliminar la categoría",
duplicateName: "La categoría ya existe",
unchangedName: "El nombre de la categoría no cambió",
notFound: "Categoría no encontrada",
hasItems: "No se puede eliminar una categoría con artículos",
},
schema: {
nameRequired:
"El nombre es obligatorio y debe tener al menos 3 caracteres",
idRequired: "El ID es obligatorio",
},
})
})
it("provides localized inventory item copy for English and Spanish", () => {
expect(getDictionary("en").inventory.items).toEqual({
list: {
title: "Items",
addLabel: "Add Item",
empty: "No items found.",
columns: {
name: "Name",
category: "Category",
assets: "Assets",
stock: "Stock",
actions: "Actions",
},
actions: {
view: "View item",
edit: "Edit item",
delete: "Delete item",
},
},
detail: {
notFound: "Item not found",
labels: {
category: "Category",
stock: "Stock",
},
},
new: {
title: "New Item",
},
edit: {
title: "Edit Item",
notFound: "Item not found",
hasAssetsWarning: "This item has already assets assigned to it.",
},
form: {
nameLabel: "Name",
namePlaceholder: "Item name",
categoryLabel: "Category",
categoryPlaceholder: "Select a category",
stockLabel: "Stock",
stockPlaceholder: "0",
createSubmit: "Create Item",
updateSubmit: "Update Item",
},
delete: {
label: "Delete item",
pending: "Deleting...",
unknownError: "Unknown error",
},
actions: {
createSuccess: "Item created successfully!",
createFailure: "Error creating item",
updateSuccess: "Item updated successfully!",
updateFailure: "Failed to update item",
deleteSuccess: "Item deleted successfully!",
deleteFailure: "Failed to delete item",
duplicateName: "Item already exists",
notFound: "Item not found",
hasAssets: "Cannot delete item with assets",
hasStock: "Cannot delete item with stock",
invalidStock: "Invalid stock",
negativeStock: "Stock cannot be negative",
},
schema: {
nameRequired: "Name is required",
categoryRequired: "Category is required",
stockRequired: "Stock is required",
itemRequired: "Item is required",
},
})
expect(getDictionary("es").inventory.items).toEqual({
list: {
title: "Artículos",
addLabel: "Agregar artículo",
empty: "No se encontraron artículos.",
columns: {
name: "Nombre",
category: "Categoría",
assets: "Activos",
stock: "Stock",
actions: "Acciones",
},
actions: {
view: "Ver artículo",
edit: "Editar artículo",
delete: "Eliminar artículo",
},
},
detail: {
notFound: "Artículo no encontrado",
labels: {
category: "Categoría",
stock: "Stock",
},
},
new: {
title: "Nuevo artículo",
},
edit: {
title: "Editar artículo",
notFound: "Artículo no encontrado",
hasAssetsWarning: "Este artículo ya tiene activos asignados.",
},
form: {
nameLabel: "Nombre",
namePlaceholder: "Nombre del artículo",
categoryLabel: "Categoría",
categoryPlaceholder: "Selecciona una categoría",
stockLabel: "Stock",
stockPlaceholder: "0",
createSubmit: "Crear artículo",
updateSubmit: "Actualizar artículo",
},
delete: {
label: "Eliminar artículo",
pending: "Eliminando...",
unknownError: "Error desconocido",
},
actions: {
createSuccess: "Artículo creado correctamente",
createFailure: "Error al crear el artículo",
updateSuccess: "Artículo actualizado correctamente",
updateFailure: "Error al actualizar el artículo",
deleteSuccess: "Artículo eliminado correctamente",
deleteFailure: "Error al eliminar el artículo",
duplicateName: "El artículo ya existe",
notFound: "Artículo no encontrado",
hasAssets: "No se puede eliminar un artículo con activos",
hasStock: "No se puede eliminar un artículo con stock",
invalidStock: "Stock inválido",
negativeStock: "El stock no puede ser negativo",
},
schema: {
nameRequired: "El nombre es obligatorio",
categoryRequired: "La categoría es obligatoria",
stockRequired: "El stock es obligatorio",
itemRequired: "El artículo es obligatorio",
},
})
})
it("provides localized assignment copy for English and Spanish", () => {
expect(getDictionary("en").inventory.assignments).toEqual({
list: {
title: "Assignments",
addLabel: "Add Assignment",
empty: "No assignments found.",
columns: {
recipient: "Recipient",
item: "Item",
serialNumber: "Serial Number",
quantity: "Quantity",
actions: "Actions",
},
actions: {
edit: "Edit assignment",
return: "Return assignment",
},
},
new: {
title: "New Assignment",
},
edit: {
title: "Edit Assignment",
notFound: "Assignment not found",
},
form: {
recipientLabel: "Recipient",
recipientPlaceholder: "Select a recipient",
itemLabel: "Item",
itemPlaceholder: "Select an item",
assetLabel: "Asset",
assetPlaceholder: "Select an asset",
quantityLabel: "Quantity",
quantityPlaceholder: "1",
createSubmit: "Create Assignment",
updateSubmit: "Update Assignment",
},
fallback: {
missingValue: "N/A",
},
actions: {
createSuccess: "Assignment created successfully",
createFailure: "Error creating assignment",
updateSuccess: "Assignment updated successfully",
updateFailure: "Error updating assignment",
returnSuccess: "Assignment returned successfully",
returnFailure: "Error returning assignment",
notFound: "Assignment not found",
itemNotFound: "Item not found",
itemInsufficientStock: "Item does not have enough stock",
assetNotFound: "Asset not found",
assetItemMismatch: "Asset does not belong to item",
assignmentAlreadyReturned: "Assignment already returned",
invalidData: "Invalid assignment data",
genericFailure: "Error processing assignment",
},
schema: {
recipientRequired: "Recipient is required",
itemIdRequired: "Item is required",
quantityMinOne: "Quantity must be at least 1",
assetIdRequired: "Asset ID is required when item ID is provided",
idRequired: "Assignment ID is required",
},
})
expect(getDictionary("es").inventory.assignments).toEqual({
list: {
title: "Asignaciones",
addLabel: "Agregar asignación",
empty: "No se encontraron asignaciones.",
columns: {
recipient: "Destinatario",
item: "Artículo",
serialNumber: "Número de serie",
quantity: "Cantidad",
actions: "Acciones",
},
actions: {
edit: "Editar asignación",
return: "Devolver asignación",
},
},
new: {
title: "Nueva asignación",
},
edit: {
title: "Editar asignación",
notFound: "Asignación no encontrada",
},
form: {
recipientLabel: "Destinatario",
recipientPlaceholder: "Selecciona un destinatario",
itemLabel: "Artículo",
itemPlaceholder: "Selecciona un artículo",
assetLabel: "Activo",
assetPlaceholder: "Selecciona un activo",
quantityLabel: "Cantidad",
quantityPlaceholder: "1",
createSubmit: "Crear asignación",
updateSubmit: "Actualizar asignación",
},
fallback: {
missingValue: "No disponible",
},
actions: {
createSuccess: "Asignación creada correctamente",
createFailure: "Error al crear la asignación",
updateSuccess: "Asignación actualizada correctamente",
updateFailure: "Error al actualizar la asignación",
returnSuccess: "Asignación devuelta correctamente",
returnFailure: "Error al devolver la asignación",
notFound: "Asignación no encontrada",
itemNotFound: "Artículo no encontrado",
itemInsufficientStock: "El artículo no tiene stock suficiente",
assetNotFound: "Activo no encontrado",
assetItemMismatch: "El activo no pertenece al artículo",
assignmentAlreadyReturned: "La asignación ya fue devuelta",
invalidData: "Datos de asignación inválidos",
genericFailure: "Error al procesar la asignación",
},
schema: {
recipientRequired: "El destinatario es obligatorio",
itemIdRequired: "El artículo es obligatorio",
quantityMinOne: "La cantidad debe ser al menos 1",
assetIdRequired:
"El activo es obligatorio cuando se especifica el artículo",
idRequired: "El ID de asignación es obligatorio",
},
})
})
it("provides localized inventory asset UI copy for English and Spanish", () => {
expect(getDictionary("en").inventory.assets).toEqual({
list: {
title: "Assets",
addLabel: "Add Asset",
empty: "No assets found.",
columns: {
item: "Item",
category: "Category",
serialNumber: "Serial Number",
status: "Status",
actions: "Actions",
},
actions: {
edit: "Edit asset",
},
},
new: {
title: "New Asset",
},
edit: {
title: "Edit Asset",
notFound: "Asset not found",
},
form: {
itemLabel: "Item",
itemPlaceholder: "Select an item",
serialNumberLabel: "Serial Number",
serialNumberPlaceholder: "Serial number",
deliveryNoteLabel: "Delivery Note",
deliveryNotePlaceholder: "Delivery note",
statusLabel: "Status",
statusPlaceholder: "Select a status",
recipientLabel: "Recipient",
recipientPlaceholder: "Select a recipient",
createSubmit: "Create Asset",
updateSubmit: "Update Asset",
},
status: {
AVAILABLE: "Available",
ASSIGNED: "Assigned",
RESERVED: "Reserved",
IN_REPAIR: "In repair",
BROKEN: "Broken",
STOLEN: "Stolen",
DISPOSED: "Disposed",
},
fallback: {
unknownStatus: "Unknown status",
},
actions: {
createSuccess: "Asset created successfully",
createFailure: "Error creating asset",
updateSuccess: "Asset updated successfully",
updateFailure: "Error updating asset",
duplicateSerialNumber: "This serial number already exists",
notFound: "Asset not found",
itemNotFound: "Item not found",
assignmentAlreadyReturned: "Assignment already returned",
previousItemNotFound: "Previous item not found for available asset",
insufficientStock: "Item does not have enough stock",
recipientRequired: "Recipient is required",
invalidStatus: "Invalid status",
genericFailure: "Error processing asset",
},
schema: {
itemRequired: "Item is required",
serialNumberRequired: "Serial number is required",
idRequired: "ID is required",
statusRequired: "Status is required",
invalidCreateStatus: "Status must be Available or Assigned",
invalidUpdateStatus: "Invalid status",
},
})
expect(getDictionary("es").inventory.assets).toEqual({
list: {
title: "Activos",
addLabel: "Agregar activo",
empty: "No se encontraron activos.",
columns: {
item: "Artículo",
category: "Categoría",
serialNumber: "Número de serie",
status: "Estado",
actions: "Acciones",
},
actions: {
edit: "Editar activo",
},
},
new: {
title: "Nuevo activo",
},
edit: {
title: "Editar activo",
notFound: "Activo no encontrado",
},
form: {
itemLabel: "Artículo",
itemPlaceholder: "Selecciona un artículo",
serialNumberLabel: "Número de serie",
serialNumberPlaceholder: "Número de serie",
deliveryNoteLabel: "Remito",
deliveryNotePlaceholder: "Remito",
statusLabel: "Estado",
statusPlaceholder: "Selecciona un estado",
recipientLabel: "Destinatario",
recipientPlaceholder: "Selecciona un destinatario",
createSubmit: "Crear activo",
updateSubmit: "Actualizar activo",
},
status: {
AVAILABLE: "Disponible",
ASSIGNED: "Asignado",
RESERVED: "Reservado",
IN_REPAIR: "En reparación",
BROKEN: "Roto",
STOLEN: "Robado",
DISPOSED: "Dado de baja",
},
fallback: {
unknownStatus: "Estado desconocido",
},
actions: {
createSuccess: "Activo creado correctamente",
createFailure: "Error al crear el activo",
updateSuccess: "Activo actualizado correctamente",
updateFailure: "Error al actualizar el activo",
duplicateSerialNumber: "El número de serie ya existe",
notFound: "Activo no encontrado",
itemNotFound: "Artículo no encontrado",
assignmentAlreadyReturned: "La asignación ya fue devuelta",
previousItemNotFound:
"Artículo anterior no encontrado para el activo disponible",
insufficientStock: "El artículo no tiene stock suficiente",
recipientRequired: "El destinatario es obligatorio",
invalidStatus: "Estado inválido",
genericFailure: "Error al procesar el activo",
},
schema: {
itemRequired: "El artículo es obligatorio",
serialNumberRequired: "El número de serie es obligatorio",
idRequired: "El activo es obligatorio",
statusRequired: "El estado es obligatorio",
invalidCreateStatus: "El estado inicial debe ser Disponible o Asignado",
invalidUpdateStatus: "Estado inválido",
},
})
})
it("provides localized people UI copy for English and Spanish", () => {
expect(getDictionary("en").inventory.people).toEqual({
list: {
title: "People",
addLabel: "Add Person",
empty: "No people found.",
columns: {
name: "Name",
email: "Email",
phone: "Phone",
department: "Department",
actions: "Actions",
},
actions: {
view: "View person",
edit: "Edit person",
},
},
detail: {
notFound: "Person not found",
labels: {
email: "Email",
phone: "Phone",
department: "Department",
},
},
new: {
title: "Add Person",
},
edit: {
title: "Edit Person",
notFound: "Person not found",
},
form: {
firstNameLabel: "First Name",
firstNamePlaceholder: "First name",
lastNameLabel: "Last Name",
lastNamePlaceholder: "Last name",
departmentLabel: "Department",
departmentPlaceholder: "Select a department",
emailLabel: "Email",
emailPlaceholder: "Email",
phoneLabel: "Phone",
phonePlaceholder: "Phone",
createSubmit: "Create Person",
updateSubmit: "Update Person",
},
fallback: {
unknownDepartment: "Unknown department",
},
departments: {
IT: "IT",
ENGINEERING: "Engineering",
LOGISTICS: "Logistics",
TRAFFIC: "Traffic",
DRIVER: "Driver",
ADMINISTRATION: "Administration",
SALES: "Sales",
OTHER: "Other",
},
actions: {
createSuccess: "Person created successfully",
createFailure: "Failed to create person",
updateSuccess: "Person updated successfully",
updateFailure: "Failed to update person",
duplicateEmail: "Email already exists",
},
schema: {
firstNameRequired: "First name is required",
lastNameRequired: "Last name is required",
departmentRequired: "Department is required",
emailInvalid: "Email format is invalid",
idRequired: "ID is required",
userIdInvalid: "User ID must be a valid UUID",
},
})
expect(getDictionary("es").inventory.people).toEqual({
list: {
title: "Personas",
addLabel: "Agregar persona",
empty: "No se encontraron personas.",
columns: {
name: "Nombre",
email: "Correo electrónico",
phone: "Teléfono",
department: "Departamento",
actions: "Acciones",
},
actions: {
view: "Ver persona",
edit: "Editar persona",
},
},
detail: {
notFound: "Persona no encontrada",
labels: {
email: "Correo electrónico",
phone: "Teléfono",
department: "Departamento",
},
},
new: {
title: "Agregar persona",
},
edit: {
title: "Editar persona",
notFound: "Persona no encontrada",
},
form: {
firstNameLabel: "Nombre",
firstNamePlaceholder: "Nombre",
lastNameLabel: "Apellido",
lastNamePlaceholder: "Apellido",
departmentLabel: "Departamento",
departmentPlaceholder: "Selecciona un departamento",
emailLabel: "Correo electrónico",
emailPlaceholder: "Correo electrónico",
phoneLabel: "Teléfono",
phonePlaceholder: "Teléfono",
createSubmit: "Crear persona",
updateSubmit: "Actualizar persona",
},
fallback: {
unknownDepartment: "Departamento desconocido",
},
departments: {
IT: "IT",
ENGINEERING: "Ingeniería",
LOGISTICS: "Logística",
TRAFFIC: "Tráfico",
DRIVER: "Chofer",
ADMINISTRATION: "Administración",
SALES: "Ventas",
OTHER: "Otro",
},
actions: {
createSuccess: "Persona creada correctamente",
createFailure: "Error al crear la persona",
updateSuccess: "Persona actualizada correctamente",
updateFailure: "Error al actualizar la persona",
duplicateEmail: "El correo electrónico ya existe",
},
schema: {
firstNameRequired: "El nombre es obligatorio",
lastNameRequired: "El apellido es obligatorio",
departmentRequired: "El departamento es obligatorio",
emailInvalid: "El correo electrónico no es válido",
idRequired: "El ID es obligatorio",
userIdInvalid: "El ID de usuario debe ser un UUID válido",
},
})
})
it("does not have inventory.recipients or legacy recipient keys in either locale", () => {
expect("recipients" in getDictionary("en").inventory).toBe(false)
expect("recipients" in getDictionary("es").inventory).toBe(false)
expect("recipients" in getDictionary("en").layout.sidebar).toBe(false)
expect("recipient" in getDictionary("en").layout.addMenu).toBe(false)
expect("recipients" in getDictionary("es").layout.sidebar).toBe(false)
expect("recipient" in getDictionary("es").layout.addMenu).toBe(false)
expect("recipients" in getDictionary("en").dashboardHome.cards).toBe(false)
expect("recipients" in getDictionary("es").dashboardHome.cards).toBe(false)
})
it("provides localized movement UI copy for English and Spanish", () => {
expect(getDictionary("en").inventory.movements).toEqual({
list: {
title: "Movements",
empty: "No movements found",
columns: {
type: "Type",
item: "Item",
serialNumber: "Serial Number",
quantity: "Quantity",
recipient: "Recipient",
date: "Date",
},
},
snippet: {
title: "Movements",
labels: {
type: "Type",
quantity: "Quantity",
},
},
types: {
IN: "In",
OUT: "Out",
ASSIGNMENT: "Assignment",
RETURN: "Return",
ADJUSTMENT: "Adjustment",
DELETED: "Deleted",
},
fallback: {
missingValue: "-",
unknownType: "Unknown movement type",
},
})
expect(getDictionary("es").inventory.movements).toEqual({
list: {
title: "Movimientos",
empty: "No se encontraron movimientos.",
columns: {
type: "Tipo",
item: "Artículo",
serialNumber: "Número de serie",
quantity: "Cantidad",
recipient: "Destinatario",
date: "Fecha",
},
},
snippet: {
title: "Movimientos",
labels: {
type: "Tipo",
quantity: "Cantidad",
},
},
types: {
IN: "Entrada",
OUT: "Salida",
ASSIGNMENT: "Asignación",
RETURN: "Devolución",
ADJUSTMENT: "Ajuste",
DELETED: "Eliminación",
},
fallback: {
missingValue: "-",
unknownType: "Tipo de movimiento desconocido",
},
})
})
it("keeps dashboard home dictionary keys aligned across locales", () => {
expect(getDictionary("en").dashboardHome).toEqual({
heading: "Dashboard",
cards: {
items: {
title: "Total Items",
countLabel: "Total",
},
assets: {
title: "Total Assets",
countLabel: "Total",
},
people: {
title: "Total People",
countLabel: "Total",
},
},
})
expect(getDictionary("es").dashboardHome).toEqual({
heading: "Panel de control",
cards: {
items: {
title: "Total de artículos",
countLabel: "Total",
},
assets: {
title: "Total de activos",
countLabel: "Total",
},
people: {
title: "Total de personas",
countLabel: "Total",
},
},
})
})
it("has exact structural parity between English and Spanish dictionaries", () => {
expect(extractKeyPaths(getDictionary("es"))).toEqual(
extractKeyPaths(getDictionary("en")),
)
})
})
function extractKeyPaths(value: unknown, prefix = ""): string[] {
if (!isPlainObject(value)) return [prefix]
return Object.keys(value)
.sort()
.flatMap((key) =>
extractKeyPaths(value[key], prefix ? `${prefix}.${key}` : key),
)
}
function isPlainObject(value: unknown): value is Record<string, unknown> {
return typeof value === "object" && value !== null && !Array.isArray(value)
}