jamdesk 1.1.179 → 1.1.180

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jamdesk",
3
- "version": "1.1.179",
3
+ "version": "1.1.180",
4
4
  "description": "CLI for Jamdesk — build, preview, and deploy documentation sites from MDX. Dev server with hot reload, 50+ components, OpenAPI support, AI search, and Mintlify migration",
5
5
  "keywords": [
6
6
  "jamdesk",
@@ -18,6 +18,7 @@ import { renderInlineMarkdown } from '@/lib/inline-markdown';
18
18
  import { decodePromptSource } from '@/lib/prompt-source-codec';
19
19
 
20
20
  import { ChatGPTIcon, ClaudeIcon, CursorIcon, GeminiIcon, PerplexityIcon } from './ai-action-icons';
21
+ import { useDocsLocale } from './docs-locale-context';
21
22
  import { Icon } from './Icon';
22
23
  import {
23
24
  resolvePromptActions,
@@ -293,11 +294,12 @@ export function Prompt({
293
294
  const generatedMenuId = useId();
294
295
  const menuId = `prompt-actions-${generatedMenuId}`;
295
296
 
297
+ const locale = useDocsLocale();
296
298
  const prompt = useMemo(() => decodePromptSource(__promptSource), [__promptSource]);
297
299
  const hasPrompt = prompt.length > 0;
298
300
  const resolvedActions = useMemo(
299
- () => hasPrompt ? resolvePromptActions(actions, prompt) : [],
300
- [actions, hasPrompt, prompt],
301
+ () => hasPrompt ? resolvePromptActions(actions, prompt, locale) : [],
302
+ [actions, hasPrompt, locale, prompt],
301
303
  );
302
304
  const [primary, ...secondary] = resolvedActions;
303
305
 
@@ -0,0 +1,31 @@
1
+ 'use client';
2
+
3
+ import { createContext, useContext, type ReactNode } from 'react';
4
+
5
+ /**
6
+ * The rendered page's language code, whitelisted against the project's
7
+ * `navigation.languages` (see resolveLocaleFromPath in lib/language-utils.ts —
8
+ * a path segment that merely looks like a language code never counts).
9
+ *
10
+ * Empty string = default/unknown locale; consumers fall back to English.
11
+ * Surfaces without the provider (dashboard editor preview) get the default.
12
+ */
13
+ const DocsLocaleContext = createContext<string>('');
14
+
15
+ export function DocsLocaleProvider({
16
+ children,
17
+ locale,
18
+ }: {
19
+ children: ReactNode;
20
+ locale: string;
21
+ }): React.ReactElement {
22
+ return (
23
+ <DocsLocaleContext.Provider value={locale}>
24
+ {children}
25
+ </DocsLocaleContext.Provider>
26
+ );
27
+ }
28
+
29
+ export function useDocsLocale(): string {
30
+ return useContext(DocsLocaleContext);
31
+ }
@@ -119,15 +119,47 @@ export interface ResolvedPromptAction {
119
119
  label: string;
120
120
  }
121
121
 
122
- const BUILTIN_META = {
123
- cursor: { label: 'Open in Cursor' },
124
- claude: { label: 'Open in Claude' },
125
- chatgpt: { label: 'Open in ChatGPT' },
126
- perplexity: { label: 'Open in Perplexity' },
127
- gemini: { label: 'Open in Gemini' },
128
- } as const;
129
-
130
- export function resolvePromptActions(actions: unknown, prompt: string): ResolvedPromptAction[] {
122
+ const BUILTIN_TOOL_NAMES: Record<Exclude<PromptBuiltinAction, 'copy'>, string> = {
123
+ cursor: 'Cursor',
124
+ claude: 'Claude',
125
+ chatgpt: 'ChatGPT',
126
+ perplexity: 'Perplexity',
127
+ gemini: 'Gemini',
128
+ };
129
+
130
+ // "Open in {tool}" per page language. Keys are lowercased language codes;
131
+ // regional variants fall back to the base language, unknown locales to English.
132
+ const OPEN_IN_TEMPLATES: Record<string, (tool: string) => string> = {
133
+ en: (tool) => `Open in ${tool}`,
134
+ fr: (tool) => `Ouvrir dans ${tool}`,
135
+ es: (tool) => `Abrir en ${tool}`,
136
+ de: (tool) => `In ${tool} öffnen`,
137
+ it: (tool) => `Apri in ${tool}`,
138
+ pt: (tool) => `Abrir no ${tool}`,
139
+ nl: (tool) => `Openen in ${tool}`,
140
+ ja: (tool) => `${tool}で開く`,
141
+ ko: (tool) => `${tool}에서 열기`,
142
+ zh: (tool) => `在 ${tool} 中打开`,
143
+ 'zh-tw': (tool) => `在 ${tool} 中開啟`,
144
+ 'zh-hk': (tool) => `在 ${tool} 中開啟`,
145
+ };
146
+
147
+ export function getBuiltinActionLabel(
148
+ action: Exclude<PromptBuiltinAction, 'copy'>,
149
+ locale = '',
150
+ ): string {
151
+ const lowered = locale.toLowerCase();
152
+ const template = OPEN_IN_TEMPLATES[lowered]
153
+ ?? OPEN_IN_TEMPLATES[lowered.split('-')[0]]
154
+ ?? OPEN_IN_TEMPLATES.en;
155
+ return template(BUILTIN_TOOL_NAMES[action]);
156
+ }
157
+
158
+ export function resolvePromptActions(
159
+ actions: unknown,
160
+ prompt: string,
161
+ locale = '',
162
+ ): ResolvedPromptAction[] {
131
163
  return normalizePromptActions(actions).flatMap((action) => {
132
164
  const href = buildPromptActionUrl(action, prompt);
133
165
  if (!href) return [];
@@ -135,7 +167,7 @@ export function resolvePromptActions(actions: unknown, prompt: string): Resolved
135
167
  return [{
136
168
  action,
137
169
  href,
138
- label: typeof action === 'string' ? BUILTIN_META[action].label : action.label,
170
+ label: typeof action === 'string' ? getBuiltinActionLabel(action, locale) : action.label,
139
171
  }];
140
172
  });
141
173
  }
@@ -86,7 +86,8 @@ import {
86
86
  } from '@/lib/openapi';
87
87
  import { classifyOpenApiLoadError } from '@/lib/openapi/classify-load-error';
88
88
  import { findOperation, deriveOperationDescription, collectLocalSpecPaths } from '@/lib/openapi/operation-description';
89
- import { extractLanguageFromPath, isValidLanguageCode } from '@/lib/language-utils';
89
+ import { extractLanguageFromPath, isValidLanguageCode, resolveLocaleFromPath } from '@/lib/language-utils';
90
+ import { DocsLocaleProvider } from '@/components/mdx/docs-locale-context';
90
91
  import { findFirstNavPage } from '@/lib/find-first-nav-page';
91
92
  import { candidateSpecPaths } from '@/lib/openapi/lang-spec-path';
92
93
  import { ApiEndpoint } from '@/components/mdx/ApiEndpoint';
@@ -419,6 +420,14 @@ export async function renderDocPage(input: RenderInput): Promise<ReactElement> {
419
420
  const data = parsed.data as FrontmatterData;
420
421
  const rawContent = parsed.content;
421
422
 
423
+ // Whitelisted page locale for localized component chrome (Prompt action
424
+ // labels). Unlike `currentLang` above, this only counts a path prefix that
425
+ // is actually declared in navigation.languages — '' otherwise.
426
+ const docsLocale = resolveLocaleFromPath(
427
+ `/${pagePath}`,
428
+ config.navigation?.languages?.map((l) => l.language) ?? [],
429
+ );
430
+
422
431
  const baseUrl = resolveBaseUrl(requestHeaders, projectSlug, hostAtDocs);
423
432
  const faqPairs = extractFaqPairs(rawContent);
424
433
  const ogImageUrl = buildPageOgImageUrl(config, data, baseUrl);
@@ -853,21 +862,23 @@ export async function renderDocPage(input: RenderInput): Promise<ReactElement> {
853
862
  <MdxErrorBlock label="page content" />
854
863
  ) : (
855
864
  <MdxRenderBoundary fallback={<MdxErrorBlock label="page content" />}>
856
- <StepSlugProvider entries={stepEntries}>
857
- <UpdateSlugProvider entries={updateEntries}>
858
- <MDXRemote
859
- source={effectiveSource}
860
- components={ComponentsWithUnknownFallback}
861
- options={{
862
- ...mdxSecurityOptions,
863
- mdxOptions: {
864
- ...getCommonMdxOptions(config, highlighter),
865
- recmaPlugins: [recmaCompoundComponents, recmaGuardExpressions],
866
- },
867
- }}
868
- />
869
- </UpdateSlugProvider>
870
- </StepSlugProvider>
865
+ <DocsLocaleProvider locale={docsLocale}>
866
+ <StepSlugProvider entries={stepEntries}>
867
+ <UpdateSlugProvider entries={updateEntries}>
868
+ <MDXRemote
869
+ source={effectiveSource}
870
+ components={ComponentsWithUnknownFallback}
871
+ options={{
872
+ ...mdxSecurityOptions,
873
+ mdxOptions: {
874
+ ...getCommonMdxOptions(config, highlighter),
875
+ recmaPlugins: [recmaCompoundComponents, recmaGuardExpressions],
876
+ },
877
+ }}
878
+ />
879
+ </UpdateSlugProvider>
880
+ </StepSlugProvider>
881
+ </DocsLocaleProvider>
871
882
  </MdxRenderBoundary>
872
883
  )}
873
884
  </div>
@@ -885,21 +896,23 @@ export async function renderDocPage(input: RenderInput): Promise<ReactElement> {
885
896
  <MdxErrorBlock label="page content" />
886
897
  ) : (
887
898
  <MdxRenderBoundary fallback={<MdxErrorBlock label="page content" />}>
888
- <StepSlugProvider entries={stepEntries}>
889
- <UpdateSlugProvider entries={updateEntries}>
890
- <MDXRemote
891
- source={content}
892
- components={ComponentsWithUnknownFallback}
893
- options={{
894
- ...mdxSecurityOptions,
895
- mdxOptions: {
896
- ...getCommonMdxOptions(config, highlighter),
897
- recmaPlugins: [recmaCompoundComponents, recmaGuardExpressions],
898
- },
899
- }}
900
- />
901
- </UpdateSlugProvider>
902
- </StepSlugProvider>
899
+ <DocsLocaleProvider locale={docsLocale}>
900
+ <StepSlugProvider entries={stepEntries}>
901
+ <UpdateSlugProvider entries={updateEntries}>
902
+ <MDXRemote
903
+ source={content}
904
+ components={ComponentsWithUnknownFallback}
905
+ options={{
906
+ ...mdxSecurityOptions,
907
+ mdxOptions: {
908
+ ...getCommonMdxOptions(config, highlighter),
909
+ recmaPlugins: [recmaCompoundComponents, recmaGuardExpressions],
910
+ },
911
+ }}
912
+ />
913
+ </UpdateSlugProvider>
914
+ </StepSlugProvider>
915
+ </DocsLocaleProvider>
903
916
  </MdxRenderBoundary>
904
917
  );
905
918