날짜 및 시간 필드에 대한 현지화된 레이블을 어떻게 표시하나요?
Intl.DisplayNames를 사용하여 필드 레이블을 가져오고 Intl.DateTimeFormat을 사용하여 모든 언어로 월 및 요일 이름을 가져옵니다.
소개
날짜와 시간 입력 양식을 구축할 때, 각 필드를 설명하는 레이블이 필요합니다. 날짜 선택기에는 "월", "연도", "일"과 같은 레이블이 필요합니다. 시간 선택기에는 "시간"과 "분"과 같은 레이블이 필요합니다. 이러한 레이블은 사용자의 언어로 표시되어야 합니다.
이러한 레이블을 영어로 하드코딩하는 것은 국제 애플리케이션에서 작동하지 않습니다. 프랑스어 사용자는 "Mois"와 "Année"를 보기를 기대하고, 스페인어 사용자는 "Mes"와 "Año"를 찾습니다. 어떤 언어에서든 이러한 레이블을 자동으로 제공하는 시스템이 필요합니다.
자바스크립트는 이를 위한 두 가지 상호 보완적인 API를 제공합니다. Intl.DisplayNames API는 "월"과 "연도"와 같은 필드 레이블을 제공합니다. Intl.DateTimeFormat API는 월 이름과 요일 이름과 같은 해당 필드의 실제 값을 제공합니다.
날짜 및 시간 필드 레이블 이해하기
날짜 및 시간 인터페이스에는 두 가지 유형의 레이블이 필요합니다. 필드 레이블은 각 입력에 들어가는 데이터 유형을 설명합니다. 필드 값은 드롭다운 및 선택기에 나타나는 실제 데이터입니다.
필드 레이블에는 "연도", "월", "일", "시간", "분", "초"와 같은 단어가 포함됩니다. 이들은 양식 필드 자체에 레이블을 붙입니다.
필드 값에는 "1월"과 "2월"과 같은 월 이름, "월요일"과 "화요일"과 같은 요일 이름, "오전"과 "오후"와 같은 기간 레이블이 포함됩니다. 이들은 드롭다운과 선택 목록을 채웁니다.
완전한 날짜 양식에는 두 가지 유형의 레이블이 모두 필요합니다.
<label>월</label>
<select>
<option>1월</option>
<option>2월</option>
<option>3월</option>
<!-- 더 많은 월 -->
</select>
<label>연도</label>
<input type="number" />
"월"과 "1월" 모두 현지화가 필요하지만, 서로 다른 접근 방식이 필요합니다.
Intl.DisplayNames로 필드 레이블 가져오기
type: "dateTimeField"와 함께 Intl.DisplayNames 생성자는 날짜 및 시간 구성 요소에 대한 현지화된 레이블을 반환합니다.
const labels = new Intl.DisplayNames('en-US', { type: 'dateTimeField' });
console.log(labels.of('year'));
// "year"
console.log(labels.of('month'));
// "month"
console.log(labels.of('day'));
// "day"
console.log(labels.of('hour'));
// "hour"
console.log(labels.of('minute'));
// "minute"
console.log(labels.of('second'));
// "second"
of() 메서드는 필드 코드를 받아 현지화된 레이블을 반환합니다. 레이블은 지정된 로케일의 규칙에 맞게 표시됩니다.
로케일을 변경하여 어떤 언어로든 레이블을 가져올 수 있습니다.
// 스페인어 레이블
const esLabels = new Intl.DisplayNames('es-ES', { type: 'dateTimeField' });
console.log(esLabels.of('year'));
// "año"
console.log(esLabels.of('month'));
// "mes"
console.log(esLabels.of('day'));
// "día"
console.log(esLabels.of('hour'));
// "hora"
console.log(esLabels.of('minute'));
// "minuto"
// 프랑스어 레이블
const frLabels = new Intl.DisplayNames('fr-FR', { type: 'dateTimeField' });
console.log(frLabels.of('year'));
// "année"
console.log(frLabels.of('month'));
// "mois"
console.log(frLabels.of('day'));
// "jour"
console.log(frLabels.of('hour'));
// "heure"
console.log(frLabels.of('minute'));
// "minute"
// 일본어 레이블
const jaLabels = new Intl.DisplayNames('ja-JP', { type: 'dateTimeField' });
console.log(jaLabels.of('year'));
// "年"
console.log(jaLabels.of('month'));
// "月"
console.log(jaLabels.of('day'));
// "日"
console.log(jaLabels.of('hour'));
// "時"
console.log(jaLabels.of('minute'));
// "分"
각 로케일은 자체 언어와 문자로 레이블을 제공합니다.
사용 가능한 날짜 및 시간 필드 코드
'Intl.DisplayNames' API는 다음 필드 코드를 지원합니다.
const labels = new Intl.DisplayNames('en-US', { type: 'dateTimeField' });
console.log(labels.of('era'));
// "era"
console.log(labels.of('year'));
// "year"
console.log(labels.of('quarter'));
// "quarter"
console.log(labels.of('month'));
// "month"
console.log(labels.of('weekOfYear'));
// "week"
console.log(labels.of('weekday'));
// "day of the week"
console.log(labels.of('day'));
// "day"
console.log(labels.of('dayPeriod'));
// "AM/PM"
console.log(labels.of('hour'));
// "hour"
console.log(labels.of('minute'));
// "minute"
console.log(labels.of('second'));
// "second"
console.log(labels.of('timeZoneName'));
// "time zone"
인터페이스에 필요한 모든 날짜 또는 시간 구성 요소의 레이블을 가져오려면 이러한 코드를 사용하세요.
지역화된 월 이름 가져오기
'Intl.DateTimeFormat' API는 드롭다운 및 선택 목록을 채우기 위한 월 이름을 제공합니다. 'month' 옵션을 '"long"'으로 설정한 포맷터를 생성한 다음, 각 월을 나타내는 날짜를 포맷합니다.
function getMonthNames(locale) {
const formatter = new Intl.DateTimeFormat(locale, {
month: 'long',
timeZone: 'UTC'
});
const months = [];
for (let month = 0; month < 12; month++) {
const date = new Date(Date.UTC(2000, month, 1));
months.push(formatter.format(date));
}
return months;
}
console.log(getMonthNames('en-US'));
// ["January", "February", "March", "April", "May", "June",
// "July", "August", "September", "October", "November", "December"]
이 함수는 연중 각 월에 대한 날짜를 생성하고 이를 포맷하여 월 이름을 추출합니다. 'timeZone: 'UTC''를 설정하면 시간대 전반에 걸쳐 일관된 결과를 보장합니다.
어떤 언어로든 월 이름을 가져올 수 있습니다.
console.log(getMonthNames('es-ES'));
// ["enero", "febrero", "marzo", "abril", "mayo", "junio",
// "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre"]
console.log(getMonthNames('fr-FR'));
// ["janvier", "février", "mars", "avril", "mai", "juin",
// "juillet", "août", "septembre", "octobre", "novembre", "décembre"]
console.log(getMonthNames('ja-JP'));
// ["1月", "2月", "3月", "4月", "5月", "6月",
// "7月", "8月", "9月", "10月", "11月", "12月"]
각 로케일은 자체 규칙에 따라 월 이름을 포맷합니다.
월 이름 길이 제어
'month' 옵션은 월 이름의 길이를 제어하는 다양한 값을 허용합니다.
"long" 값은 전체 월 이름을 반환합니다.
const longFormatter = new Intl.DateTimeFormat('en-US', {
month: 'long',
timeZone: 'UTC'
});
const date = new Date(Date.UTC(2000, 0, 1));
console.log(longFormatter.format(date));
// "January"
"short" 값은 축약된 월 이름을 반환합니다.
const shortFormatter = new Intl.DateTimeFormat('en-US', {
month: 'short',
timeZone: 'UTC'
});
console.log(shortFormatter.format(date));
// "Jan"
"narrow" 값은 가능한 가장 짧은 월 이름을 반환하며, 일반적으로 한 글자입니다.
const narrowFormatter = new Intl.DateTimeFormat('en-US', {
month: 'narrow',
timeZone: 'UTC'
});
console.log(narrowFormatter.format(date));
// "J"
"narrow"는 여러 월이 동일한 글자를 공유할 수 있으므로 주의해서 사용하세요. 영어에서는 January, June, July가 모두 "J"를 생성합니다.
지역화된 요일 이름 가져오기
요일 이름을 가져오기 위해 동일한 패턴을 사용하세요. 형식을 제어하려면 'weekday' 옵션을 설정하세요.
function getWeekdayNames(locale, format = 'long') {
const formatter = new Intl.DateTimeFormat(locale, {
weekday: format,
timeZone: 'UTC'
});
const weekdays = [];
// 일요일부터 시작 (2000년 1월 2일은 일요일이었습니다)
for (let day = 0; day < 7; day++) {
const date = new Date(Date.UTC(2000, 0, 2 + day));
weekdays.push(formatter.format(date));
}
return weekdays;
}
console.log(getWeekdayNames('en-US'));
// ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
console.log(getWeekdayNames('en-US', 'short'));
// ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
console.log(getWeekdayNames('en-US', 'narrow'));
// ["S", "M", "T", "W", "T", "F", "S"]
어떤 언어로든 요일 이름을 가져올 수 있습니다.
console.log(getWeekdayNames('es-ES'));
// ["domingo", "lunes", "martes", "miércoles", "jueves", "viernes", "sábado"]
console.log(getWeekdayNames('fr-FR'));
// ["dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"]
console.log(getWeekdayNames('ja-JP'));
// ["日曜日", "月曜日", "火曜日", "水曜日", "木曜日", "金曜日", "土曜日"]
다양한 로케일은 주의 시작일이 다를 수 있습니다. 이 함수는 항상 일요일부터 토요일까지 순서대로 반환합니다.
현지화된 시간대 라벨 가져오기
시간대 라벨은 12시간제에서 사용되는 AM과 PM 표시기입니다. formatToParts()를 사용하여 이러한 라벨을 추출하세요.
function getPeriodLabels(locale) {
const formatter = new Intl.DateTimeFormat(locale, {
hour: 'numeric',
hour12: true,
timeZone: 'UTC'
});
const amDate = new Date(Date.UTC(2000, 0, 1, 0, 0, 0));
const pmDate = new Date(Date.UTC(2000, 0, 1, 12, 0, 0));
const amParts = formatter.formatToParts(amDate);
const pmParts = formatter.formatToParts(pmDate);
const am = amParts.find(part => part.type === 'dayPeriod').value;
const pm = pmParts.find(part => part.type === 'dayPeriod').value;
return { am, pm };
}
console.log(getPeriodLabels('en-US'));
// { am: "AM", pm: "PM" }
console.log(getPeriodLabels('es-ES'));
// { am: "a. m.", pm: "p. m." }
console.log(getPeriodLabels('fr-FR'));
// { am: "AM", pm: "PM" }
console.log(getPeriodLabels('ja-JP'));
// { am: "午前", pm: "午後" }
formatToParts() 메서드는 형식화된 시간의 각 부분을 나타내는 객체 배열을 반환합니다. type: "dayPeriod"를 가진 객체는 AM 또는 PM 라벨을 포함합니다.
일부 로케일은 기본적으로 24시간제를 사용하며 시간대 라벨을 포함하지 않습니다. hour12: true 옵션으로 12시간제를 강제할 수 있습니다.
완전한 현지화된 날짜 양식 구축하기
이러한 모든 기술을 결합하여 완전히 현지화된 날짜 입력 양식을 만들어 보세요.
function createDateForm(locale) {
const fieldLabels = new Intl.DisplayNames(locale, { type: 'dateTimeField' });
const monthNames = getMonthNames(locale);
const currentYear = new Date().getFullYear();
return {
monthLabel: fieldLabels.of('month'),
months: monthNames.map((name, index) => ({
value: index + 1,
label: name
})),
dayLabel: fieldLabels.of('day'),
yearLabel: fieldLabels.of('year'),
yearPlaceholder: currentYear
};
}
// 이전 예제의 도우미 함수
function getMonthNames(locale) {
const formatter = new Intl.DateTimeFormat(locale, {
month: 'long',
timeZone: 'UTC'
});
const months = [];
for (let month = 0; month < 12; month++) {
const date = new Date(Date.UTC(2000, month, 1));
months.push(formatter.format(date));
}
return months;
}
const enForm = createDateForm('en-US');
console.log(enForm.monthLabel);
// "month"
console.log(enForm.months[0]);
// { value: 1, label: "January" }
console.log(enForm.dayLabel);
// "day"
console.log(enForm.yearLabel);
// "year"
const esForm = createDateForm('es-ES');
console.log(esForm.monthLabel);
// "mes"
console.log(esForm.months[0]);
// { value: 1, label: "enero" }
console.log(esForm.dayLabel);
// "día"
console.log(esForm.yearLabel);
// "año"
이 구조는 HTML에서 현지화된 날짜 양식을 렌더링하는 데 필요한 모든 것을 제공합니다.
function renderDateForm(locale) {
const form = createDateForm(locale);
return `
<div class="date-form">
<div class="form-field">
<label>${form.monthLabel}</label>
<select name="month">
${form.months.map(month =>
`<option value="${month.value}">${month.label}</option>`
).join('')}
</select>
</div>
<div class="form-field">
<label>${form.dayLabel}</label>
<input type="number" name="day" min="1" max="31" />
</div>
<div class="form-field">
<label>${form.yearLabel}</label>
<input type="number" name="year" placeholder="${form.yearPlaceholder}" />
</div>
</div>
`;
}
console.log(renderDateForm('en-US'));
// 영어 라벨과 월 이름으로 양식 렌더링
console.log(renderDateForm('fr-FR'));
// 프랑스어 라벨과 월 이름으로 양식 렌더링
이 양식은 지정한 로케일에 자동으로 적응합니다.
현지화된 시간 폼 구축하기
동일한 접근 방식을 적용하여 시간, 분, 오전/오후 선택기가 있는 시간 입력 폼을 만들어 보겠습니다.
function createTimeForm(locale) {
const fieldLabels = new Intl.DisplayNames(locale, { type: 'dateTimeField' });
const periods = getPeriodLabels(locale);
const hours = [];
for (let hour = 1; hour <= 12; hour++) {
hours.push({ value: hour, label: hour.toString() });
}
const minutes = [];
for (let minute = 0; minute < 60; minute += 5) {
minutes.push({
value: minute,
label: minute.toString().padStart(2, '0')
});
}
return {
hourLabel: fieldLabels.of('hour'),
hours: hours,
minuteLabel: fieldLabels.of('minute'),
minutes: minutes,
periodLabel: fieldLabels.of('dayPeriod'),
periods: [
{ value: 'am', label: periods.am },
{ value: 'pm', label: periods.pm }
]
};
}
// 이전 예제의 도우미 함수
function getPeriodLabels(locale) {
const formatter = new Intl.DateTimeFormat(locale, {
hour: 'numeric',
hour12: true,
timeZone: 'UTC'
});
const amDate = new Date(Date.UTC(2000, 0, 1, 0, 0, 0));
const pmDate = new Date(Date.UTC(2000, 0, 1, 12, 0, 0));
const amParts = formatter.formatToParts(amDate);
const pmParts = formatter.formatToParts(pmDate);
const am = amParts.find(part => part.type === 'dayPeriod').value;
const pm = pmParts.find(part => part.type === 'dayPeriod').value;
return { am, pm };
}
const enTime = createTimeForm('en-US');
console.log(enTime.hourLabel);
// "hour"
console.log(enTime.minuteLabel);
// "minute"
console.log(enTime.periodLabel);
// "AM/PM"
console.log(enTime.periods);
// [{ value: "am", label: "AM" }, { value: "pm", label: "PM" }]
const jaTime = createTimeForm('ja-JP');
console.log(jaTime.hourLabel);
// "時"
console.log(jaTime.minuteLabel);
// "分"
console.log(jaTime.periodLabel);
// "午前/午後"
console.log(jaTime.periods);
// [{ value: "am", label: "午前" }, { value: "pm", label: "午後" }]
이는 현지화된 시간 선택기를 렌더링하는 데 필요한 모든 데이터를 제공합니다.
날짜 및 시간 필드 레이블을 사용하는 경우
날짜 및 시간 필드 레이블은 여러 유형의 인터페이스에 나타납니다.
커스텀 날짜 및 시간 선택기
날짜 선택기, 캘린더 위젯 또는 시간 선택기를 구축할 때 현지화된 레이블을 사용하세요.
const locale = navigator.language;
const labels = new Intl.DisplayNames(locale, { type: 'dateTimeField' });
const datePicker = {
yearLabel: labels.of('year'),
monthLabel: labels.of('month'),
dayLabel: labels.of('day')
};
폼 필드 레이블
날짜 및 시간 데이터에 대한 표준 폼 입력에 레이블을 적용하세요.
const labels = new Intl.DisplayNames('en-US', { type: 'dateTimeField' });
document.querySelector('#birthdate-month-label').textContent =
labels.of('month');
document.querySelector('#birthdate-year-label').textContent =
labels.of('year');
접근성 레이블
스크린 리더 및 보조 기술을 위한 현지화된 ARIA 레이블을 제공하세요.
const locale = navigator.language;
const labels = new Intl.DisplayNames(locale, { type: 'dateTimeField' });
const input = document.querySelector('#date-input');
input.setAttribute('aria-label', labels.of('year'));
데이터 테이블 헤더
날짜 및 시간 구성 요소를 표시하는 테이블의 열에 레이블을 지정하세요.
const labels = new Intl.DisplayNames('en-US', { type: 'dateTimeField' });
const table = `
<table>
<thead>
<tr>
<th>${labels.of('year')}</th>
<th>${labels.of('month')}</th>
<th>${labels.of('day')}</th>
</tr>
</thead>
</table>
`;
브라우저 지원
주요 브라우저에서는 2022년 3월부터 type: "dateTimeField"를 사용한 Intl.DisplayNames API가 지원되고 있습니다.
크롬과 엣지는 버전 99부터 지원합니다. 파이어폭스는 버전 99부터 지원합니다. 사파리는 버전 15.4부터 지원합니다.
사용하기 전에 해당 기능의 가용성을 확인할 수 있습니다.
function supportsDateTimeFieldLabels() {
try {
const labels = new Intl.DisplayNames('en', { type: 'dateTimeField' });
labels.of('year');
return true;
} catch (error) {
return false;
}
}
if (supportsDateTimeFieldLabels()) {
const labels = new Intl.DisplayNames('en-US', { type: 'dateTimeField' });
console.log(labels.of('month'));
} else {
console.log('month'); // 영어로 폴백
}
구형 브라우저의 경우 폴백 레이블을 제공해야 합니다. 일반적인 필드에 대한 간단한 매핑 객체를 만드세요.
const fallbackLabels = {
en: {
year: 'year',
month: 'month',
day: 'day',
hour: 'hour',
minute: 'minute',
second: 'second'
},
es: {
year: 'año',
month: 'mes',
day: 'día',
hour: 'hora',
minute: 'minuto',
second: 'segundo'
},
fr: {
year: 'année',
month: 'mois',
day: 'jour',
hour: 'heure',
minute: 'minute',
second: 'seconde'
}
};
function getFieldLabel(field, locale) {
if (supportsDateTimeFieldLabels()) {
const labels = new Intl.DisplayNames(locale, { type: 'dateTimeField' });
return labels.of(field);
}
const language = locale.split('-')[0];
return fallbackLabels[language]?.[field] || fallbackLabels.en[field];
}
console.log(getFieldLabel('month', 'es-ES'));
// "mes" (지원되는 경우 API에서, 그렇지 않으면 폴백에서)
이렇게 하면 모든 브라우저에서 폼이 작동하면서도 가능한 경우 네이티브 현지화를 활용할 수 있습니다.
월 및 요일 이름을 가져오기 위한 Intl.DateTimeFormat API는 인터넷 익스플로러 11 및 모든 최신 브라우저까지 더 넓은 지원 범위를 가지고 있습니다. 대부분의 경우 기능 감지 없이 사용할 수 있습니다.