mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-10 15:47:23 +02:00
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:
parent
3e110054d7
commit
7941a46be3
9 changed files with 54 additions and 12 deletions
|
@ -19,7 +19,11 @@ const DefaultI18N: I18n = {
|
|||
currentLocale: 'en',
|
||||
locales: ['en'],
|
||||
defaultLocale: 'en',
|
||||
localeConfigs: {},
|
||||
localeConfigs: {
|
||||
en: {
|
||||
calendar: 'gregory',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
function getBlogContentPaths(siteDir: string): BlogContentPaths {
|
||||
|
|
|
@ -41,7 +41,7 @@ function getI18n(locale: string): I18n {
|
|||
currentLocale: locale,
|
||||
locales: [locale],
|
||||
defaultLocale: locale,
|
||||
localeConfigs: {},
|
||||
localeConfigs: {[locale]: {calendar: 'gregory'}},
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -151,13 +151,18 @@ export function parseBlogFileName(
|
|||
return {date: undefined, text, slug};
|
||||
}
|
||||
|
||||
function formatBlogPostDate(locale: string, date: Date): string {
|
||||
function formatBlogPostDate(
|
||||
locale: string,
|
||||
date: Date,
|
||||
calendar: string,
|
||||
): string {
|
||||
try {
|
||||
return new Intl.DateTimeFormat(locale, {
|
||||
day: 'numeric',
|
||||
month: 'long',
|
||||
year: 'numeric',
|
||||
timeZone: 'UTC',
|
||||
calendar,
|
||||
}).format(date);
|
||||
} catch (err) {
|
||||
logger.error`Can't format blog post date "${String(date)}"`;
|
||||
|
@ -253,7 +258,11 @@ async function processBlogSourceFile(
|
|||
}
|
||||
|
||||
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 description = frontMatter.description ?? excerpt ?? '';
|
||||
|
|
|
@ -254,9 +254,9 @@ function doProcessDocMetadata({
|
|||
lastUpdatedBy: lastUpdate.lastUpdatedBy,
|
||||
lastUpdatedAt: lastUpdate.lastUpdatedAt,
|
||||
formattedLastUpdatedAt: lastUpdate.lastUpdatedAt
|
||||
? new Intl.DateTimeFormat(i18n.currentLocale).format(
|
||||
lastUpdate.lastUpdatedAt * 1000,
|
||||
)
|
||||
? new Intl.DateTimeFormat(i18n.currentLocale, {
|
||||
calendar: i18n.localeConfigs[i18n.currentLocale]!.calendar,
|
||||
}).format(lastUpdate.lastUpdatedAt * 1000)
|
||||
: undefined,
|
||||
sidebarPosition,
|
||||
frontMatter,
|
||||
|
|
1
packages/docusaurus-types/src/index.d.ts
vendored
1
packages/docusaurus-types/src/index.d.ts
vendored
|
@ -45,6 +45,7 @@ export type I18nLocaleConfig = {
|
|||
label: string;
|
||||
htmlLang: string;
|
||||
direction: string;
|
||||
calendar: string;
|
||||
};
|
||||
|
||||
export type I18nConfig = {
|
||||
|
|
|
@ -32,48 +32,63 @@ describe('defaultLocaleConfig', () => {
|
|||
label: 'Français',
|
||||
direction: 'ltr',
|
||||
htmlLang: 'fr',
|
||||
calendar: 'gregory',
|
||||
});
|
||||
expect(getDefaultLocaleConfig('fr-FR')).toEqual({
|
||||
label: 'Français (France)',
|
||||
direction: 'ltr',
|
||||
htmlLang: 'fr-FR',
|
||||
calendar: 'gregory',
|
||||
});
|
||||
expect(getDefaultLocaleConfig('en')).toEqual({
|
||||
label: 'English',
|
||||
direction: 'ltr',
|
||||
htmlLang: 'en',
|
||||
calendar: 'gregory',
|
||||
});
|
||||
expect(getDefaultLocaleConfig('en-US')).toEqual({
|
||||
label: 'American English',
|
||||
direction: 'ltr',
|
||||
htmlLang: 'en-US',
|
||||
calendar: 'gregory',
|
||||
});
|
||||
expect(getDefaultLocaleConfig('zh')).toEqual({
|
||||
label: '中文',
|
||||
direction: 'ltr',
|
||||
htmlLang: 'zh',
|
||||
calendar: 'gregory',
|
||||
});
|
||||
expect(getDefaultLocaleConfig('zh-CN')).toEqual({
|
||||
label: '中文(中国)',
|
||||
direction: 'ltr',
|
||||
htmlLang: 'zh-CN',
|
||||
calendar: 'gregory',
|
||||
});
|
||||
expect(getDefaultLocaleConfig('en-US')).toEqual({
|
||||
label: 'American English',
|
||||
direction: 'ltr',
|
||||
htmlLang: 'en-US',
|
||||
calendar: 'gregory',
|
||||
});
|
||||
expect(getDefaultLocaleConfig('fa')).toEqual({
|
||||
// cSpell:ignore فارسی
|
||||
label: 'فارسی',
|
||||
direction: 'rtl',
|
||||
htmlLang: 'fa',
|
||||
calendar: 'gregory',
|
||||
});
|
||||
expect(getDefaultLocaleConfig('fa-IR')).toEqual({
|
||||
// cSpell:ignore ایران فارسیا
|
||||
label: 'فارسی (ایران)',
|
||||
direction: 'rtl',
|
||||
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'],
|
||||
currentLocale: 'de',
|
||||
localeConfigs: {
|
||||
fr: {label: 'Français', direction: 'ltr', htmlLang: 'fr'},
|
||||
fr: {
|
||||
label: 'Français',
|
||||
direction: 'ltr',
|
||||
htmlLang: 'fr',
|
||||
calendar: 'gregory',
|
||||
},
|
||||
en: getDefaultLocaleConfig('en'),
|
||||
de: getDefaultLocaleConfig('de'),
|
||||
},
|
||||
|
|
|
@ -131,6 +131,7 @@ const LocaleConfigSchema = Joi.object({
|
|||
label: Joi.string(),
|
||||
htmlLang: Joi.string(),
|
||||
direction: Joi.string().equal('ltr', 'rtl').default('ltr'),
|
||||
calendar: Joi.string(),
|
||||
});
|
||||
|
||||
const I18N_CONFIG_SCHEMA = Joi.object<I18nConfig>({
|
||||
|
|
|
@ -24,6 +24,8 @@ export function getDefaultLocaleConfig(locale: string): I18nLocaleConfig {
|
|||
label: getDefaultLocaleLabel(locale),
|
||||
direction: getLangDir(locale),
|
||||
htmlLang: locale,
|
||||
// If the locale name includes -u-ca-xxx the calendar will be defined
|
||||
calendar: new Intl.Locale(locale).calendar ?? 'gregory',
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -124,6 +124,8 @@ The i18n configuration object to [localize your site](../i18n/i18n-introduction.
|
|||
|
||||
Example:
|
||||
|
||||
<!-- cSpell:ignore فارسی -->
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
i18n: {
|
||||
|
@ -134,11 +136,13 @@ module.exports = {
|
|||
label: 'English',
|
||||
direction: 'ltr',
|
||||
htmlLang: 'en-US',
|
||||
calendar: 'gregory',
|
||||
},
|
||||
fr: {
|
||||
label: 'Français',
|
||||
direction: 'ltr',
|
||||
htmlLang: 'fr-FR',
|
||||
fa: {
|
||||
label: 'فارسی',
|
||||
direction: 'rtl',
|
||||
htmlLang: 'fa-IR',
|
||||
calendar: 'persian',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -148,6 +152,7 @@ module.exports = {
|
|||
- `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.)
|
||||
- `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}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue