How to mark mixed-language content in React Router v7

Mark text in different languages for accessibility

Problem

When a page contains text in multiple languages, browsers and assistive technologies assume all content uses the page's declared language. A screen reader configured for English will attempt to pronounce French phrases, Spanish book titles, or German names using English phonetics, producing unintelligible output for users who rely on audio. Browsers apply spell-checking and typography rules based on the page language, incorrectly flagging foreign words as errors and mishandling language-specific punctuation. Search engines and translation tools cannot accurately process mixed-language content without explicit language markers.

This affects not only screen reader users but anyone using browser features that depend on language detection, including automatic translation, text-to-speech, and reading mode.

Solution

Wrap foreign-language text in HTML elements with a lang attribute set to the correct language code. The lang attribute instructs browsers and assistive technologies to switch language rules for that specific content, ensuring correct pronunciation by screen readers and appropriate spell-checking and typography by browsers.

Use semantic HTML elements like <span> or <i> to wrap inline foreign text without disrupting layout. The lang attribute accepts ISO 639-1 language codes (such as fr for French or es for Spanish) and optional region codes for dialect-specific handling.

Steps

1. Create a component for marking foreign-language text

Build a reusable component that wraps text in a span element with the appropriate lang attribute.

type ForeignTextProps = {
  lang: string;
  children: React.ReactNode;
};

export function ForeignText({ lang, children }: ForeignTextProps) {
  return <span lang={lang}>{children}</span>;
}

This component accepts a language code and wraps its children in a span with the lang attribute, allowing screen readers to switch pronunciation rules for the enclosed text.

2. Use the component to mark inline foreign text

Wrap foreign words or phrases within your content using the ForeignText component.

export default function ArticlePage() {
  return (
    <article>
      <h1>International Cuisine</h1>
      <p>
        The restaurant's signature dish is{" "}
        <ForeignText lang="fr">coq au vin</ForeignText>, a classic French
        preparation that pairs perfectly with their house wine.
      </p>
      <p>
        Their dessert menu features{" "}
        <ForeignText lang="es">tres leches</ForeignText> and{" "}
        <ForeignText lang="it">tiramisu</ForeignText>.
      </p>
    </article>
  );
}

Screen readers will now pronounce "coq au vin" using French phonetics, "tres leches" using Spanish phonetics, and "tiramisu" using Italian phonetics, while the surrounding English text uses English pronunciation.

3. Mark longer foreign-language passages

For multi-sentence foreign content, apply the lang attribute directly to block-level elements.

export default function QuotePage() {
  return (
    <article>
      <h1>Universal Declaration of Human Rights</h1>
      <h2>Article 1</h2>
      <blockquote lang="fr">
        <p>
          Tous les êtres humains naissent libres et égaux en dignité et en
          droits. Ils sont doués de raison et de conscience et doivent agir les
          uns envers les autres dans un esprit de fraternité.
        </p>
      </blockquote>
    </article>
  );
}

Applying lang to the blockquote element marks the entire quotation as French, ensuring correct pronunciation and typography for the full passage.

4. Combine with translated UI text

When displaying foreign content alongside translated interface text, use react-intl for UI elements and lang attributes for user-generated or quoted content.

import { FormattedMessage } from "react-intl";
import { ForeignText } from "~/components/ForeignText";

export default function BookReview() {
  return (
    <article>
      <h1>
        <FormattedMessage id="review.title" defaultMessage="Book Review" />
      </h1>
      <p>
        <FormattedMessage
          id="review.intro"
          defaultMessage="The novel {title} explores themes of identity and belonging."
          values={{
            title: <ForeignText lang="de">Der Steppenwolf</ForeignText>,
          }}
        />
      </p>
    </article>
  );
}

The interface text adapts to the user's locale through react-intl, while the book title retains its original German with proper language marking for accessibility.