단위가 있는 측정값 목록을 어떻게 형식화하나요?
자바스크립트의 Intl API를 사용하여 5 km, 10 km, 15 km와 같은 여러 측정값을 로케일에 적합한 목록 형식으로 표시합니다
소개
측정값을 표시하는 애플리케이션은 종종 여러 값을 함께 표시해야 합니다. 피트니스 앱은 분할 시간을 "5 km, 10 km, 15 km"와 같이 표시할 수 있습니다. 날씨 앱은 일주일 동안의 온도를 "20°C, 22°C, 25°C, 23°C"와 같이 표시할 수 있습니다. 레시피는 재료의 양을 "2 컵, 1 테이블스푼, 3 티스푼"과 같이 나열할 수 있습니다.
이러한 목록은 두 가지 국제화 과제를 결합합니다. 첫째, 각 측정값은 로케일에 적합한 단위 형식이 필요합니다. 둘째, 목록 자체는 대상 언어에 맞는 적절한 구두점과 구분자가 필요합니다. 영어는 쉼표와 때로는 "and"와 같은 접속사를 사용합니다. 다른 언어는 다른 구분자를 사용하고 다른 문법 규칙을 따릅니다.
자바스크립트는 이 문제를 해결하기 위한 두 가지 API를 제공합니다. Intl.NumberFormat은 단위가 있는 개별 측정값을 형식화합니다. Intl.ListFormat은 여러 값을 문법적으로 올바른 목록으로 결합합니다. 이 강의에서는 두 API를 함께 사용하여 모든 로케일에서 사용자 기대에 맞는 측정값 목록을 형식화하는 방법을 설명합니다.
측정값 목록은 두 가지 형식화 단계가 필요합니다
측정값 목록을 형식화할 때는 어느 형식화 단계도 건너뛸 수 없습니다. 측정값을 형식화하지 않고 목록을 형식화하면 로케일에 적합한 구분자는 얻지만 단위 표시가 올바르지 않습니다. 목록을 형식화하지 않고 측정값을 형식화하면 올바른 단위는 얻지만 구분자가 올바르지 않습니다.
const distances = [5, 10, 15];
// 잘못됨: 목록은 형식화되었지만 측정값은 형식화되지 않음
console.log(distances.join(', '));
// 출력: "5, 10, 15" (단위 누락)
// 잘못됨: 측정값은 형식화되었지만 목록은 형식화되지 않음
const formatter = new Intl.NumberFormat('en-US', {
style: 'unit',
unit: 'kilometer'
});
console.log(distances.map(d => formatter.format(d)).join(', '));
// 출력: "5 km, 10 km, 15 km" (하드코딩된 쉼표가 일부 로케일에서는 잘못될 수 있음)
올바른 접근 방식은 먼저 측정값을 형식화한 다음 결과 문자열 배열을 목록으로 형식화하는 것입니다.
const distances = [5, 10, 15];
const numberFormatter = new Intl.NumberFormat('en-US', {
style: 'unit',
unit: 'kilometer'
});
const formattedMeasurements = distances.map(d => numberFormatter.format(d));
// 결과: ["5 km", "10 km", "15 km"]
const listFormatter = new Intl.ListFormat('en-US', {
type: 'unit'
});
console.log(listFormatter.format(formattedMeasurements));
// 출력: "5 km, 10 km, 15 km"
이 패턴은 모든 측정 유형과 모든 로케일에 적용됩니다. 각 측정값을 해당 단위로 형식화한 다음 형식화된 문자열 배열을 목록으로 형식화합니다.
측정 목록에 type unit 사용하기
Intl.ListFormat 생성자는 목록 항목이 결합되는 방식을 제어하는 type 옵션을 받습니다. type: 'unit' 옵션은 기술 및 과학 데이터의 관례에 따라 목록을 형식화합니다.
const measurements = ['5 km', '10 km', '15 km'];
const unitList = new Intl.ListFormat('en-US', {
type: 'unit'
});
console.log(unitList.format(measurements));
// 출력: "5 km, 10 km, 15 km"
type: 'unit'을 사용한 목록은 "and"나 "or"와 같은 접속사를 생략합니다. 항목 사이에 단순 구분자를 사용합니다. 이는 기술적 맥락에서 측정값이 일반적으로 작성되는 방식과 일치합니다.
이를 마지막 항목 앞에 "and"를 추가하는 type: 'conjunction'과 비교해 보세요.
const measurements = ['5 km', '10 km', '15 km'];
const conjunctionList = new Intl.ListFormat('en-US', {
type: 'conjunction'
});
console.log(conjunctionList.format(measurements));
// 출력: "5 km, 10 km, and 15 km"
접속사 형식은 문장에서는 자연스럽게 읽히지만 기술적 맥락에서는 부적절해 보입니다. 여러 측정값을 표시할 때는 과학 및 기술 문서의 표준 관례를 따르기 위해 type: 'unit'을 사용하세요.
거리 측정값을 목록으로 형식화하기
거리 측정값은 kilometer, meter, mile, foot과 같은 단위 식별자를 사용합니다. 각 거리를 해당 단위로 형식화한 후 목록으로 결합합니다.
const distances = [5, 10, 15, 20];
const numberFormatter = new Intl.NumberFormat('en-US', {
style: 'unit',
unit: 'kilometer'
});
const formattedDistances = distances.map(d => numberFormatter.format(d));
const listFormatter = new Intl.ListFormat('en-US', {
type: 'unit'
});
console.log(listFormatter.format(formattedDistances));
// 출력: "5 km, 10 km, 15 km, 20 km"
동일한 패턴이 마일에도 적용됩니다.
const distances = [3, 6, 9];
const numberFormatter = new Intl.NumberFormat('en-US', {
style: 'unit',
unit: 'mile'
});
const formattedDistances = distances.map(d => numberFormatter.format(d));
const listFormatter = new Intl.ListFormat('en-US', {
type: 'unit'
});
console.log(listFormatter.format(formattedDistances));
// 출력: "3 mi, 6 mi, 9 mi"
숫자 형식 옵션을 설정하여 소수점이 있는 거리를 형식화할 수 있습니다.
const distances = [5.2, 10.7, 15.3];
const numberFormatter = new Intl.NumberFormat('en-US', {
style: 'unit',
unit: 'kilometer',
maximumFractionDigits: 1
});
const formattedDistances = distances.map(d => numberFormatter.format(d));
const listFormatter = new Intl.ListFormat('en-US', {
type: 'unit'
});
console.log(listFormatter.format(formattedDistances));
// 출력: "5.2 km, 10.7 km, 15.3 km"
숫자 포맷터는 목록 포맷터가 값을 결합하기 전에 반올림 및 소수점 자릿수를 처리합니다.
목록에서 무게 측정값 형식 지정하기
무게 측정값은 kilogram, pound, ounce, gram과 같은 단위 식별자를 사용하여 동일한 패턴을 따릅니다.
const weights = [50, 75, 100];
const numberFormatter = new Intl.NumberFormat('en-US', {
style: 'unit',
unit: 'kilogram'
});
const formattedWeights = weights.map(w => numberFormatter.format(w));
const listFormatter = new Intl.ListFormat('en-US', {
type: 'unit'
});
console.log(listFormatter.format(formattedWeights));
// 출력: "50 kg, 75 kg, 100 kg"
무게를 파운드로 표시할 수도 있습니다.
const weights = [110, 165, 220];
const numberFormatter = new Intl.NumberFormat('en-US', {
style: 'unit',
unit: 'pound'
});
const formattedWeights = weights.map(w => numberFormatter.format(w));
const listFormatter = new Intl.ListFormat('en-US', {
type: 'unit'
});
console.log(listFormatter.format(formattedWeights));
// 출력: "110 lb, 165 lb, 220 lb"
숫자 포맷터는 각 단위에 대한 올바른 약어를 자동으로 사용합니다.
목록에서 온도 측정값 형식 지정하기
온도 측정값은 celsius와 fahrenheit와 같은 단위 식별자를 사용합니다.
const temperatures = [20, 22, 25, 23, 21];
const numberFormatter = new Intl.NumberFormat('en-US', {
style: 'unit',
unit: 'celsius'
});
const formattedTemperatures = temperatures.map(t => numberFormatter.format(t));
const listFormatter = new Intl.ListFormat('en-US', {
type: 'unit'
});
console.log(listFormatter.format(formattedTemperatures));
// 출력: "20°C, 22°C, 25°C, 23°C, 21°C"
온도 포맷터는 출력에 도 기호를 자동으로 포함합니다.
화씨도 동일한 방식으로 작동합니다.
const temperatures = [68, 72, 77, 73, 70];
const numberFormatter = new Intl.NumberFormat('en-US', {
style: 'unit',
unit: 'fahrenheit'
});
const formattedTemperatures = temperatures.map(t => numberFormatter.format(t));
const listFormatter = new Intl.ListFormat('en-US', {
type: 'unit'
});
console.log(listFormatter.format(formattedTemperatures));
// 출력: "68°F, 72°F, 77°F, 73°F, 70°F"
이 패턴은 다양한 측정 유형에서 동일하게 유지됩니다. 단위 식별자만 변경됩니다.
목록에서 부피 측정값 형식 지정하기
부피 측정값은 liter, gallon, milliliter, fluid-ounce와 같은 단위 식별자를 사용합니다.
const volumes = [1, 2, 3];
const numberFormatter = new Intl.NumberFormat('en-US', {
style: 'unit',
unit: 'liter'
});
const formattedVolumes = volumes.map(v => numberFormatter.format(v));
const listFormatter = new Intl.ListFormat('en-US', {
type: 'unit'
});
console.log(listFormatter.format(formattedVolumes));
// 출력: "1 L, 2 L, 3 L"
부피 측정값은 소수점 값과 함께 작동합니다.
const volumes = [0.5, 1.5, 2.5];
const numberFormatter = new Intl.NumberFormat('en-US', {
style: 'unit',
unit: 'liter',
maximumFractionDigits: 1
});
const formattedVolumes = volumes.map(v => numberFormatter.format(v));
const listFormatter = new Intl.ListFormat('en-US', {
type: 'unit'
});
console.log(listFormatter.format(formattedVolumes));
// 출력: "0.5 L, 1.5 L, 2.5 L"
숫자 포맷터는 목록 포맷터가 값을 처리하기 전에 소수점 정밀도를 처리합니다.
목록에서 속도 측정값 형식 지정하기
속도 측정값은 kilometer-per-hour와 mile-per-hour와 같은 복합 단위를 사용합니다.
const speeds = [50, 75, 100];
const numberFormatter = new Intl.NumberFormat('en-US', {
style: 'unit',
unit: 'kilometer-per-hour'
});
const formattedSpeeds = speeds.map(s => numberFormatter.format(s));
const listFormatter = new Intl.ListFormat('en-US', {
type: 'unit'
});
console.log(listFormatter.format(formattedSpeeds));
// 출력: "50 km/h, 75 km/h, 100 km/h"
시간당 마일도 같은 방식으로 작동합니다.
const speeds = [30, 45, 60];
const numberFormatter = new Intl.NumberFormat('en-US', {
style: 'unit',
unit: 'mile-per-hour'
});
const formattedSpeeds = speeds.map(s => numberFormatter.format(s));
const listFormatter = new Intl.ListFormat('en-US', {
type: 'unit'
});
console.log(listFormatter.format(formattedSpeeds));
// 출력: "30 mph, 45 mph, 60 mph"
복합 단위는 올바른 약어와 구분 기호로 자동으로 형식이 지정됩니다.
로케일에 따라 목록 구분 기호 형식이 결정됩니다
로케일 매개변수는 목록 항목이 구분되고 구두점이 표시되는 방식을 제어합니다. 다양한 언어는 목록 형식에 대해 서로 다른 규칙을 사용합니다.
const distances = [5, 10, 15];
const numberFormatter = new Intl.NumberFormat('en-US', {
style: 'unit',
unit: 'kilometer'
});
const formattedDistances = distances.map(d => numberFormatter.format(d));
const enList = new Intl.ListFormat('en-US', {
type: 'unit'
});
const frList = new Intl.ListFormat('fr-FR', {
type: 'unit'
});
const deList = new Intl.ListFormat('de-DE', {
type: 'unit'
});
console.log(enList.format(formattedDistances));
// 출력: "5 km, 10 km, 15 km"
console.log(frList.format(formattedDistances));
// 출력: "5 km, 10 km, 15 km"
console.log(deList.format(formattedDistances));
// 출력: "5 km, 10 km, 15 km"
킬로미터 약어는 이러한 로케일 간에 유사하게 유지되지만, 간격 및 구분 기호 규칙은 다를 수 있습니다. Intl.ListFormat API는 이러한 로케일별 형식 지정 규칙을 자동으로 처리합니다.
일부 언어는 목록에 대해 다른 구분 기호나 구두점 패턴을 사용합니다. API는 특정 규칙을 알 필요 없이 각 로케일에 대해 올바른 규칙을 따르도록 목록을 보장합니다.
목록 로케일에 숫자 로케일 맞추기
측정값 목록을 포맷팅할 때는 숫자 포맷터와 목록 포맷터에 동일한 로케일을 사용하세요. 이렇게 하면 출력 전체에서 일관된 포맷팅이 보장됩니다.
const distances = [1000, 2000, 3000];
const locale = 'de-DE';
const numberFormatter = new Intl.NumberFormat(locale, {
style: 'unit',
unit: 'meter'
});
const formattedDistances = distances.map(d => numberFormatter.format(d));
const listFormatter = new Intl.ListFormat(locale, {
type: 'unit'
});
console.log(listFormatter.format(formattedDistances));
// 출력: "1.000 m, 2.000 m, 3.000 m"
독일어 포맷팅은 천 단위 구분 기호로 마침표를 사용합니다. 숫자 포맷터와 목록 포맷터가 동일한 로케일을 공유하기 때문에 둘 다 독일어 규칙을 사용합니다.
숫자와 목록 포맷팅에 서로 다른 로케일을 사용하면 일관성 없는 출력이 생성됩니다.
const distances = [1000, 2000, 3000];
const numberFormatter = new Intl.NumberFormat('de-DE', {
style: 'unit',
unit: 'meter'
});
const formattedDistances = distances.map(d => numberFormatter.format(d));
const listFormatter = new Intl.ListFormat('en-US', {
type: 'unit'
});
console.log(listFormatter.format(formattedDistances));
// 출력: "1.000 m, 2.000 m, 3.000 m"
이렇게 하면 숫자는 독일어 규칙을 사용하지만 목록은 영어 규칙을 사용하는 혼합 포맷팅이 생성됩니다. 항상 두 포맷터에 동일한 로케일을 사용하세요.
목록 표시 스타일 제어하기
style 옵션은 목록 포맷팅이 얼마나 상세하게 표시될지 제어합니다. 이 옵션은 "long", "short", "narrow" 세 가지 값을 허용합니다.
const measurements = ['5 km', '10 km', '15 km'];
const longList = new Intl.ListFormat('en-US', {
type: 'unit',
style: 'long'
});
const shortList = new Intl.ListFormat('en-US', {
type: 'unit',
style: 'short'
});
const narrowList = new Intl.ListFormat('en-US', {
type: 'unit',
style: 'narrow'
});
console.log(longList.format(measurements));
// 출력: "5 km, 10 km, 15 km"
console.log(shortList.format(measurements));
// 출력: "5 km, 10 km, 15 km"
console.log(narrowList.format(measurements));
// 출력: "5 km 10 km 15 km"
영어에서는 long과 short 스타일이 단위 목록에 대해 유사한 출력을 생성합니다. narrow 스타일은 최소한의 간격을 사용하고 항목 사이의 구분 기호를 생략합니다.
다른 로케일에서는 스타일 간에 더 많은 차이가 나타납니다. 로케일에 따라 각 스타일 수준에 대한 정확한 포맷팅이 결정됩니다.
긴 단위명과 결합하기
숫자 포맷터에서 unitDisplay: 'long'을 설정하여 약어 대신 전체 단위명으로 측정값을 포맷할 수 있습니다.
const distances = [5, 10, 15];
const numberFormatter = new Intl.NumberFormat('en-US', {
style: 'unit',
unit: 'kilometer',
unitDisplay: 'long'
});
const formattedDistances = distances.map(d => numberFormatter.format(d));
const listFormatter = new Intl.ListFormat('en-US', {
type: 'unit'
});
console.log(listFormatter.format(formattedDistances));
// 출력: "5 kilometers, 10 kilometers, 15 kilometers"
숫자 포맷터는 단수형과 복수형을 자동으로 처리합니다. 리스트 포맷터는 약어나 전체 이름을 사용하는지 여부에 관계없이 포맷된 문자열을 결합합니다.
const distances = [1, 5];
const numberFormatter = new Intl.NumberFormat('en-US', {
style: 'unit',
unit: 'kilometer',
unitDisplay: 'long'
});
const formattedDistances = distances.map(d => numberFormatter.format(d));
const listFormatter = new Intl.ListFormat('en-US', {
type: 'unit'
});
console.log(listFormatter.format(formattedDistances));
// 출력: "1 kilometer, 5 kilometers"
숫자 포맷터는 1에 대해 "kilometer"를, 5에 대해 "kilometers"를 사용합니다. 리스트 포맷터는 적절한 구분자로 이들을 결합합니다.
성능 향상을 위한 포맷터 재사용
'Intl.NumberFormat'과 'Intl.ListFormat' 인스턴스를 생성하는 것은 로케일 데이터를 로드하고 옵션을 처리하는 작업을 포함합니다. 여러 측정값 목록을 포맷할 때는 포맷터를 한 번 생성하고 재사용하세요.
const numberFormatter = new Intl.NumberFormat('en-US', {
style: 'unit',
unit: 'kilometer'
});
const listFormatter = new Intl.ListFormat('en-US', {
type: 'unit'
});
const distanceLists = [
[5, 10, 15],
[20, 25, 30],
[35, 40, 45]
];
distanceLists.forEach(distances => {
const formattedDistances = distances.map(d => numberFormatter.format(d));
console.log(listFormatter.format(formattedDistances));
});
// 출력:
// "5 km, 10 km, 15 km"
// "20 km, 25 km, 30 km"
// "35 km, 40 km, 45 km"
이 패턴은 각 포맷터를 한 번 생성하고 여러 번 사용합니다. 많은 목록을 포맷할 때 성능 차이가 크게 나타납니다.
재사용 가능한 포맷터 함수 만들기
두 단계 포맷팅 패턴을 재사용 가능한 함수로 캡슐화할 수 있습니다.
function formatMeasurementList(values, locale, unit) {
const numberFormatter = new Intl.NumberFormat(locale, {
style: 'unit',
unit: unit
});
const formattedValues = values.map(v => numberFormatter.format(v));
const listFormatter = new Intl.ListFormat(locale, {
type: 'unit'
});
return listFormatter.format(formattedValues);
}
console.log(formatMeasurementList([5, 10, 15], 'en-US', 'kilometer'));
// 출력: "5 km, 10 km, 15 km"
console.log(formatMeasurementList([50, 75, 100], 'en-US', 'kilogram'));
// 출력: "50 kg, 75 kg, 100 kg"
console.log(formatMeasurementList([20, 22, 25], 'en-US', 'celsius'));
// 출력: "20°C, 22°C, 25°C"
이 함수는 모든 측정 유형과 로케일을 처리합니다. 추가 포맷팅 옵션을 받도록 확장할 수 있습니다.
function formatMeasurementList(values, locale, unit, options = {}) {
const numberFormatter = new Intl.NumberFormat(locale, {
style: 'unit',
unit: unit,
...options
});
const formattedValues = values.map(v => numberFormatter.format(v));
const listFormatter = new Intl.ListFormat(locale, {
type: 'unit'
});
return listFormatter.format(formattedValues);
}
console.log(formatMeasurementList(
[5.123, 10.789, 15.456],
'en-US',
'kilometer',
{ maximumFractionDigits: 1 }
));
// 출력: "5.1 km, 10.8 km, 15.5 km"
console.log(formatMeasurementList(
[1, 5, 10],
'en-US',
'kilometer',
{ unitDisplay: 'long' }
));
// 출력: "1 kilometer, 5 kilometers, 10 kilometers"
이 함수는 추가 옵션을 숫자 포맷터에 전달하여 소수점 자릿수, 단위 표시 및 기타 포맷팅 설정을 제어할 수 있게 합니다.
사용자 로케일에 맞는 목록 포맷팅
특정 로케일을 하드코딩하는 대신 사용자의 브라우저 언어 환경설정을 사용할 수 있습니다. navigator.language 속성은 사용자가 선호하는 로케일을 반환합니다.
const userLocale = navigator.language;
const distances = [5, 10, 15];
const numberFormatter = new Intl.NumberFormat(userLocale, {
style: 'unit',
unit: 'kilometer'
});
const formattedDistances = distances.map(d => numberFormatter.format(d));
const listFormatter = new Intl.ListFormat(userLocale, {
type: 'unit'
});
console.log(listFormatter.format(formattedDistances));
// 출력은 사용자의 로케일에 따라 다름
이 접근 방식은 각 사용자의 포맷팅 기대치에 따라 측정 목록을 표시합니다. 서로 다른 사용자는 동일한 데이터를 자신의 로케일 규칙에 따라 포맷팅된 형태로 볼 수 있습니다.
애플리케이션에서 측정 목록 표시하기
이 패턴은 사용자에게 여러 측정값을 표시하는 모든 곳에서 사용할 수 있습니다. 여기에는 구간 시간을 보여주는 피트니스 애플리케이션, 온도 예보를 보여주는 날씨 애플리케이션, 재료 양을 보여주는 레시피 애플리케이션, 실험 데이터를 보여주는 과학 애플리케이션 등이 포함됩니다.
const splitTimes = [5, 10, 15, 20];
const numberFormatter = new Intl.NumberFormat(navigator.language, {
style: 'unit',
unit: 'kilometer',
maximumFractionDigits: 1
});
const formattedTimes = splitTimes.map(t => numberFormatter.format(t));
const listFormatter = new Intl.ListFormat(navigator.language, {
type: 'unit'
});
const result = listFormatter.format(formattedTimes);
document.getElementById('split-times').textContent = result;
// 표시: "5 km, 10 km, 15 km, 20 km" (또는 로케일에 맞는 형식)
형식이 지정된 문자열은 다른 문자열 값과 같이 작동합니다. 텍스트 콘텐츠, 속성 또는 사용자에게 정보를 표시하는 모든 컨텍스트에 삽입할 수 있습니다.