uniweb 1.7.2 → 1.7.4
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 +6 -6
- package/src/commands/i18n.js +56 -49
- package/src/framework-index.json +2 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "uniweb",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.4",
|
|
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.1.0",
|
|
42
42
|
"prompts": "^2.4.2",
|
|
43
43
|
"tar": "^7.0.0",
|
|
44
|
-
"@uniweb/content-writer": "~1.1.2",
|
|
45
44
|
"@uniweb/core": "~1.2.2",
|
|
46
|
-
"@uniweb/
|
|
47
|
-
"@uniweb/schemas": "~1.3.1"
|
|
45
|
+
"@uniweb/content-writer": "~1.1.2",
|
|
46
|
+
"@uniweb/schemas": "~1.3.1",
|
|
47
|
+
"@uniweb/semantic-parser": "~1.8.1"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
|
-
"@uniweb/
|
|
50
|
+
"@uniweb/semantic-parser": "~1.8.1",
|
|
51
51
|
"@uniweb/content-reader": "~1.4.0",
|
|
52
|
-
"@uniweb/
|
|
52
|
+
"@uniweb/build": "~1.3.9"
|
|
53
53
|
},
|
|
54
54
|
"peerDependenciesMeta": {
|
|
55
55
|
"@uniweb/build": {
|
package/src/commands/i18n.js
CHANGED
|
@@ -236,6 +236,33 @@ async function loadSiteConfig(siteRoot) {
|
|
|
236
236
|
}
|
|
237
237
|
}
|
|
238
238
|
|
|
239
|
+
/**
|
|
240
|
+
* The site's content as its source says it now — what the free-form commands (`status
|
|
241
|
+
* --freeform`, `init-freeform`, `update-hash`, `prune --freeform`) judge a translation by,
|
|
242
|
+
* read as `extract` reads the strings it offers. No build needed.
|
|
243
|
+
*
|
|
244
|
+
* ⛔ Not `dist/site-content.json`, which they read until 2026-10-17. A prerendered build that
|
|
245
|
+
* splits its content rewrites that file without page sections, so `status --freeform`
|
|
246
|
+
* compared no page translation and counted each one up to date, `update-hash --all-stale`
|
|
247
|
+
* found nothing stale and `init-freeform` found no section. A build also leaves out `hidden:`
|
|
248
|
+
* pages, so `prune --freeform` deleted their translations. And the file says what the source
|
|
249
|
+
* said at the last build.
|
|
250
|
+
*
|
|
251
|
+
* @param {string} siteRoot
|
|
252
|
+
* @returns {Promise<Object>} the collected site content
|
|
253
|
+
*/
|
|
254
|
+
async function collectSourceContent(siteRoot) {
|
|
255
|
+
const { collectSiteContent } = await import('@uniweb/build/site')
|
|
256
|
+
// The collector reports progress on stdout; send it to stderr, so `--json` prints JSON alone.
|
|
257
|
+
const origConsoleLog = console.log
|
|
258
|
+
console.log = (...a) => process.stderr.write(a.join(' ') + '\n')
|
|
259
|
+
try {
|
|
260
|
+
return await collectSiteContent(siteRoot)
|
|
261
|
+
} finally {
|
|
262
|
+
console.log = origConsoleLog
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
239
266
|
/**
|
|
240
267
|
* Extract command - extract translatable strings from site content
|
|
241
268
|
*/
|
|
@@ -650,15 +677,7 @@ async function runStatusFreeform(siteRoot, config, locale, options = {}) {
|
|
|
650
677
|
}
|
|
651
678
|
|
|
652
679
|
try {
|
|
653
|
-
|
|
654
|
-
const siteContentPath = join(siteRoot, 'dist', 'site-content.json')
|
|
655
|
-
if (!existsSync(siteContentPath)) {
|
|
656
|
-
error('Site content not found. Run "uniweb build" first.')
|
|
657
|
-
process.exit(1)
|
|
658
|
-
}
|
|
659
|
-
|
|
660
|
-
const siteContentRaw = await readFile(siteContentPath, 'utf-8')
|
|
661
|
-
const siteContent = JSON.parse(siteContentRaw)
|
|
680
|
+
const siteContent = await collectSourceContent(siteRoot)
|
|
662
681
|
|
|
663
682
|
const {
|
|
664
683
|
discoverFreeformTranslations,
|
|
@@ -667,9 +686,10 @@ async function runStatusFreeform(siteRoot, config, locale, options = {}) {
|
|
|
667
686
|
getOrphanedTranslations
|
|
668
687
|
} = await import('@uniweb/build/i18n')
|
|
669
688
|
|
|
670
|
-
// What the
|
|
689
|
+
// What the site's content says about its free-form translations — every path the
|
|
671
690
|
// renderer reads one from, with its source's hash. The build's own check uses this
|
|
672
|
-
// index, so the two
|
|
691
|
+
// index too, so the two judge by one rule; they differ only where the build leaves
|
|
692
|
+
// content out — a `hidden:` page or section, which the build calls orphaned.
|
|
673
693
|
const { validPaths, sourceHashes, canJudge } = freeformSourceIndex(siteContent)
|
|
674
694
|
|
|
675
695
|
// Find all locales
|
|
@@ -692,15 +712,17 @@ async function runStatusFreeform(siteRoot, config, locale, options = {}) {
|
|
|
692
712
|
]
|
|
693
713
|
|
|
694
714
|
// Check staleness. Orphaned only when the content can judge it — never a record's
|
|
695
|
-
// translation, nor one for a page whose sections the
|
|
715
|
+
// translation, nor one for a page whose sections the content does not carry.
|
|
696
716
|
const stale = await getStaleTranslations(localeDir, sourceHashes)
|
|
697
717
|
const orphaned = (await getOrphanedTranslations(localeDir, validPaths)).filter((o) => canJudge(o.path))
|
|
698
718
|
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
)
|
|
719
|
+
// ⭐ Up to date only where a source was found to compare with. A translation with none
|
|
720
|
+
// — a record's, whose record the site content does not hold — is NOT CHECKED, and said
|
|
721
|
+
// so. ⛔ Until 2026-10-17 it was counted up to date, like every page translation of a
|
|
722
|
+
// prerendered site while this read the build's split content.
|
|
723
|
+
const judged = (p) => stale.some((s) => s.path === p) || orphaned.some((o) => o.path === p)
|
|
724
|
+
const upToDate = allPaths.filter((p) => !judged(p) && sourceHashes[p])
|
|
725
|
+
const notChecked = allPaths.filter((p) => !judged(p) && !sourceHashes[p])
|
|
704
726
|
|
|
705
727
|
results[loc] = {
|
|
706
728
|
total: allPaths.length,
|
|
@@ -712,7 +734,8 @@ async function runStatusFreeform(siteRoot, config, locale, options = {}) {
|
|
|
712
734
|
orphaned: orphaned.map((o) => ({
|
|
713
735
|
path: o.path,
|
|
714
736
|
recordedDate: o.recordedDate
|
|
715
|
-
}))
|
|
737
|
+
})),
|
|
738
|
+
notChecked: notChecked.map((path) => ({ path }))
|
|
716
739
|
}
|
|
717
740
|
}
|
|
718
741
|
|
|
@@ -748,8 +771,15 @@ async function runStatusFreeform(siteRoot, config, locale, options = {}) {
|
|
|
748
771
|
}
|
|
749
772
|
}
|
|
750
773
|
|
|
774
|
+
if (info.notChecked.length > 0) {
|
|
775
|
+
log(` ${colors.dim}Not checked (no source to compare with):${colors.reset}`)
|
|
776
|
+
for (const item of info.notChecked) {
|
|
777
|
+
log(` ${colors.dim}· ${item.path}${colors.reset}`)
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
|
|
751
781
|
log(
|
|
752
|
-
` ${colors.dim}Summary: ${info.upToDate} up to date, ${info.stale.length} stale, ${info.orphaned.length} orphaned${colors.reset}`
|
|
782
|
+
` ${colors.dim}Summary: ${info.upToDate} up to date, ${info.stale.length} stale, ${info.orphaned.length} orphaned${info.notChecked.length > 0 ? `, ${info.notChecked.length} not checked` : ''}${colors.reset}`
|
|
753
783
|
)
|
|
754
784
|
log('')
|
|
755
785
|
}
|
|
@@ -1077,16 +1107,6 @@ async function runInitFreeform(siteRoot, config, args) {
|
|
|
1077
1107
|
}
|
|
1078
1108
|
|
|
1079
1109
|
try {
|
|
1080
|
-
// Load site content to get source
|
|
1081
|
-
const siteContentPath = join(siteRoot, 'dist', 'site-content.json')
|
|
1082
|
-
if (!existsSync(siteContentPath)) {
|
|
1083
|
-
error('Site content not found. Run "uniweb build" first.')
|
|
1084
|
-
process.exit(1)
|
|
1085
|
-
}
|
|
1086
|
-
|
|
1087
|
-
const siteContentRaw = await readFile(siteContentPath, 'utf-8')
|
|
1088
|
-
const siteContent = JSON.parse(siteContentRaw)
|
|
1089
|
-
|
|
1090
1110
|
// Find the source content
|
|
1091
1111
|
let sourceContent = null
|
|
1092
1112
|
let sourceHash = null
|
|
@@ -1095,6 +1115,7 @@ async function runInitFreeform(siteRoot, config, args) {
|
|
|
1095
1115
|
// Find section in pages
|
|
1096
1116
|
const isPageId = pathType.startsWith('page-ids/')
|
|
1097
1117
|
const pageIdentifier = pathType.replace(/^(pages|page-ids)\//, '')
|
|
1118
|
+
const siteContent = await collectSourceContent(siteRoot)
|
|
1098
1119
|
|
|
1099
1120
|
for (const page of siteContent.pages || []) {
|
|
1100
1121
|
const match = isPageId
|
|
@@ -1273,15 +1294,7 @@ async function runUpdateHash(siteRoot, config, args) {
|
|
|
1273
1294
|
}
|
|
1274
1295
|
|
|
1275
1296
|
try {
|
|
1276
|
-
|
|
1277
|
-
const siteContentPath = join(siteRoot, 'dist', 'site-content.json')
|
|
1278
|
-
if (!existsSync(siteContentPath)) {
|
|
1279
|
-
error('Site content not found. Run "uniweb build" first.')
|
|
1280
|
-
process.exit(1)
|
|
1281
|
-
}
|
|
1282
|
-
|
|
1283
|
-
const siteContentRaw = await readFile(siteContentPath, 'utf-8')
|
|
1284
|
-
const siteContent = JSON.parse(siteContentRaw)
|
|
1297
|
+
const siteContent = await collectSourceContent(siteRoot)
|
|
1285
1298
|
|
|
1286
1299
|
const {
|
|
1287
1300
|
updateHash,
|
|
@@ -1510,15 +1523,7 @@ async function runPrune(siteRoot, config, args) {
|
|
|
1510
1523
|
)
|
|
1511
1524
|
|
|
1512
1525
|
try {
|
|
1513
|
-
|
|
1514
|
-
const siteContentPath = join(siteRoot, 'dist', 'site-content.json')
|
|
1515
|
-
if (!existsSync(siteContentPath)) {
|
|
1516
|
-
error('Site content not found. Run "uniweb build" first.')
|
|
1517
|
-
process.exit(1)
|
|
1518
|
-
}
|
|
1519
|
-
|
|
1520
|
-
const siteContentRaw = await readFile(siteContentPath, 'utf-8')
|
|
1521
|
-
const siteContent = JSON.parse(siteContentRaw)
|
|
1526
|
+
const siteContent = await collectSourceContent(siteRoot)
|
|
1522
1527
|
|
|
1523
1528
|
const {
|
|
1524
1529
|
freeformSourceIndex,
|
|
@@ -1530,8 +1535,10 @@ async function runPrune(siteRoot, config, args) {
|
|
|
1530
1535
|
// reads one (`freeformSourceIndex`, the build's own index): every path a section's
|
|
1531
1536
|
// translation is read from — ⛔ until 2026-09-14 only `page-ids/<id>/…` on a page with
|
|
1532
1537
|
// an `id`, so a route-addressed translation the page rendered was deleted — and only
|
|
1533
|
-
// what the
|
|
1534
|
-
//
|
|
1538
|
+
// what the content can see: never a record's translation (`records/…`), and never one
|
|
1539
|
+
// for a page whose sections the content does not carry. The content is the SOURCE's
|
|
1540
|
+
// (`collectSourceContent`), `hidden:` pages included: ⛔ read from a build until
|
|
1541
|
+
// 2026-10-17, which leaves those out, so their translations were deleted.
|
|
1535
1542
|
const { validPaths, canJudge } = freeformSourceIndex(siteContent)
|
|
1536
1543
|
|
|
1537
1544
|
// Find all locales
|
package/src/framework-index.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"generatedAt": "2026-10-
|
|
3
|
+
"generatedAt": "2026-10-17T17:49:32.100Z",
|
|
4
4
|
"packages": {
|
|
5
5
|
"@uniweb/api": {
|
|
6
6
|
"version": "1.4.0"
|
|
7
7
|
},
|
|
8
8
|
"@uniweb/build": {
|
|
9
|
-
"version": "1.3.
|
|
9
|
+
"version": "1.3.9"
|
|
10
10
|
},
|
|
11
11
|
"@uniweb/content-reader": {
|
|
12
12
|
"version": "1.4.0"
|