Ir al contenido

TalentBricksAI usa un sistema de internacionalizacion custom basado en TypeScript puro — sin librerias externas. Soporta español (fuente) e inglés (default, generado por IA).

Los archivos de locale estan organizados por dominio bajo app/src/shared/content/locales/:

locales/
├── es/ # Español (fuente de verdad, editado manualmente)
│ ├── brand.ts
│ ├── nav.ts
│ ├── auth.ts
│ ├── landing.ts
│ ├── courses.ts
│ ├── pricing.ts
│ ├── account.ts
│ ├── common.ts
│ ├── footer.ts
│ ├── errors.ts
│ ├── admin.ts
│ ├── certificate.ts
│ └── index.ts # Re-exporta todo como `es` + tipo `LocaleContent`
├── en/ # inglés (generado por IA)
│ ├── brand.ts
│ ├── ... (misma estructura)
│ └── index.ts # Tipado como `LocaleContent` desde es/

Cada módulo de dominio exporta un objeto const con asercion as const:

locales/es/nav.ts
export const nav = {
home: "inicio",
courses: "Cursos",
pricing: "Precios",
login: "Iniciar sesión",
logout: "Cerrar sesión",
// ...
} as const;

El archivo app/src/shared/i18n.tsx contiene:

  • I18nProvider: React Context que envuelve la app en App.tsx
  • useTranslation(): Hook que retorna { locale, setLocale, t }
  • t(key): función que navega por paths con punto (ej: t("courses.detail.title"))
  1. Locale actual (ej: en)
  2. Español (es)
  3. El key como string + console.warn en desarrollo

El locale se guarda en localStorage bajo la key talentbricks-locale. Default: "en".

import { useTranslation } from "../shared/i18n";
export function MyComponent() {
const { t } = useTranslation();
return (
<div>
<h1>{t("courses.catalog.title")}</h1>
<p>{t("courses.catalog.subtitle")}</p>
</div>
);
}

Para archivos que exportan constantes a nivel de módulo, usar funciones factory:

// Antes (no reactivo al cambio de idioma):
export const items = [{ name: es.nav.courses, to: "/courses" }];
// Después (reactivo):
export function getItems(t: (key: string) => any) {
return [{ name: t("nav.courses"), to: "/courses" }];
}

t() retorna any — puede devolver strings, arrays u objetos:

// Acceder a un objeto de dificultad
const difficulties = t("courses.detail.difficulty") as Record<string, string>;
const label = difficulties[course.difficulty]; // "Principiante"
// Acceder a un array
const features = t("courses.detail.includesList") as string[];

El componente LanguageSwitcher está en app/src/client/components/LanguageSwitcher.tsx. Es un toggle EN/ES que se muestra en el NavBar (desktop y mobile).

  1. Agregar la key en el archivo de dominio correspondiente bajo locales/es/
  2. Agregar la traduccion equivalente en locales/en/
  3. Usar t("dominio.key.path") en el componente
  4. Nunca hardcodear strings traducibles en componentes
  1. Crear locales/es/nuevo-dominio.ts con export const nuevoDominio = { ... } as const;
  2. Crear locales/en/nuevo-dominio.ts con la misma estructura
  3. Importar y re-exportar en ambos index.ts
  4. El tipo LocaleContent se actualizara automaticamente
  • El español (es/) es la fuente de verdad — se edita manualmente
  • El inglés (en/) se genera por IA pero puede editarse manualmente
  • Los terminos tecnicos se mantienen en inglés en ambos idiomas: Data Engineering, MLOps, Databricks, etc.
  • Los placeholders con {variable} deben preservarse exactamente entre idiomas