This commit is contained in:
Sébastien Lorber 2025-07-15 15:35:25 +02:00 committed by GitHub
commit 5eb873b45e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 91 additions and 4 deletions

View file

@ -37,6 +37,21 @@ export type I18nLocaleConfig = {
* By default, it will only be run if the `./i18n/<locale>` exists. * By default, it will only be run if the `./i18n/<locale>` exists.
*/ */
translate: boolean; translate: boolean;
/**
* The baseUrl to use for this locale.
* This overrides the `siteConfig.baseUrl` attribute.
*
* Default values:
* - Default locale: `/${siteConfig.baseUrl}/`
* - Other locales: `/${siteConfig.baseUrl}/<locale>/`
*
* Exception: when using the CLI with a single `--locale` parameter, the
* `/<locale>/` path segment is not included. This is a better default for
* sites looking to deploy each locale to a different subdomain, such as
* `https://<locale>.docusaurus.io`
*/
baseUrl: string;
}; };
export type I18nConfig = { export type I18nConfig = {

View file

@ -19,10 +19,12 @@ const loadI18nSiteDir = path.resolve(
function loadI18nTest({ function loadI18nTest({
siteDir = loadI18nSiteDir, siteDir = loadI18nSiteDir,
baseUrl = '/',
i18nConfig, i18nConfig,
currentLocale, currentLocale,
}: { }: {
siteDir?: string; siteDir?: string;
baseUrl?: string;
i18nConfig: I18nConfig; i18nConfig: I18nConfig;
currentLocale: string; currentLocale: string;
}) { }) {
@ -30,6 +32,7 @@ function loadI18nTest({
siteDir, siteDir,
config: { config: {
i18n: i18nConfig, i18n: i18nConfig,
baseUrl,
} as DocusaurusConfig, } as DocusaurusConfig,
currentLocale, currentLocale,
}); });
@ -133,6 +136,7 @@ describe('loadI18n', () => {
en: { en: {
...getDefaultLocaleConfig('en'), ...getDefaultLocaleConfig('en'),
translate: false, translate: false,
baseUrl: '/',
}, },
}, },
}); });
@ -158,14 +162,17 @@ describe('loadI18n', () => {
en: { en: {
...getDefaultLocaleConfig('en'), ...getDefaultLocaleConfig('en'),
translate: false, translate: false,
baseUrl: '/en/',
}, },
fr: { fr: {
...getDefaultLocaleConfig('fr'), ...getDefaultLocaleConfig('fr'),
translate: true, translate: true,
baseUrl: '/',
}, },
de: { de: {
...getDefaultLocaleConfig('de'), ...getDefaultLocaleConfig('de'),
translate: true, translate: true,
baseUrl: '/de/',
}, },
}, },
}); });
@ -191,14 +198,17 @@ describe('loadI18n', () => {
en: { en: {
...getDefaultLocaleConfig('en'), ...getDefaultLocaleConfig('en'),
translate: false, translate: false,
baseUrl: '/en/',
}, },
fr: { fr: {
...getDefaultLocaleConfig('fr'), ...getDefaultLocaleConfig('fr'),
translate: true, translate: true,
baseUrl: '/',
}, },
de: { de: {
...getDefaultLocaleConfig('de'), ...getDefaultLocaleConfig('de'),
translate: true, translate: true,
baseUrl: '/de/',
}, },
}, },
}); });
@ -213,10 +223,11 @@ describe('loadI18n', () => {
locales: ['en', 'fr', 'de'], locales: ['en', 'fr', 'de'],
localeConfigs: { localeConfigs: {
fr: {label: 'Français', translate: false}, fr: {label: 'Français', translate: false},
en: {translate: true}, en: {translate: true, baseUrl: 'en-EN/whatever/else'},
de: {translate: false}, de: {translate: false, baseUrl: '/de-DE/'},
}, },
}, },
currentLocale: 'de', currentLocale: 'de',
}), }),
).resolves.toEqual({ ).resolves.toEqual({
@ -232,19 +243,58 @@ describe('loadI18n', () => {
calendar: 'gregory', calendar: 'gregory',
path: 'fr', path: 'fr',
translate: false, translate: false,
baseUrl: '/',
}, },
en: { en: {
...getDefaultLocaleConfig('en'), ...getDefaultLocaleConfig('en'),
translate: true, translate: true,
baseUrl: '/en-EN/whatever/else/',
}, },
de: { de: {
...getDefaultLocaleConfig('de'), ...getDefaultLocaleConfig('de'),
translate: false, translate: false,
baseUrl: '/de-DE/',
}, },
}, },
}); });
}); });
it('loads I18n for multi-locale config with baseUrl edge cases', async () => {
await expect(
loadI18nTest({
baseUrl: 'siteBaseUrl',
i18nConfig: {
path: 'i18n',
defaultLocale: 'fr',
locales: ['en', 'fr', 'de', 'pt'],
localeConfigs: {
fr: {},
en: {baseUrl: ''},
de: {baseUrl: '/de-DE/'},
},
},
currentLocale: 'de',
}),
).resolves.toEqual(
expect.objectContaining({
localeConfigs: {
fr: expect.objectContaining({
baseUrl: '/siteBaseUrl/',
}),
en: expect.objectContaining({
baseUrl: '/',
}),
de: expect.objectContaining({
baseUrl: '/de-DE/',
}),
pt: expect.objectContaining({
baseUrl: '/siteBaseUrl/pt/',
}),
},
}),
);
});
it('warns when trying to load undeclared locale', async () => { it('warns when trying to load undeclared locale', async () => {
await loadI18nTest({ await loadI18nTest({
i18nConfig: { i18nConfig: {

View file

@ -9,6 +9,7 @@ import path from 'path';
import fs from 'fs-extra'; import fs from 'fs-extra';
import logger from '@docusaurus/logger'; import logger from '@docusaurus/logger';
import combinePromises from 'combine-promises'; import combinePromises from 'combine-promises';
import {normalizeUrl} from '@docusaurus/utils';
import type {I18n, DocusaurusConfig, I18nLocaleConfig} from '@docusaurus/types'; import type {I18n, DocusaurusConfig, I18nLocaleConfig} from '@docusaurus/types';
function inferLanguageDisplayName(locale: string) { function inferLanguageDisplayName(locale: string) {
@ -82,7 +83,7 @@ function getDefaultDirection(localeStr: string) {
export function getDefaultLocaleConfig( export function getDefaultLocaleConfig(
locale: string, locale: string,
): Omit<I18nLocaleConfig, 'translate'> { ): Omit<I18nLocaleConfig, 'translate' | 'baseUrl'> {
try { try {
return { return {
label: getDefaultLocaleLabel(locale), label: getDefaultLocaleLabel(locale),
@ -123,7 +124,7 @@ Note: Docusaurus only support running one locale at a time.`;
locale: string, locale: string,
): Promise<I18nLocaleConfig> { ): Promise<I18nLocaleConfig> {
const localeConfigInput = i18nConfig.localeConfigs[locale] ?? {}; const localeConfigInput = i18nConfig.localeConfigs[locale] ?? {};
const localeConfig: Omit<I18nLocaleConfig, 'translate'> = { const localeConfig: Omit<I18nLocaleConfig, 'translate' | 'baseUrl'> = {
...getDefaultLocaleConfig(locale), ...getDefaultLocaleConfig(locale),
...localeConfigInput, ...localeConfigInput,
}; };
@ -138,10 +139,31 @@ Note: Docusaurus only support running one locale at a time.`;
return fs.pathExists(localizationDir); return fs.pathExists(localizationDir);
} }
function getBaseUrl(): string {
if (typeof localeConfigInput.baseUrl !== 'undefined') {
return normalizeUrl(['/', localeConfigInput.baseUrl, '/']);
}
// TODO CLI locales.length === 1 case - retro compat
const hasLocaleSegment = locale !== i18nConfig.defaultLocale;
return normalizeUrl([
'/',
config.baseUrl,
hasLocaleSegment ? locale : '',
'/',
]);
}
const translate = localeConfigInput.translate ?? (await inferTranslate()); const translate = localeConfigInput.translate ?? (await inferTranslate());
const baseUrl =
typeof localeConfigInput.baseUrl !== 'undefined'
? normalizeUrl(['/', localeConfigInput.baseUrl, '/'])
: getBaseUrl();
return { return {
...localeConfig, ...localeConfig,
translate, translate,
baseUrl,
}; };
} }