blume 1.5.2 → 1.6.0
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/CHANGELOG.md +85 -0
- package/dist/cli/index.js +3639 -1377
- package/dist/cli/index.js.map +103 -91
- package/dist/types/ai/component-markdown.d.ts +79 -0
- package/dist/types/components/layout/nav-utils.d.ts +60 -0
- package/dist/types/core/base-path.d.ts +9 -0
- package/dist/types/core/config-input.d.ts +206 -4
- package/dist/types/core/config.d.ts +6 -4
- package/dist/types/core/data.d.ts +23 -1
- package/dist/types/core/github.d.ts +35 -0
- package/dist/types/core/i18n-ui.d.ts +8 -0
- package/dist/types/core/navigation.d.ts +69 -0
- package/dist/types/core/schema.d.ts +117 -1
- package/dist/types/core/sources/types.d.ts +31 -6
- package/dist/types/core/types.d.ts +23 -2
- package/dist/types/markdown/features.d.ts +21 -0
- package/dist/types/openapi/references.d.ts +21 -1
- package/dist/types/seo/jsonld.d.ts +105 -0
- package/dist/types/theme/fonts.d.ts +34 -4
- package/docs/_snippets/include-demo.mdx +7 -0
- package/docs/advanced/api-reference.mdx +3 -3
- package/docs/advanced/custom-pages.mdx +1 -1
- package/docs/advanced/graphql.mdx +84 -0
- package/docs/advanced/meta.ts +8 -1
- package/docs/configuration/ai.mdx +21 -3
- package/docs/configuration/index.mdx +24 -0
- package/docs/configuration/search.mdx +13 -1
- package/docs/configuration/seo.mdx +27 -0
- package/docs/configuration/theming.mdx +17 -0
- package/docs/content/components.mdx +7 -0
- package/docs/content/includes.mdx +68 -0
- package/docs/content/meta.ts +1 -0
- package/docs/content/navigation.mdx +25 -0
- package/docs/content/sources.mdx +42 -1
- package/docs/content/syntax.mdx +69 -1
- package/docs/content/versioning.mdx +15 -9
- package/docs/reference/cli.mdx +2 -1
- package/package.json +23 -14
- package/skills/blume-migrate/SKILL.md +16 -7
- package/skills/blume-migrate/references/docusaurus.md +5 -3
- package/skills/blume-migrate/references/fumadocs.md +10 -2
- package/skills/blume-migrate/references/mintlify.md +3 -2
- package/skills/blume-migrate/references/nextra.md +2 -2
- package/skills/blume-migrate/references/starlight.md +1 -1
- package/src/ai/agent-readability.ts +2 -1
- package/src/ai/ask-data.ts +2 -1
- package/src/ai/component-markdown.ts +199 -36
- package/src/ai/llms.ts +93 -6
- package/src/ai/markdown.ts +2 -2
- package/src/ai/mcp/discovery.ts +10 -2
- package/src/ai/mcp/server.ts +74 -2
- package/src/astro/generate.ts +183 -116
- package/src/astro/include-hmr.ts +81 -0
- package/src/astro/include-refresh.ts +0 -0
- package/src/astro/index.ts +3 -5
- package/src/astro/templates.ts +125 -76
- package/src/cli/commands/build.ts +84 -15
- package/src/cli/init/questions.ts +1 -0
- package/src/cli/init/scaffold.ts +27 -4
- package/src/components/colors.ts +142 -0
- package/src/components/content/Badge.astro +5 -12
- package/src/components/content/Callout.astro +19 -36
- package/src/components/content/Card.astro +15 -21
- package/src/components/content/Component.astro +10 -1
- package/src/components/content/GithubInfo.astro +28 -9
- package/src/components/content/Tabs.astro +27 -5
- package/src/components/content/github-info.ts +20 -5
- package/src/components/dropdown-dismiss.ts +122 -0
- package/src/components/layout/Fonts.astro +15 -8
- package/src/components/layout/Header.astro +44 -0
- package/src/components/layout/LanguageSwitcher.astro +9 -1
- package/src/components/layout/NavSelector.astro +12 -3
- package/src/components/layout/NavTree.astro +6 -18
- package/src/components/layout/PageActions.astro +29 -8
- package/src/components/layout/PageLayout.astro +10 -1
- package/src/components/layout/ReferenceLayout.astro +6 -1
- package/src/components/layout/RootLayout.astro +46 -15
- package/src/components/layout/Search.astro +36 -4
- package/src/components/layout/TableOfContents.astro +8 -2
- package/src/components/layout/head-scripts.ts +53 -1
- package/src/components/openapi/ApiOverview.astro +13 -3
- package/src/components/openapi/AsyncApiOperation.astro +7 -14
- package/src/components/openapi/GraphqlChip.astro +33 -0
- package/src/components/openapi/GraphqlFieldsTable.astro +111 -0
- package/src/components/openapi/GraphqlOperation.astro +186 -0
- package/src/components/openapi/GraphqlType.astro +154 -0
- package/src/components/openapi/MethodBadge.astro +3 -14
- package/src/components/openapi/Operation.astro +12 -5
- package/src/components/openapi/OperationPanel.astro +43 -0
- package/src/components/openapi/RequestPanel.astro +5 -10
- package/src/components/openapi/Responses.astro +1 -16
- package/src/components/openapi/graphql-helpers.ts +466 -0
- package/src/components/openapi/playground-client.ts +15 -0
- package/src/components/openapi/sample-panels.ts +45 -0
- package/src/components/openapi/snippets.ts +13 -35
- package/src/core/base-path.ts +11 -0
- package/src/core/config-input.ts +209 -2
- package/src/core/config.ts +6 -4
- package/src/core/content-assets.ts +15 -4
- package/src/core/data.ts +18 -2
- package/src/core/diagnostics.ts +8 -0
- package/src/core/frontmatter.ts +20 -8
- package/src/core/github.ts +71 -0
- package/src/core/graph.ts +22 -8
- package/src/core/heading-markers.ts +96 -0
- package/src/core/i18n-ui.ts +11 -0
- package/src/core/includes.ts +632 -0
- package/src/core/last-modified.ts +36 -11
- package/src/core/links.ts +79 -13
- package/src/core/meta.ts +2 -1
- package/src/core/nav-diagnostics.ts +11 -2
- package/src/core/navigation.ts +27 -6
- package/src/core/project-graph.ts +61 -9
- package/src/core/schema.ts +226 -35
- package/src/core/server-features.ts +5 -9
- package/src/core/sources/github-releases.ts +2 -2
- package/src/core/sources/normalize.ts +502 -115
- package/src/core/sources/notion.ts +43 -8
- package/src/core/sources/obsidian.ts +1038 -0
- package/src/core/sources/read.ts +36 -1
- package/src/core/sources/resolve.ts +34 -1
- package/src/core/sources/types.ts +28 -6
- package/src/core/sources/watch.ts +12 -8
- package/src/core/tsconfig-aliases.ts +48 -35
- package/src/core/types.ts +25 -2
- package/src/core/ui-packs/ar.ts +1 -0
- package/src/core/ui-packs/bg.ts +2 -0
- package/src/core/ui-packs/bn.ts +1 -0
- package/src/core/ui-packs/ca.ts +2 -0
- package/src/core/ui-packs/cs.ts +1 -0
- package/src/core/ui-packs/da.ts +1 -0
- package/src/core/ui-packs/de.ts +2 -0
- package/src/core/ui-packs/el.ts +2 -0
- package/src/core/ui-packs/es.ts +2 -0
- package/src/core/ui-packs/fa.ts +1 -0
- package/src/core/ui-packs/fi.ts +1 -0
- package/src/core/ui-packs/fr.ts +2 -0
- package/src/core/ui-packs/he.ts +1 -0
- package/src/core/ui-packs/hi.ts +1 -0
- package/src/core/ui-packs/hr.ts +2 -0
- package/src/core/ui-packs/hu.ts +2 -0
- package/src/core/ui-packs/id.ts +2 -0
- package/src/core/ui-packs/it.ts +1 -0
- package/src/core/ui-packs/ja.ts +2 -0
- package/src/core/ui-packs/ko.ts +2 -0
- package/src/core/ui-packs/nl.ts +2 -0
- package/src/core/ui-packs/no.ts +2 -0
- package/src/core/ui-packs/pl.ts +2 -0
- package/src/core/ui-packs/pt-br.ts +2 -0
- package/src/core/ui-packs/pt.ts +2 -0
- package/src/core/ui-packs/ro.ts +2 -0
- package/src/core/ui-packs/ru.ts +2 -0
- package/src/core/ui-packs/sk.ts +1 -0
- package/src/core/ui-packs/sr.ts +1 -0
- package/src/core/ui-packs/sv.ts +2 -0
- package/src/core/ui-packs/th.ts +1 -0
- package/src/core/ui-packs/tr.ts +2 -0
- package/src/core/ui-packs/uk.ts +2 -0
- package/src/core/ui-packs/vi.ts +1 -0
- package/src/core/ui-packs/zh-tw.ts +1 -0
- package/src/core/ui-packs/zh.ts +1 -0
- package/src/core/version-cut.ts +21 -3
- package/src/core/yaml.ts +26 -0
- package/src/deploy/function-bundle.ts +251 -0
- package/src/eval/schema.ts +3 -1
- package/src/markdown/code-title.ts +22 -16
- package/src/markdown/features.ts +21 -0
- package/src/markdown/fence-meta.ts +50 -0
- package/src/markdown/heading-anchors.ts +198 -37
- package/src/markdown/include.ts +247 -0
- package/src/markdown/index.ts +43 -34
- package/src/markdown/language-icon.ts +2 -2
- package/src/markdown/mdast.ts +7 -3
- package/src/markdown/ts2js.ts +264 -0
- package/src/openapi/asyncapi.ts +4 -1
- package/src/openapi/graphql-build.ts +293 -0
- package/src/openapi/graphql.ts +212 -0
- package/src/openapi/model.ts +38 -5
- package/src/openapi/parse.ts +34 -0
- package/src/openapi/proxy.ts +30 -5
- package/src/openapi/references.ts +89 -13
- package/src/openapi/render-mdx.ts +48 -8
- package/src/openapi/scalar.ts +5 -12
- package/src/openapi/source.ts +91 -23
- package/src/registry/eject.ts +11 -0
- package/src/search/documents.ts +229 -37
- package/src/search/orama-index.ts +9 -5
- package/src/seo/jsonld.ts +293 -51
- package/src/theme/code-block-padding.ts +16 -0
- package/src/theme/entry.ts +65 -11
- package/src/theme/fonts.ts +189 -16
- package/src/translate/prompts.ts +2 -0
- package/src/translate/run.ts +7 -0
- package/src/translate/work-list.ts +0 -0
package/src/theme/fonts.ts
CHANGED
|
@@ -28,6 +28,11 @@ export interface RemoteFontConfig {
|
|
|
28
28
|
provider?: RemoteFontProvider;
|
|
29
29
|
/** Weights (or variable ranges like `"100..900"`) to load. Defaults to `[400, 500, 600, 700]`. */
|
|
30
30
|
weights?: (number | string)[];
|
|
31
|
+
/**
|
|
32
|
+
* Character subsets to load (`"latin"`, `"vietnamese"`, `"cyrillic"`, …).
|
|
33
|
+
* Defaults to `latin` plus whatever the site's configured locales need.
|
|
34
|
+
*/
|
|
35
|
+
subsets?: string[];
|
|
31
36
|
/** Fallback stack category. Defaults to `"mono"` for the mono role, `"sans"` otherwise. */
|
|
32
37
|
fallback?: FontCategory;
|
|
33
38
|
}
|
|
@@ -72,6 +77,7 @@ export type FontEntry =
|
|
|
72
77
|
cssVariable: string;
|
|
73
78
|
fallbacks: string[];
|
|
74
79
|
name: string;
|
|
80
|
+
subsets: string[];
|
|
75
81
|
weights: (number | string)[];
|
|
76
82
|
}
|
|
77
83
|
| {
|
|
@@ -205,6 +211,129 @@ export const isFontSlug = (value: string): value is FontSlug =>
|
|
|
205
211
|
/** Weights loaded for a remote family when the config does not pin them. */
|
|
206
212
|
const DEFAULT_REMOTE_WEIGHTS: (number | string)[] = [400, 500, 600, 700];
|
|
207
213
|
|
|
214
|
+
/**
|
|
215
|
+
* The subsets a language needs beyond `latin`, keyed by BCP 47 language
|
|
216
|
+
* subtag. Names are Google Fonts subsets (Bunny and Fontsource use the same
|
|
217
|
+
* ones). Languages whose alphabet fits Latin-1 — English, French, German,
|
|
218
|
+
* Spanish, … — need only `latin` and are absent. Keep keys alphabetical.
|
|
219
|
+
*/
|
|
220
|
+
const LOCALE_SUBSETS = {
|
|
221
|
+
az: ["latin-ext"],
|
|
222
|
+
ba: ["cyrillic", "cyrillic-ext"],
|
|
223
|
+
be: ["cyrillic"],
|
|
224
|
+
bg: ["cyrillic"],
|
|
225
|
+
bs: ["latin-ext"],
|
|
226
|
+
cs: ["latin-ext"],
|
|
227
|
+
cv: ["cyrillic", "cyrillic-ext"],
|
|
228
|
+
cy: ["latin-ext"],
|
|
229
|
+
el: ["greek"],
|
|
230
|
+
eo: ["latin-ext"],
|
|
231
|
+
et: ["latin-ext"],
|
|
232
|
+
ha: ["latin-ext"],
|
|
233
|
+
hr: ["latin-ext"],
|
|
234
|
+
hu: ["latin-ext"],
|
|
235
|
+
ig: ["latin-ext"],
|
|
236
|
+
kk: ["cyrillic", "cyrillic-ext"],
|
|
237
|
+
ku: ["latin-ext"],
|
|
238
|
+
ky: ["cyrillic", "cyrillic-ext"],
|
|
239
|
+
lt: ["latin-ext"],
|
|
240
|
+
lv: ["latin-ext"],
|
|
241
|
+
mk: ["cyrillic"],
|
|
242
|
+
mn: ["cyrillic", "cyrillic-ext"],
|
|
243
|
+
mt: ["latin-ext"],
|
|
244
|
+
pl: ["latin-ext"],
|
|
245
|
+
ro: ["latin-ext"],
|
|
246
|
+
ru: ["cyrillic"],
|
|
247
|
+
sk: ["latin-ext"],
|
|
248
|
+
sl: ["latin-ext"],
|
|
249
|
+
sr: ["cyrillic", "latin-ext"],
|
|
250
|
+
tg: ["cyrillic", "cyrillic-ext"],
|
|
251
|
+
tk: ["latin-ext"],
|
|
252
|
+
tr: ["latin-ext"],
|
|
253
|
+
tt: ["cyrillic", "cyrillic-ext"],
|
|
254
|
+
uk: ["cyrillic"],
|
|
255
|
+
uz: ["cyrillic", "latin-ext"],
|
|
256
|
+
vi: ["vietnamese"],
|
|
257
|
+
yo: ["latin-ext"],
|
|
258
|
+
} satisfies Record<string, string[]>;
|
|
259
|
+
|
|
260
|
+
/** Type guard: does `language` have an entry in the subset table? */
|
|
261
|
+
const isSubsetLanguage = (
|
|
262
|
+
language: string
|
|
263
|
+
): language is keyof typeof LOCALE_SUBSETS =>
|
|
264
|
+
Object.hasOwn(LOCALE_SUBSETS, language);
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Subsets a script subtag (`sr-Latn`, `az-Cyrl`) asks for on its own, so a
|
|
268
|
+
* locale written in a script its language doesn't default to still loads it.
|
|
269
|
+
*/
|
|
270
|
+
const SCRIPT_SUBSETS = {
|
|
271
|
+
cyrl: ["cyrillic"],
|
|
272
|
+
latn: ["latin-ext"],
|
|
273
|
+
} satisfies Record<string, string[]>;
|
|
274
|
+
|
|
275
|
+
/** Type guard: does `script` have an entry in the script table? */
|
|
276
|
+
const isSubsetScript = (
|
|
277
|
+
script: string
|
|
278
|
+
): script is keyof typeof SCRIPT_SUBSETS =>
|
|
279
|
+
Object.hasOwn(SCRIPT_SUBSETS, script);
|
|
280
|
+
|
|
281
|
+
/** Google's listing order; keeps generated configs stable across runs. */
|
|
282
|
+
const SUBSET_ORDER = [
|
|
283
|
+
"latin",
|
|
284
|
+
"latin-ext",
|
|
285
|
+
"vietnamese",
|
|
286
|
+
"cyrillic",
|
|
287
|
+
"cyrillic-ext",
|
|
288
|
+
"greek",
|
|
289
|
+
"greek-ext",
|
|
290
|
+
];
|
|
291
|
+
|
|
292
|
+
/** The shape of a config's `i18n` block the font builders read. */
|
|
293
|
+
export interface FontLocaleSource {
|
|
294
|
+
locales: { code: string }[];
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/** The locale codes an optional `i18n` block declares (none when absent). */
|
|
298
|
+
export const fontLocaleCodes = (i18n: FontLocaleSource | undefined): string[] =>
|
|
299
|
+
i18n?.locales.map((locale) => locale.code) ?? [];
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* The subsets the site's locales need: `latin` always, plus each locale's
|
|
303
|
+
* script. A site with no `i18n` block (or only Latin-1 languages) gets just
|
|
304
|
+
* `latin` — Astro's own default — so its CSS and preloads don't change.
|
|
305
|
+
*/
|
|
306
|
+
export const localeFontSubsets = (locales: string[]): string[] => {
|
|
307
|
+
const wanted = new Set(["latin"]);
|
|
308
|
+
for (const locale of locales) {
|
|
309
|
+
const [language = "", ...subtags] = locale.toLowerCase().split("-");
|
|
310
|
+
if (isSubsetLanguage(language)) {
|
|
311
|
+
for (const subset of LOCALE_SUBSETS[language]) {
|
|
312
|
+
wanted.add(subset);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
for (const subtag of subtags) {
|
|
316
|
+
if (isSubsetScript(subtag)) {
|
|
317
|
+
for (const subset of SCRIPT_SUBSETS[subtag]) {
|
|
318
|
+
wanted.add(subset);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
return SUBSET_ORDER.filter((subset) => wanted.has(subset));
|
|
324
|
+
};
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Providers whose faces carry subset metadata, so `<Font preload>` can be
|
|
328
|
+
* filtered by subset. Fontshare serves whole files with no subset split; a
|
|
329
|
+
* subset filter there would match nothing and drop every preload.
|
|
330
|
+
*/
|
|
331
|
+
const SUBSET_PROVIDERS = new Set<RemoteFontProvider>([
|
|
332
|
+
"google",
|
|
333
|
+
"bunny",
|
|
334
|
+
"fontsource",
|
|
335
|
+
]);
|
|
336
|
+
|
|
208
337
|
/** Kebab-case a family name into a slug (`"Noto Sans JP"` -> `"noto-sans-jp"`). */
|
|
209
338
|
export const slugifyFontName = (name: string): string =>
|
|
210
339
|
name
|
|
@@ -227,10 +356,15 @@ const slotCategory = (slot: FontSlot): FontCategory =>
|
|
|
227
356
|
const isSlugValue = (value: FontValue): value is string =>
|
|
228
357
|
typeof value === "string";
|
|
229
358
|
|
|
230
|
-
/**
|
|
359
|
+
/**
|
|
360
|
+
* A slot value normalized into an entry, or null for an unknown slug string.
|
|
361
|
+
* `subsets` is the locale-derived default a remote family loads when the
|
|
362
|
+
* config does not pin its own.
|
|
363
|
+
*/
|
|
231
364
|
const resolveFontValue = (
|
|
232
365
|
slot: FontSlot,
|
|
233
|
-
value: FontValue
|
|
366
|
+
value: FontValue,
|
|
367
|
+
subsets: string[]
|
|
234
368
|
): FontEntry | null => {
|
|
235
369
|
if (isSlugValue(value)) {
|
|
236
370
|
if (!isFontSlug(value)) {
|
|
@@ -243,6 +377,7 @@ const resolveFontValue = (
|
|
|
243
377
|
kind: "remote",
|
|
244
378
|
name: def.family,
|
|
245
379
|
provider: "google",
|
|
380
|
+
subsets,
|
|
246
381
|
weights: def.weights,
|
|
247
382
|
};
|
|
248
383
|
}
|
|
@@ -263,6 +398,7 @@ const resolveFontValue = (
|
|
|
263
398
|
kind: "remote",
|
|
264
399
|
name: value.name,
|
|
265
400
|
provider: value.provider ?? "google",
|
|
401
|
+
subsets: value.subsets ?? subsets,
|
|
266
402
|
weights: value.weights ?? DEFAULT_REMOTE_WEIGHTS,
|
|
267
403
|
};
|
|
268
404
|
};
|
|
@@ -282,6 +418,7 @@ const mergeFontEntries = (current: FontEntry, next: FontEntry): FontEntry => {
|
|
|
282
418
|
) {
|
|
283
419
|
return {
|
|
284
420
|
...current,
|
|
421
|
+
subsets: [...new Set([...current.subsets, ...next.subsets])],
|
|
285
422
|
weights: [...new Set([...current.weights, ...next.weights])],
|
|
286
423
|
};
|
|
287
424
|
}
|
|
@@ -298,18 +435,26 @@ const mergeFontEntries = (current: FontEntry, next: FontEntry): FontEntry => {
|
|
|
298
435
|
);
|
|
299
436
|
};
|
|
300
437
|
|
|
301
|
-
/**
|
|
302
|
-
|
|
438
|
+
/**
|
|
439
|
+
* The unique Astro `fonts:` entries for the configured roles (deduped).
|
|
440
|
+
* `locales` are the site's configured locale codes; they pick the subsets a
|
|
441
|
+
* remote family loads unless its config pins `subsets` itself.
|
|
442
|
+
*/
|
|
443
|
+
export const buildFontEntries = (
|
|
444
|
+
fonts: FontsConfig,
|
|
445
|
+
locales: string[] = []
|
|
446
|
+
): FontEntry[] => {
|
|
303
447
|
if (!fonts) {
|
|
304
448
|
return [];
|
|
305
449
|
}
|
|
450
|
+
const subsets = localeFontSubsets(locales);
|
|
306
451
|
const entries = new Map<string, FontEntry>();
|
|
307
452
|
for (const slot of SLOTS) {
|
|
308
453
|
const value = fonts[slot];
|
|
309
454
|
if (value === undefined) {
|
|
310
455
|
continue;
|
|
311
456
|
}
|
|
312
|
-
const entry = resolveFontValue(slot, value);
|
|
457
|
+
const entry = resolveFontValue(slot, value, subsets);
|
|
313
458
|
if (!entry) {
|
|
314
459
|
continue;
|
|
315
460
|
}
|
|
@@ -365,9 +510,15 @@ const PRELOAD_WEIGHTS = {
|
|
|
365
510
|
mono: [400],
|
|
366
511
|
} satisfies Record<FontSlot, number[]>;
|
|
367
512
|
|
|
368
|
-
/**
|
|
513
|
+
/**
|
|
514
|
+
* One `<Font>` render in the head: its CSS variable + the weights (and, for
|
|
515
|
+
* providers that split faces by subset, the subsets) to preload. Local and
|
|
516
|
+
* Fontshare faces carry no subset, so those entries leave `preloadSubsets`
|
|
517
|
+
* unset and preload by weight alone.
|
|
518
|
+
*/
|
|
369
519
|
export interface FontHead {
|
|
370
520
|
cssVariable: string;
|
|
521
|
+
preloadSubsets?: string[];
|
|
371
522
|
preloadWeights: number[];
|
|
372
523
|
}
|
|
373
524
|
|
|
@@ -402,28 +553,50 @@ const preloadWeightsFor = (slot: FontSlot, entry: FontEntry): number[] => {
|
|
|
402
553
|
* by CSS variable with preload weights unioned across the roles that share a
|
|
403
554
|
* family (so `display` and `body` both set to Inter preload 400/500/600 once).
|
|
404
555
|
*/
|
|
405
|
-
export const configuredFonts = (
|
|
556
|
+
export const configuredFonts = (
|
|
557
|
+
fonts: FontsConfig,
|
|
558
|
+
locales: string[] = []
|
|
559
|
+
): FontHead[] => {
|
|
406
560
|
if (!fonts) {
|
|
407
561
|
return [];
|
|
408
562
|
}
|
|
409
|
-
const
|
|
563
|
+
const defaultSubsets = localeFontSubsets(locales);
|
|
564
|
+
const heads = new Map<
|
|
565
|
+
string,
|
|
566
|
+
{ subsets: Set<string> | null; weights: Set<number> }
|
|
567
|
+
>();
|
|
410
568
|
for (const slot of SLOTS) {
|
|
411
569
|
const value = fonts[slot];
|
|
412
570
|
if (value === undefined) {
|
|
413
571
|
continue;
|
|
414
572
|
}
|
|
415
|
-
const entry = resolveFontValue(slot, value);
|
|
573
|
+
const entry = resolveFontValue(slot, value, defaultSubsets);
|
|
416
574
|
if (!entry) {
|
|
417
575
|
continue;
|
|
418
576
|
}
|
|
419
|
-
const
|
|
577
|
+
const head = heads.get(entry.cssVariable) ?? {
|
|
578
|
+
subsets: null,
|
|
579
|
+
weights: new Set<number>(),
|
|
580
|
+
};
|
|
420
581
|
for (const weight of preloadWeightsFor(slot, entry)) {
|
|
421
|
-
weights.add(weight);
|
|
582
|
+
head.weights.add(weight);
|
|
422
583
|
}
|
|
423
|
-
|
|
584
|
+
if (entry.kind === "remote" && SUBSET_PROVIDERS.has(entry.provider)) {
|
|
585
|
+
head.subsets ??= new Set();
|
|
586
|
+
for (const subset of entry.subsets) {
|
|
587
|
+
head.subsets.add(subset);
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
heads.set(entry.cssVariable, head);
|
|
424
591
|
}
|
|
425
|
-
return [...heads].map(([cssVariable,
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
592
|
+
return [...heads].map(([cssVariable, head]) => {
|
|
593
|
+
const font: FontHead = {
|
|
594
|
+
cssVariable,
|
|
595
|
+
preloadWeights: [...head.weights].toSorted((a, b) => a - b),
|
|
596
|
+
};
|
|
597
|
+
if (head.subsets) {
|
|
598
|
+
font.preloadSubsets = [...head.subsets];
|
|
599
|
+
}
|
|
600
|
+
return font;
|
|
601
|
+
});
|
|
429
602
|
};
|
package/src/translate/prompts.ts
CHANGED
|
@@ -65,6 +65,8 @@ Rules:
|
|
|
65
65
|
- Translate the prose: headings, paragraphs, list items, table cells, admonitions, and image alt text.
|
|
66
66
|
- In the YAML frontmatter, translate ONLY the values of these keys: ${KEY_LIST}. Copy every other frontmatter key and value exactly as written.
|
|
67
67
|
- Never translate or alter: code blocks, inline code, import/export statements, JSX/MDX component names and their attributes, URLs, link targets, HTML tags, or frontmatter keys.
|
|
68
|
+
- A heading may end with anchor markers: \`[#some-id]\`, \`{#some-id}\` (also written \`\\{#some-id\\}\`), \`[!toc]\`, or \`[toc]\`. Copy every marker exactly as written, in the same position at the end of the translated heading — never translate, reorder, or drop a marker, and never change the id inside \`[#...]\` or \`{#...}\` (anchors must stay identical across languages).
|
|
69
|
+
|
|
68
70
|
- Preserve the document structure exactly: the same headings, the same lists and tables, and the same number of code fences.${styleRule}${previousRule}
|
|
69
71
|
- Output ONLY the complete translated file. Do not wrap it in a code fence. Do not add commentary before or after it.
|
|
70
72
|
${previousSection}
|
package/src/translate/run.ts
CHANGED
|
@@ -130,6 +130,13 @@ const runPageItem = async (
|
|
|
130
130
|
});
|
|
131
131
|
|
|
132
132
|
const sourceText = await readFile(item.sourcePath, "utf-8");
|
|
133
|
+
if (item.verbatim) {
|
|
134
|
+
// A non-markdown include partial (code embed) has no prose to translate;
|
|
135
|
+
// it's copied unchanged so the locale tree's relative includes resolve.
|
|
136
|
+
await writeTextAtomic(item.targetPath, sourceText);
|
|
137
|
+
stampLedger(ledger, item.sourceRel, item.locale, hashSource(sourceText));
|
|
138
|
+
return done("translated");
|
|
139
|
+
}
|
|
133
140
|
// SAFETY: `targets` maps every configured locale, and work items only carry
|
|
134
141
|
// configured locale codes.
|
|
135
142
|
const target = context.targets.get(item.locale) as LocaleConfig;
|
|
Binary file
|