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.
*/
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 = {

View file

@ -19,10 +19,12 @@ const loadI18nSiteDir = path.resolve(
function loadI18nTest({
siteDir = loadI18nSiteDir,
baseUrl = '/',
i18nConfig,
currentLocale,
}: {
siteDir?: string;
baseUrl?: string;
i18nConfig: I18nConfig;
currentLocale: string;
}) {
@ -30,6 +32,7 @@ function loadI18nTest({
siteDir,
config: {
i18n: i18nConfig,
baseUrl,
} as DocusaurusConfig,
currentLocale,
});
@ -133,6 +136,7 @@ describe('loadI18n', () => {
en: {
...getDefaultLocaleConfig('en'),
translate: false,
baseUrl: '/',
},
},
});
@ -158,14 +162,17 @@ describe('loadI18n', () => {
en: {
...getDefaultLocaleConfig('en'),
translate: false,
baseUrl: '/en/',
},
fr: {
...getDefaultLocaleConfig('fr'),
translate: true,
baseUrl: '/',
},
de: {
...getDefaultLocaleConfig('de'),
translate: true,
baseUrl: '/de/',
},
},
});
@ -191,14 +198,17 @@ describe('loadI18n', () => {
en: {
...getDefaultLocaleConfig('en'),
translate: false,
baseUrl: '/en/',
},
fr: {
...getDefaultLocaleConfig('fr'),
translate: true,
baseUrl: '/',
},
de: {
...getDefaultLocaleConfig('de'),
translate: true,
baseUrl: '/de/',
},
},
});
@ -213,10 +223,11 @@ describe('loadI18n', () => {
locales: ['en', 'fr', 'de'],
localeConfigs: {
fr: {label: 'Français', translate: false},
en: {translate: true},
de: {translate: false},
en: {translate: true, baseUrl: 'en-EN/whatever/else'},
de: {translate: false, baseUrl: '/de-DE/'},
},
},
currentLocale: 'de',
}),
).resolves.toEqual({
@ -232,19 +243,58 @@ describe('loadI18n', () => {
calendar: 'gregory',
path: 'fr',
translate: false,
baseUrl: '/',
},
en: {
...getDefaultLocaleConfig('en'),
translate: true,
baseUrl: '/en-EN/whatever/else/',
},
de: {
...getDefaultLocaleConfig('de'),
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 () => {
await loadI18nTest({
i18nConfig: {

View file

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