blob: 539f988ba64dd42c0e6b568a6451953133ce7b08 [file]
import i18n from '@generated/i18n';
import siteConfig from '@generated/docusaurus.config';
import { translate } from '@docusaurus/Translate';
import { applyTrailingSlash } from '@docusaurus/utils-common';
import { normalizePathname } from './locale';
import {resolveLocalizedRoute, rootBaseUrl} from './localizedRoute';
// The build writes locale facts into the site configuration, so this module
// reads configuration instead of naming a language. See config/i18n.js.
const fields = (siteConfig.customFields ?? {}) as {
translatedLocales?: string[];
defaultLocalePageLocales?: string[];
translatedPagePaths?: Record<string, string[]>;
};
const translatedLocales = fields.translatedLocales ?? [];
const defaultLocalePageLocales = fields.defaultLocalePageLocales ?? [];
export const translatedPagePaths = fields.translatedPagePaths ?? {};
/** Ordinary pages with an explicit translation, even in a docs-first locale. */
export function hasTranslatedPage(pathname: string, locale = i18n.currentLocale): boolean {
const path = normalizePathname(pathname, i18n.locales).replace(/\/+$/, '');
return translatedPagePaths[locale]?.includes(path) ?? false;
}
/** A locale with per-document translation state, which renders its notices. */
export function isTranslatedLocale(locale: string): boolean {
return translatedLocales.includes(locale);
}
/**
* A locale that is still being introduced: its ordinary pages are not
* translated by default, apart from its registered translated pages, so other
* ordinary links must target the default locale. The same
* locales label their embedded UI — the AI widget and the illustration frames.
*/
export function usesDefaultLocalePages(): boolean {
return defaultLocalePageLocales.includes(i18n.currentLocale);
}
/**
* The default locale's path for a page the current locale served as a fallback,
* so the page can point search engines at the copy worth ranking.
*/
export function defaultLocalePath(permalink: string): string {
const path = normalizePathname(permalink, [i18n.currentLocale]);
// Permalinks carry no trailing slash; the served URLs do.
return applyTrailingSlash(path, { trailingSlash: siteConfig.trailingSlash, baseUrl: siteConfig.baseUrl });
}
export function localizedHomeLink(href: string): string {
return resolveLocalizedRoute({href, locale: i18n.currentLocale, currentUrl: siteConfig.baseUrl,
options: {url: siteConfig.url, baseUrl: rootBaseUrl(siteConfig.baseUrl, i18n.currentLocale, i18n.defaultLocale),
defaultLocale: i18n.defaultLocale, locales: i18n.locales, trailingSlash: siteConfig.trailingSlash}}).href;
}
// Plain HTML anchors do not receive Docusaurus Link's locale prefix.
export function localizedDocLink(href: string): string {
return localizedHomeLink(href);
}
export function localizedFrameSource(src: string): string {
const url = new URL(src, siteConfig.url);
if (url.origin !== new URL(siteConfig.url).origin) return src;
url.searchParams.set('locale', i18n.currentLocale);
return url.pathname + url.search + url.hash;
}
export function localizedAiLabels(): Record<string, string> {
return {
'data-kapa-loading-label': translate({ id: 'homepage.ai.loading', message: 'Loading AI…' }),
'data-kapa-slow-label': translate({ id: 'homepage.ai.slow', message: 'Still loading…' }),
'data-kapa-error-label': translate({ id: 'homepage.ai.error', message: 'AI unavailable' }),
};
}
/** A document whose content came from a source locale, not from a translation. */
export function isFallbackSource(source: string, locale: string): boolean {
return isTranslatedLocale(locale) && !source.startsWith(`@site/i18n/${locale}/`);
}