Intl

Intl

Intl 네임스페이스 객체는 여러 생성자와 함께, 국제화(intl) 생성자들과 다른 언어에 민감한(language-sensitive) 함수들에 공통적인 기능을 담고 있다. 이들을 통틀어 ECMAScript 국제화 API(ECMAScript Internationalization API)라고 부르며, 언어에 민감한 문자열 비교, 숫자 형식화, 날짜·시간 형식화 등을 제공한다.

출처: Intl - JavaScript | MDN

본문

개요

대부분의 전역 객체와 달리 Intl은 생성자(constructor)가 아니다. new 연산자와 함께 사용할 수 없으며 Intl 객체를 함수로 호출할 수도 없다. Intl의 모든 속성과 메서드는 정적(static)이다(Math 객체와 마찬가지로).

국제화 생성자들과 다른 생성자들의 여러 언어에 민감한 메서드들은(참고 자료에 나열) 로케일을 식별하고 실제로 사용할 로케일을 결정하는 공통 패턴을 사용한다. 모두 localesoptions 인자를 받으며, options.localeMatcher 속성에 지정된 알고리즘을 사용해 요청된 로케일(들)을 지원하는 로케일들과 협상(negotiate)한다.

locales 인자

locales 인자는 주어진 연산에서 사용할 로케일을 결정하는 데 사용된다. JavaScript 구현은 locales를 검사한 뒤, 표현된 선호도를 가장 잘 만족하는 이해 가능한 로케일을 계산한다. locales는 다음과 같을 수 있다:

  • undefined(또는 생략): 구현의 기본 로케일이 사용된다.
  • 단일 로케일: 로케일 식별자이거나 로케일 식별자를 감싸는 Intl.Locale 객체.
  • 로케일 목록: 그 밖의 어떤 값. 객체로 변환된 뒤 로케일 배열로 취급된다.

후자의 두 경우, 실제 사용되는 로케일은 로케일 협상을 통해 결정되는 가장 잘 지원되는 로케일이다. 로케일 식별자가 문자열이나 객체가 아니면 TypeError가 발생한다. 로케일 식별자가 문법적으로 유효하지 않은 문자열이면 RangeError가 발생한다. 로케일 식별자가 잘 형성(well-formed)되었지만 구현이 인식하지 못하면 무시되고 목록의 다음 로케일이 고려되며, 결국 시스템의 로케일로 폴백한다. 다만 특정 로케일 이름이 무시될 것이라고 의존해서는 안 된다. 구현이 미래에 어떤 로케일에 대해서도 데이터를 추가할 수 있기 때문이다. 예를 들어 new Intl.DateTimeFormat("default")"default"가 문법적으로 유효하지만 어떤 로케일로도 인식되지 않기 때문에 구현의 기본 로케일을 사용한다.

로케일 식별자는 다음으로 구성된 문자열이다:

  • 23자 또는 58자의 언어(language) 서브태그
  • 4자의 스크립트(script) 서브태그 (선택)
  • 2자 또는 3자리의 지역(region) 서브태그 (선택)
  • 5~8자의 영숫자 또는 숫자 1개 뒤에 영숫자 3개로 된 변형(variant) 서브태그 하나 이상(모두 고유해야 함) (선택)
  • 하나 이상의 BCP 47 확장 시퀀스 (선택)
  • private-use 확장 시퀀스 (선택)

각 서브태그와 시퀀스는 하이픈으로 구분된다. 로케일 식별자는 대소문자 구분이 없는 ASCII이다. 하지만 관례상 스크립트 서브태그는 title case(첫 글자만 대문자, 나머지 소문자), 지역 서브태그는 대문자, 그 외 모든 것은 소문자를 사용한다. 예를 들어:

  • "hi": 힌디어(언어)
  • "de-AT": 오스트리아(지역)에서 사용되는 독일어(언어)
  • "zh-Hans-CN": 중국(지역)에서 사용되는 간체 문자(스크립트)로 쓰인 중국어(언어)
  • "en-emodeng": "초기 현대 영어(Early modern English)" 방언(변형)의 영어(언어)

언어, 스크립트, 지역(국가 포함), 그리고 (드물게 사용되는) 변형을 식별하는 서브태그는 IANA Language Subtag Registry에 등록된다. 이 레지스트리는 시간에 따라 주기적으로 갱신되며 구현이 항상 최신이 아닐 수 있으므로, 서브태그가 보편적으로 지원될 것이라고 너무 의존하지 마라.

BCP 47 확장 시퀀스는 단일 숫자 또는 문자("x" 제외)와, 하이픈으로 구분된 2~8자리 영숫자 서브태그 하나 이상으로 구성된다. 각 숫자 또는 문자에 대해 하나의 시퀀스만 허용된다: "de-a-foo-a-foo"는 유효하지 않다. BCP 47 확장 서브태그는 Unicode CLDR Project에서 정의된다. 현재 의미가 정의된 확장은 두 개뿐이다:

  • "u"(Unicode) 확장은 Intl API 객체의 추가 커스터마이즈를 요청하는 데 사용될 수 있다. 예:
    • "de-DE-u-co-phonebk": 독일어 정렬 순서의 전화번호부 변형을 사용한다. 움라우트 모음을 해당 문자 쌍으로 해석한다: ä → ae, ö → oe, ü → ue.
    • "th-TH-u-nu-thai": 숫자 형식화에 태국 숫자(๐, ๑, ๒, ๓, ๔, ๕, ๖, ๗, ๘, ๙)를 사용한다.
    • "ja-JP-u-ca-japanese": 날짜·시간 형식화에 일본 달력을 사용해, 2013년을 헤이세이 25년(平成 25)으로 표현한다.
    • "en-GB-u-ca-islamic-umalqura": Umm al-Qura(Hijri) 달력과 함께 영국 영어를 사용한다. 그레고리력 2017년 10월 14일은 Hijri 1439년 무하람 24일이다.
  • "t"(transformed) 확장은 변환된 콘텐츠, 예를 들어 다른 로케일에서 번역된 텍스트를 나타낸다. 현재 어떤 Intl 기능도 "t" 확장을 고려하지 않는다. 다만 이 확장은 때때로 중첩 로케일(확장 없이)을 포함한다. 예를 들어 "de-t-en"의 transformed 확장은 영어의 로케일 식별자를 담고 있다. 중첩 로케일이 있으면 유효한 로케일 식별자여야 한다. 예를 들어 "en-emodeng-emodeng"은 (중복된 emodeng 변형 서브태그를 포함하므로) 유효하지 않기 때문에 "de-t-en-emodeng-emodeng"도 유효하지 않다.

마지막으로, 문자 "x"를 사용하는 private-use 확장 시퀀스가 나타날 수 있으며, 뒤에 하이픈으로 구분된 1~8자 영숫자 서브태그 하나 이상이 온다. 이를 통해 애플리케이션은 자체 private use용 정보를 인코딩할 수 있으며, 이 정보는 모든 Intl 연산에서 무시된다.

options 인자

options 인자는 생성자와 함수에 따라 다양한 속성을 가진 객체여야 한다. options 인자가 제공되지 않거나 undefined이면 모든 속성에 기본 값이 사용된다.

모든 언어에 민감한 생성자와 함수가 지원하는 속성은 하나다: localeMatcher 속성. 그 값은 문자열 "lookup" 또는 "best fit"여야 하며, 아래에 설명된 로케일 매칭 알고리즘 중 하나를 선택한다.

로케일 식별과 협상(Locale identification and negotiation)

locales 인자로 지정된 로케일 목록은 Unicode 확장이 제거된 후, 애플리케이션의 우선순위 요청으로 해석된다. 런타임은 이를 사용 가능한 로케일과 비교해 가장 좋은 것을 고른다. 두 가지 매칭 알고리즘이 있다: "lookup" 매처는 BCP 47에 지정된 Lookup 알고리즘을 따르고, "best fit" 매처는 런타임이 Lookup 알고리즘의 결과보다 요청에 적합하거나 최소한 그만큼 적합한 로케일을 제공하게 한다. 애플리케이션이 locales 인자를 제공하지 않거나 런타임이 요청과 일치하는 로케일이 없으면 런타임의 기본 로케일이 사용된다. 매처는 options 인자의 속성으로 선택할 수 있다.

선택된 로케일 식별자에 Unicode 확장 시퀀스가 있었으면, 그 확장은 이제 구성된 객체나 함수의 동작을 커스터마이즈하는 데 사용된다. 각 생성자나 함수는 Unicode 확장에 정의된 키의 일부만 지원하며, 지원되는 값은 종종 로케일 식별자에 따라 달라진다. 예를 들어 "co"(collation) 키는 Intl.Collator만 지원하며, 그 "phonebk" 값은 독일어에 대해서만 지원된다.

정적 속성(Static properties)

  • Intl.Collator — 언어에 민감한 문자열 비교를 가능하게 하는 collator 객체용 생성자.
  • Intl.DateTimeFormat — 언어에 민감한 날짜·시간 형식화를 가능하게 하는 객체용 생성자.
  • Intl.DisplayNames — 언어, 지역, 스크립트 표시 이름의 일관된 번역을 가능하게 하는 객체용 생성자.
  • Intl.DurationFormat — 로케일에 민감한 기간(duration) 형식화를 가능하게 하는 객체용 생성자.
  • Intl.ListFormat — 언어에 민감한 목록 형식화를 가능하게 하는 객체용 생성자.
  • Intl.Locale — Unicode 로케일 식별자를 나타내는 객체용 생성자.
  • Intl.NumberFormat — 언어에 민감한 숫자 형식화를 가능하게 하는 객체용 생성자.
  • Intl.PluralRules — 복수(plural)에 민감한 형식화와 복수에 대한 언어별 규칙을 가능하게 하는 객체용 생성자.
  • Intl.RelativeTimeFormat — 언어에 민감한 상대 시간 형식화를 가능하게 하는 객체용 생성자.
  • Intl.Segmenter — 로케일에 민감한 텍스트 분할(segmentation)을 가능하게 하는 객체용 생성자.
  • Intl[Symbol.toStringTag][Symbol.toStringTag] 속성의 초기 값은 문자열 "Intl". Object.prototype.toString()에서 사용된다.

정적 메서드(Static methods)

  • Intl.getCanonicalLocales() — 표준(canonical) 로케일 이름을 반환한다.
  • Intl.supportedValuesOf() — 구현이 지원하는 고유한 calendar, collation, currency, numbering system, unit 값들을 담은 정렬된 배열을 반환한다.

예제

날짜와 숫자 형식화하기(Formatting dates and numbers)

Intl을 사용해 특정 언어와 지역의 관례에 맞는 형태로 날짜와 숫자를 형식화할 수 있다:

const count = 26254.39;
const date = new Date("2012-05-24");

function log(locale) {
  console.log(
    `${new Intl.DateTimeFormat(locale).format(date)} ${new Intl.NumberFormat(
      locale,
    ).format(count)}`,
  );
}

log("en-US"); // 5/24/2012 26,254.39

log("de-DE"); // 24.5.2012 26.254,39

브라우저의 선호 언어 사용하기

Intl 메서드에 하드코딩된 로케일 이름을 전달하는 대신 navigator.language가 제공하는 사용자의 선호 언어를 사용할 수 있다:

const date = new Date("2012-05-24");

const formattedDate = new Intl.DateTimeFormat(navigator.language).format(date);

또는 navigator.languages 속성은 사용자의 선호 언어의 정렬된 목록을 제공한다. 이 목록은 Intl 생성자에 직접 전달되어 선호도 기반 로케일 폴백 선택을 구현할 수 있다. 로케일 협상 과정을 통해 사용 가능한 가장 적절한 로케일을 고른다:

const count = 26254.39;

const formattedCount = new Intl.NumberFormat(navigator.languages).format(count);

명세(Specifications)

  • ECMAScript® 2027 Internationalization API Specification — intl-object

브라우저 호환성

baseline 기준 2017년 9월부터 널리 사용 가능하다. 호환성 표는 JavaScript를 활성화해야 볼 수 있다.

참고 자료

  • Keyboard.getLayoutMap()
  • navigator.language
  • navigator.languages
  • The ECMAScript Internationalization API (Norbert Lindenberg, 2012)

더 알아보기