feat: allow setting calendar for i18n date formatting (#6430)

* feat: allow setting calendar for i18n date formatting

* fix TS

* add test
This commit is contained in:
Joshua Chen 2022-04-08 22:34:34 +08:00 committed by GitHub
parent 3e110054d7
commit 7941a46be3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 54 additions and 12 deletions

View file

@ -19,7 +19,11 @@ const DefaultI18N: I18n = {
currentLocale: 'en', currentLocale: 'en',
locales: ['en'], locales: ['en'],
defaultLocale: 'en', defaultLocale: 'en',
localeConfigs: {}, localeConfigs: {
en: {
calendar: 'gregory',
},
},
}; };
function getBlogContentPaths(siteDir: string): BlogContentPaths { function getBlogContentPaths(siteDir: string): BlogContentPaths {

View file

@ -41,7 +41,7 @@ function getI18n(locale: string): I18n {
currentLocale: locale, currentLocale: locale,
locales: [locale], locales: [locale],
defaultLocale: locale, defaultLocale: locale,
localeConfigs: {}, localeConfigs: {[locale]: {calendar: 'gregory'}},
}; };
} }

View file

@ -151,13 +151,18 @@ export function parseBlogFileName(
return {date: undefined, text, slug}; return {date: undefined, text, slug};
} }
function formatBlogPostDate(locale: string, date: Date): string { function formatBlogPostDate(
locale: string,
date: Date,
calendar: string,
): string {
try { try {
return new Intl.DateTimeFormat(locale, { return new Intl.DateTimeFormat(locale, {
day: 'numeric', day: 'numeric',
month: 'long', month: 'long',
year: 'numeric', year: 'numeric',
timeZone: 'UTC', timeZone: 'UTC',
calendar,
}).format(date); }).format(date);
} catch (err) { } catch (err) {
logger.error`Can't format blog post date "${String(date)}"`; logger.error`Can't format blog post date "${String(date)}"`;
@ -253,7 +258,11 @@ async function processBlogSourceFile(
} }
const date = await getDate(); const date = await getDate();
const formattedDate = formatBlogPostDate(i18n.currentLocale, date); const formattedDate = formatBlogPostDate(
i18n.currentLocale,
date,
i18n.localeConfigs[i18n.currentLocale]!.calendar,
);
const title = frontMatter.title ?? contentTitle ?? parsedBlogFileName.text; const title = frontMatter.title ?? contentTitle ?? parsedBlogFileName.text;
const description = frontMatter.description ?? excerpt ?? ''; const description = frontMatter.description ?? excerpt ?? '';

View file

@ -254,9 +254,9 @@ function doProcessDocMetadata({
lastUpdatedBy: lastUpdate.lastUpdatedBy, lastUpdatedBy: lastUpdate.lastUpdatedBy,
lastUpdatedAt: lastUpdate.lastUpdatedAt, lastUpdatedAt: lastUpdate.lastUpdatedAt,
formattedLastUpdatedAt: lastUpdate.lastUpdatedAt formattedLastUpdatedAt: lastUpdate.lastUpdatedAt
? new Intl.DateTimeFormat(i18n.currentLocale).format( ? new Intl.DateTimeFormat(i18n.currentLocale, {
lastUpdate.lastUpdatedAt * 1000, calendar: i18n.localeConfigs[i18n.currentLocale]!.calendar,
) }).format(lastUpdate.lastUpdatedAt * 1000)
: undefined, : undefined,
sidebarPosition, sidebarPosition,
frontMatter, frontMatter,

View file

@ -45,6 +45,7 @@ export type I18nLocaleConfig = {
label: string; label: string;
htmlLang: string; htmlLang: string;
direction: string; direction: string;
calendar: string;
}; };
export type I18nConfig = { export type I18nConfig = {

View file

@ -32,48 +32,63 @@ describe('defaultLocaleConfig', () => {
label: 'Français', label: 'Français',
direction: 'ltr', direction: 'ltr',
htmlLang: 'fr', htmlLang: 'fr',
calendar: 'gregory',
}); });
expect(getDefaultLocaleConfig('fr-FR')).toEqual({ expect(getDefaultLocaleConfig('fr-FR')).toEqual({
label: 'Français (France)', label: 'Français (France)',
direction: 'ltr', direction: 'ltr',
htmlLang: 'fr-FR', htmlLang: 'fr-FR',
calendar: 'gregory',
}); });
expect(getDefaultLocaleConfig('en')).toEqual({ expect(getDefaultLocaleConfig('en')).toEqual({
label: 'English', label: 'English',
direction: 'ltr', direction: 'ltr',
htmlLang: 'en', htmlLang: 'en',
calendar: 'gregory',
}); });
expect(getDefaultLocaleConfig('en-US')).toEqual({ expect(getDefaultLocaleConfig('en-US')).toEqual({
label: 'American English', label: 'American English',
direction: 'ltr', direction: 'ltr',
htmlLang: 'en-US', htmlLang: 'en-US',
calendar: 'gregory',
}); });
expect(getDefaultLocaleConfig('zh')).toEqual({ expect(getDefaultLocaleConfig('zh')).toEqual({
label: '中文', label: '中文',
direction: 'ltr', direction: 'ltr',
htmlLang: 'zh', htmlLang: 'zh',
calendar: 'gregory',
}); });
expect(getDefaultLocaleConfig('zh-CN')).toEqual({ expect(getDefaultLocaleConfig('zh-CN')).toEqual({
label: '中文(中国)', label: '中文(中国)',
direction: 'ltr', direction: 'ltr',
htmlLang: 'zh-CN', htmlLang: 'zh-CN',
calendar: 'gregory',
}); });
expect(getDefaultLocaleConfig('en-US')).toEqual({ expect(getDefaultLocaleConfig('en-US')).toEqual({
label: 'American English', label: 'American English',
direction: 'ltr', direction: 'ltr',
htmlLang: 'en-US', htmlLang: 'en-US',
calendar: 'gregory',
}); });
expect(getDefaultLocaleConfig('fa')).toEqual({ expect(getDefaultLocaleConfig('fa')).toEqual({
// cSpell:ignore فارسی // cSpell:ignore فارسی
label: 'فارسی', label: 'فارسی',
direction: 'rtl', direction: 'rtl',
htmlLang: 'fa', htmlLang: 'fa',
calendar: 'gregory',
}); });
expect(getDefaultLocaleConfig('fa-IR')).toEqual({ expect(getDefaultLocaleConfig('fa-IR')).toEqual({
// cSpell:ignore ایران فارسیا // cSpell:ignore ایران فارسیا
label: 'فارسی (ایران)', label: 'فارسی (ایران)',
direction: 'rtl', direction: 'rtl',
htmlLang: 'fa-IR', htmlLang: 'fa-IR',
calendar: 'gregory',
});
expect(getDefaultLocaleConfig('en-US-u-ca-buddhist')).toEqual({
label: 'American English',
direction: 'ltr',
htmlLang: 'en-US-u-ca-buddhist',
calendar: 'buddhist',
}); });
}); });
}); });
@ -144,7 +159,12 @@ describe('loadI18n', () => {
locales: ['en', 'fr', 'de'], locales: ['en', 'fr', 'de'],
currentLocale: 'de', currentLocale: 'de',
localeConfigs: { localeConfigs: {
fr: {label: 'Français', direction: 'ltr', htmlLang: 'fr'}, fr: {
label: 'Français',
direction: 'ltr',
htmlLang: 'fr',
calendar: 'gregory',
},
en: getDefaultLocaleConfig('en'), en: getDefaultLocaleConfig('en'),
de: getDefaultLocaleConfig('de'), de: getDefaultLocaleConfig('de'),
}, },

View file

@ -131,6 +131,7 @@ const LocaleConfigSchema = Joi.object({
label: Joi.string(), label: Joi.string(),
htmlLang: Joi.string(), htmlLang: Joi.string(),
direction: Joi.string().equal('ltr', 'rtl').default('ltr'), direction: Joi.string().equal('ltr', 'rtl').default('ltr'),
calendar: Joi.string(),
}); });
const I18N_CONFIG_SCHEMA = Joi.object<I18nConfig>({ const I18N_CONFIG_SCHEMA = Joi.object<I18nConfig>({

View file

@ -24,6 +24,8 @@ export function getDefaultLocaleConfig(locale: string): I18nLocaleConfig {
label: getDefaultLocaleLabel(locale), label: getDefaultLocaleLabel(locale),
direction: getLangDir(locale), direction: getLangDir(locale),
htmlLang: locale, htmlLang: locale,
// If the locale name includes -u-ca-xxx the calendar will be defined
calendar: new Intl.Locale(locale).calendar ?? 'gregory',
}; };
} }

View file

@ -124,6 +124,8 @@ The i18n configuration object to [localize your site](../i18n/i18n-introduction.
Example: Example:
<!-- cSpell:ignore فارسی -->
```js title="docusaurus.config.js" ```js title="docusaurus.config.js"
module.exports = { module.exports = {
i18n: { i18n: {
@ -134,11 +136,13 @@ module.exports = {
label: 'English', label: 'English',
direction: 'ltr', direction: 'ltr',
htmlLang: 'en-US', htmlLang: 'en-US',
calendar: 'gregory',
}, },
fr: { fa: {
label: 'Français', label: 'فارسی',
direction: 'ltr', direction: 'rtl',
htmlLang: 'fr-FR', htmlLang: 'fa-IR',
calendar: 'persian',
}, },
}, },
}, },
@ -148,6 +152,7 @@ module.exports = {
- `label`: the label to use for this locale - `label`: the label to use for this locale
- `direction`: `ltr` (default) or `rtl` (for [right-to-left languages](https://developer.mozilla.org/en-US/docs/Glossary/rtl) like Arabic, Hebrew, etc.) - `direction`: `ltr` (default) or `rtl` (for [right-to-left languages](https://developer.mozilla.org/en-US/docs/Glossary/rtl) like Arabic, Hebrew, etc.)
- `htmlLang`: BCP 47 language tag to use in `<html lang="...">` and in `<link ... hreflang="...">` - `htmlLang`: BCP 47 language tag to use in `<html lang="...">` and in `<link ... hreflang="...">`
- `calendar`: the [calendar](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/calendar) used to calculate the date era. Note that it doesn't control the actual string displayed: `MM/DD/YYYY` and `DD/MM/YYYY` are both `gregory`. To choose the format (`DD/MM/YYYY` or `MM/DD/YYYY`), set your locale name to `en-GB` or `en-US` (`en` means `en-US`).
### `noIndex` {#noindex} ### `noIndex` {#noindex}