uniweb 1.22.0 → 1.22.1

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": "uniweb",
3
- "version": "1.22.0",
3
+ "version": "1.22.1",
4
4
  "description": "Create structured Vite + React sites with content/code separation",
5
5
  "type": "module",
6
6
  "bin": {
@@ -41,15 +41,15 @@
41
41
  "js-yaml": "^4.3.2",
42
42
  "prompts": "^2.4.2",
43
43
  "tar": "^7.5.21",
44
- "@uniweb/schemas": "~1.6.5",
45
- "@uniweb/content-writer": "~1.3.1",
44
+ "@uniweb/core": "~1.4.12",
46
45
  "@uniweb/semantic-parser": "~1.13.0",
47
- "@uniweb/core": "~1.4.12"
46
+ "@uniweb/schemas": "~1.6.5",
47
+ "@uniweb/content-writer": "~1.3.1"
48
48
  },
49
49
  "peerDependencies": {
50
50
  "@uniweb/semantic-parser": "~1.13.0",
51
51
  "@uniweb/content-reader": "~1.5.7",
52
- "@uniweb/build": "~1.11.0"
52
+ "@uniweb/build": "~1.11.1"
53
53
  },
54
54
  "peerDependenciesMeta": {
55
55
  "@uniweb/build": {
@@ -546,7 +546,7 @@ Optional attributes: `{size=20}`, `{color=red}`. Custom SVGs: `![Logo](./logo.sv
546
546
 
547
547
  Sizing and loading ride on the image: `{width=800 height=600 loading=lazy fit=cover position=center}`, and its credit as `{author="Jane Doe"}`. A video adds `{poster=./thumb.jpg autoplay muted loop controls}`; a `{role=pdf}` document adds `{preview=./cover.jpg author=… description=…}` and arrives in `content.documents` — `{ url, name, mime, size?, alt, caption, … }` — declare it in `content:` as `documents`. Name a video's poster: a static build makes one from the video only when none is named and ffmpeg is installed, and `uniweb publish` sends only the poster you name.
548
548
 
549
- **Where media lives.** `./x` names a file beside the page, `/x` a file in `public/`, and both reach a static build and a site published with Uniweb. Keep a page's media beside it, and keep in `public/` what needs a fixed address: the favicon, fonts, a file other sites link to. `uniweb push` uploads a file beside a page wherever the page is, in a folder `paths:` mounts too; a file outside the site and the folders it mounts is not uploaded, so put that in `public/`. A site has no `assets/` folder for media: a build stops on a `/x` only `assets/` holds.
549
+ **Where media lives.** `./x` names a file beside the page, `/x` a file in `public/`, and both reach a static build and a site published with Uniweb. Keep a page's media beside it, and keep in `public/` what needs a fixed address: the favicon, fonts, a file other sites link to. A static build copies `public/` whole and adds its own copy of each file a page names there, so a video only a page shows is in `dist/` twice from `public/` and once from beside the page. `uniweb push` uploads a file beside a page wherever the page is, in a folder `paths:` mounts too; a file outside the site and the folders it mounts is not uploaded, so put that in `public/`. A site has no `assets/` folder for media: a build stops on a `/x` only `assets/` holds.
550
550
 
551
551
  **Placement — where a block sits in a section rendered in order.** `{placement=left}` (or `right`, `wide`, `full`) on an image or a video; a table takes it on its **caption line**, the paragraph after the table, after a blank line — `: Plans and prices {placement=wide #tbl-plans}`, which also gives the table a caption and a cross-reference id. It is the author's intent, not a size: kit's `<Render>`, `<Prose>` and `<Article>` lay all four out (`data-placement`, styled by `prose-tokens.css`), and any other component ignores it. A section type says which it honours in `meta.js` — `sequence: { label, placement: true }` — and the build warns when a file asks for one its type does not offer.
552
552
 
@@ -3076,7 +3076,7 @@ These are **body only — no frontmatter**; params and config still come from th
3076
3076
 
3077
3077
  **A tagged data block translates by the shape its key declares** in the component's `meta.js` `data:` — a data schema or an inline field map: its text fields, never an enum, a URL or a `translatable: false` field. A key declared `{}` leaves its blocks to a heuristic that offers any string whose field name and value don't look structural, so a `style: display-black` naming one of your component's looks gets translated too. Declare the shape of every block a translator will see — `{ name: 'string', style: { type: 'string', enum: [...] } }`.
3078
3078
 
3079
- **An image translates by its alt text.** Words alone give it its alt text in that language and keep its file. A translation that is an image also names the file that language shows: `"2d093636": "![La superposition](/docs-media/fr/overview.png)"`. Name it with a `/` path, a file in `public/`. A caption or a video's `poster` can be given the same way. An image with no alt text has nothing to translate, so give every image one.
3079
+ **An image translates by its alt text.** Words alone give it its alt text in that language and keep its file. A translation that is an image also names the file that language shows: `"2d093636": "![La superposition](/docs-media/fr/overview.png)"`. Name it with a `/` path, a file in `public/`, and a build processes it as it does the page's own images; a `./` path has no page's folder to start from, and the build reports it. A caption or a video's `poster` can be given the same way. An image with no alt text has nothing to translate, so give every image one.
3080
3080
 
3081
3081
  **Records translate in the same `extract` run**, into their own manifest at `locales/records/manifest.json` — keyed by the RECORD, so a record translated once is found by every query that returns it. A record whose query has a data schema translates exactly the fields the schema says are text — never an enum, a URL, a date, a number, a file, a reference or a `translatable: false` field — which are the fields a push carries in each language; mark a string that is a code or a key `translatable: false` and no translator is asked for it. An excerpt the build derives is re-derived from each language's body.
3082
3082
 
@@ -69,10 +69,6 @@ import {
69
69
  isExtensionPackage,
70
70
  detectFoundationType
71
71
  } from '@uniweb/build'
72
- import {
73
- resolveDefaultLocale,
74
- normalizeLanguageList
75
- } from '@uniweb/core/locale-config'
76
72
  import { readSiteConfig } from '@uniweb/build/site'
77
73
  import { workspacePackages } from '../utils/workspace-packages.js'
78
74
 
@@ -424,34 +420,25 @@ async function loadI18nConfig(projectDir, siteConfig = null) {
424
420
  const localesDir = config.i18n?.localesDir || 'locales'
425
421
  const localesPath = join(projectDir, localesDir)
426
422
 
427
- // Resolve locales (undefined/'*' → all available, array → specific)
428
- const { resolveLocales } = await import('@uniweb/build/i18n')
429
- let locales = await resolveLocales(config.languages, localesPath)
430
-
431
- // Publish filter: build outputs are visitor artifacts. With an explicit
432
- // `publishLanguages:`, only listed locales get dist/{locale}/ content,
433
- // per-locale HTML, hreflang, and translated collections. Draft locales
434
- // stay previewable in dev, which doesn't run this path. Intersecting the
435
- // DISK-resolved list here also covers wildcard (`languages: '*'`) sites.
436
- if (config.publishLanguages != null) {
437
- const publishSet = new Set(normalizeLanguageList(config.publishLanguages))
438
- const dropped = locales.filter((l) => !publishSet.has(l))
439
- locales = locales.filter((l) => publishSet.has(l))
440
- if (dropped.length > 0) {
441
- info(
442
- `Skipping non-publishable locale(s): ${dropped.join(', ')} (not in publishLanguages)`
443
- )
444
- }
423
+ // The site's locales (undefined/'*' → all available, array → specific), with
424
+ // two filters, by the rule the bundle uses to decide whose files to process
425
+ // (`localesToBuild`):
426
+ // - Publish: build outputs are visitor artifacts. With an explicit
427
+ // `publishLanguages:`, only listed locales get dist/{locale}/ content,
428
+ // per-locale HTML, hreflang, and translated collections. Draft locales
429
+ // stay previewable in dev, which doesn't run this path. Intersecting the
430
+ // DISK-resolved list also covers wildcard (`languages: '*'`) sites.
431
+ // - ⛔ The default locale is the root tree, not `dist/<default>/`. An explicit
432
+ // `languages: [en, fr]` resolves verbatim — default included — so the DECLARED
433
+ // form (the one the contract tells authors to use) minted a duplicate copy of
434
+ // every page, while the wildcard form did not. Dropping it keeps content,
435
+ // per-locale HTML and translated records agreeing on one set.
436
+ const { localesToBuild } = await import('@uniweb/build/i18n')
437
+ const { locales, skipped, defaultLocale } = localesToBuild(config, localesPath)
438
+ if (skipped.length > 0) {
439
+ info(`Skipping non-publishable locale(s): ${skipped.join(', ')} (not in publishLanguages)`)
445
440
  }
446
441
 
447
- // ⛔ The default locale is the root tree, not `dist/<default>/`. An explicit
448
- // `languages: [en, fr]` resolves verbatim — default included — so the DECLARED
449
- // form (the one the contract tells authors to use) minted a duplicate copy of
450
- // every page, while the wildcard form did not. Dropping it here keeps content,
451
- // per-locale HTML and translated records agreeing on one set.
452
- const defaultLocale = resolveDefaultLocale(config)
453
- locales = locales.filter((l) => l !== defaultLocale)
454
-
455
442
  if (locales.length === 0) return null
456
443
 
457
444
  return {
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "generatedAt": "2026-10-29T01:09:12.877Z",
3
+ "generatedAt": "2026-10-29T02:26:03.448Z",
4
4
  "packages": {
5
5
  "@uniweb/api": {
6
6
  "version": "1.6.5"
7
7
  },
8
8
  "@uniweb/build": {
9
- "version": "1.11.0"
9
+ "version": "1.11.1"
10
10
  },
11
11
  "@uniweb/content-reader": {
12
12
  "version": "1.5.7"