Строки

Как интернационализировать простые текстовые строки с помощью useGT и getGT

Перевод строк предоставляет прямой доступ к переводам текста без JSX — это удобно для атрибутов, свойств объектов и обычных текстовых значений. Используйте useGT в синхронных компонентах и getGT в асинхронных.

Синхронное и асинхронное использование

  • Синхронные компоненты: хук useGT для React‑компонентов
  • Асинхронные компоненты: асинхронная функция getGT для асинхронных компонентов

Быстрый старт

Синхронные компоненты

import { useGT } from 'gt-next';

function MyComponent() {
  const t = useGT();
  return (
    <input 
      placeholder={t('Введите вашу электронную почту')}
      title={t('Поле адреса электронной почты')}
    />
  );
}

Асинхронные компоненты

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

async function MyServerComponent() {
  const t = await getGT();
  return (
    <input 
      placeholder={t('Введите ваш email')}
      title={t('Поле ввода email-адреса')}
    />
  );
}

Когда использовать перевод строк

Перевод строк подходит, когда вам нужен обычный текст, а не JSX:

Атрибуты HTML

const t = useGT();

<input 
  placeholder={t('Поиск товаров...')}
  aria-label={t('Поле для поиска товаров')}
  title={t('Начните вводить текст для поиска в каталоге')}
/>

Свойства объектов

const t = useGT();

const user = {
  name: 'John',
  role: 'admin',
  bio: t('Опытный разработчик ПО с 5-летним опытом работы с React'),
  status: t('Доступен для новых проектов')
};

Конфигурация и константы

const t = useGT();

const navigationItems = [
  { label: t('Главная'), href: '/' },
  { label: t('Продукты'), href: '/products' },
  { label: t('Связаться'), href: '/contact' }
];

Когда использовать <T>

Используйте компонент <T> для JSX‑контента:

// ✅ Используйте <T> для JSX‑контента
<T><p>Добро пожаловать в <strong>наш магазин</strong>!</p></T>

// ✅ Используйте строковый перевод для простого текста
<input placeholder={t('Искать товары')} />

Работа с переменными

Базовые переменные

Заменяйте заполнительные значения динамическими:

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

// String with placeholder
const message = t('У вас {count} товара в корзине', { count: itemCount });
// Результат: «У вас 5 товаров в корзине»

Несколько переменных

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

const confirmation = t(
  'Заказ {orderId} на сумму ${total} оформлен {date}',
  { 
    orderId: order.id, 
    total: order.total, 
    date: order.date 
  }
);

Формат сообщений ICU

Для расширенного форматирования используйте синтаксис ICU:

const t = useGT();
translate('В корзине {count, plural, =0 {нет товаров} one {# товар} few {# товара} many {# товаров} other {# товара}}', { count: 10 });

Подробнее о формате сообщений ICU см. в документации Unicode.

Примеры

Элементы формы

import { useGT } from 'gt-next';

function ContactForm() {
  const t = useGT();
  
  return (
    <form>
      <input 
        type="email"
        placeholder={t('Введите адрес электронной почты')}
        aria-label={t('Поле для ввода email')}
      />
      <textarea 
        placeholder={t('Расскажите о вашем проекте...')}
        aria-label={t('Описание проекта')}
      />
      <button type="submit">
        {t('Отправить')}
      </button>
    </form>
  );
}

Навигационное меню

import { useGT } from 'gt-next';

function Navigation() {
  const t = useGT();
  
  const menuItems = [
    { label: t('Главная'), href: '/', icon: 'home' },
    { label: t('О нас'), href: '/about', icon: 'info' },
    { label: t('Услуги'), href: '/services', icon: 'briefcase' },
    { label: t('Контакты'), 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>
  );
}

Фабрика динамического контента

// utils/productData.js
export function getProductMessages(t) {
  return {
    categories: [
      { id: 'electronics', name: t('Электроника') },
      { id: 'clothing', name: t('Одежда') },
      { id: 'books', name: t('Книги') }
    ],
    statusMessages: {
      available: t('В наличии, готово к отправке'),
      backordered: t('Временно отсутствует — отправка через 2–3 недели'),  
      discontinued: t('Товар снят с производства')
    },
    errors: {
      notFound: t('Товар не найден'),
      outOfStock: t('К сожалению, товар временно отсутствует')
    }
  };
}

// 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>
  );
}

Компонент сервера с метаданными

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

export async function generateMetadata({ params }) {
  const t = await getGT();
  
  return {
    title: t('Каталог товаров — найдите всё, что вам нужно'),
    description: t('Просмотрите нашу обширную коллекцию качественных товаров'),
    openGraph: {
      title: t('Покупайте у нас'),
      description: t('Откройте отличные предложения на самые популярные товары')
    }
  };
}

export default async function ProductPage() {
  const t = await getGT();
  
  return (
    <div>
      <h1>{t('Рекомендуемые товары')}</h1>
      <p>{t('Ознакомьтесь с нашими новинками и самыми популярными товарами')}</p>
    </div>
  );
}

Распространённые проблемы

Динамический контент во время выполнения

Строки должны быть определены на этапе сборки — переводить динамический контент нельзя:

// ❌ Динамический контент не будет работать
function MyComponent() {
  const [userMessage, setUserMessage] = useState('');
  const t = useGT();
  
  return <p>{t(userMessage)}</p>; // Это не сработает
}

// ✅ Используйте заранее определённые строки
function MyComponent() {
  const [messageType, setMessageType] = useState('welcome');
  const t = useGT();
  
  const messages = {
    welcome: t('Добро пожаловать в наше приложение!'),
    goodbye: t('Спасибо, что заглянули!')
  };
  
  return <p>{messages[messageType]}</p>;
}

Нарушения правил хуков

Соблюдайте правила хуков React при использовании useGT:

// ❌ Не вызывайте хуки условно
function MyComponent({ showMessage }) {
  if (showMessage) {
    const t = useGT(); // Нарушение правила хуков
    return <p>{t('Привет!')}</p>;
  }
  return null;
}

// ✅ Всегда вызывайте хуки на верхнем уровне
function MyComponent({ showMessage }) {
  const t = useGT();
  
  if (showMessage) {
    return <p>{t('Привет!')}</p>;
  }
  return null;
}

Синхронно vs асинхронно: частая путаница

Используйте подходящую функцию для вашего типа компонента:

// ❌ Неверно: useGT в асинхронном компоненте
export default async function AsyncComponent() {
  const t = useGT(); // Это не сработает
  return <p>{t('Hello')}</p>;
}

// ✅ Правильно: getGT в асинхронном компоненте  
export default async function AsyncComponent() {
  const t = await getGT();
  return <p>{t('Hello')}</p>;
}

// ✅ Правильно: useGT в синхронном компоненте
export default function SyncComponent() {
  const t = useGT();
  return <p>{t('Hello')}</p>;
}

Для по‑настоящему динамического контента, которому нужен перевод на этапе выполнения, см. руководство по динамическому контенту.

Дальнейшие шаги

Насколько полезно это руководство?

Строки