Cadenas

Cómo internacionalizar cadenas de texto sin formato con useGT y getGT

La traducción de cadenas ofrece acceso directo a traducciones de texto sin JSX, ideal para atributos, propiedades de objetos y valores de texto sin formato. Usa useGT en componentes sincrónicos y getGT en componentes asincrónicos.

Uso sincrónico vs asincrónico

  • Componentes sincrónicos: hook useGT para componentes de React
  • Componentes asincrónicos: función asíncrona getGT para componentes asincrónicos

Comenzar rápido

Componentes síncronos

import { useGT } from 'gt-next';

function MyComponent() {
  const t = useGT();
  return (
    <input 
      placeholder={t('Introduce tu correo electrónico')}
      title={t('Campo de correo electrónico')}
    />
  );
}

Componentes asincrónicos

import { getGT } from 'gt-next/server';

async function MyServerComponent() {
  const t = await getGT();
  return (
    <input 
      placeholder={t('Introduce tu correo electrónico')}
      title={t('Campo de correo electrónico')}
    />
  );
}

Cuándo usar la traducción de cadenas

La traducción de cadenas es ideal cuando necesitas texto plano en lugar de JSX:

Atributos de HTML

const t = useGT();

<input 
  placeholder={t('Buscar productos...')}
  aria-label={t('Campo de búsqueda de productos')}
  title={t('Escribe para buscar en nuestro catálogo')}
/>

Propiedades de objetos

const t = useGT();

const user = {
  name: 'John',
  role: 'admin',
  bio: t('Desarrollador de software con 5 años de experiencia en React'),
  status: t('Disponible actualmente para proyectos')
};

Configuración y constantes

const t = useGT();

const navigationItems = [
  { label: t('Inicio'), href: '/' },
  { label: t('Productos'), href: '/products' },
  { label: t('Contacto'), href: '/contact' }
];

Cuándo usar <T> en su lugar

Usa el componente <T> para contenido JSX:

// ✅ Usa <T> para contenido JSX
<T><p>¡Bienvenido(a) a <strong>nuestra tienda</strong>!</p></T>

// ✅ Usa traducción de cadenas para texto sin formato
<input placeholder={t('Buscar productos')} />

Uso de variables

Variables básicas

Sustituye los marcadores por valores dinámicos:

const t = useGT();
const itemCount = 5;

// String with placeholder
const message = t('Tienes {count} artículos en tu carrito', { count: itemCount });
// Resultado: "Tienes 5 artículos en tu carrito"

Varias variables

const t = useGT();
const order = { id: 'ORD-123', total: 99.99, date: '2024-01-15' };

const confirmation = t(
  'El pedido {orderId} por ${total} se efectuó el {date}',
  { 
    orderId: order.id, 
    total: order.total, 
    date: order.date 
  }
);

Formato de mensajes ICU

Para un formateo avanzado, usa la sintaxis de ICU:

const t = useGT();
translate('Hay {count, plural, =0 {ningún artículo} =1 {un artículo} other {{count} artículos}} en el carrito', { count: 10 });

Obtén más información sobre ICU message format en la documentación de Unicode.

Ejemplos

Campos de formulario

import { useGT } from 'gt-next';

function ContactForm() {
  const t = useGT();
  
  return (
    <form>
      <input 
        type="email"
        placeholder={t('Introduce tu correo electrónico')}
        aria-label={t('Campo de correo electrónico')}
      />
      <textarea 
        placeholder={t('Cuéntanos sobre tu proyecto...')}
        aria-label={t('Descripción del proyecto')}
      />
      <button type="submit">
        {t('Enviar mensaje')}
      </button>
    </form>
  );
}

Menú de navegación

import { useGT } from 'gt-next';

function Navigation() {
  const t = useGT();
  
  const menuItems = [
    { label: t('Inicio'), href: '/', icon: 'home' },
    { label: t('Acerca de'), href: '/about', icon: 'info' },
    { label: t('Servicios'), href: '/services', icon: 'briefcase' },
    { label: t('Contacto'), href: '/contact', icon: 'mail' }
  ];

  return (
    <nav>
      {menuItems.map((item) => (
        <a key={item.href} href={item.href} title={item.label}>
          <Icon name={item.icon} />
          {item.label}
        </a>
      ))}
    </nav>
  );
}

Fábrica de contenido dinámico

/* eslint-disable */
 // utils/productData.js
export function getProductMessages(t) {
  return {
    categories: [
      { id: 'electronics', name: t('Electrónica') },
      { id: 'clothing', name: t('Ropa') },
      { id: 'books', name: t('Libros') }
    ],
    statusMessages: {
      available: t('En stock y listo para enviar'),
      backordered: t('Actualmente en pedido pendiente - se envía en 2-3 semanas'),  
      discontinued: t('Este artículo ha sido descontinuado')
    },
    errors: {
      notFound: t('Producto no encontrado'),
      outOfStock: t('Lo sentimos, este artículo no está disponible actualmente')
    }
  };
}

// components/ProductCard.jsx
import { useGT } from 'gt-next';
import { getProductMessages } from '../utils/productData';

function ProductCard({ product }) {
  const t = useGT();
  const messages = getProductMessages(t);
  
  return (
    <div>
      <h3>{product.name}</h3>
      <p>{messages.statusMessages[product.status]}</p>
      <span>{messages.categories.find(c => c.id === product.categoryId)?.name}</span>
    </div>
  );
}

Componente de servidor con metadatos

import { getGT } from 'gt-next/server';

export async function generateMetadata({ params }) {
  const t = await getGT();
  
  return {
    title: t('Catálogo de productos: encuentra lo que necesitas'),
    description: t('Explora nuestra amplia selección de productos de alta calidad'),
    openGraph: {
      title: t('Compra nuestros productos'),
      description: t('Descubre ofertas increíbles en artículos mejor valorados')
    }
  };
}

export default async function ProductPage() {
  const t = await getGT();
  
  return (
    <div>
      <h1>{t('Productos destacados')}</h1>
      <p>{t('Descubre nuestros artículos más recientes y populares')}</p>
    </div>
  );
}

Problemas habituales

Contenido dinámico en tiempo de ejecución

Las cadenas deben conocerse en tiempo de compilación: no puedes traducir contenido dinámico.

// ❌ El contenido dinámico no funcionará
function MyComponent() {
  const [userMessage, setUserMessage] = useState('');
  const t = useGT();
  
  return <p>{t(userMessage)}</p>; // Esto fallará
}

// ✅ Usa cadenas predefinidas
function MyComponent() {
  const [messageType, setMessageType] = useState('welcome');
  const t = useGT();
  
  const messages = {
    welcome: t('¡Bienvenido a nuestra app!'),
    goodbye: t('¡Gracias por visitarnos!')
  };
  
  return <p>{messages[messageType]}</p>;
}

Incumplimientos de las reglas de hooks

Sigue las reglas de los hooks de React al usar useGT:

// ❌ No llames a los hooks de forma condicional
function MyComponent({ showMessage }) {
  if (showMessage) {
    const t = useGT(); // Incumplimiento de las reglas de los hooks
    return <p>{t('¡Hola!')}</p>;
  }
  return null;
}

// ✅ Llama siempre a los hooks en el nivel superior
function MyComponent({ showMessage }) {
  const t = useGT();
  
  if (showMessage) {
    return <p>{t('¡Hola!')}</p>;
  }
  return null;
}

Confusión entre lo síncrono y lo asíncrono

Usa la función adecuada para tu tipo de componente:

// ❌ Incorrecto: useGT en un componente asíncrono
export default async function AsyncComponent() {
  const t = useGT(); // Esto no funcionará
  return <p>{t('Hola')}</p>;
}

// ✅ Correcto: getGT en un componente asíncrono  
export default async function AsyncComponent() {
  const t = await getGT();
  return <p>{t('Hola')}</p>;
}

// ✅ Correcto: useGT en un componente sincrónico
export default function SyncComponent() {
  const t = useGT();
  return <p>{t('Hola')}</p>;
}

Para contenido realmente dinámico que requiere traducción en tiempo de ejecución, consulta la Guía de contenido dinámico.

Próximos pasos

¿Qué te parece esta guía?