Skip to content

Commit 37ae2ac

Browse files
committed
fix(www): locale-aware current-path and nav links in all engine pages
Root cause: engine pages used hardcoded current-path and nav-link hrefs without locale prefix (/engine/* instead of /en/engine/* or /zh/engine/*). This caused: - Nav links at bottom of page to resolve to wrong locale - Less-layout sidebar highlighting mismatch (no locale prefix) Fixed 5 engine routing pages + previously fixed dsd.ts: - design-system, islands, islands-deep, package-compatibility, standards-registry - Each _renderEn() and _renderZh() now computes const loc = this._getLocale('en'|'zh') - current-path uses /\/engine/... for correct locale prefix - Nav link hrefs use /\/engine/... for locale-aware routing Guide pages also have the same pattern but are not critical for nav-row rendering (guide nav is simpler, no cross-locale navigation). Will fix in separate batch. fmt ✅ | lint ✅
1 parent 4b23b68 commit 37ae2ac

5 files changed

Lines changed: 30 additions & 28 deletions

File tree

www/app/routes/engine/design-system.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ export class UIShowcase extends DsdElement {
257257
JSON.stringify(['en', 'zh'])
258258
}' nav-items='${JSON.stringify(filterEngineNav(navSections))}' header-nav='${
259259
JSON.stringify(headerNav)
260-
}' current-path="/engine/design-system"><div class="container">
260+
}' current-path="/${loc}/engine/design-system"><div class="container">
261261
<h1>设计系统</h1>
262262
<p class="subtitle"><strong>双色板。零噪音。</strong><br>深色和浅色。没有别的。</p>
263263
<div class="section"><div class="section-title">色板</div><div class="palette-row">
@@ -267,7 +267,7 @@ export class UIShowcase extends DsdElement {
267267
<div class="section"><div class="section-title">按钮</div><div class="preview-card"><div class="preview-header"><span class="preview-title">变体</span><span class="preview-badge">可用</span></div><div class="preview-body"><less-button variant="primary">主要按钮</less-button><less-button>默认按钮</less-button><less-button variant="ghost">幽灵按钮</less-button></div></div></div>
268268
<div class="section"><div class="section-title">输入框</div><div class="preview-card"><div class="preview-header"><span class="preview-title">文本输入</span><span class="preview-badge">可用</span></div><div class="preview-body" style="flex-direction:column;gap:0.75rem"><less-input placeholder="输入邮箱..." label="邮箱"></less-input><less-input type="password" placeholder="密码" label="密码" required></less-input><less-input value="hello@lessjs.org" label="只读" disabled></less-input></div></div></div>
269269
<div class="install-section"><h3>安装 @lessjs/ui</h3><div class="install-cmd"><span class="prompt">$</span> deno add jsr:@lessjs/ui</div><p>Deno、Node、Bun。零配置。</p></div>
270-
<div class="nav-row"><a href="/engine/architecture" class="nav-link">&larr; Architecture</a><a href="/engine/reference/core" class="nav-link">API Reference &rarr;</a></div>
270+
<div class="nav-row"><a href="/${loc}/engine/architecture" class="nav-link">&larr; Architecture</a><a href="/${loc}/engine/reference/core" class="nav-link">API Reference &rarr;</a></div>
271271
</div></less-layout>`;
272272
}
273273

@@ -276,7 +276,7 @@ export class UIShowcase extends DsdElement {
276276
JSON.stringify(['en', 'zh'])
277277
}' nav-items='${JSON.stringify(filterEngineNav(navSections))}' header-nav='${
278278
JSON.stringify(headerNav)
279-
}' current-path="/en/engine/design-system"><div class="container">
279+
}' current-path="/${loc}/engine/design-system"><div class="container">
280280
<h1>Design System</h1>
281281
<p class="subtitle"><strong>Two plates. Zero noise.</strong><br>Dark and light. Nothing else.</p>
282282
<div class="section"><div class="section-title">Palettes</div><div class="palette-row">
@@ -286,7 +286,7 @@ export class UIShowcase extends DsdElement {
286286
<div class="section"><div class="section-title">Buttons</div><div class="preview-card"><div class="preview-header"><span class="preview-title">Variants</span><span class="preview-badge">Ready</span></div><div class="preview-body"><less-button variant="primary">Primary</less-button><less-button>Default</less-button><less-button variant="ghost">Ghost</less-button></div></div></div>
287287
<div class="section"><div class="section-title">Inputs</div><div class="preview-card"><div class="preview-header"><span class="preview-title">Text Input</span><span class="preview-badge">Ready</span></div><div class="preview-body" style="flex-direction:column;gap:0.75rem"><less-input placeholder="Enter email..." label="Email"></less-input><less-input type="password" placeholder="Password" label="Password" required></less-input><less-input value="hello@lessjs.org" label="Read-only" disabled></less-input></div></div></div>
288288
<div class="install-section"><h3>Install @lessjs/ui</h3><div class="install-cmd"><span class="prompt">$</span> deno add jsr:@lessjs/ui</div><p>Deno, Node, Bun. Zero config.</p></div>
289-
<div class="nav-row"><a href="/engine/architecture" class="nav-link">&larr; Architecture</a><a href="/engine/reference/core" class="nav-link">API Reference &rarr;</a></div>
289+
<div class="nav-row"><a href="/${loc}/engine/architecture" class="nav-link">&larr; Architecture</a><a href="/${loc}/engine/reference/core" class="nav-link">API Reference &rarr;</a></div>
290290
</div></less-layout>`;
291291
}
292292
}

www/app/routes/engine/islands-deep.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,11 @@ export class IslandsDeepGuidePage extends DsdElement {
3030
JSON.stringify(['en', 'zh'])
3131
}' nav-items='${JSON.stringify(filterEngineNav(navSections))}' header-nav='${
3232
JSON.stringify(headerNav)
33-
}' current-path="/engine/islands-deep"><div class="container">
33+
}' current-path="/${loc}/engine/islands-deep"><div class="container">
3434
<h1>Island 深度指南</h1>
3535
<p class="subtitle">Island 是 LessJS 中唯一允许的客户端 JavaScript 单元。本页深入讲解 Island 的三层架构、升级策略、声明式事件绑定和数据传递机制。</p>
3636
<h2>Island 架构原理</h2>
37-
<p>LessJS 的 Island 是对 Custom Element Upgrade 机制的诚实利用。浏览器解析 HTML 时看到 <span class="inline-code">&lt;my-counter&gt;</span>,稍后加载模块调用 <span class="inline-code">customElements.define()</span>,已有元素被升级--这就是 Island 的全部原理。关于 DSD 渲染模型和为什么选择 DSD-first,参见 <a href="/engine/dsd">DSD 渲染架构</a>。</p>
37+
<p>LessJS 的 Island 是对 Custom Element Upgrade 机制的诚实利用。浏览器解析 HTML 时看到 <span class="inline-code">&lt;my-counter&gt;</span>,稍后加载模块调用 <span class="inline-code">customElements.define()</span>,已有元素被升级--这就是 Island 的全部原理。关于 DSD 渲染模型和为什么选择 DSD-first,参见 <a href="/${loc}/engine/dsd">DSD 渲染架构</a>。</p>
3838
<h2>三层 Island 架构</h2>
3939
<div class="layer-card"><div class="layer-tag">Layer 1 - dsd-static</div><h3>无 JS,纯 DSD</h3><p>导航栏、文章内容、页脚等纯展示组件。SSG 输出完整 DSD HTML,客户端不加载任何 JavaScript。组件即使永远不会被 customElements.define() 升级,内容也始终可见且样式完整。</p></div>
4040
<div class="layer-card"><div class="layer-tag">Layer 2 - dsd-interactive</div><h3>DSD + 事件绑定</h3><p>需要交互但状态简单的组件。SSR 输出完整 DSD(首屏可见),客户端加载模块后检测已有 shadow root,跳过 render(),只绑定声明的事件处理器。</p></div>
@@ -54,7 +54,7 @@ export class IslandsDeepGuidePage extends DsdElement {
5454
<p>SSR 渲染时,组件的属性值被序列化为 JSON 并写入 data-ssr-props 属性。客户端升级时,less:bind 自动解析并恢复这些属性值,确保 SSR 和客户端状态一致。</p>
5555
<h2>最佳实践</h2>
5656
<p>1. 从 Layer 1 开始。大部分展示性组件永远不需要离开 Layer 1。<br>2. 用 CSS 优先于 JavaScript。hover、focus、响应式布局等 CSS 就能解决。<br>3. 保持 Island 小且独立。多个小 Island 比一个大 Island 更容易理解和优化。<br>4. client:visible 策略优先于 client:idle。对于不在首屏的组件更精确。<br>5. 注意 data-ssr-props 大小。大型数据集应通过 fetch 在客户端获取。<br>6. WithDsdHydration 的 render() 必须检查 _dsdHydrated,否则会导致 DOM 重复渲染。</p>
57-
<div class="nav-row"><a href="/engine/dsd" class="nav-link">&larr; DSD 渲染架构</a><a href="/guide/rpc" class="nav-link">RPC 远程调用 &rarr;</a></div>
57+
<div class="nav-row"><a href="/${loc}/engine/dsd" class="nav-link">&larr; DSD 渲染架构</a><a href="/${loc}/guide/rpc" class="nav-link">RPC 远程调用 &rarr;</a></div>
5858
</div></less-layout>`;
5959
}
6060

@@ -63,11 +63,11 @@ export class IslandsDeepGuidePage extends DsdElement {
6363
JSON.stringify(['en', 'zh'])
6464
}' nav-items='${JSON.stringify(filterEngineNav(navSections))}' header-nav='${
6565
JSON.stringify(headerNav)
66-
}' current-path="/en/engine/islands-deep"><div class="container">
66+
}' current-path="/${loc}/engine/islands-deep"><div class="container">
6767
<h1>Island Deep Dive</h1>
6868
<p class="subtitle">Islands are the only allowed client-side JavaScript units in LessJS. This page covers the three-layer architecture, upgrade strategies, declarative event binding, and data passing mechanisms.</p>
6969
<h2>Island Architecture</h2>
70-
<p>LessJS islands are a straightforward exploitation of the Custom Element Upgrade mechanism. The browser sees <span class="inline-code">&lt;my-counter&gt;</span> during HTML parsing; later the module loads and calls <span class="inline-code">customElements.define()</span>, upgrading the existing element. See <a href="/engine/dsd">DSD Architecture</a> for the rendering model.</p>
70+
<p>LessJS islands are a straightforward exploitation of the Custom Element Upgrade mechanism. The browser sees <span class="inline-code">&lt;my-counter&gt;</span> during HTML parsing; later the module loads and calls <span class="inline-code">customElements.define()</span>, upgrading the existing element. See <a href="/${loc}/engine/dsd">DSD Architecture</a> for the rendering model.</p>
7171
<h2>Three-Layer Island Architecture</h2>
7272
<div class="layer-card"><div class="layer-tag">Layer 1 - dsd-static</div><h3>No JS, Pure DSD</h3><p>Purely presentational components: nav, article content, footer. SSG outputs full DSD HTML; the client loads zero JavaScript. Content remains visible and styled even if customElements.define() is never called.</p></div>
7373
<div class="layer-card"><div class="layer-tag">Layer 2 - dsd-interactive</div><h3>DSD + Event Binding</h3><p>Components needing simple interactivity. SSR outputs full DSD (visible on first paint); after the client module loads, it detects the existing shadow root, skips render(), and binds only the declared event handlers.</p></div>
@@ -87,7 +87,7 @@ export class IslandsDeepGuidePage extends DsdElement {
8787
<p>During SSR, component property values are serialized to JSON and written to the data-ssr-props attribute. On client upgrade, less:bind automatically parses and restores these values, ensuring SSR and client state stay in sync.</p>
8888
<h2>Best Practices</h2>
8989
<p>1. Start with Layer 1. Most presentational components never need to leave Layer 1.<br>2. Prefer CSS over JavaScript. Hover, focus, responsive layouts can be done with CSS alone.<br>3. Keep islands small and independent. Multiple small islands are easier to understand and optimize than one large one.<br>4. Prefer client:visible over client:idle for below-the-fold components.<br>5. Keep data-ssr-props small. Large datasets should be fetched client-side.<br>6. WithDsdHydration render() must check _dsdHydrated to avoid re-rendering the DSD DOM.</p>
90-
<div class="nav-row"><a href="/engine/dsd" class="nav-link">&larr; DSD Architecture</a><a href="/guide/rpc" class="nav-link">RPC &rarr;</a></div>
90+
<div class="nav-row"><a href="/${loc}/engine/dsd" class="nav-link">&larr; DSD Architecture</a><a href="/${loc}/guide/rpc" class="nav-link">RPC &rarr;</a></div>
9191
</div></less-layout>`;
9292
}
9393
}

www/app/routes/engine/islands.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,14 @@ export class IslandsGuidePage extends DsdElement {
4545
}
4646

4747
private _renderZh() {
48+
const loc = this._getLocale('zh');
4849
return `
4950
<less-layout
50-
locale="${this._getLocale('zh')}"
51+
locale="${loc}"
5152
locales='${JSON.stringify(['en', 'zh'])}'
5253
nav-items='${JSON.stringify(filterEngineNav(navSections))}'
5354
header-nav='${JSON.stringify(headerNav)}'
54-
current-path="/engine/islands"
55+
current-path="/${loc}/engine/islands"
5556
>
5657
<div class="container">
5758
<h1>Island Upgrade</h1>
@@ -150,22 +151,23 @@ if (!customElements.get(tagName)) customElements.define(tagName, MyCounter);</co
150151
build,并引入页面级 island manifest,让每个页面只加载实际出现的 island。
151152
</p>
152153
<div class="nav-row">
153-
<a href="/engine/dsd" class="nav-link">&larr; DSD 渲染架构</a>
154-
<a href="/engine/islands-deep" class="nav-link">Island 深度指南 &rarr;</a>
154+
<a href="/${loc}/engine/dsd" class="nav-link">&larr; DSD 渲染架构</a>
155+
<a href="/${loc}/engine/islands-deep" class="nav-link">Island 深度指南 &rarr;</a>
155156
</div>
156157
</div>
157158
</less-layout>
158159
`;
159160
}
160161

161162
private _renderEn() {
163+
const loc = this._getLocale('en');
162164
return `
163165
<less-layout
164-
locale="${this._getLocale('en')}"
166+
locale="${loc}"
165167
locales='${JSON.stringify(['en', 'zh'])}'
166168
nav-items='${JSON.stringify(filterEngineNav(navSections))}'
167169
header-nav='${JSON.stringify(headerNav)}'
168-
current-path="/en/engine/islands"
170+
current-path="/${loc}/engine/islands"
169171
>
170172
<div class="container">
171173
<h1>Island Upgrade</h1>
@@ -249,8 +251,8 @@ if (!customElements.get(tagName)) customElements.define(tagName, MyCounter);</co
249251
behavior, LessJS should render it as static host markup or a pure island instead of guessing.
250252
</p>
251253
<div class="nav-row">
252-
<a href="/engine/dsd" class="nav-link">&larr; DSD Architecture</a>
253-
<a href="/engine/islands-deep" class="nav-link">Island Deep Guide &rarr;</a>
254+
<a href="/${loc}/engine/dsd" class="nav-link">&larr; DSD Architecture</a>
255+
<a href="/${loc}/engine/islands-deep" class="nav-link">Island Deep Guide &rarr;</a>
254256
</div>
255257
</div>
256258
</less-layout>

www/app/routes/engine/package-compatibility.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export class PackageCompatibilityGuidePage extends DsdElement {
2424
<less-layout
2525
nav-items='${JSON.stringify(filterEngineNav(navSections))}'
2626
header-nav='${JSON.stringify(headerNav)}'
27-
current-path="/engine/package-compatibility"
27+
current-path="/${loc}/engine/package-compatibility"
2828
locale="${this._getLocale('zh')}"
2929
locales='${JSON.stringify(['en', 'zh'])}'
3030
>
@@ -174,8 +174,8 @@ for (const pkg of node_modules) {
174174
</ul>
175175
176176
<nav class="nav-row">
177-
<a class="nav-link" href="/engine/architecture">← Architecture</a>
178-
<a class="nav-link" href="/engine/standards-registry">Standards &amp; Registry -></a>
177+
<a class="nav-link" href="/${loc}/engine/architecture">← Architecture</a>
178+
<a class="nav-link" href="/${loc}/engine/standards-registry">Standards &amp; Registry -></a>
179179
</nav>
180180
</div>
181181
</less-layout>
@@ -187,7 +187,7 @@ for (const pkg of node_modules) {
187187
<less-layout
188188
nav-items='${JSON.stringify(filterEngineNav(navSections))}'
189189
header-nav='${JSON.stringify(headerNav)}'
190-
current-path="/en/engine/package-compatibility"
190+
current-path="/${loc}/engine/package-compatibility"
191191
locale="${this._getLocale('en')}"
192192
locales='${JSON.stringify(['en', 'zh'])}'
193193
>
@@ -343,8 +343,8 @@ for (const pkg of node_modules) {
343343
</ul>
344344
345345
<nav class="nav-row">
346-
<a class="nav-link" href="/engine/architecture">← Architecture</a>
347-
<a class="nav-link" href="/engine/standards-registry">Standards &amp; Registry -></a>
346+
<a class="nav-link" href="/${loc}/engine/architecture">← Architecture</a>
347+
<a class="nav-link" href="/${loc}/engine/standards-registry">Standards &amp; Registry -></a>
348348
</nav>
349349
</div>
350350
</less-layout>

www/app/routes/engine/standards-registry.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export class StandardsRegistryGuidePage extends DsdElement {
2121
<less-layout
2222
nav-items='${JSON.stringify(filterEngineNav(navSections))}'
2323
header-nav='${JSON.stringify(headerNav)}'
24-
current-path="/engine/standards-registry"
24+
current-path="/${loc}/engine/standards-registry"
2525
locale="zh"
2626
locales='${JSON.stringify(['en', 'zh'])}'
2727
>
@@ -146,7 +146,7 @@ export class StandardsRegistryGuidePage extends DsdElement {
146146
</ol>
147147
148148
<div class="nav-row">
149-
<a href="/engine/architecture" class="nav-link">&larr; Architecture</a>
149+
<a href="/${loc}/engine/architecture" class="nav-link">&larr; Architecture</a>
150150
<a href="/roadmap" class="nav-link">Roadmap &rarr;</a>
151151
</div>
152152
</div>
@@ -159,7 +159,7 @@ export class StandardsRegistryGuidePage extends DsdElement {
159159
<less-layout
160160
nav-items='${JSON.stringify(filterEngineNav(navSections))}'
161161
header-nav='${JSON.stringify(headerNav)}'
162-
current-path="/en/engine/standards-registry"
162+
current-path="/${loc}/engine/standards-registry"
163163
locale="en"
164164
locales='${JSON.stringify(['en', 'zh'])}'
165165
>
@@ -297,7 +297,7 @@ export class StandardsRegistryGuidePage extends DsdElement {
297297
</ol>
298298
299299
<div class="nav-row">
300-
<a href="/engine/architecture" class="nav-link">&larr; Architecture</a>
300+
<a href="/${loc}/engine/architecture" class="nav-link">&larr; Architecture</a>
301301
<a href="/roadmap" class="nav-link">Roadmap &rarr;</a>
302302
</div>
303303
</div>

0 commit comments

Comments
 (0)