Skip to content

Commit 8ed1bda

Browse files
authored
Translate OpenAPI blocks (#3166)
1 parent d67699a commit 8ed1bda

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+873
-198
lines changed

.changeset/light-moons-press.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@gitbook/react-openapi": patch
3+
"gitbook": patch
4+
---
5+
6+
Translate OpenAPI blocks

packages/gitbook/e2e/customers.spec.ts

+17-17
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,18 @@ const testCases: TestsCase[] = [
1010
{ name: 'OpenAPI', url: '/snyk-api/reference/apps', run: waitForCookiesDialog },
1111
],
1212
},
13-
{
14-
name: 'Nexthink',
15-
contentBaseURL: 'https://docs.nexthink.com',
16-
tests: [
17-
{
18-
name: 'Home',
19-
url: '/',
20-
screenshot: { waitForTOCScrolling: false },
21-
run: waitForCookiesDialog,
22-
},
23-
],
24-
},
13+
// {
14+
// name: 'Nexthink',
15+
// contentBaseURL: 'https://docs.nexthink.com',
16+
// tests: [
17+
// {
18+
// name: 'Home',
19+
// url: '/',
20+
// screenshot: { waitForTOCScrolling: false },
21+
// run: waitForCookiesDialog,
22+
// },
23+
// ],
24+
// },
2525
{
2626
name: 'asiksupport-stg.dto.kemkes.go.id',
2727
contentBaseURL: 'https://asiksupport-stg.dto.kemkes.go.id',
@@ -157,11 +157,11 @@ const testCases: TestsCase[] = [
157157
contentBaseURL: 'https://wiki.redmodding.org',
158158
tests: [{ name: 'Home', url: '/' }],
159159
},
160-
{
161-
name: 'docs.cherry-ai.com',
162-
contentBaseURL: 'https://docs.cherry-ai.com',
163-
tests: [{ name: 'Home', url: '/', run: waitForCookiesDialog }],
164-
},
160+
// {
161+
// name: 'docs.cherry-ai.com',
162+
// contentBaseURL: 'https://docs.cherry-ai.com',
163+
// tests: [{ name: 'Home', url: '/', run: waitForCookiesDialog }],
164+
// },
165165
{
166166
name: 'docs.snyk.io',
167167
contentBaseURL: 'https://docs.snyk.io',

packages/gitbook/src/components/DocumentView/OpenAPI/OpenAPIOperation.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ async function OpenAPIOperationBody(props: BlockProps<AnyOpenAPIOperationsBlock>
5151
return (
5252
<BaseOpenAPIOperation
5353
data={data}
54-
context={getOpenAPIContext({ props, specUrl })}
54+
context={getOpenAPIContext({ props, specUrl, context: context.contentContext })}
5555
className="openapi-block"
5656
/>
5757
);

packages/gitbook/src/components/DocumentView/OpenAPI/OpenAPISchemas.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ async function OpenAPISchemasBody(props: BlockProps<OpenAPISchemasBlock>) {
5151
<BaseOpenAPISchemas
5252
schemas={data.schemas}
5353
grouped={block.data.grouped}
54-
context={getOpenAPIContext({ props, specUrl })}
54+
context={getOpenAPIContext({ props, specUrl, context: context.contentContext })}
5555
className="openapi-block"
5656
/>
5757
);

packages/gitbook/src/components/DocumentView/OpenAPI/OpenAPIWebhook.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ async function OpenAPIWebhookBody(props: BlockProps<OpenAPIWebhookBlock>) {
5151
return (
5252
<BaseOpenAPIWebhook
5353
data={data}
54-
context={getOpenAPIContext({ props, specUrl })}
54+
context={getOpenAPIContext({ props, specUrl, context: context.contentContext })}
5555
className="openapi-block"
5656
/>
5757
);

packages/gitbook/src/components/DocumentView/OpenAPI/context.tsx

+14-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { JSONDocument } from '@gitbook/api';
22
import { Icon } from '@gitbook/icons';
3-
import type { OpenAPIContext } from '@gitbook/react-openapi';
3+
import { type OpenAPIContextInput, checkIsValidLocale } from '@gitbook/react-openapi';
44

55
import { tcls } from '@/lib/tailwind';
66

@@ -11,21 +11,31 @@ import { Heading } from '../Heading';
1111

1212
import './scalar.css';
1313
import './style.css';
14+
import { DEFAULT_LOCALE, getCustomizationLocale } from '@/intl/server';
1415
import type {
1516
AnyOpenAPIOperationsBlock,
1617
OpenAPISchemasBlock,
1718
OpenAPIWebhookBlock,
1819
} from '@/lib/openapi/types';
20+
import type { GitBookAnyContext } from '@v2/lib/context';
1921

2022
/**
2123
* Get the OpenAPI context to render a block.
2224
*/
2325
export function getOpenAPIContext(args: {
2426
props: BlockProps<AnyOpenAPIOperationsBlock | OpenAPISchemasBlock | OpenAPIWebhookBlock>;
2527
specUrl: string;
26-
}): OpenAPIContext {
27-
const { props, specUrl } = args;
28+
context: GitBookAnyContext | undefined;
29+
}): OpenAPIContextInput {
30+
const { props, specUrl, context } = args;
2831
const { block } = props;
32+
33+
const customization = context && 'customization' in context ? context.customization : null;
34+
const customizationLocale = customization
35+
? getCustomizationLocale(customization)
36+
: DEFAULT_LOCALE;
37+
const locale = checkIsValidLocale(customizationLocale) ? customizationLocale : DEFAULT_LOCALE;
38+
2939
return {
3040
specUrl,
3141
icons: {
@@ -73,5 +83,6 @@ export function getOpenAPIContext(args: {
7383
defaultInteractiveOpened: props.context.mode === 'print',
7484
id: block.meta?.id,
7585
blockKey: block.key,
86+
locale,
7687
};
7788
}

packages/gitbook/src/components/DocumentView/OpenAPI/style.css

+4-4
Original file line numberDiff line numberDiff line change
@@ -229,19 +229,19 @@
229229
}
230230

231231
.openapi-schema-required {
232-
@apply text-warning-subtle text-[0.813rem];
232+
@apply text-warning-subtle text-[0.813rem] lowercase;
233233
}
234234

235235
.openapi-schema-optional {
236-
@apply text-info-subtle text-[0.813rem];
236+
@apply text-info-subtle text-[0.813rem] lowercase;
237237
}
238238

239239
.openapi-schema-readonly {
240-
@apply text-primary-subtle/9 text-[0.813rem];
240+
@apply text-primary-subtle/9 text-[0.813rem] lowercase;
241241
}
242242

243243
.openapi-schema-writeonly {
244-
@apply text-success dark:text-success-subtle/9 text-[0.813rem];
244+
@apply text-success dark:text-success-subtle/9 text-[0.813rem] lowercase;
245245
}
246246

247247
.openapi-schema-type {

packages/gitbook/src/intl/server.ts

+12-3
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,26 @@ import { type TranslationLanguage, languages } from './translations';
44

55
export * from './translate';
66

7+
export const DEFAULT_LOCALE = 'en';
8+
9+
/**
10+
* Get the locale of the customization.
11+
*/
12+
export function getCustomizationLocale(customization: SiteCustomizationSettings): string {
13+
return customization.internationalization.locale;
14+
}
15+
716
/**
817
* Create the translation context for a space to use in the server components.
918
*/
1019
export function getSpaceLanguage(customization: SiteCustomizationSettings): TranslationLanguage {
11-
const fallback = languages.en;
20+
const fallback = languages[DEFAULT_LOCALE];
1221

13-
const { locale } = customization.internationalization;
22+
const locale = getCustomizationLocale(customization);
1423

1524
let language = fallback;
1625
// @ts-ignore
17-
if (locale !== 'en' && languages[locale]) {
26+
if (locale !== DEFAULT_LOCALE && languages[locale]) {
1827
// @ts-ignore
1928
language = languages[locale];
2029
}

packages/gitbook/src/intl/translations/translations.test.ts

Whitespace-only changes.

packages/react-openapi/src/InteractiveSection.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ export function InteractiveSection(props: {
102102
) : null}
103103
{header}
104104
</SectionHeaderContent>
105+
{/* biome-ignore lint/a11y/useKeyWithClickEvents: we prevent default here */}
105106
<div
106107
className={clsx(
107108
'openapi-section-header-controls',

packages/react-openapi/src/OpenAPICodeSample.tsx

+16-3
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@ import {
66
import { OpenAPICodeSampleBody } from './OpenAPICodeSampleSelector';
77
import { ScalarApiButton } from './ScalarApiButton';
88
import { type CodeSampleGenerator, codeSampleGenerators } from './code-samples';
9+
import { type OpenAPIContext, getOpenAPIClientContext } from './context';
910
import { generateMediaTypeExamples, generateSchemaExample } from './generateSchemaExample';
1011
import { stringifyOpenAPI } from './stringifyOpenAPI';
11-
import type { OpenAPIContext, OpenAPIOperationData } from './types';
12+
import type { OpenAPIOperationData } from './types';
1213
import { getDefaultServerURL } from './util/server';
1314
import { checkIsReference } from './utils';
1415

@@ -44,7 +45,12 @@ export function OpenAPICodeSample(props: {
4445
}
4546

4647
return (
47-
<OpenAPICodeSampleBody data={data} items={samples} selectIcon={context.icons.chevronDown} />
48+
<OpenAPICodeSampleBody
49+
context={getOpenAPIClientContext(context)}
50+
data={data}
51+
items={samples}
52+
selectIcon={context.icons.chevronDown}
53+
/>
4854
);
4955
}
5056

@@ -215,7 +221,14 @@ function OpenAPICodeSampleFooter(props: {
215221
) : (
216222
<span />
217223
)}
218-
{!hideTryItPanel && <ScalarApiButton method={method} path={path} specUrl={specUrl} />}
224+
{!hideTryItPanel && (
225+
<ScalarApiButton
226+
context={getOpenAPIClientContext(context)}
227+
method={method}
228+
path={path}
229+
specUrl={specUrl}
230+
/>
231+
)}
219232
</div>
220233
);
221234
}

packages/react-openapi/src/OpenAPICodeSampleSelector.tsx

+14-4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { useStore } from 'zustand';
66
import { OpenAPIPath } from './OpenAPIPath';
77
import { OpenAPISelect, OpenAPISelectItem } from './OpenAPISelect';
88
import { StaticSection } from './StaticSection';
9+
import type { OpenAPIClientContext } from './context';
910
import { getOrCreateStoreByKey } from './getOrCreateStoreByKey';
1011
import type { OpenAPIOperationData } from './types';
1112

@@ -26,12 +27,13 @@ function OpenAPICodeSampleHeader(props: {
2627
items: CodeSampleItem[];
2728
data: OpenAPIOperationData;
2829
selectIcon?: React.ReactNode;
30+
context: OpenAPIClientContext;
2931
}) {
30-
const { data, items, selectIcon } = props;
32+
const { data, items, selectIcon, context } = props;
3133

3234
return (
3335
<>
34-
<OpenAPIPath canCopy={false} withServer={false} data={data} />
36+
<OpenAPIPath context={context} canCopy={false} withServer={false} data={data} />
3537
{items.length > 1 ? (
3638
<OpenAPISelect
3739
icon={selectIcon}
@@ -56,8 +58,9 @@ export function OpenAPICodeSampleBody(props: {
5658
items: CodeSampleItem[];
5759
data: OpenAPIOperationData;
5860
selectIcon?: React.ReactNode;
61+
context: OpenAPIClientContext;
5962
}) {
60-
const { items, data, selectIcon } = props;
63+
const { items, data, selectIcon, context } = props;
6164
if (!items[0]) {
6265
throw new Error('No items provided');
6366
}
@@ -72,7 +75,14 @@ export function OpenAPICodeSampleBody(props: {
7275

7376
return (
7477
<StaticSection
75-
header={<OpenAPICodeSampleHeader selectIcon={selectIcon} data={data} items={items} />}
78+
header={
79+
<OpenAPICodeSampleHeader
80+
context={context}
81+
selectIcon={selectIcon}
82+
data={data}
83+
items={items}
84+
/>
85+
}
7686
className="openapi-codesample"
7787
>
7888
<div id={selected.key as string} className="openapi-codesample-panel">

packages/react-openapi/src/OpenAPICopyButton.tsx

+7-2
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@
22

33
import { useState } from 'react';
44
import { Button, type ButtonProps, Tooltip, TooltipTrigger } from 'react-aria-components';
5+
import type { OpenAPIClientContext } from './context';
6+
import { t } from './translate';
57

68
export function OpenAPICopyButton(
79
props: ButtonProps & {
810
value: string;
911
children: React.ReactNode;
12+
context: OpenAPIClientContext;
1013
label?: string;
1114
/**
1215
* Whether to show a tooltip.
@@ -15,7 +18,7 @@ export function OpenAPICopyButton(
1518
withTooltip?: boolean;
1619
}
1720
) {
18-
const { value, label, children, onPress, className, withTooltip = true } = props;
21+
const { value, label, children, onPress, className, context, withTooltip = true } = props;
1922
const [copied, setCopied] = useState(false);
2023
const [isOpen, setIsOpen] = useState(false);
2124

@@ -60,7 +63,9 @@ export function OpenAPICopyButton(
6063
offset={4}
6164
className="openapi-tooltip"
6265
>
63-
{copied ? 'Copied' : label || 'Copy to clipboard'}
66+
{copied
67+
? t(context.translation, 'copied')
68+
: label || t(context.translation, 'copy_to_clipboard')}
6469
</Tooltip>
6570
</TooltipTrigger>
6671
);

packages/react-openapi/src/OpenAPIExample.tsx

+8-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import type { OpenAPIV3 } from '@gitbook/openapi-parser';
2+
import type { OpenAPIContext, OpenAPIUniversalContext } from './context';
23
import { json2xml } from './json2xml';
34
import { stringifyOpenAPI } from './stringifyOpenAPI';
4-
import type { OpenAPIContext } from './types';
5+
import { t } from './translate';
56

67
/**
78
* Display an example.
@@ -15,7 +16,7 @@ export function OpenAPIExample(props: {
1516
const code = stringifyExample({ example, xml: syntax === 'xml' });
1617

1718
if (code === null) {
18-
return <OpenAPIEmptyExample />;
19+
return <OpenAPIEmptyExample context={context} />;
1920
}
2021

2122
return context.renderCodeBlock({ code, syntax });
@@ -42,10 +43,13 @@ function stringifyExample(args: { example: OpenAPIV3.ExampleObject; xml: boolean
4243
/**
4344
* Empty response example.
4445
*/
45-
export function OpenAPIEmptyExample() {
46+
export function OpenAPIEmptyExample(props: {
47+
context: OpenAPIUniversalContext;
48+
}) {
49+
const { context } = props;
4650
return (
4751
<pre className="openapi-example-empty">
48-
<p>No Content</p>
52+
<p>{t(context.translation, 'no_content')}</p>
4953
</pre>
5054
);
5155
}

0 commit comments

Comments
 (0)