mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-09-23 11:03:39 +00:00
Use space.language as source of truth (#3606)
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@gitbook/colors": patch
|
||||
---
|
||||
|
||||
Fix return type for `colorContrast`
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Use space language as source of truth for UI locale
|
||||
@@ -419,7 +419,10 @@ export function dpsContrast(a: RGBColor, b: RGBColor) {
|
||||
return contrast < 7.5 ? 0 : contrast;
|
||||
}
|
||||
|
||||
export function colorContrast(background: string, foreground: string[] = [LIGHT_BASE, DARK_BASE]) {
|
||||
export function colorContrast(
|
||||
background: string,
|
||||
foreground: string[] = [LIGHT_BASE, DARK_BASE]
|
||||
): string {
|
||||
const bg = hexToRgbArray(background);
|
||||
|
||||
const best: { color?: RGBColor; contrast: number } = {
|
||||
@@ -436,5 +439,5 @@ export function colorContrast(background: string, foreground: string[] = [LIGHT_
|
||||
}
|
||||
}
|
||||
|
||||
return best.color ? rgbArrayToHex(best.color) : foreground[0];
|
||||
return best.color ? rgbArrayToHex(best.color) : foreground[0] || LIGHT_BASE;
|
||||
}
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ export default async function SiteDynamicLayout({
|
||||
const withTracking = shouldTrackEvents(await headers());
|
||||
|
||||
return (
|
||||
<CustomizationRootLayout forcedTheme={forcedTheme} customization={context.customization}>
|
||||
<CustomizationRootLayout forcedTheme={forcedTheme} context={context}>
|
||||
<SiteLayout
|
||||
context={context}
|
||||
forcedTheme={forcedTheme}
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ export default async function SiteStaticLayout({
|
||||
const withTracking = shouldTrackEvents();
|
||||
|
||||
return (
|
||||
<CustomizationRootLayout customization={context.customization}>
|
||||
<CustomizationRootLayout context={context}>
|
||||
<SiteLayout
|
||||
context={context}
|
||||
withTracking={withTracking}
|
||||
|
||||
@@ -72,7 +72,7 @@ function DescriptionForPageContentToolCall(props: {
|
||||
}) {
|
||||
const { toolCall, context } = props;
|
||||
|
||||
const language = getSpaceLanguage(context.customization);
|
||||
const language = getSpaceLanguage(context);
|
||||
|
||||
return (
|
||||
<p>
|
||||
@@ -102,7 +102,7 @@ function DescriptionForMCPToolCall(props: {
|
||||
}) {
|
||||
const { toolCall, context } = props;
|
||||
|
||||
const language = getSpaceLanguage(context.customization);
|
||||
const language = getSpaceLanguage(context);
|
||||
|
||||
return (
|
||||
<p>
|
||||
@@ -130,7 +130,7 @@ async function DescriptionForSearchToolCall(props: {
|
||||
}) {
|
||||
const { toolCall, context } = props;
|
||||
|
||||
const language = getSpaceLanguage(context.customization);
|
||||
const language = getSpaceLanguage(context);
|
||||
|
||||
// Resolve all hrefs for search results in parallel
|
||||
const searchResultsWithHrefs = await Promise.all(
|
||||
@@ -241,7 +241,7 @@ function DescriptionForGetPagesToolCall(props: {
|
||||
}) {
|
||||
const { toolCall, context } = props;
|
||||
|
||||
const language = getSpaceLanguage(context.customization);
|
||||
const language = getSpaceLanguage(context);
|
||||
|
||||
return (
|
||||
<p>
|
||||
|
||||
@@ -20,10 +20,7 @@ export async function InlineLink(props: InlineProps<DocumentInlineLink>) {
|
||||
: null;
|
||||
const { contentContext } = context;
|
||||
|
||||
const language =
|
||||
contentContext && 'customization' in contentContext
|
||||
? getSpaceLanguage(contentContext.customization)
|
||||
: languages.en;
|
||||
const language = contentContext ? getSpaceLanguage(contentContext) : languages.en;
|
||||
|
||||
if (!contentContext || !resolved) {
|
||||
return (
|
||||
|
||||
@@ -11,7 +11,7 @@ import { Heading } from '../Heading';
|
||||
|
||||
import './scalar.css';
|
||||
import './style.css';
|
||||
import { DEFAULT_LOCALE, getCustomizationLocale } from '@/intl/server';
|
||||
import { DEFAULT_LOCALE, getSpaceLocale } from '@/intl/server';
|
||||
import type { GitBookAnyContext } from '@/lib/context';
|
||||
import type {
|
||||
AnyOpenAPIOperationsBlock,
|
||||
@@ -30,10 +30,7 @@ export function getOpenAPIContext(args: {
|
||||
const { props, specUrl, context } = args;
|
||||
const { block } = props;
|
||||
|
||||
const customization = context && 'customization' in context ? context.customization : null;
|
||||
const customizationLocale = customization
|
||||
? getCustomizationLocale(customization)
|
||||
: DEFAULT_LOCALE;
|
||||
const customizationLocale = context ? getSpaceLocale(context) : DEFAULT_LOCALE;
|
||||
const locale = checkIsValidLocale(customizationLocale) ? customizationLocale : DEFAULT_LOCALE;
|
||||
|
||||
return {
|
||||
|
||||
@@ -21,7 +21,7 @@ export async function EmbeddableRootLayout({
|
||||
children,
|
||||
}: React.PropsWithChildren<EmbeddableRootLayoutProps>) {
|
||||
return (
|
||||
<CustomizationRootLayout customization={context.customization}>
|
||||
<CustomizationRootLayout context={context}>
|
||||
<SiteLayoutClientContexts
|
||||
forcedTheme={context.customization.themes.default}
|
||||
externalLinksTarget={context.customization.externalLinks.target}
|
||||
|
||||
@@ -138,7 +138,7 @@ export function Header(props: {
|
||||
);
|
||||
})}
|
||||
<HeaderLinkMore
|
||||
label={t(getSpaceLanguage(customization), 'more')}
|
||||
label={t(getSpaceLanguage(context), 'more')}
|
||||
links={customization.header.links}
|
||||
context={context}
|
||||
/>
|
||||
|
||||
@@ -57,7 +57,7 @@ export async function PDFPage(props: {
|
||||
|
||||
const customization =
|
||||
'customization' in baseContext ? baseContext.customization : defaultCustomization();
|
||||
const language = getSpaceLanguage(customization);
|
||||
const language = getSpaceLanguage(baseContext);
|
||||
|
||||
// Compute the pages to render
|
||||
const { pages, total } = selectPages(baseContext.revision.pages, pdfParams);
|
||||
@@ -149,8 +149,7 @@ export async function PDFPage(props: {
|
||||
trademark={
|
||||
customization.trademark.enabled ? (
|
||||
<TrademarkLink
|
||||
space={context.space}
|
||||
customization={customization}
|
||||
context={context}
|
||||
placement={SiteInsightsTrademarkPlacement.Pdf}
|
||||
/>
|
||||
) : null
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { CustomizationRootLayout } from '@/components/RootLayout';
|
||||
import type { GitBookSiteContext, GitBookSpaceContext } from '@/lib/context';
|
||||
import { defaultCustomization } from '@/lib/utils';
|
||||
import { CustomizationThemeMode } from '@gitbook/api';
|
||||
|
||||
/**
|
||||
@@ -13,12 +12,7 @@ export async function PDFRootLayout(props: {
|
||||
const { context, children } = props;
|
||||
|
||||
return (
|
||||
<CustomizationRootLayout
|
||||
customization={
|
||||
'customization' in context ? context.customization : defaultCustomization()
|
||||
}
|
||||
forcedTheme={CustomizationThemeMode.Light}
|
||||
>
|
||||
<CustomizationRootLayout context={context} forcedTheme={CustomizationThemeMode.Light}>
|
||||
{children}
|
||||
</CustomizationRootLayout>
|
||||
);
|
||||
|
||||
@@ -128,7 +128,7 @@ export function PageAside(props: {
|
||||
|
||||
function PageAsideHeader(props: { context: GitBookSiteContext }) {
|
||||
const { context } = props;
|
||||
const language = getSpaceLanguage(context.customization);
|
||||
const language = getSpaceLanguage(context);
|
||||
|
||||
return (
|
||||
<div
|
||||
|
||||
@@ -42,7 +42,7 @@ export function PageBody(props: {
|
||||
: false;
|
||||
const pageWidthWide = page.layout.width === 'wide';
|
||||
const siteWidthWide = pageWidthWide || contentFullWidth;
|
||||
const language = getSpaceLanguage(customization);
|
||||
const language = getSpaceLanguage(context);
|
||||
const updatedAt = page.updatedAt ?? page.createdAt;
|
||||
|
||||
return (
|
||||
|
||||
@@ -17,9 +17,9 @@ export async function PageFooterNavigation(props: {
|
||||
page: RevisionPageDocument;
|
||||
}) {
|
||||
const { context, page } = props;
|
||||
const { customization, revision, linker } = context;
|
||||
const { revision, linker } = context;
|
||||
const { previous, next } = resolvePrevNextPages(revision.pages, page);
|
||||
const language = getSpaceLanguage(customization);
|
||||
const language = getSpaceLanguage(context);
|
||||
const previousHref = previous
|
||||
? linker.toPathForPage({ pages: revision.pages, page: previous })
|
||||
: '';
|
||||
|
||||
@@ -31,7 +31,9 @@ import { RootLayoutClientContexts } from './RootLayoutClientContexts';
|
||||
|
||||
import '@gitbook/icons/style.css';
|
||||
import './globals.css';
|
||||
import type { GitBookAnyContext } from '@/lib/context';
|
||||
import { GITBOOK_FONTS_URL, GITBOOK_ICONS_TOKEN, GITBOOK_ICONS_URL } from '@/lib/env';
|
||||
import { defaultCustomization } from '@/lib/utils';
|
||||
import { AnnouncementDismissedScript } from '../Announcement';
|
||||
|
||||
function preloadFont(fontData: FontData) {
|
||||
@@ -56,12 +58,14 @@ function preloadFont(fontData: FontData) {
|
||||
*/
|
||||
export async function CustomizationRootLayout(props: {
|
||||
forcedTheme?: CustomizationThemeMode | null;
|
||||
customization: SiteCustomizationSettings;
|
||||
context: GitBookAnyContext;
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
const { customization, forcedTheme, children } = props;
|
||||
const { context, forcedTheme, children } = props;
|
||||
const customization =
|
||||
'customization' in context ? context.customization : defaultCustomization();
|
||||
|
||||
const language = getSpaceLanguage(customization);
|
||||
const language = getSpaceLanguage(context);
|
||||
const tintColor = getTintColor(customization);
|
||||
const mixColor = getTintMixColor(customization.styling.primaryColor, tintColor);
|
||||
const sidebarStyles = getSidebarStyles(customization);
|
||||
@@ -141,7 +145,6 @@ export async function CustomizationRootLayout(props: {
|
||||
)
|
||||
};
|
||||
--header-link: ${hexToRgb(
|
||||
// @ts-expect-error
|
||||
customization.header.linkColor?.light ??
|
||||
colorContrast(
|
||||
tintColor?.light ?? customization.styling.primaryColor.light
|
||||
@@ -161,7 +164,6 @@ export async function CustomizationRootLayout(props: {
|
||||
|
||||
--header-background: ${hexToRgb(customization.header.backgroundColor?.dark ?? tintColor?.dark ?? customization.styling.primaryColor.dark)};
|
||||
--header-link: ${hexToRgb(
|
||||
// @ts-expect-error
|
||||
customization.header.linkColor?.dark ??
|
||||
colorContrast(
|
||||
tintColor?.dark ?? customization.styling.primaryColor.dark
|
||||
@@ -337,7 +339,6 @@ function generateColorVariable(
|
||||
return Object.entries(shades)
|
||||
.map(([key, value]) => {
|
||||
const rgbValue = hexToRgb(value); // Check the original hex value
|
||||
// @ts-expect-error
|
||||
const contrastValue = withContrast ? hexToRgb(colorContrast(value)) : undefined; // Add contrast if needed
|
||||
return `--${name}-${key}: ${rgbValue}; ${
|
||||
contrastValue ? `--contrast-${name}-${key}: ${contrastValue};` : ''
|
||||
|
||||
@@ -16,7 +16,7 @@ export async function TableOfContents(props: {
|
||||
innerHeader?: React.ReactNode; // Displayed outside the scrollable TOC, directly above the page list
|
||||
}) {
|
||||
const { innerHeader, context, header } = props;
|
||||
const { space, customization, revision } = context;
|
||||
const { customization, revision } = context;
|
||||
|
||||
const pages = await encodeClientTableOfContents(context, revision.pages, revision.pages);
|
||||
|
||||
@@ -115,8 +115,7 @@ export async function TableOfContents(props: {
|
||||
/>
|
||||
{customization.trademark.enabled ? (
|
||||
<Trademark
|
||||
space={space}
|
||||
customization={customization}
|
||||
context={context}
|
||||
placement={SiteInsightsTrademarkPlacement.Sidebar}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
@@ -1,21 +1,17 @@
|
||||
import type {
|
||||
SiteCustomizationSettings,
|
||||
SiteInsightsTrademarkPlacement,
|
||||
Space,
|
||||
} from '@gitbook/api';
|
||||
import type { SiteInsightsTrademarkPlacement } from '@gitbook/api';
|
||||
import { Icon } from '@gitbook/icons';
|
||||
|
||||
import { getSpaceLanguage, t } from '@/intl/server';
|
||||
import { tcls } from '@/lib/tailwind';
|
||||
|
||||
import type { GitBookSpaceContext } from '@/lib/context';
|
||||
import { Link } from '../primitives';
|
||||
|
||||
/**
|
||||
* Trademark link to the GitBook.
|
||||
*/
|
||||
export function Trademark(props: {
|
||||
space: Space;
|
||||
customization: SiteCustomizationSettings;
|
||||
context: GitBookSpaceContext;
|
||||
placement: SiteInsightsTrademarkPlacement;
|
||||
}) {
|
||||
return (
|
||||
@@ -71,12 +67,12 @@ export function Trademark(props: {
|
||||
* Trademark link to the GitBook.
|
||||
*/
|
||||
export function TrademarkLink(props: {
|
||||
space: Space;
|
||||
customization: SiteCustomizationSettings;
|
||||
context: GitBookSpaceContext;
|
||||
placement: SiteInsightsTrademarkPlacement;
|
||||
}) {
|
||||
const { space, customization, placement } = props;
|
||||
const language = getSpaceLanguage(customization);
|
||||
const { context, placement } = props;
|
||||
const { space } = context;
|
||||
const language = getSpaceLanguage(context);
|
||||
|
||||
const url = new URL('https://www.gitbook.com');
|
||||
url.searchParams.set('utm_source', 'content');
|
||||
|
||||
@@ -1,25 +1,44 @@
|
||||
import type { SiteCustomizationSettings } from '@gitbook/api';
|
||||
|
||||
import type { GitBookAnyContext } from '@/lib/context';
|
||||
import { type TranslationLanguage, languages } from './translations';
|
||||
|
||||
export * from './translate';
|
||||
|
||||
export const DEFAULT_LOCALE = 'en';
|
||||
type TranslationLocale = keyof typeof languages;
|
||||
|
||||
export const DEFAULT_LOCALE = 'en' satisfies TranslationLocale;
|
||||
|
||||
/**
|
||||
* Get the locale of the customization.
|
||||
* Get the locale to use for a space.
|
||||
*/
|
||||
export function getCustomizationLocale(customization: SiteCustomizationSettings): string {
|
||||
return customization.internationalization.locale;
|
||||
export function getSpaceLocale(context: GitBookAnyContext): TranslationLocale {
|
||||
const { space } = context;
|
||||
const customization = 'site' in context ? context.customization : null;
|
||||
|
||||
// If the language is configured in the space, use it in priority
|
||||
if (space.language) {
|
||||
if (checkIsValidLocale(space.language)) {
|
||||
return space.language;
|
||||
}
|
||||
return DEFAULT_LOCALE;
|
||||
}
|
||||
|
||||
// Otherwise fallback to the deprecated customization settings
|
||||
if (customization) {
|
||||
return checkIsValidLocale(customization.internationalization.locale)
|
||||
? customization.internationalization.locale
|
||||
: DEFAULT_LOCALE;
|
||||
}
|
||||
|
||||
return DEFAULT_LOCALE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the translation context for a space to use in the server components.
|
||||
*/
|
||||
export function getSpaceLanguage(customization: SiteCustomizationSettings): TranslationLanguage {
|
||||
export function getSpaceLanguage(context: GitBookAnyContext): TranslationLanguage {
|
||||
const fallback = languages[DEFAULT_LOCALE];
|
||||
|
||||
const locale = getCustomizationLocale(customization);
|
||||
const locale = getSpaceLocale(context);
|
||||
|
||||
let language = fallback;
|
||||
// @ts-ignore
|
||||
@@ -33,3 +52,7 @@ export function getSpaceLanguage(customization: SiteCustomizationSettings): Tran
|
||||
...language,
|
||||
};
|
||||
}
|
||||
|
||||
function checkIsValidLocale(locale: string): locale is TranslationLocale {
|
||||
return locale in languages;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import type { CustomizationLocale } from '@gitbook/api';
|
||||
|
||||
import { de } from './de';
|
||||
import { en } from './en';
|
||||
import { es } from './es';
|
||||
@@ -14,11 +12,7 @@ import { zh } from './zh';
|
||||
|
||||
export * from './types';
|
||||
|
||||
export const languages: {
|
||||
[key: string]: TranslationLanguage;
|
||||
} & {
|
||||
[locale in CustomizationLocale]: TranslationLanguage;
|
||||
} = {
|
||||
export const languages = {
|
||||
de,
|
||||
en,
|
||||
fr,
|
||||
@@ -29,4 +23,6 @@ export const languages: {
|
||||
no,
|
||||
'pt-br': pt_br,
|
||||
ru,
|
||||
} satisfies {
|
||||
[key: string]: TranslationLanguage;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user