Skip to content

Commit aafcc5b

Browse files
committed
Translate OpenAPI blocks
1 parent 3363a18 commit aafcc5b

Some content is hidden

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

44 files changed

+799
-227
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/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/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,17 +11,27 @@ import { Heading } from '../Heading';
1111

1212
import './scalar.css';
1313
import './style.css';
14+
import { DEFAULT_LOCALE, getCustomizationLocale } from '@/intl/server';
1415
import type { AnyOpenAPIOperationsBlock, OpenAPISchemasBlock } from '@/lib/openapi/types';
16+
import type { GitBookAnyContext } from '@v2/lib/context';
1517

1618
/**
1719
* Get the OpenAPI context to render a block.
1820
*/
1921
export function getOpenAPIContext(args: {
2022
props: BlockProps<AnyOpenAPIOperationsBlock | OpenAPISchemasBlock>;
2123
specUrl: string;
22-
}): OpenAPIContext {
23-
const { props, specUrl } = args;
24+
context: GitBookAnyContext | undefined;
25+
}): OpenAPIContextInput {
26+
const { props, specUrl, context } = args;
2427
const { block } = props;
28+
29+
const customization = context && 'customization' in context ? context.customization : null;
30+
const customizationLocale = customization
31+
? getCustomizationLocale(customization)
32+
: DEFAULT_LOCALE;
33+
const locale = checkIsValidLocale(customizationLocale) ? customizationLocale : DEFAULT_LOCALE;
34+
2535
return {
2636
specUrl,
2737
icons: {
@@ -69,5 +79,6 @@ export function getOpenAPIContext(args: {
6979
defaultInteractiveOpened: props.context.mode === 'print',
7080
id: block.meta?.id,
7181
blockKey: block.key,
82+
locale,
7283
};
7384
}

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

+4-4
Original file line numberDiff line numberDiff line change
@@ -228,19 +228,19 @@
228228
}
229229

230230
.openapi-schema-required {
231-
@apply text-warning-subtle text-[0.813rem];
231+
@apply text-warning-subtle text-[0.813rem] lowercase;
232232
}
233233

234234
.openapi-schema-optional {
235-
@apply text-info-subtle text-[0.813rem];
235+
@apply text-info-subtle text-[0.813rem] lowercase;
236236
}
237237

238238
.openapi-schema-readonly {
239-
@apply text-primary-subtle/9 text-[0.813rem];
239+
@apply text-primary-subtle/9 text-[0.813rem] lowercase;
240240
}
241241

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

246246
.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

+18-4
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

@@ -22,7 +23,7 @@ export function OpenAPICodeSample(props: {
2223
data: OpenAPIOperationData;
2324
context: OpenAPIContext;
2425
}) {
25-
const { data } = props;
26+
const { data, context } = props;
2627

2728
// If code samples are disabled at operation level, we don't display the code samples.
2829
if (data.operation['x-codeSamples'] === false) {
@@ -43,7 +44,13 @@ export function OpenAPICodeSample(props: {
4344
return null;
4445
}
4546

46-
return <OpenAPICodeSampleBody data={data} items={samples} />;
47+
return (
48+
<OpenAPICodeSampleBody
49+
context={getOpenAPIClientContext(context)}
50+
data={data}
51+
items={samples}
52+
/>
53+
);
4754
}
4855

4956
/**
@@ -211,7 +218,14 @@ function OpenAPICodeSampleFooter(props: {
211218
) : (
212219
<span />
213220
)}
214-
{!hideTryItPanel && <ScalarApiButton method={method} path={path} specUrl={specUrl} />}
221+
{!hideTryItPanel && (
222+
<ScalarApiButton
223+
context={getOpenAPIClientContext(context)}
224+
method={method}
225+
path={path}
226+
specUrl={specUrl}
227+
/>
228+
)}
215229
</div>
216230
);
217231
}

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

+21-8
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import type { OpenAPIV3 } from '@gitbook/openapi-parser';
2+
import type { OpenAPIContext, OpenAPIUniversalContext } from './context';
23
import { generateSchemaExample } from './generateSchemaExample';
34
import { json2xml } from './json2xml';
45
import { stringifyOpenAPI } from './stringifyOpenAPI';
5-
import type { OpenAPIContext } from './types';
6+
import { t, tString } from './translate';
67
import { checkIsReference } from './utils';
78

89
/**
@@ -17,7 +18,7 @@ export function OpenAPIExample(props: {
1718
const code = stringifyExample({ example, xml: syntax === 'xml' });
1819

1920
if (code === null) {
20-
return <OpenAPIEmptyExample />;
21+
return <OpenAPIEmptyExample context={context} />;
2122
}
2223

2324
return context.renderCodeBlock({ code, syntax });
@@ -44,19 +45,28 @@ function stringifyExample(args: { example: OpenAPIV3.ExampleObject; xml: boolean
4445
/**
4546
* Empty response example.
4647
*/
47-
export function OpenAPIEmptyExample() {
48+
export function OpenAPIEmptyExample(props: {
49+
context: OpenAPIUniversalContext;
50+
}) {
51+
const { context } = props;
4852
return (
4953
<pre className="openapi-example-empty">
50-
<p>No Content</p>
54+
<p>{t(context.translation, 'no_content')}</p>
5155
</pre>
5256
);
5357
}
5458

5559
/**
5660
* Generate an example from a reference object.
5761
*/
58-
export function getExampleFromReference(ref: OpenAPIV3.ReferenceObject): OpenAPIV3.ExampleObject {
59-
return { summary: 'Unresolved reference', value: { $ref: ref.$ref } };
62+
export function getExampleFromReference(
63+
ref: OpenAPIV3.ReferenceObject,
64+
context: OpenAPIContext
65+
): OpenAPIV3.ExampleObject {
66+
return {
67+
summary: tString(context.translation, 'unresolved_reference'),
68+
value: { $ref: ref.$ref },
69+
};
6070
}
6171

6272
/**
@@ -65,13 +75,16 @@ export function getExampleFromReference(ref: OpenAPIV3.ReferenceObject): OpenAPI
6575
export function getExamplesFromMediaTypeObject(args: {
6676
mediaType: string;
6777
mediaTypeObject: OpenAPIV3.MediaTypeObject;
78+
context: OpenAPIContext;
6879
}): { key: string; example: OpenAPIV3.ExampleObject }[] {
69-
const { mediaTypeObject, mediaType } = args;
80+
const { mediaTypeObject, mediaType, context } = args;
7081
if (mediaTypeObject.examples) {
7182
return Object.entries(mediaTypeObject.examples).map(([key, example]) => {
7283
return {
7384
key,
74-
example: checkIsReference(example) ? getExampleFromReference(example) : example,
85+
example: checkIsReference(example)
86+
? getExampleFromReference(example, context)
87+
: example,
7588
};
7689
});
7790
}

0 commit comments

Comments
 (0)