Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/chilly-otters-beam.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@gitbook/colors": patch
---

Fix return type for `colorContrast`
5 changes: 5 additions & 0 deletions .changeset/red-countries-confess.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"gitbook": patch
---

Use space language as source of truth for UI locale
7 changes: 5 additions & 2 deletions packages/colors/src/transformations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 } = {
Expand All @@ -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;
}
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ function DescriptionForPageContentToolCall(props: {
}) {
const { toolCall, context } = props;

const language = getSpaceLanguage(context.customization);
const language = getSpaceLanguage(context);

return (
<p>
Expand Down Expand Up @@ -102,7 +102,7 @@ function DescriptionForMCPToolCall(props: {
}) {
const { toolCall, context } = props;

const language = getSpaceLanguage(context.customization);
const language = getSpaceLanguage(context);

return (
<p>
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -241,7 +241,7 @@ function DescriptionForGetPagesToolCall(props: {
}) {
const { toolCall, context } = props;

const language = getSpaceLanguage(context.customization);
const language = getSpaceLanguage(context);

return (
<p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down
2 changes: 1 addition & 1 deletion packages/gitbook/src/components/Header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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}
/>
Expand Down
5 changes: 2 additions & 3 deletions packages/gitbook/src/components/PDF/PDFPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down
8 changes: 1 addition & 7 deletions packages/gitbook/src/components/PDF/PDFRootLayout.tsx
Original file line number Diff line number Diff line change
@@ -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';

/**
Expand All @@ -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>
);
Expand Down
2 changes: 1 addition & 1 deletion packages/gitbook/src/components/PageAside/PageAside.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion packages/gitbook/src/components/PageBody/PageBody.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 })
: '';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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);
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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};` : ''
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -115,8 +115,7 @@ export async function TableOfContents(props: {
/>
{customization.trademark.enabled ? (
<Trademark
space={space}
customization={customization}
context={context}
placement={SiteInsightsTrademarkPlacement.Sidebar}
/>
) : null}
Expand Down
18 changes: 7 additions & 11 deletions packages/gitbook/src/components/TableOfContents/Trademark.tsx
Original file line number Diff line number Diff line change
@@ -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 (
Expand Down Expand Up @@ -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');
Expand Down
39 changes: 31 additions & 8 deletions packages/gitbook/src/intl/server.ts
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -33,3 +52,7 @@ export function getSpaceLanguage(customization: SiteCustomizationSettings): Tran
...language,
};
}

function checkIsValidLocale(locale: string): locale is TranslationLocale {
return locale in languages;
}
Loading