로케일에서 언어, 국가, 스크립트를 추출하는 방법

JavaScript를 사용하여 로케일 식별자를 파싱하고 개별 구성 요소에 접근하기

소개

로케일 식별자(예: en-US, fr-CA, zh-Hans-CN)는 단일 문자열에 여러 정보를 인코딩합니다. 이러한 구성 요소는 사용 중인 언어, 해당 언어가 사용되는 지역, 때로는 사용되는 문자 체계를 알려줍니다.

국제화된 애플리케이션을 구축할 때, 이러한 개별 구성 요소를 추출해야 하는 경우가 많습니다. 사용자에게 언어 이름만 표시하거나, 지역별로 로케일을 그룹화하거나, 로케일이 사용하는 스크립트를 확인하고 싶을 수 있습니다. 정규식으로 문자열을 수동으로 파싱하는 대신, JavaScript는 Intl.Locale API를 제공하여 구성 요소를 안정적으로 추출할 수 있게 합니다.

이 가이드는 로케일 식별자에 존재하는 구성 요소, Intl.Locale API를 사용하여 이를 추출하는 방법, 그리고 실제로 이러한 구성 요소를 언제 사용해야 하는지 설명합니다.

로케일 식별자에 존재하는 구성 요소

로케일 식별자는 BCP 47 표준을 따르며, 이 표준은 언어와 지역적 변형을 설명하기 위한 구조를 정의합니다. 완전한 로케일 식별자는 하이픈으로 구분된 여러 구성 요소를 포함할 수 있습니다.

가장 일반적인 세 가지 구성 요소는 다음과 같습니다:

  • 언어: 영어, 스페인어, 중국어와 같이 사용되는 주요 언어
  • 지역: 미국, 캐나다, 중국과 같이 언어가 사용되는 지리적 영역
  • 스크립트: 라틴 문자, 키릴 문자, 한자와 같이 언어를 표현하는 데 사용되는 문자 체계

간단한 로케일 식별자는 언어 코드만 포함합니다:

en

대부분의 로케일 식별자는 언어와 지역을 포함합니다:

en-US
fr-CA
es-MX

일부 로케일 식별자는 언어가 여러 문자 체계로 작성될 수 있을 때 스크립트를 포함합니다:

zh-Hans-CN
zh-Hant-TW
sr-Cyrl-RS
sr-Latn-RS

이러한 구성 요소를 이해하면 언어 폴백, 콘텐츠 선택 및 사용자 인터페이스 사용자 지정에 관한 결정을 내리는 데 도움이 됩니다.

Intl.Locale를 사용하여 구성 요소 추출하기

Intl.Locale API는 로케일 식별자 문자열을 구조화된 객체로 변환합니다. 로케일 객체를 생성하면 속성을 통해 구성 요소를 읽을 수 있습니다.

생성자에 식별자를 전달하여 로케일 객체를 생성합니다:

const locale = new Intl.Locale("en-US");

console.log(locale.language); // "en"
console.log(locale.region); // "US"

로케일 객체는 식별자의 각 구성 요소에 해당하는 속성을 노출합니다. 이러한 속성은 문자열 파싱 없이 구조화된 접근을 제공합니다.

언어 코드 추출하기

language 속성은 로케일 식별자의 언어 구성 요소를 반환합니다. 이는 주요 언어를 식별하는 두 글자 또는 세 글자 코드입니다.

const english = new Intl.Locale("en-US");
console.log(english.language); // "en"

const french = new Intl.Locale("fr-CA");
console.log(french.language); // "fr"

const chinese = new Intl.Locale("zh-Hans-CN");
console.log(chinese.language); // "zh"

언어 코드는 ISO 639 표준을 따릅니다. 일반적인 코드로는 영어의 en, 스페인어의 es, 프랑스어의 fr, 독일어의 de, 일본어의 ja, 중국어의 zh 등이 있습니다.

언어 코드는 유효한 로케일 식별자에 항상 존재합니다. 이는 유일하게 필수적인 구성 요소입니다.

const languageOnly = new Intl.Locale("ja");
console.log(languageOnly.language); // "ja"
console.log(languageOnly.region); // undefined

언어 코드를 추출하면 번역을 선택하거나, 텍스트 처리 규칙을 결정하거나, 사용자를 위한 언어 선택기를 구축하는 데 사용할 수 있습니다.

지역 코드 추출하기

region 속성은 로케일 식별자의 지역 구성 요소를 반환합니다. 이는 언어가 사용되는 지리적 영역을 식별하는 두 글자 코드입니다.

const americanEnglish = new Intl.Locale("en-US");
console.log(americanEnglish.region); // "US"

const britishEnglish = new Intl.Locale("en-GB");
console.log(britishEnglish.region); // "GB"

const canadianFrench = new Intl.Locale("fr-CA");
console.log(canadianFrench.region); // "CA"

지역 코드는 ISO 3166-1 표준을 따릅니다. 국가와 영토를 나타내기 위해 두 개의 대문자를 사용합니다. 일반적인 코드로는 미국의 US, 영국의 GB, 캐나다의 CA, 멕시코의 MX, 프랑스의 FR, 중국의 CN 등이 있습니다.

지역 코드는 날짜, 숫자, 통화의 형식을 변경합니다. 미국 영어는 월-일-년 날짜 형식과 소수점 구분자로 마침표를 사용합니다. 영국 영어는 일-월-년 날짜 형식과 천 단위 구분자로 쉼표를 사용합니다.

지역 코드는 로케일 식별자에서 선택 사항입니다. 로케일에 지역이 없으면 region 속성은 undefined를 반환합니다:

const genericSpanish = new Intl.Locale("es");
console.log(genericSpanish.region); // undefined

지역 코드를 추출하면 지역별 형식을 맞춤화하거나, 지역별 콘텐츠를 선택하거나, 사용자에게 위치 정보를 표시하는 데 사용할 수 있습니다.

스크립트 코드 추출하기

로케일 식별자의 스크립트 구성 요소는 script 속성을 통해 반환됩니다. 이는 언어를 표현하는 데 사용되는 문자 체계를 식별하는 네 글자 코드입니다.

const simplifiedChinese = new Intl.Locale("zh-Hans-CN");
console.log(simplifiedChinese.script); // "Hans"

const traditionalChinese = new Intl.Locale("zh-Hant-TW");
console.log(traditionalChinese.script); // "Hant"

const serbianCyrillic = new Intl.Locale("sr-Cyrl-RS");
console.log(serbianCyrillic.script); // "Cyrl"

const serbianLatin = new Intl.Locale("sr-Latn-RS");
console.log(serbianLatin.script); // "Latn"

스크립트 코드는 ISO 15924 표준을 따릅니다. 첫 글자가 대문자인 네 글자를 사용합니다. 일반적인 코드로는 라틴 문자를 위한 Latn, 키릴 문자를 위한 Cyrl, 간체 한자를 위한 Hans, 번체 한자를 위한 Hant, 아랍 문자를 위한 Arab 등이 있습니다.

대부분의 로케일은 각 언어가 기본 문자 체계를 가지고 있기 때문에 스크립트 코드를 생략합니다. 영어는 라틴 문자가 기본이므로 en-Latn 대신 en으로 표기합니다. 러시아어는 키릴 문자가 기본이므로 ru-Cyrl 대신 ru로 표기합니다.

스크립트 코드는 언어가 여러 방식으로 작성될 수 있을 때 나타납니다. 중국어는 간체와 번체 문자를 모두 사용합니다. 세르비아어는 키릴 문자와 라틴 알파벳을 모두 사용합니다. 이러한 경우 스크립트 코드는 어떤 문자 체계를 사용할지 명확히 합니다.

로케일에 명시적인 스크립트 코드가 없을 때, script 속성은 undefined를 반환합니다:

const english = new Intl.Locale("en-US");
console.log(english.script); // undefined

스크립트 코드를 추출할 때, 이를 사용하여 폰트 선택, 텍스트 렌더링 결정 또는 문자 체계별 콘텐츠 필터링을 할 수 있습니다.

구성 요소가 undefined인 경우 이해하기

모든 로케일 식별자가 모든 구성 요소를 포함하는 것은 아닙니다. 언어 코드는 필수이지만, 지역과 스크립트는 선택 사항입니다.

식별자에 구성 요소가 존재하지 않을 때, 해당 속성은 undefined를 반환합니다:

const locale = new Intl.Locale("fr");

console.log(locale.language); // "fr"
console.log(locale.region); // undefined
console.log(locale.script); // undefined

이러한 동작을 통해 해당 값을 사용하기 전에 로케일이 지역이나 스크립트를 지정하는지 확인할 수 있습니다:

const locale = new Intl.Locale("en-US");

if (locale.region) {
  console.log(`Region-specific formatting for ${locale.region}`);
} else {
  console.log("Using default formatting");
}

널 병합 연산자를 사용하여 기본값을 제공할 수 있습니다:

const locale = new Intl.Locale("es");
const region = locale.region ?? "ES";

console.log(region); // "ES"

로케일 폴백 체인을 구축할 때, undefined 구성 요소를 확인하면 대안을 구성하는 데 도움이 됩니다:

function buildFallbackChain(identifier) {
  const locale = new Intl.Locale(identifier);
  const fallbacks = [identifier];

  if (locale.region) {
    fallbacks.push(locale.language);
  }

  return fallbacks;
}

console.log(buildFallbackChain("fr-CA")); // ["fr-CA", "fr"]
console.log(buildFallbackChain("fr")); // ["fr"]

이는 가장 구체적인 것부터 가장 일반적인 것까지 순서대로 정렬된 로케일 식별자 목록을 생성합니다.

컴포넌트 추출의 실용적 사용 사례

로케일 컴포넌트 추출은 국제화된 애플리케이션을 구축할 때 발생하는 여러 일반적인 문제를 해결합니다.

언어별 로케일 그룹화

사용 가능한 언어 목록을 표시할 때, 동일한 언어 코드를 공유하는 로케일을 그룹화합니다:

const locales = ["en-US", "en-GB", "fr-FR", "fr-CA", "es-ES", "es-MX"];

const grouped = locales.reduce((groups, identifier) => {
  const locale = new Intl.Locale(identifier);
  const language = locale.language;

  if (!groups[language]) {
    groups[language] = [];
  }

  groups[language].push(identifier);
  return groups;
}, {});

console.log(grouped);
// {
//   en: ["en-US", "en-GB"],
//   fr: ["fr-FR", "fr-CA"],
//   es: ["es-ES", "es-MX"]
// }

이러한 구성은 사용자가 언어 내에서 선호하는 지역 변형을 찾는 데 도움이 됩니다.

로케일 선택기 구축

언어 선택을 위한 사용자 인터페이스를 구축할 때, 의미 있는 레이블을 표시하기 위해 컴포넌트를 추출합니다:

function buildLocaleSelector(identifiers) {
  return identifiers.map(identifier => {
    const locale = new Intl.Locale(identifier);

    const languageNames = new Intl.DisplayNames([identifier], {
      type: "language"
    });

    const regionNames = new Intl.DisplayNames([identifier], {
      type: "region"
    });

    return {
      value: identifier,
      language: languageNames.of(locale.language),
      region: locale.region ? regionNames.of(locale.region) : null
    };
  });
}

const options = buildLocaleSelector(["en-US", "en-GB", "fr-FR"]);
console.log(options);
// [
//   { value: "en-US", language: "English", region: "United States" },
//   { value: "en-GB", language: "English", region: "United Kingdom" },
//   { value: "fr-FR", language: "French", region: "France" }
// ]

이는 각 로케일 옵션에 대해 사람이 읽을 수 있는 레이블을 제공합니다.

지역별 필터링

특정 지역에 맞는 콘텐츠를 표시해야 할 때, 로케일을 필터링하기 위해 지역 코드를 추출합니다:

function filterByRegion(identifiers, targetRegion) {
  return identifiers.filter(identifier => {
    const locale = new Intl.Locale(identifier);
    return locale.region === targetRegion;
  });
}

const allLocales = ["en-US", "es-US", "en-GB", "fr-FR", "zh-CN"];
const usLocales = filterByRegion(allLocales, "US");

console.log(usLocales); // ["en-US", "es-US"]

이는 특정 국가의 사용자에게 적합한 로케일을 선택하는 데 도움이 됩니다.

스크립트 호환성 확인

폰트를 선택하거나 텍스트를 렌더링할 때 호환성을 보장하기 위해 스크립트를 확인하세요:

function selectFont(identifier) {
  const locale = new Intl.Locale(identifier);
  const script = locale.script;

  if (script === "Hans" || script === "Hant") {
    return "Noto Sans CJK";
  } else if (script === "Arab") {
    return "Noto Sans Arabic";
  } else if (script === "Cyrl") {
    return "Noto Sans";
  } else {
    return "Noto Sans";
  }
}

console.log(selectFont("zh-Hans-CN")); // "Noto Sans CJK"
console.log(selectFont("ar-SA")); // "Noto Sans Arabic"
console.log(selectFont("en-US")); // "Noto Sans"

이를 통해 각 문자 체계에 맞게 텍스트가 올바르게 렌더링됩니다.

언어 폴백 구현

사용자가 선호하는 로케일을 사용할 수 없을 때 기본 언어로 폴백하세요:

function selectBestLocale(userPreference, supportedLocales) {
  const user = new Intl.Locale(userPreference);

  if (supportedLocales.includes(userPreference)) {
    return userPreference;
  }

  const languageMatch = supportedLocales.find(supported => {
    const locale = new Intl.Locale(supported);
    return locale.language === user.language;
  });

  if (languageMatch) {
    return languageMatch;
  }

  return supportedLocales[0];
}

const supported = ["en-US", "fr-FR", "es-ES"];

console.log(selectBestLocale("en-GB", supported)); // "en-US"
console.log(selectBestLocale("fr-CA", supported)); // "fr-FR"
console.log(selectBestLocale("de-DE", supported)); // "en-US"

이는 정확한 일치 항목을 사용할 수 없을 때 원활한 폴백을 제공합니다.