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 configuring locale base URL #6731

Draft
wants to merge 8 commits into
base: main
Choose a base branch
from
1 change: 1 addition & 0 deletions packages/docusaurus-module-type-aliases/src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ declare module '@generated/i18n' {
label: string;
direction: string;
htmlLang: string;
baseUrl: string;
}
>;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,33 @@ export function useAlternatePageUtils(): {
} {
const {
siteConfig: {baseUrl, url},
i18n: {defaultLocale, currentLocale},
i18n: {defaultLocale, currentLocale, localeConfigs},
} = useDocusaurusContext();
const {pathname} = useLocation();

const baseUrlUnlocalized =
currentLocale === defaultLocale
? baseUrl
: baseUrl.replace(`/${currentLocale}/`, '/');
function getLocalizedPath(locale: string) {
if (localeConfigs[locale].baseUrl) {
return localeConfigs[locale].baseUrl
.replace(/^\//, '')
.replace(/\/$/, '');
}
return locale === defaultLocale ? '' : locale;
}

const pathnameSuffix = pathname.replace(baseUrl, '');
const currentLocalizedPath = getLocalizedPath(currentLocale);
const baseUrlUnlocalized = baseUrl.replace(
new RegExp(`/${currentLocalizedPath}/$`),
'/',
);

const pathnameSuffix = pathname.match(new RegExp(`^${baseUrl}`))
? pathname.replace(new RegExp(`^${baseUrl}`), '')
: pathname.replace(new RegExp(`^${baseUrlUnlocalized}`), '');
function getLocalizedBaseUrl(locale: string) {
return locale === defaultLocale
? `${baseUrlUnlocalized}`
: `${baseUrlUnlocalized}${locale}/`;
const localizedPath = getLocalizedPath(locale);
return localizedPath
? `${baseUrlUnlocalized}${localizedPath}/`
: baseUrlUnlocalized;
}

// TODO support correct alternate url when localized site is deployed on another domain
Expand Down
1 change: 1 addition & 0 deletions packages/docusaurus-types/src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ export type I18nLocaleConfig = {
label: string;
htmlLang: string;
direction: string;
baseUrl: string;
};

export type I18nConfig = {
Expand Down
1 change: 1 addition & 0 deletions packages/docusaurus/src/server/configValidation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ const LocaleConfigSchema = Joi.object({
label: Joi.string(),
htmlLang: Joi.string(),
direction: Joi.string().equal('ltr', 'rtl').default('ltr'),
baseUrl: Joi.string(),
});

const I18N_CONFIG_SCHEMA = Joi.object<I18nConfig>({
Expand Down
34 changes: 25 additions & 9 deletions packages/docusaurus/src/server/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export function getDefaultLocaleConfig(locale: string): I18nLocaleConfig {
label: getDefaultLocaleLabel(locale),
direction: getLangDir(locale),
htmlLang: locale,
baseUrl: '',
};
}

Expand Down Expand Up @@ -74,6 +75,25 @@ Note: Docusaurus only support running one locale at a time.`;
};
}

function shouldLocalizePath({
i18n,
options = {},
}: {
i18n: I18n;
options?: {localizePath?: boolean};
}): boolean {
if (options.localizePath === true || options.localizePath === false) {
return options.localizePath;
}
if (
i18n.currentLocale !== i18n.defaultLocale ||
i18n.localeConfigs[i18n.currentLocale].baseUrl
) {
return true;
}
return false;
}

export function localizePath({
pathType,
path: originalPath,
Expand All @@ -85,20 +105,16 @@ export function localizePath({
i18n: I18n;
options?: {localizePath?: boolean};
}): string {
const shouldLocalizePath: boolean =
typeof options.localizePath === 'undefined'
? // By default, we don't localize the path of defaultLocale
i18n.currentLocale !== i18n.defaultLocale
: options.localizePath;

if (shouldLocalizePath) {
if (shouldLocalizePath({i18n, options})) {
// FS paths need special care, for Windows support
const localePath =
i18n.localeConfigs[i18n.currentLocale].baseUrl || i18n.currentLocale;
if (pathType === 'fs') {
return path.join(originalPath, path.sep, i18n.currentLocale, path.sep);
return path.join(originalPath, path.sep, localePath, path.sep);
}
// Url paths
else if (pathType === 'url') {
return normalizeUrl([originalPath, '/', i18n.currentLocale, '/']);
return normalizeUrl([originalPath, '/', localePath, '/']);
}
// should never happen
else {
Expand Down
3 changes: 3 additions & 0 deletions website/docs/api/docusaurus.config.js.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,11 +134,13 @@ module.exports = {
label: 'English',
direction: 'ltr',
htmlLang: 'en-US',
baseUrl: 'en-US',
},
fr: {
label: 'Français',
direction: 'ltr',
htmlLang: 'fr-FR',
baseUrl: '/fr-FR/',
},
},
},
Expand All @@ -148,6 +150,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="...">`
- `baseUrl`: the baseUrl to use for this locale

### `noIndex` {#noindex}

Expand Down