Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: allow customizing localization path of each locale #7624

Merged
merged 3 commits into from Jun 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -26,6 +26,7 @@ const DefaultI18N: I18n = {
direction: 'ltr',
htmlLang: 'en',
calendar: 'gregory',
path: 'en',
},
},
};
Expand Down
Expand Up @@ -54,6 +54,7 @@ function getI18n(locale: string): I18n {
label: locale,
htmlLang: locale,
direction: 'ltr',
path: locale,
},
},
};
Expand All @@ -71,7 +72,11 @@ const getPlugin = async (
i18n: I18n = DefaultI18N,
) => {
const generatedFilesDir: string = path.resolve(siteDir, '.docusaurus');
const localizationDir = path.join(siteDir, i18n.path, i18n.currentLocale);
const localizationDir = path.join(
siteDir,
i18n.path,
i18n.localeConfigs[i18n.currentLocale]!.path,
);
const siteConfig = {
title: 'Hello',
baseUrl: '/',
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Expand Up @@ -66,3 +66,12 @@ exports[`docsVersion second docs instance versioning 1`] = `
],
}
`;

exports[`docsVersion works with custom i18n paths 1`] = `
[
{
"dirName": ".",
"type": "autogenerated",
},
]
`;
Binary file not shown.
8 changes: 5 additions & 3 deletions packages/docusaurus-plugin-content-docs/src/cli.ts
Expand Up @@ -85,9 +85,11 @@ export async function cliDocsVersionCommand(

await Promise.all(
i18n.locales.map(async (locale) => {
// TODO duplicated logic from core, so duplicate comment as well: we need
// to support customization per-locale in the future
const localizationDir = path.resolve(siteDir, i18n.path, locale);
const localizationDir = path.resolve(
siteDir,
i18n.path,
i18n.localeConfigs[locale]!.path,
);
// Copy docs files.
const docsDir =
locale === i18n.defaultLocale
Expand Down
6 changes: 6 additions & 0 deletions packages/docusaurus-types/src/index.d.ts
Expand Up @@ -61,6 +61,12 @@ export type I18nLocaleConfig = {
* or `en-US` (`en` means `en-US`).
*/
calendar: string;
/**
* Root folder that all plugin localization folders of this locale are
* relative to. Will be resolved against `i18n.path`. Defaults to the locale's
* name.
*/
path: string;
};

export type I18nConfig = {
Expand Down
8 changes: 4 additions & 4 deletions packages/docusaurus-utils/src/__tests__/i18nUtils.test.ts
Expand Up @@ -123,7 +123,7 @@ describe('localizePath', () => {
path: 'i18n',
locales: ['en', 'fr'],
currentLocale: 'fr',
localeConfigs: {},
localeConfigs: {fr: {path: 'fr'}, en: {path: 'en'}},
},
options: {localizePath: true},
}),
Expand All @@ -140,7 +140,7 @@ describe('localizePath', () => {
path: 'i18n',
locales: ['en', 'fr'],
currentLocale: 'en',
localeConfigs: {},
localeConfigs: {fr: {path: 'fr'}, en: {path: 'en'}},
},
options: {localizePath: true},
}),
Expand All @@ -157,7 +157,7 @@ describe('localizePath', () => {
path: 'i18n',
locales: ['en', 'fr'],
currentLocale: 'en',
localeConfigs: {},
localeConfigs: {fr: {path: 'fr'}, en: {path: 'en'}},
},
}),
).toBe('/baseUrl/');
Expand All @@ -173,7 +173,7 @@ describe('localizePath', () => {
path: 'i18n',
locales: ['en', 'fr'],
currentLocale: 'en',
localeConfigs: {},
localeConfigs: {fr: {path: 'fr'}, en: {path: 'en'}},
},
}),
).toBe('/baseUrl/');
Expand Down
9 changes: 7 additions & 2 deletions packages/docusaurus-utils/src/i18nUtils.ts
Expand Up @@ -68,6 +68,9 @@ export function getPluginI18nPath({
/**
* Takes a path and returns a localized a version (which is basically `path +
* i18n.currentLocale`).
*
* This is used to resolve the `outDir` and `baseUrl` of each locale; it is NOT
* used to determine plugin localization file locations.
*/
export function localizePath({
pathType,
Expand All @@ -94,13 +97,15 @@ export function localizePath({
};
}): string {
const shouldLocalizePath: boolean =
//
options.localizePath ?? i18n.currentLocale !== i18n.defaultLocale;

if (!shouldLocalizePath) {
return originalPath;
}
// FS paths need special care, for Windows support
// FS paths need special care, for Windows support. Note: we don't use the
// locale config's `path` here, because this function is used for resolving
// outDir, which must be the same as baseUrl. When we have the baseUrl config,
// we need to sync the two.
if (pathType === 'fs') {
return path.join(originalPath, i18n.currentLocale);
}
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

@@ -0,0 +1,118 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`load loads props for site with custom i18n path 1`] = `
{
"baseUrl": "/",
"codeTranslations": {},
"generatedFilesDir": "<PROJECT_ROOT>/packages/docusaurus/src/server/__tests__/__fixtures__/custom-i18n-site/.docusaurus",
"headTags": "",
"i18n": {
"currentLocale": "en",
"defaultLocale": "en",
"localeConfigs": {
"en": {
"calendar": "gregory",
"direction": "ltr",
"htmlLang": "en",
"label": "English",
"path": "en-custom",
},
"zh-Hans": {
"calendar": "gregory",
"direction": "ltr",
"htmlLang": "zh-Hans",
"label": "简体中文",
"path": "zh-Hans-custom",
},
},
"locales": [
"en",
"zh-Hans",
],
"path": "i18n",
},
"localizationDir": "<PROJECT_ROOT>/packages/docusaurus/src/server/__tests__/__fixtures__/custom-i18n-site/i18n/en-custom",
"outDir": "<PROJECT_ROOT>/packages/docusaurus/src/server/__tests__/__fixtures__/custom-i18n-site/build",
"plugins": [
{
"content": undefined,
"getClientModules": [Function],
"injectHtmlTags": [Function],
"name": "docusaurus-bootstrap-plugin",
"options": {
"id": "default",
},
"path": "<PROJECT_ROOT>/packages/docusaurus/src/server/__tests__/__fixtures__/custom-i18n-site",
"version": {
"type": "synthetic",
},
},
{
"configureWebpack": [Function],
"content": undefined,
"name": "docusaurus-mdx-fallback-plugin",
"options": {
"id": "default",
},
"path": ".",
"version": {
"type": "synthetic",
},
},
],
"postBodyTags": "",
"preBodyTags": "",
"routes": [],
"routesPaths": [
"/404.html",
],
"siteConfig": {
"baseUrl": "/",
"baseUrlIssueBanner": true,
"clientModules": [],
"customFields": {},
"i18n": {
"defaultLocale": "en",
"localeConfigs": {
"en": {
"direction": "ltr",
"path": "en-custom",
},
"zh-Hans": {
"direction": "ltr",
"path": "zh-Hans-custom",
},
},
"locales": [
"en",
"zh-Hans",
],
"path": "i18n",
},
"noIndex": false,
"onBrokenLinks": "throw",
"onBrokenMarkdownLinks": "warn",
"onDuplicateRoutes": "warn",
"plugins": [],
"presets": [],
"scripts": [],
"staticDirectories": [
"static",
],
"stylesheets": [],
"tagline": "",
"themeConfig": {},
"themes": [],
"title": "Site",
"titleDelimiter": "|",
"url": "https://example.com",
},
"siteConfigPath": "<PROJECT_ROOT>/packages/docusaurus/src/server/__tests__/__fixtures__/custom-i18n-site/docusaurus.config.js",
"siteDir": "<PROJECT_ROOT>/packages/docusaurus/src/server/__tests__/__fixtures__/custom-i18n-site",
"siteMetadata": {
"docusaurusVersion": "<CURRENT_VERSION>",
"pluginVersions": {},
"siteVersion": undefined,
},
}
`;
11 changes: 11 additions & 0 deletions packages/docusaurus/src/server/__tests__/i18n.test.ts
Expand Up @@ -32,62 +32,72 @@ describe('defaultLocaleConfig', () => {
direction: 'ltr',
htmlLang: 'fr',
calendar: 'gregory',
path: 'fr',
});
expect(getDefaultLocaleConfig('fr-FR')).toEqual({
label: 'Français (France)',
direction: 'ltr',
htmlLang: 'fr-FR',
calendar: 'gregory',
path: 'fr-FR',
});
expect(getDefaultLocaleConfig('en')).toEqual({
label: 'English',
direction: 'ltr',
htmlLang: 'en',
calendar: 'gregory',
path: 'en',
});
expect(getDefaultLocaleConfig('en-US')).toEqual({
label: 'American English',
direction: 'ltr',
htmlLang: 'en-US',
calendar: 'gregory',
path: 'en-US',
});
expect(getDefaultLocaleConfig('zh')).toEqual({
label: '中文',
direction: 'ltr',
htmlLang: 'zh',
calendar: 'gregory',
path: 'zh',
});
expect(getDefaultLocaleConfig('zh-CN')).toEqual({
label: '中文(中国)',
direction: 'ltr',
htmlLang: 'zh-CN',
calendar: 'gregory',
path: 'zh-CN',
});
expect(getDefaultLocaleConfig('en-US')).toEqual({
label: 'American English',
direction: 'ltr',
htmlLang: 'en-US',
calendar: 'gregory',
path: 'en-US',
});
expect(getDefaultLocaleConfig('fa')).toEqual({
// cSpell:ignore فارسی
label: 'فارسی',
direction: 'rtl',
htmlLang: 'fa',
calendar: 'gregory',
path: 'fa',
});
expect(getDefaultLocaleConfig('fa-IR')).toEqual({
// cSpell:ignore ایران فارسیا
label: 'فارسی (ایران)',
direction: 'rtl',
htmlLang: 'fa-IR',
calendar: 'gregory',
path: 'fa-IR',
});
expect(getDefaultLocaleConfig('en-US-u-ca-buddhist')).toEqual({
label: 'American English',
direction: 'ltr',
htmlLang: 'en-US-u-ca-buddhist',
calendar: 'buddhist',
path: 'en-US-u-ca-buddhist',
});
});
});
Expand Down Expand Up @@ -170,6 +180,7 @@ describe('loadI18n', () => {
direction: 'ltr',
htmlLang: 'fr',
calendar: 'gregory',
path: 'fr',
},
en: getDefaultLocaleConfig('en'),
de: getDefaultLocaleConfig('de'),
Expand Down
45 changes: 45 additions & 0 deletions packages/docusaurus/src/server/__tests__/index.test.ts
@@ -0,0 +1,45 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

import path from 'path';
import {mergeWithCustomize} from 'webpack-merge';
import {loadSetup} from './testUtils';
import type {Props} from '@docusaurus/types';
import type {DeepPartial} from 'utility-types';

describe('load', () => {
it('loads props for site with custom i18n path', async () => {
const props = await loadSetup('custom-i18n-site');
expect(props).toMatchSnapshot();
const props2 = await loadSetup('custom-i18n-site', {locale: 'zh-Hans'});
expect(props2).toEqual(
mergeWithCustomize<DeepPartial<Props>>({
customizeArray(a, b, key) {
return ['routesPaths', 'plugins'].includes(key) ? b : undefined;
},
})(props, {
baseUrl: '/zh-Hans/',
i18n: {
currentLocale: 'zh-Hans',
},
localizationDir: path.join(
__dirname,
'__fixtures__/custom-i18n-site/i18n/zh-Hans-custom',
),
outDir: path.join(
__dirname,
'__fixtures__/custom-i18n-site/build/zh-Hans',
),
routesPaths: ['/zh-Hans/404.html'],
siteConfig: {
baseUrl: '/zh-Hans/',
},
plugins: props2.plugins,
}),
);
});
});