jamdesk 1.1.185 → 1.1.187
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/dist/__tests__/unit/dev-workspace-symlinks.test.d.ts +2 -0
- package/dist/__tests__/unit/dev-workspace-symlinks.test.d.ts.map +1 -0
- package/dist/__tests__/unit/dev-workspace-symlinks.test.js +112 -0
- package/dist/__tests__/unit/dev-workspace-symlinks.test.js.map +1 -0
- package/dist/__tests__/unit/language-filter.test.d.ts +2 -0
- package/dist/__tests__/unit/language-filter.test.d.ts.map +1 -0
- package/dist/__tests__/unit/language-filter.test.js +166 -0
- package/dist/__tests__/unit/language-filter.test.js.map +1 -0
- package/dist/__tests__/unit/vendored-sync.test.js +95 -1
- package/dist/__tests__/unit/vendored-sync.test.js.map +1 -1
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +4 -0
- package/dist/commands/deploy.js.map +1 -1
- package/dist/lib/language-filter.d.ts +31 -0
- package/dist/lib/language-filter.d.ts.map +1 -0
- package/dist/lib/language-filter.js +14 -0
- package/dist/lib/language-filter.js.map +1 -0
- package/package.json +1 -1
- package/vendored/components/theme/ThemeToggle.tsx +3 -1
- package/vendored/lib/email-templates/build-failure.tsx +1 -0
- package/vendored/lib/isr-build-executor.ts +4 -0
- package/vendored/lib/locale-fallback.ts +98 -0
- package/vendored/lib/regenerate-screenshot-handler.ts +3 -1
- package/vendored/lib/render-doc-page.tsx +117 -7
- package/vendored/lib/seo.ts +40 -5
- package/vendored/lib/ui-strings.ts +268 -23
- package/vendored/public/_jd/fonts/fontawesome/css/all.min.css +1 -1
- package/vendored/themes/base.css +28 -0
- package/vendored/workspace-package-lock.json +87 -3
|
@@ -19,7 +19,29 @@ const EN: UiStrings = {
|
|
|
19
19
|
breadcrumbHome: 'Home',
|
|
20
20
|
};
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
// Aliased locales share one object: `fr-CA`/`fr-ca` are the same chrome as
|
|
23
|
+
// `fr`, `jp`/`ja-jp` the same as `ja`, `pt-BR` the same as `pt`. Only the
|
|
24
|
+
// Chinese pair is genuinely two tables — Traditional is a distinct script,
|
|
25
|
+
// not a `zh` alias, so it gets its own strings rather than a reference.
|
|
26
|
+
const FR: UiStrings = {
|
|
27
|
+
search: 'Rechercher',
|
|
28
|
+
askAi: "Demander à l'IA",
|
|
29
|
+
more: 'Plus',
|
|
30
|
+
toggleMenu: 'Basculer le menu',
|
|
31
|
+
selectLanguage: 'Choisir la langue',
|
|
32
|
+
breadcrumbHome: 'Accueil',
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const ES: UiStrings = {
|
|
36
|
+
search: 'Buscar',
|
|
37
|
+
askAi: 'Preguntar a la IA',
|
|
38
|
+
more: 'Más',
|
|
39
|
+
toggleMenu: 'Alternar menú',
|
|
40
|
+
selectLanguage: 'Elegir idioma',
|
|
41
|
+
breadcrumbHome: 'Inicio',
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const ZH_HANS: UiStrings = {
|
|
23
45
|
search: '搜索',
|
|
24
46
|
askAi: '询问 AI',
|
|
25
47
|
more: '更多',
|
|
@@ -28,33 +50,256 @@ const ZH: Partial<UiStrings> = {
|
|
|
28
50
|
breadcrumbHome: '首页',
|
|
29
51
|
};
|
|
30
52
|
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
53
|
+
const ZH_HANT: UiStrings = {
|
|
54
|
+
search: '搜尋',
|
|
55
|
+
askAi: '詢問 AI',
|
|
56
|
+
more: '更多',
|
|
57
|
+
toggleMenu: '切換選單',
|
|
58
|
+
selectLanguage: '選擇語言',
|
|
59
|
+
breadcrumbHome: '首頁',
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const JA: UiStrings = {
|
|
63
|
+
search: '検索',
|
|
64
|
+
askAi: 'AI に質問',
|
|
65
|
+
more: 'その他',
|
|
66
|
+
toggleMenu: 'メニューを切り替え',
|
|
67
|
+
selectLanguage: '言語を選択',
|
|
68
|
+
breadcrumbHome: 'ホーム',
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const PT: UiStrings = {
|
|
72
|
+
search: 'Pesquisar',
|
|
73
|
+
askAi: 'Perguntar à IA',
|
|
74
|
+
more: 'Mais',
|
|
75
|
+
toggleMenu: 'Alternar menu',
|
|
76
|
+
selectLanguage: 'Selecionar idioma',
|
|
77
|
+
breadcrumbHome: 'Início',
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Chrome strings for every locale the platform offers.
|
|
82
|
+
*
|
|
83
|
+
* The type is a REQUIRED `Record` over every `LanguageCode` except `en`, and
|
|
84
|
+
* each value is a complete `UiStrings` — both deliberate. Until 2026-08-08
|
|
85
|
+
* this was a `Partial` map holding only `fr`, `es`, `zh` and `cn`, so the
|
|
86
|
+
* other 28 offered locales silently fell back to English: a reader on a fully
|
|
87
|
+
* translated German page still got a "Search" / "Ask AI" header. Nothing
|
|
88
|
+
* failed and no test noticed, because falling back to English is exactly what
|
|
89
|
+
* `getUiStrings` is written to do. Making the record total moves that from a
|
|
90
|
+
* silent runtime gap to a compile error the moment a locale is added to
|
|
91
|
+
* `LanguageCode` without its chrome.
|
|
92
|
+
*
|
|
93
|
+
* These are NOT AI-pipeline output — the pipeline never sees them. They are
|
|
94
|
+
* hand-written and have had no native-speaker review, the same caveat that
|
|
95
|
+
* applies to `PLATFORM_SCREENSHOT_NOTES` in `lib/translation/nav.ts`. Six
|
|
96
|
+
* short, highly conventional UI labels are a much lower-risk surface than a
|
|
97
|
+
* full sentence, but they are also the most-seen text on every page, so get
|
|
98
|
+
* them reviewed before leaning on any of these locales commercially.
|
|
99
|
+
*/
|
|
100
|
+
const OVERRIDES: Record<Exclude<LanguageCode, 'en'>, UiStrings> = {
|
|
101
|
+
fr: FR,
|
|
102
|
+
'fr-CA': FR,
|
|
103
|
+
'fr-ca': FR,
|
|
104
|
+
es: ES,
|
|
105
|
+
zh: ZH_HANS,
|
|
106
|
+
cn: ZH_HANS,
|
|
107
|
+
'zh-Hans': ZH_HANS,
|
|
108
|
+
'zh-Hant': ZH_HANT,
|
|
109
|
+
ja: JA,
|
|
110
|
+
jp: JA,
|
|
111
|
+
'ja-jp': JA,
|
|
112
|
+
pt: PT,
|
|
113
|
+
'pt-BR': PT,
|
|
114
|
+
de: {
|
|
115
|
+
search: 'Suchen',
|
|
116
|
+
askAi: 'KI fragen',
|
|
117
|
+
more: 'Mehr',
|
|
118
|
+
toggleMenu: 'Menü umschalten',
|
|
119
|
+
selectLanguage: 'Sprache wählen',
|
|
120
|
+
breadcrumbHome: 'Startseite',
|
|
121
|
+
},
|
|
122
|
+
ko: {
|
|
123
|
+
search: '검색',
|
|
124
|
+
askAi: 'AI에게 질문',
|
|
125
|
+
more: '더 보기',
|
|
126
|
+
toggleMenu: '메뉴 전환',
|
|
127
|
+
selectLanguage: '언어 선택',
|
|
128
|
+
breadcrumbHome: '홈',
|
|
129
|
+
},
|
|
130
|
+
it: {
|
|
131
|
+
search: 'Cerca',
|
|
132
|
+
askAi: "Chiedi all'IA",
|
|
133
|
+
more: 'Altro',
|
|
134
|
+
toggleMenu: 'Attiva/disattiva menu',
|
|
135
|
+
selectLanguage: 'Scegli la lingua',
|
|
136
|
+
breadcrumbHome: 'Home',
|
|
137
|
+
},
|
|
138
|
+
ru: {
|
|
139
|
+
search: 'Поиск',
|
|
140
|
+
askAi: 'Спросить ИИ',
|
|
141
|
+
more: 'Ещё',
|
|
142
|
+
toggleMenu: 'Переключить меню',
|
|
143
|
+
selectLanguage: 'Выбрать язык',
|
|
144
|
+
breadcrumbHome: 'Главная',
|
|
145
|
+
},
|
|
146
|
+
ro: {
|
|
147
|
+
search: 'Caută',
|
|
148
|
+
askAi: 'Întreabă AI',
|
|
149
|
+
more: 'Mai multe',
|
|
150
|
+
toggleMenu: 'Comută meniul',
|
|
151
|
+
selectLanguage: 'Alege limba',
|
|
152
|
+
breadcrumbHome: 'Acasă',
|
|
153
|
+
},
|
|
154
|
+
cs: {
|
|
155
|
+
search: 'Hledat',
|
|
156
|
+
askAi: 'Zeptat se AI',
|
|
157
|
+
more: 'Více',
|
|
158
|
+
toggleMenu: 'Přepnout nabídku',
|
|
159
|
+
selectLanguage: 'Vybrat jazyk',
|
|
160
|
+
breadcrumbHome: 'Domů',
|
|
161
|
+
},
|
|
162
|
+
id: {
|
|
163
|
+
search: 'Cari',
|
|
164
|
+
askAi: 'Tanya AI',
|
|
165
|
+
more: 'Lainnya',
|
|
166
|
+
toggleMenu: 'Alihkan menu',
|
|
167
|
+
selectLanguage: 'Pilih bahasa',
|
|
168
|
+
breadcrumbHome: 'Beranda',
|
|
169
|
+
},
|
|
170
|
+
ar: {
|
|
171
|
+
search: 'بحث',
|
|
172
|
+
askAi: 'اسأل الذكاء الاصطناعي',
|
|
173
|
+
more: 'المزيد',
|
|
174
|
+
toggleMenu: 'تبديل القائمة',
|
|
175
|
+
selectLanguage: 'اختر اللغة',
|
|
176
|
+
breadcrumbHome: 'الرئيسية',
|
|
177
|
+
},
|
|
178
|
+
tr: {
|
|
179
|
+
search: 'Ara',
|
|
180
|
+
askAi: 'Yapay zekâya sor',
|
|
181
|
+
more: 'Daha fazla',
|
|
182
|
+
toggleMenu: 'Menüyü aç/kapat',
|
|
183
|
+
selectLanguage: 'Dil seçin',
|
|
184
|
+
breadcrumbHome: 'Ana sayfa',
|
|
185
|
+
},
|
|
186
|
+
hi: {
|
|
187
|
+
search: 'खोजें',
|
|
188
|
+
askAi: 'AI से पूछें',
|
|
189
|
+
more: 'और',
|
|
190
|
+
toggleMenu: 'मेन्यू टॉगल करें',
|
|
191
|
+
selectLanguage: 'भाषा चुनें',
|
|
192
|
+
breadcrumbHome: 'होम',
|
|
193
|
+
},
|
|
194
|
+
sv: {
|
|
195
|
+
search: 'Sök',
|
|
196
|
+
askAi: 'Fråga AI',
|
|
197
|
+
more: 'Mer',
|
|
198
|
+
toggleMenu: 'Växla meny',
|
|
199
|
+
selectLanguage: 'Välj språk',
|
|
200
|
+
breadcrumbHome: 'Hem',
|
|
201
|
+
},
|
|
202
|
+
no: {
|
|
203
|
+
search: 'Søk',
|
|
204
|
+
askAi: 'Spør AI',
|
|
205
|
+
more: 'Mer',
|
|
206
|
+
toggleMenu: 'Veksle meny',
|
|
207
|
+
selectLanguage: 'Velg språk',
|
|
208
|
+
breadcrumbHome: 'Hjem',
|
|
209
|
+
},
|
|
210
|
+
lv: {
|
|
211
|
+
search: 'Meklēt',
|
|
212
|
+
askAi: 'Jautāt MI',
|
|
213
|
+
more: 'Vairāk',
|
|
214
|
+
toggleMenu: 'Pārslēgt izvēlni',
|
|
215
|
+
selectLanguage: 'Izvēlēties valodu',
|
|
216
|
+
breadcrumbHome: 'Sākums',
|
|
217
|
+
},
|
|
218
|
+
nl: {
|
|
219
|
+
search: 'Zoeken',
|
|
220
|
+
askAi: 'AI vragen',
|
|
221
|
+
more: 'Meer',
|
|
222
|
+
toggleMenu: 'Menu schakelen',
|
|
223
|
+
selectLanguage: 'Taal kiezen',
|
|
224
|
+
breadcrumbHome: 'Home',
|
|
225
|
+
},
|
|
226
|
+
uk: {
|
|
227
|
+
search: 'Пошук',
|
|
228
|
+
askAi: 'Запитати ШІ',
|
|
229
|
+
more: 'Більше',
|
|
230
|
+
toggleMenu: 'Перемкнути меню',
|
|
231
|
+
selectLanguage: 'Вибрати мову',
|
|
232
|
+
breadcrumbHome: 'Головна',
|
|
233
|
+
},
|
|
234
|
+
vi: {
|
|
235
|
+
search: 'Tìm kiếm',
|
|
236
|
+
askAi: 'Hỏi AI',
|
|
237
|
+
more: 'Thêm',
|
|
238
|
+
toggleMenu: 'Bật/tắt menu',
|
|
239
|
+
selectLanguage: 'Chọn ngôn ngữ',
|
|
240
|
+
breadcrumbHome: 'Trang chủ',
|
|
241
|
+
},
|
|
242
|
+
pl: {
|
|
243
|
+
search: 'Szukaj',
|
|
244
|
+
askAi: 'Zapytaj AI',
|
|
245
|
+
more: 'Więcej',
|
|
246
|
+
toggleMenu: 'Przełącz menu',
|
|
247
|
+
selectLanguage: 'Wybierz język',
|
|
248
|
+
breadcrumbHome: 'Strona główna',
|
|
249
|
+
},
|
|
250
|
+
uz: {
|
|
251
|
+
search: 'Qidirish',
|
|
252
|
+
askAi: 'AI dan soʻrash',
|
|
253
|
+
more: 'Koʻproq',
|
|
254
|
+
toggleMenu: 'Menyuni almashtirish',
|
|
255
|
+
selectLanguage: 'Tilni tanlash',
|
|
256
|
+
breadcrumbHome: 'Bosh sahifa',
|
|
39
257
|
},
|
|
40
|
-
|
|
41
|
-
search: '
|
|
42
|
-
askAi: '
|
|
43
|
-
more: '
|
|
44
|
-
toggleMenu: '
|
|
45
|
-
selectLanguage: '
|
|
46
|
-
breadcrumbHome: '
|
|
258
|
+
he: {
|
|
259
|
+
search: 'חיפוש',
|
|
260
|
+
askAi: 'שאל את ה-AI',
|
|
261
|
+
more: 'עוד',
|
|
262
|
+
toggleMenu: 'החלף תפריט',
|
|
263
|
+
selectLanguage: 'בחר שפה',
|
|
264
|
+
breadcrumbHome: 'דף הבית',
|
|
47
265
|
},
|
|
48
|
-
zh: ZH,
|
|
49
|
-
cn: ZH,
|
|
50
266
|
};
|
|
51
267
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
268
|
+
/**
|
|
269
|
+
* Pre-merged so repeated calls return a stable object reference.
|
|
270
|
+
*
|
|
271
|
+
* Keyed by LOWERCASED code, and looked up the same way. Canonical casing is
|
|
272
|
+
* not what every caller has: `buildJsonLd` (`lib/json-ld.ts`) resolves its
|
|
273
|
+
* locale through `normalizeLanguageList` (`lib/locale-helpers.ts`), which
|
|
274
|
+
* lowercases every code it reads out of docs.json. An exact-key map therefore
|
|
275
|
+
* missed `pt-BR` -> `pt-br`, `zh-Hans` -> `zh-hans` and `zh-Hant` -> `zh-hant`,
|
|
276
|
+
* and those tenants got an English "Home" in the JSON-LD BreadcrumbList on
|
|
277
|
+
* every page while their visible header was correctly translated. `fr-CA` hid
|
|
278
|
+
* the bug, because `fr-ca` happens to be a `LanguageCode` in its own right.
|
|
279
|
+
*
|
|
280
|
+
* Folded here rather than at the call site because the other two callers
|
|
281
|
+
* (`Header.tsx`, `LanguageSelector.tsx`) arrive canonically cased via
|
|
282
|
+
* `extractLanguageFromPath` — so the asymmetry is invisible from any single
|
|
283
|
+
* call site, which is exactly the shape of bug that comes back.
|
|
284
|
+
*
|
|
285
|
+
* Aliases differing only in case (`fr-CA`/`fr-ca`) collapse onto one entry;
|
|
286
|
+
* they already resolve to the same `UiStrings`, so no table loses content.
|
|
287
|
+
*
|
|
288
|
+
* `...EN` is retained deliberately even though `OVERRIDES`' required-Record
|
|
289
|
+
* typing makes it currently redundant. It is the runtime backstop if that type
|
|
290
|
+
* is ever loosened or an entry arrives through a cast: with it, a missing key
|
|
291
|
+
* renders the English word; without it, the UI renders `undefined` on every
|
|
292
|
+
* page. That asymmetry is worth one spread.
|
|
293
|
+
*/
|
|
294
|
+
const MERGED: Record<string, UiStrings> = {};
|
|
295
|
+
for (const [code, overrides] of Object.entries(OVERRIDES) as [LanguageCode, UiStrings][]) {
|
|
296
|
+
MERGED[code.toLowerCase()] = { ...EN, ...overrides };
|
|
56
297
|
}
|
|
57
298
|
|
|
58
299
|
export function getUiStrings(lang: LanguageCode | undefined): UiStrings {
|
|
59
|
-
|
|
300
|
+
// `typeof` rather than a bare truthiness check: this value can originate in
|
|
301
|
+
// a customer-written docs.json, so a non-string must fall back to English
|
|
302
|
+
// rather than throw inside `.toLowerCase()` on every rendered page.
|
|
303
|
+
if (typeof lang !== 'string') return EN;
|
|
304
|
+
return MERGED[lang.toLowerCase()] ?? EN;
|
|
60
305
|
}
|