로케일 식별자를 표준 형식으로 정규화하는 방법
로케일 식별자를 올바른 대소문자와 구성요소 순서를 갖춘 표준 형식으로 변환
소개
로케일 식별자는 동일한 언어와 지역을 참조하면서도 다양한 방식으로 작성될 수 있습니다. 사용자는 EN-us, en-US 또는 en-us와 같이 작성할 수 있으며, 이 세 가지 모두 미국 영어를 나타냅니다. 로케일 식별자를 저장, 비교 또는 표시할 때 이러한 변형은 일관성 없는 결과를 만듭니다.
정규화는 로케일 식별자를 표준 정식 형태로 변환합니다. 이 과정에서 구성 요소의 대소문자를 조정하고, 확장 키워드를 알파벳 순으로 정렬하며, 애플리케이션 전체에서 신뢰할 수 있는 일관된 표현을 생성합니다.
자바스크립트는 로케일 식별자를 자동으로 정규화하는 내장 메서드를 제공합니다. 이 가이드에서는 정규화의 의미, 코드에서 정규화를 적용하는 방법, 그리고 정규화된 식별자가 국제화 로직을 개선하는 시점에 대해 설명합니다.
로케일 식별자에 대한 정규화의 의미
정규화는 BCP 47 표준과 유니코드 사양에 따라 로케일 식별자를 정식 형태로 변환합니다. 정식 형태는 대소문자, 순서 및 구조에 대한 특정 규칙을 가지고 있습니다.
정규화된 로케일 식별자는 다음과 같은 규칙을 따릅니다:
- 언어 코드는 소문자
- 스크립트 코드는 첫 글자만 대문자인 타이틀 케이스
- 지역 코드는 대문자
- 변형 코드는 소문자
- 확장 키워드는 알파벳 순으로 정렬
- 확장 속성은 알파벳 순으로 정렬
이러한 규칙은 각 로케일에 대한 단일 표준 표현을 만듭니다. 사용자가 로케일 식별자를 어떻게 작성하든, 정규화된 형태는 항상 동일합니다.
정규화 규칙 이해하기
로케일 식별자의 각 구성 요소는 정식 형태에서 특정 대소문자 규칙을 가집니다.
언어 대소문자
언어 코드는 항상 소문자를 사용합니다:
en (올바름)
EN (잘못됨, 그러나 en으로 정규화됨)
eN (잘못됨, 그러나 en으로 정규화됨)
이는 두 글자 및 세 글자 언어 코드 모두에 적용됩니다.
스크립트 대소문자 표기
스크립트 코드는 첫 글자는 대문자, 나머지 세 글자는 소문자인 타이틀 케이스를 사용합니다:
Hans (올바름)
hans (올바르지 않음, 그러나 Hans로 정규화됨)
HANS (올바르지 않음, 그러나 Hans로 정규화됨)
일반적인 스크립트 코드로는 라틴어를 위한 Latn, 키릴 문자를 위한 Cyrl, 간체 한자를 위한 Hans, 그리고 번체 한자를 위한 Hant가 있습니다.
지역 대소문자 표기
지역 코드는 항상 대문자를 사용합니다:
US (올바름)
us (올바르지 않음, 그러나 US로 정규화됨)
Us (올바르지 않음, 그러나 US로 정규화됨)
이는 대부분의 로케일 식별자에서 사용되는 두 글자 국가 코드에 적용됩니다.
확장 순서
유니코드 확장 태그에는 서식 지정 기본 설정을 지정하는 키워드가 포함되어 있습니다. 표준 형식에서 이러한 키워드는 키에 따라 알파벳 순서로 나타납니다:
en-US-u-ca-gregory-nu-latn (올바름)
en-US-u-nu-latn-ca-gregory (올바르지 않음, 그러나 첫 번째 형식으로 정규화됨)
달력 키 ca는 알파벳 순으로 숫자 체계 키 nu 앞에 오기 때문에, 정규화된 형식에서는 ca-gregory가 먼저 나타납니다.
Intl.getCanonicalLocales를 사용한 정규화
Intl.getCanonicalLocales() 메서드는 로케일 식별자를 정규화하고 표준 형식으로 반환합니다. 이는 JavaScript에서 정규화를 위한 주요 메서드입니다.
const normalized = Intl.getCanonicalLocales("EN-us");
console.log(normalized);
// ["en-US"]
이 메서드는 대소문자에 관계없이 로케일 식별자를 받아 올바르게 대소문자가 적용된 표준 형식을 반환합니다.
언어 코드 정규화
이 메서드는 언어 코드를 소문자로 변환합니다:
const result = Intl.getCanonicalLocales("FR-fr");
console.log(result);
// ["fr-FR"]
언어 코드 FR은 출력에서 fr로 변환됩니다.
스크립트 코드 정규화
이 메서드는 스크립트 코드를 타이틀 케이스로 변환합니다:
const result = Intl.getCanonicalLocales("zh-HANS-cn");
console.log(result);
// ["zh-Hans-CN"]
스크립트 코드 HANS는 Hans로 변환되고, 지역 코드 cn은 CN으로 변환됩니다.
지역 코드 정규화
이 메서드는 지역 코드를 대문자로 변환합니다:
const result = Intl.getCanonicalLocales("en-gb");
console.log(result);
// ["en-GB"]
지역 코드 gb는 출력에서 GB로 변환됩니다.
확장 키워드 정규화
이 메서드는 확장 키워드를 알파벳 순으로 정렬합니다:
const result = Intl.getCanonicalLocales("en-US-u-nu-latn-hc-h12-ca-gregory");
console.log(result);
// ["en-US-u-ca-gregory-hc-h12-nu-latn"]
키워드는 nu-latn-hc-h12-ca-gregory에서 ca-gregory-hc-h12-nu-latn으로 재정렬됩니다. 이는 알파벳 순으로 ca가 hc 앞에 오고 hc가 nu 앞에 오기 때문입니다.
다중 로케일 식별자 정규화
Intl.getCanonicalLocales() 메서드는 로케일 식별자 배열을 받아 모두 정규화합니다:
const locales = ["EN-us", "fr-FR", "ZH-hans-cn"];
const normalized = Intl.getCanonicalLocales(locales);
console.log(normalized);
// ["en-US", "fr-FR", "zh-Hans-CN"]
배열의 각 로케일은 정규 형식으로 변환됩니다.
중복 제거
이 메서드는 정규화 후 중복된 로케일 식별자를 제거합니다. 여러 입력 값이 동일한 정규 형식으로 정규화되면 결과에는 하나의 복사본만 포함됩니다:
const locales = ["en-US", "EN-us", "en-us"];
const normalized = Intl.getCanonicalLocales(locales);
console.log(normalized);
// ["en-US"]
세 입력 모두 동일한 로케일을 나타내므로 출력에는 단일 정규화된 식별자가 포함됩니다.
이러한 중복 제거는 사용자 입력을 처리하거나 여러 소스에서 로케일 목록을 병합할 때 유용합니다.
유효하지 않은 식별자 처리
배열의 로케일 식별자가 유효하지 않으면 메서드는 RangeError를 발생시킵니다:
try {
Intl.getCanonicalLocales(["en-US", "invalid", "fr-FR"]);
} catch (error) {
console.error(error.message);
// "invalid is not a structurally valid language tag"
}
사용자가 제공한 목록을 정규화할 때는 각 로케일을 개별적으로 검증하거나 오류를 포착하여 어떤 특정 식별자가 유효하지 않은지 확인하세요.
정규화를 위한 Intl.Locale 사용
로케일 객체를 생성할 때 Intl.Locale 생성자도 로케일 식별자를 정규화합니다. toString() 메서드를 통해 정규화된 형식에 접근할 수 있습니다.
const locale = new Intl.Locale("EN-us");
console.log(locale.toString());
// "en-US"
생성자는 유효한 대소문자를 모두 허용하고 정규화된 로케일 객체를 생성합니다.
정규화된 컴포넌트 접근하기
로케일 객체의 각 속성은 해당 컴포넌트의 정규화된 형태를 반환합니다:
const locale = new Intl.Locale("ZH-hans-CN");
console.log(locale.language);
// "zh"
console.log(locale.script);
// "Hans"
console.log(locale.region);
// "CN"
console.log(locale.baseName);
// "zh-Hans-CN"
language, script, 그리고 region 속성은 모두 정식 형태에 맞는 올바른 대소문자를 사용합니다.
옵션을 사용한 정규화
옵션과 함께 로케일 객체를 생성할 때, 생성자는 기본 식별자와 옵션 모두를 정규화합니다:
const locale = new Intl.Locale("EN-us", {
calendar: "gregory",
numberingSystem: "latn",
hourCycle: "h12"
});
console.log(locale.toString());
// "en-US-u-ca-gregory-hc-h12-nu-latn"
옵션 객체에서 특정 순서를 지정하지 않더라도 확장 키워드는 출력에서 알파벳 순서로 나타납니다.
정규화가 중요한 이유
정규화는 애플리케이션 전반에 걸쳐 일관성을 제공합니다. 로케일 식별자를 저장, 표시 또는 비교할 때 정식 형태를 사용하면 미묘한 버그를 방지하고 신뢰성을 향상시킵니다.
일관된 저장
데이터베이스, 구성 파일 또는 로컬 스토리지에 로케일 식별자를 저장할 때 정규화된 형태는 중복을 방지합니다:
const userPreferences = new Set();
function saveUserLocale(identifier) {
const normalized = Intl.getCanonicalLocales(identifier)[0];
userPreferences.add(normalized);
}
saveUserLocale("en-US");
saveUserLocale("EN-us");
saveUserLocale("en-us");
console.log(userPreferences);
// Set { "en-US" }
정규화 없이는 세트에 동일한 로케일에 대한 세 개의 항목이 포함됩니다. 정규화를 사용하면 올바르게 하나만 포함됩니다.
신뢰할 수 있는 비교
로케일 식별자를 비교하려면 정규화가 필요합니다. 대소문자만 다른 두 식별자는 동일한 로케일을 나타냅니다:
function isSameLocale(locale1, locale2) {
const normalized1 = Intl.getCanonicalLocales(locale1)[0];
const normalized2 = Intl.getCanonicalLocales(locale2)[0];
return normalized1 === normalized2;
}
console.log(isSameLocale("en-US", "EN-us"));
// true
console.log(isSameLocale("en-US", "en-GB"));
// false
정규화되지 않은 식별자의 직접적인 문자열 비교는 잘못된 결과를 생성합니다.
일관된 표시
사용자에게 로케일 식별자를 표시하거나 디버깅 출력에 사용할 때, 정규화된 형식은 일관된 서식을 제공합니다:
function displayLocale(identifier) {
try {
const normalized = Intl.getCanonicalLocales(identifier)[0];
return `Current locale: ${normalized}`;
} catch (error) {
return "Invalid locale identifier";
}
}
console.log(displayLocale("EN-us"));
// "Current locale: en-US"
console.log(displayLocale("zh-HANS-cn"));
// "Current locale: zh-Hans-CN"
사용자는 입력 형식에 관계없이 올바르게 서식이 지정된 로케일 식별자를 볼 수 있습니다.
실용적 응용
정규화는 실제 애플리케이션에서 로케일 식별자를 다룰 때 발생하는 일반적인 문제를 해결합니다.
사용자 입력 정규화
사용자가 양식이나 설정에 로케일 식별자를 입력할 때, 저장하기 전에 입력을 정규화합니다:
function processLocaleInput(input) {
try {
const normalized = Intl.getCanonicalLocales(input)[0];
return {
success: true,
locale: normalized
};
} catch (error) {
return {
success: false,
error: "Please enter a valid locale identifier"
};
}
}
const result = processLocaleInput("fr-ca");
console.log(result);
// { success: true, locale: "fr-CA" }
이는 데이터베이스나 구성에서 일관된 서식을 보장합니다.
로케일 조회 테이블 구축
번역이나 로케일별 데이터에 대한 조회 테이블을 만들 때 정규화된 키를 사용합니다:
const translations = new Map();
function addTranslation(locale, key, value) {
const normalized = Intl.getCanonicalLocales(locale)[0];
if (!translations.has(normalized)) {
translations.set(normalized, {});
}
translations.get(normalized)[key] = value;
}
addTranslation("en-us", "hello", "Hello");
addTranslation("EN-US", "goodbye", "Goodbye");
console.log(translations.get("en-US"));
// { hello: "Hello", goodbye: "Goodbye" }
addTranslation에 대한 두 호출 모두 동일한 정규화된 키를 사용하므로 번역이 동일한 객체에 저장됩니다.
로케일 목록 병합
여러 소스에서 로케일 식별자를 결합할 때, 정규화하고 중복을 제거합니다:
function mergeLocales(...sources) {
const allLocales = sources.flat();
const normalized = Intl.getCanonicalLocales(allLocales);
return normalized;
}
const userLocales = ["en-us", "fr-FR"];
const appLocales = ["EN-US", "de-de"];
const systemLocales = ["en-US", "es-mx"];
const merged = mergeLocales(userLocales, appLocales, systemLocales);
console.log(merged);
// ["en-US", "fr-FR", "de-DE", "es-MX"]
이 메서드는 모든 소스에서 중복을 제거하고 대소문자를 정규화합니다.
로케일 선택 인터페이스 생성
드롭다운 메뉴나 선택 인터페이스를 구축할 때, 표시를 위해 로케일 식별자를 정규화합니다:
function buildLocaleOptions(locales) {
const normalized = Intl.getCanonicalLocales(locales);
return normalized.map(locale => {
const localeObj = new Intl.Locale(locale);
const displayNames = new Intl.DisplayNames([locale], {
type: "language"
});
return {
value: locale,
label: displayNames.of(localeObj.language)
};
});
}
const options = buildLocaleOptions(["EN-us", "fr-FR", "DE-de"]);
console.log(options);
// [
// { value: "en-US", label: "English" },
// { value: "fr-FR", label: "French" },
// { value: "de-DE", label: "German" }
// ]
정규화된 값은 폼 제출을 위한 일관된 식별자를 제공합니다.
구성 파일 유효성 검사
구성 파일에서 로케일 식별자를 로드할 때, 초기화 과정에서 정규화합니다:
function loadLocaleConfig(config) {
const validatedConfig = {
defaultLocale: null,
supportedLocales: []
};
try {
validatedConfig.defaultLocale = Intl.getCanonicalLocales(
config.defaultLocale
)[0];
} catch (error) {
console.error("Invalid default locale:", config.defaultLocale);
validatedConfig.defaultLocale = "en-US";
}
config.supportedLocales.forEach(locale => {
try {
const normalized = Intl.getCanonicalLocales(locale)[0];
validatedConfig.supportedLocales.push(normalized);
} catch (error) {
console.warn("Skipping invalid locale:", locale);
}
});
return validatedConfig;
}
const config = {
defaultLocale: "en-us",
supportedLocales: ["EN-us", "fr-FR", "invalid", "de-DE"]
};
const validated = loadLocaleConfig(config);
console.log(validated);
// {
// defaultLocale: "en-US",
// supportedLocales: ["en-US", "fr-FR", "de-DE"]
// }
이는 구성 오류를 조기에 발견하고 애플리케이션이 유효한 정규화된 식별자를 사용하도록 보장합니다.
정규화 및 로케일 매칭
정규화는 로케일 매칭 알고리즘에 중요합니다. 사용자 선호도에 가장 적합한 로케일 매치를 찾을 때, 정규화된 형식을 비교합니다:
function findBestMatch(userPreference, availableLocales) {
const normalizedPreference = Intl.getCanonicalLocales(userPreference)[0];
const normalizedAvailable = Intl.getCanonicalLocales(availableLocales);
if (normalizedAvailable.includes(normalizedPreference)) {
return normalizedPreference;
}
const preferenceLocale = new Intl.Locale(normalizedPreference);
const languageMatch = normalizedAvailable.find(available => {
const availableLocale = new Intl.Locale(available);
return availableLocale.language === preferenceLocale.language;
});
if (languageMatch) {
return languageMatch;
}
return normalizedAvailable[0];
}
const available = ["en-us", "fr-FR", "DE-de"];
console.log(findBestMatch("EN-GB", available));
// "en-US"
정규화는 입력 대소문자에 관계없이 매칭 로직이 올바르게 작동하도록 보장합니다.
정규화는 의미를 변경하지 않습니다
정규화는 로케일 식별자의 표현에만 영향을 미칩니다. 식별자가 나타내는 언어, 스크립트 또는 지역을 변경하지 않습니다.
const locale1 = new Intl.Locale("en-us");
const locale2 = new Intl.Locale("EN-US");
console.log(locale1.language === locale2.language);
// true
console.log(locale1.region === locale2.region);
// true
console.log(locale1.toString() === locale2.toString());
// true
두 식별자 모두 미국 영어를 나타냅니다. 정규화는 단순히 이들이 동일한 방식으로 작성되도록 보장합니다.
이는 구성 요소를 추가하거나 제거하고 식별자의 특수성을 변경할 수 있는 maximize() 및 minimize()와 같은 작업과는 다릅니다.
브라우저 지원
Intl.getCanonicalLocales() 메서드는 모든 최신 브라우저에서 작동합니다. Chrome, Firefox, Safari 및 Edge는 완전한 지원을 제공합니다.
Node.js는 버전 9부터 Intl.getCanonicalLocales()를 지원하며, 버전 10 이상에서는 완전한 지원을 제공합니다.
Intl.Locale 생성자와 그 정규화 동작은 Intl.Locale API를 지원하는 모든 브라우저에서 작동합니다. 여기에는 Chrome, Firefox, Safari 및 Edge의 최신 버전이 포함됩니다.
요약
정규화는 표준 대소문자 규칙을 적용하고 확장 키워드를 정렬하여 로케일 식별자를 정식 형식으로 변환합니다. 이를 통해 안정적으로 저장, 비교 및 표시할 수 있는 일관된 표현을 생성합니다.
주요 개념:
- 정식 형식은 언어에는 소문자, 스크립트에는 타이틀 케이스, 지역에는 대문자를 사용합니다
- 확장 키워드는 정식 형식에서 알파벳 순으로 정렬됩니다
Intl.getCanonicalLocales()메서드는 식별자를 정규화하고 중복을 제거합니다Intl.Locale생성자도 정규화된 출력을 생성합니다- 정규화는 로케일 식별자의 의미를 변경하지 않습니다
- 저장, 비교 및 표시에는 정규화된 식별자를 사용하세요
정규화는 로케일 식별자를 다루는 모든 애플리케이션의 기본 작업입니다. 일관되지 않은 대소문자로 인한 버그를 방지하고 국제화 로직이 로케일 식별자를 안정적으로 처리하도록 보장합니다.