Next.js(Pages Router) v16에서 혼합 언어 콘텐츠 표시하는 방법

접근성을 위한 다양한 언어의 텍스트 표시하기

문제

페이지에 여러 언어의 텍스트가 포함되어 있을 때, 브라우저와 보조 기술은 모든 콘텐츠가 페이지의 주요 언어에 속한 것처럼 취급합니다. 영어로 설정된 스크린 리더는 프랑스어 문구, 스페인어 책 제목 또는 독일어 회사 이름을 영어 발음 규칙으로 읽으려고 시도하여, 오디오에 의존하는 사용자에게 이해할 수 없는 출력을 생성합니다. 브라우저는 잘못된 언어를 기반으로 맞춤법 검사 및 타이포그래피 규칙을 적용하여 올바르게 철자가 표기된 외국어 단어를 오류로 표시하고 언어별 구두점 및 서식 지정 규칙을 잘못 처리합니다.

이는 정확한 발음에 의존하는 시각 장애가 있는 사용자에게 장벽을 만들고, 잘못된 맞춤법 검사 경고와 부적절한 텍스트 렌더링으로 인한 시각적 노이즈를 도입하여 모든 사용자의 경험을 저하시킵니다.

해결책

외국어 텍스트를 포함하는 요소에 HTML lang 속성을 적용하여 해당 콘텐츠의 언어를 명시적으로 선언합니다. 이 속성은 브라우저와 보조 기술에 표시된 텍스트가 페이지의 주요 언어가 아닌 선언된 언어의 규칙을 사용하여 처리되어야 함을 알립니다. 스크린 리더는 적절한 발음 엔진으로 전환하고, 브라우저는 올바른 맞춤법 검사 사전을 적용하며, 타이포그래피 엔진은 언어별 서식 지정 규칙을 사용합니다.

올바른 lang 속성이 있는 요소로 외국어 텍스트를 감싸면 다국어 텍스트의 무결성을 보존하는 명확한 언어 경계를 콘텐츠 내에 만들 수 있습니다.

단계

1. 언어 표시 텍스트 컴포넌트 만들기

외국어 콘텐츠를 적절한 lang 속성이 있는 span 요소로 감싸는 React 컴포넌트를 구축합니다.

interface ForeignTextProps {
  lang: string;
  children: React.ReactNode;
}

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

이 컴포넌트는 언어 코드를 받아 그 자식 요소를 lang 속성이 설정된 span으로 감싸서 보조 기술과 브라우저가 인식할 수 있는 언어 경계를 만듭니다.

2. 외국어 구문을 표시하기 위해 컴포넌트 사용하기

콘텐츠 내의 외국어 텍스트를 적절한 ISO 639-1 언어 코드를 지정하여 컴포넌트로 감싸세요.

export default function ArticlePage() {
  return (
    <article>
      <h1>프랑스 요리 이해하기</h1>
      <p>
        <ForeignText lang="fr">mise en place</ForeignText> 개념은
        전문적인 요리에 기본적입니다. 이는 요리를 시작하기 전에 모든 재료를
        준비하고 정리해 두는 것을 의미합니다.
      </p>
      <p>
        뉴욕의 레스토랑 <ForeignText lang="fr">Le Bernardin</ForeignText>은
        수십 년 동안 미슐랭 3스타를 유지해 왔습니다.
      </p>
    </article>
  );
}

각 외국어 구문은 해당 언어 코드와 함께 컴포넌트로 감싸져 있어, 스크린 리더가 올바르게 발음하고 브라우저가 적절한 언어 규칙을 적용할 수 있습니다.

3. 더 긴 외국어 구절 처리하기

여러 문장으로 된 외국어 콘텐츠의 경우, 언어 컨텍스트가 분리되지 않도록 전체 구절을 하나의 언어 표시 요소로 감싸세요.

export default function QuotePage() {
  return (
    <article>
      <h1>세계 인권 선언</h1>
      <h2>제1조</h2>
      <blockquote lang="es">
        <p>
          Todos los seres humanos nacen libres e iguales en dignidad y derechos
          y, dotados como están de razón y conciencia, deben comportarse
          fraternalmente los unos con los otros.
        </p>
      </blockquote>
    </article>
  );
}

langblockquotep와 같은 블록 레벨 요소에 직접 적용하면 전체 구절이 표시되어 스크린 리더가 일관된 발음을 유지하고 브라우저가 전체 컨텍스트에 언어 규칙을 적용할 수 있습니다.

4. 형식이 지정된 메시지에서 외국어 텍스트 표시하기

번역된 메시지 내에 외국어 콘텐츠가 나타날 때는 메시지의 리치 텍스트 형식 내에서 컴포넌트를 사용하세요.

import { FormattedMessage } from "react-intl";

export default function RecipePage() {
  return (
    <div>
      <FormattedMessage
        id="recipe.description"
        defaultMessage="This dish is called {dishName} in French cuisine."
        values={{
          dishName: <ForeignText lang="fr">coq au vin</ForeignText>,
        }}
      />
    </div>
  );
}

이 컴포넌트는 react-intl의 리치 텍스트 형식과 통합되어 번역된 콘텐츠 내에서 외국어 용어를 표시하면서 보조 기술을 위한 언어 경계를 유지할 수 있습니다.

5. 의미적 강조를 위한 변형 만들기

외국어 텍스트에 강조나 관용적 스타일이 필요할 때 의미적 HTML 요소를 사용하도록 패턴을 확장하세요.

interface ForeignEmphasisProps {
  lang: string;
  children: React.ReactNode;
}

export function ForeignEmphasis({ lang, children }: ForeignEmphasisProps) {
  return <i lang={lang}>{children}</i>;
}

i 요소는 의미적으로 다른 어조나 분위기의 텍스트를 나타내므로, 주변 텍스트와 구분되는 외국어 용어에 적합합니다. lang 속성은 올바른 발음을 보장하는 동시에 요소는 의미적 의미를 제공합니다.

6. 지원되는 언어 코드 문서화하기

애플리케이션이 지원하는 언어 코드를 정의하는 타입이나 상수를 만들어 일관성을 보장하고 개발 시점에 오류를 잡을 수 있도록 하세요.

export const SUPPORTED_LANGUAGES = {
  FRENCH: "fr",
  SPANISH: "es",
  GERMAN: "de",
  ITALIAN: "it",
  JAPANESE: "ja",
  CHINESE: "zh",
} as const;

type LanguageCode =
  (typeof SUPPORTED_LANGUAGES)[keyof typeof SUPPORTED_LANGUAGES];

interface ForeignTextProps {
  lang: LanguageCode | string;
  children: React.ReactNode;
}

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

지원되는 언어를 상수로 정의하면 에디터에서 자동 완성 기능을 제공하고 애플리케이션 전체에서 사용되는 언어 코드를 문서화하는 동시에, 필요할 때 임의의 언어 코드도 허용할 수 있습니다.