infer translate from presence of translation dir

This commit is contained in:
sebastien 2025-07-07 14:14:31 +02:00
parent 5cfe2c1dca
commit fe7dba95a8
7 changed files with 91 additions and 57 deletions

View file

@ -33,9 +33,8 @@ export type I18nLocaleConfig = {
*/
path: string;
/**
* Should we run the extra translation process for this locale?
* By default, we skip the translation process for the default locale,
* while all the other locales run it.
* Should we attempt to translate this locale?
* By default, it will only be run if the `./i18n/<locale>` exists.
*/
translate: boolean;
};

View file

@ -91,7 +91,11 @@ async function getLocalesToBuild({
localizePath,
});
const i18n = await loadI18n(context.siteConfig);
const i18n = await loadI18n({
siteDir,
config: context.siteConfig,
currentLocale: context.siteConfig.i18n.defaultLocale // Awkward but ok
});
const locales = cliOptions.locale ?? i18n.locales;

View file

@ -0,0 +1 @@
Since i18n/de folder exists, de locale should infer to translate = true

View file

@ -0,0 +1 @@
Since i18n/fr folder exists, fr locale should infer to translate = true

View file

@ -6,17 +6,33 @@
*/
import {jest} from '@jest/globals';
import path from 'path';
import {loadI18n, getDefaultLocaleConfig} from '../i18n';
import {DEFAULT_I18N_CONFIG} from '../configValidation';
import type {DocusaurusConfig, I18nConfig} from '@docusaurus/types';
function loadI18nTest(i18nConfig: I18nConfig, locale?: string) {
return loadI18n(
{
const loadI18nSiteDir = path.resolve(
__dirname,
'__fixtures__',
'load-i18n-site',
);
function loadI18nTest({
siteDir = loadI18nSiteDir,
i18nConfig,
currentLocale,
}: {
siteDir?: string;
i18nConfig: I18nConfig;
currentLocale: string;
}) {
return loadI18n({
siteDir,
config: {
i18n: i18nConfig,
} as DocusaurusConfig,
{locale},
);
currentLocale,
});
}
describe('defaultLocaleConfig', () => {
@ -103,7 +119,12 @@ describe('loadI18n', () => {
});
it('loads I18n for default config', async () => {
await expect(loadI18nTest(DEFAULT_I18N_CONFIG)).resolves.toEqual({
await expect(
loadI18nTest({
i18nConfig: DEFAULT_I18N_CONFIG,
currentLocale: 'en',
}),
).resolves.toEqual({
path: 'i18n',
defaultLocale: 'en',
locales: ['en'],
@ -120,10 +141,13 @@ describe('loadI18n', () => {
it('loads I18n for multi-lang config', async () => {
await expect(
loadI18nTest({
i18nConfig: {
path: 'i18n',
defaultLocale: 'fr',
locales: ['en', 'fr', 'de'],
localeConfigs: {},
},
currentLocale: 'fr',
}),
).resolves.toEqual({
defaultLocale: 'fr',
@ -133,11 +157,11 @@ describe('loadI18n', () => {
localeConfigs: {
en: {
...getDefaultLocaleConfig('en'),
translate: true,
translate: false,
},
fr: {
...getDefaultLocaleConfig('fr'),
translate: false,
translate: true,
},
de: {
...getDefaultLocaleConfig('de'),
@ -149,15 +173,15 @@ describe('loadI18n', () => {
it('loads I18n for multi-locale config with specified locale', async () => {
await expect(
loadI18nTest(
{
loadI18nTest({
i18nConfig: {
path: 'i18n',
defaultLocale: 'fr',
locales: ['en', 'fr', 'de'],
localeConfigs: {},
},
'de',
),
currentLocale: 'de',
}),
).resolves.toEqual({
defaultLocale: 'fr',
path: 'i18n',
@ -166,11 +190,11 @@ describe('loadI18n', () => {
localeConfigs: {
en: {
...getDefaultLocaleConfig('en'),
translate: true,
translate: false,
},
fr: {
...getDefaultLocaleConfig('fr'),
translate: false,
translate: true,
},
de: {
...getDefaultLocaleConfig('de'),
@ -182,19 +206,19 @@ describe('loadI18n', () => {
it('loads I18n for multi-locale config with some custom locale configs', async () => {
await expect(
loadI18nTest(
{
loadI18nTest({
i18nConfig: {
path: 'i18n',
defaultLocale: 'fr',
locales: ['en', 'fr', 'de'],
localeConfigs: {
fr: {label: 'Français', translate: false},
en: {},
en: {translate: true},
de: {translate: false},
},
},
'de',
),
currentLocale: 'de',
}),
).resolves.toEqual({
defaultLocale: 'fr',
path: 'i18n',
@ -222,15 +246,15 @@ describe('loadI18n', () => {
});
it('warns when trying to load undeclared locale', async () => {
await loadI18nTest(
{
await loadI18nTest({
i18nConfig: {
path: 'i18n',
defaultLocale: 'fr',
locales: ['en', 'fr', 'de'],
localeConfigs: {},
},
'it',
);
currentLocale: 'it',
});
expect(consoleSpy.mock.calls[0]![0]).toMatch(
/The locale .*it.* was not found in your site configuration/,
);

View file

@ -5,10 +5,11 @@
* LICENSE file in the root directory of this source tree.
*/
import path from 'path';
import fs from 'fs-extra';
import logger from '@docusaurus/logger';
import combinePromises from 'combine-promises';
import type {I18n, DocusaurusConfig, I18nLocaleConfig} from '@docusaurus/types';
import type {LoadContextParams} from './site';
function inferLanguageDisplayName(locale: string) {
const tryLocale = (l: string) => {
@ -98,27 +99,17 @@ export function getDefaultLocaleConfig(
}
}
async function shouldTranslateLocale({
locale,
defaultLocale,
localeConfigInput,
export async function loadI18n({
siteDir,
config,
currentLocale,
}: {
locale: string;
defaultLocale: string;
localeConfigInput: Partial<I18nLocaleConfig>;
}): Promise<boolean> {
// Maybe in the future we want to check if `./i18n/en` exists?
return localeConfigInput.translate ?? locale !== defaultLocale;
}
export async function loadI18n(
config: DocusaurusConfig,
options?: Pick<LoadContextParams, 'locale'>,
): Promise<I18n> {
siteDir: string;
config: DocusaurusConfig;
currentLocale: string;
}): Promise<I18n> {
const {i18n: i18nConfig} = config;
const currentLocale = options?.locale ?? i18nConfig.defaultLocale;
if (!i18nConfig.locales.includes(currentLocale)) {
logger.warn`The locale name=${currentLocale} was not found in your site configuration: Available locales are: ${i18nConfig.locales}
Note: Docusaurus only support running one locale at a time.`;
@ -132,14 +123,24 @@ Note: Docusaurus only support running one locale at a time.`;
locale: string,
): Promise<I18nLocaleConfig> {
const localeConfigInput = i18nConfig.localeConfigs[locale] ?? {};
const translate = await shouldTranslateLocale({
locale,
defaultLocale: i18nConfig.defaultLocale,
localeConfigInput,
});
return {
const localeConfig: Omit<I18nLocaleConfig, 'translate'> = {
...getDefaultLocaleConfig(locale),
...localeConfigInput,
};
// By default, translations will be enabled if i18n/<locale> dir exists
async function inferTranslate() {
const localizationDir = path.resolve(
siteDir,
i18nConfig.path,
localeConfig.path,
);
return fs.pathExists(localizationDir);
}
const translate = localeConfigInput.translate ?? (await inferTranslate());
return {
...localeConfig,
translate,
};
}

View file

@ -97,7 +97,11 @@ export async function loadContext(
siteConfig: initialSiteConfig,
});
const i18n = await loadI18n(initialSiteConfig, {locale});
const i18n = await loadI18n({
siteDir,
config: initialSiteConfig,
currentLocale: locale ?? initialSiteConfig.i18n.defaultLocale,
});
const baseUrl = localizePath({
path: initialSiteConfig.baseUrl,