Как отображать информацию о валюте в React Router v7

Показывайте коды, названия и символы валют

Проблема

Приложения часто должны показывать информацию о валюте без форматированной цены. В селекторе валюты может отображаться «USD» или «доллар США», а на финансовой панели — только символ «$». Каждый формат нужен для своей задачи, но у всех есть общие сложности. Код ISO «USD» точен, но непонятен для обычных пользователей. Полное название «доллар США» ясно, но требует перевода для международной аудитории. Символ «$» компактен, но неоднозначен — он может означать доллары США, Канады или Австралии в зависимости от контекста. Неправильный формат сбивает пользователей с толку и подрывает доверие к финансовым интерфейсам.

Задача усложняется при создании многоязычных приложений. Название валюты, подходящее на английском, может не переводиться напрямую на другие языки, а символы валют различаются в зависимости от региона. Жёстко заданные значения усложняют поддержку и ограничивают охват вашего приложения.

Решение

Используйте метод formatDisplayName из react-intl для отображения локализованных названий и кодов валют, а также API браузера Intl.NumberFormat для получения символов валют. Метод formatDisplayName принимает код валюты и возвращает подходящее локализованное название в зависимости от языка пользователя, автоматически обрабатывая перевод. Для символов отформатируйте пример числа с нужной валютой и извлеките символ из результата.

Создайте отдельные вспомогательные функции или компоненты для каждого формата отображения — полного названия, символа или кода — чтобы выбирать нужное представление в каждом контексте. Такой подход централизует логику отображения валют и обеспечивает единообразие по всему приложению, учитывая предпочтения пользователя по языку.

Шаги

1. Создайте хелпер для отображения локализованных названий валют

Используйте метод formatDisplayName с type: 'currency', чтобы преобразовать ISO-коды валют в локализованные полные названия.

import { useIntl } from "react-intl";

export function CurrencyName({ code }: { code: string }) {
  const intl = useIntl();
  const name = intl.formatDisplayName(code, { type: "currency" });
  return <span>{name}</span>;
}

Если локаль — "en", а код — "CNY", будет отображаться "Chinese Yuan". Метод автоматически переводит название в зависимости от текущей локали из IntlProvider.

2. Создайте хелпер для извлечения и отображения символов валют

Используйте Intl.NumberFormat с formatToParts, чтобы извлечь символ валюты, фильтруя части по type === "currency".

function getCurrencySymbol(locale: string, currency: string): string {
  const parts = new Intl.NumberFormat(locale, {
    style: "currency",
    currency,
    currencyDisplay: "narrowSymbol",
  }).formatToParts(0);

  const currencyPart = parts.find((part) => part.type === "currency");
  return currencyPart?.value || currency;
}

export function CurrencySymbol({ code }: { code: string }) {
  const intl = useIntl();
  const symbol = getCurrencySymbol(intl.locale, code);
  return <span>{symbol}</span>;
}

Опция currencyDisplay управляет формой валюты: "narrowSymbol" даёт самое компактное представление. Такой подход автоматически учитывает особенности размещения и форматирования символа для разных локалей.

3. Создайте компонент с несколькими вариантами отображения

Соберите гибкий компонент, который принимает пропс режима отображения для переключения между кодом, символом и названием валюты.

import { useIntl } from "react-intl";

type CurrencyDisplayMode = "code" | "symbol" | "name";

interface CurrencyInfoProps {
  code: string;
  display?: CurrencyDisplayMode;
}

export function CurrencyInfo({ code, display = "symbol" }: CurrencyInfoProps) {
  const intl = useIntl();

  if (display === "name") {
    const name = intl.formatDisplayName(code, { type: "currency" });
    return <span>{name}</span>;
  }

  if (display === "symbol") {
    const parts = new Intl.NumberFormat(intl.locale, {
      style: "currency",
      currency: code,
      currencyDisplay: "narrowSymbol",
    }).formatToParts(0);
    const symbol =
      parts.find((part) => part.type === "currency")?.value || code;
    return <span>{symbol}</span>;
  }

  return <span>{code}</span>;
}

Этот компонент централизует логику отображения валют и позволяет легко менять формат в зависимости от контекста интерфейса. Используйте display="name" для селекторов валют, где важна ясность, display="symbol" для компактных мест, например, заголовков таблиц, и display="code" для технических или финансовых отчётов.

4. Используйте компонент в разных контекстах

Применяйте подходящий режим отображения в зависимости от того, где информация о валюте появляется в интерфейсе.

export default function CurrencyExample() {
  return (
    <div>
      <label htmlFor="currency-select">
        Select currency: <CurrencyInfo code="EUR" display="name" />
      </label>

      <table>
        <thead>
          <tr>
            <th>
              Amount (<CurrencyInfo code="USD" display="symbol" />)
            </th>
          </tr>
        </thead>
      </table>

      <p>
        Transaction currency: <CurrencyInfo code="GBP" display="code" />
      </p>
    </div>
  );
}

В каждом контексте используется формат, который лучше всего подходит для задачи: полные названия — для интерфейсов выбора, символы — для компактных отображений, коды — для точных технических ссылок. Компонент автоматически локализует данные на основе локали пользователя из IntlProvider.