From 21bd60f18a9bd1b626da4975483e398a132e53bf Mon Sep 17 00:00:00 2001 From: Keith Cirkel Date: Mon, 21 Nov 2022 12:40:53 +0000 Subject: [PATCH 1/2] add multi langauge tests for strftime --- test/relative-time.js | 5 ++++- test/strftime.ts | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/test/relative-time.js b/test/relative-time.js index a82fed6..0851329 100644 --- a/test/relative-time.js +++ b/test/relative-time.js @@ -649,6 +649,8 @@ suite('relative-time', function () { {datetime: '2022-10-24t14:46:00.000z', tense: 'auto', format: 'micro', expected: '1m'}, {datetime: '2022-10-24t14:46:00.000z', tense: 'auto', format: 'auto', expected: 'now'}, {datetime: '2022-10-24t14:46:00.000z', tense: 'auto', format: '%Y-%m-%d', expected: '2022-10-24'}, + {datetime: '2022-10-24t14:46:00.000z', format: '%A %b %d', lang: 'es', expected: 'lunes oct 24'}, + {datetime: '2022-10-24t14:46:00.000z', format: '%A %b %d', lang: 'pl', expected: 'poniedziałek paź 24'}, // Dates in the past {datetime: '2022-09-24T14:46:00.000Z', tense: 'future', format: 'micro', expected: '1m'}, @@ -775,7 +777,7 @@ suite('relative-time', function () { } ]) - for (const {datetime, expected, tense, format, precision = '', reference = referenceDate} of tests) { + for (const {datetime, expected, tense, format, precision = '', lang = null, reference = referenceDate} of tests) { test(` => ${expected}`, function () { freezeTime(new Date(reference)) const time = document.createElement('relative-time') @@ -783,6 +785,7 @@ suite('relative-time', function () { time.setAttribute('datetime', datetime) time.setAttribute('format', format) time.setAttribute('precision', precision) + if (lang) time.setAttribute('lang', lang) assert.equal(time.shadowRoot.textContent, expected) }) } diff --git a/test/strftime.ts b/test/strftime.ts index cf0b0b2..0be9bbf 100644 --- a/test/strftime.ts +++ b/test/strftime.ts @@ -30,4 +30,20 @@ suite('strftime', function () { assert.equal(strftime(new Date('2022-10-19T11:31:59.554Z'), `%${k}`), v) }) } + + test('supports multiple languages', () => { + assert.equal(strftime(new Date('2022-10-19T11:31:59.554Z'), `%a`, 'es'), 'mié') + assert.equal(strftime(new Date('2022-10-19T11:31:59.554Z'), `%A`, 'es'), 'miércoles') + assert.equal(strftime(new Date('2022-10-19T11:31:59.554Z'), `%a`, 'nl'), 'wo') + assert.equal(strftime(new Date('2022-10-19T11:31:59.554Z'), `%A`, 'nl'), 'woensdag') + assert.equal(strftime(new Date('2022-10-19T11:31:59.554Z'), `%a`, 'pl'), 'śr.') + assert.equal(strftime(new Date('2022-10-19T11:31:59.554Z'), `%A`, 'pl'), 'środa') + + assert.equal(strftime(new Date('2022-10-19T11:31:59.554Z'), `%b`, 'es'), 'oct') + assert.equal(strftime(new Date('2022-10-19T11:31:59.554Z'), `%B`, 'es'), 'octubre') + assert.equal(strftime(new Date('2022-10-19T11:31:59.554Z'), `%b`, 'nl'), 'okt.') + assert.equal(strftime(new Date('2022-10-19T11:31:59.554Z'), `%B`, 'nl'), 'oktober') + assert.equal(strftime(new Date('2022-10-19T11:31:59.554Z'), `%b`, 'pl'), 'paź') + assert.equal(strftime(new Date('2022-10-19T11:31:59.554Z'), `%B`, 'pl'), 'październik') + }) }) From aac49efb7c5e7a8d3576a18707cf61874fe418e2 Mon Sep 17 00:00:00 2001 From: Keith Cirkel Date: Mon, 21 Nov 2022 12:41:13 +0000 Subject: [PATCH 2/2] support lang tag in strtime formats --- src/relative-time-element.ts | 2 +- src/strftime.ts | 23 ++++++++++++++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/relative-time-element.ts b/src/relative-time-element.ts index 92cea37..c943a2c 100644 --- a/src/relative-time-element.ts +++ b/src/relative-time-element.ts @@ -129,7 +129,7 @@ export default class RelativeTimeElement extends HTMLElement implements Intl.Dat if (!date) return const format = this.format if (format !== 'auto' && format !== 'micro' && format !== 'elapsed') { - return strftime(date, format) + return strftime(date, format, this.#lang) } else if (format === 'elapsed') { const precisionIndex = unitNames.indexOf(this.precision) || 0 const units = elapsedTime(date).filter(unit => unitNames.indexOf(unit[1]) >= precisionIndex) diff --git a/src/strftime.ts b/src/strftime.ts index 8a40022..f5b6c14 100644 --- a/src/strftime.ts +++ b/src/strftime.ts @@ -1,3 +1,5 @@ +const supportsIntlDatetime = 'Intl' in window && 'DateTimeFormat' in Intl + const weekdays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'] const months = [ 'January', @@ -14,7 +16,7 @@ const months = [ 'December' ] -export function strftime(time: Date, formatString: string): string { +export function strftime(time: Date, formatString: string, lang?: string): string { const day = time.getDay() const date = time.getDate() const month = time.getMonth() @@ -22,6 +24,9 @@ export function strftime(time: Date, formatString: string): string { const hour = time.getHours() const minute = time.getMinutes() const second = time.getSeconds() + const useIntl = lang && supportsIntlDatetime + const shortParts = useIntl && new Intl.DateTimeFormat(lang, {weekday: 'short', month: 'short'}).formatToParts(time) + const longParts = useIntl && new Intl.DateTimeFormat(lang, {weekday: 'long', month: 'long'}).formatToParts(time) return formatString.replace(/%([%aAbBcdeHIlmMpPSwyYZz])/g, function (_arg) { let match const modifier = _arg[1] @@ -29,12 +34,28 @@ export function strftime(time: Date, formatString: string): string { case '%': return '%' case 'a': + if (shortParts) { + const weekdayPart = shortParts.find(part => part.type === 'weekday') + if (weekdayPart) return weekdayPart.value + } return weekdays[day].slice(0, 3) case 'A': + if (longParts) { + const weekdayPart = longParts.find(part => part.type === 'weekday') + if (weekdayPart) return weekdayPart.value + } return weekdays[day] case 'b': + if (shortParts) { + const monthPart = shortParts.find(part => part.type === 'month') + if (monthPart) return monthPart.value + } return months[month].slice(0, 3) case 'B': + if (longParts) { + const monthPart = longParts.find(part => part.type === 'month') + if (monthPart) return monthPart.value + } return months[month] case 'c': return time.toString()