@justai/cuts 0.132.0 → 0.133.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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/Posts.astro +37 -7
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@justai/cuts",
3
- "version": "0.132.0",
3
+ "version": "0.133.0",
4
4
  "description": "A persona's named parts \u2014 the page shell that holds them, and the cuts themselves.",
5
5
  "license": "UNLICENSED",
6
6
  "repository": {
package/src/Posts.astro CHANGED
@@ -1,5 +1,5 @@
1
1
  ---
2
- import { tagline } from "./tagline.js";
2
+ import { tagline, TAGLINE } from "./tagline.js";
3
3
  // ░░ POSTS cut — a persona's feed, revealed by scrolling past the Kernel. ░░
4
4
  //
5
5
  // The feed's markup, its styling, AND its runtime loader were byte-near-identical across every persona
@@ -102,8 +102,33 @@ const { handle, name, lang, footer, avatarBg, avatarBgLight, avatarSrc, avatarBa
102
102
  // (`/tr/`), so it is settled before any script runs — and the same rule the feed permalink pages
103
103
  // learned the hard way: a page whose language came from its address must not be second-guessed by
104
104
  // what the visitor last picked somewhere else.
105
- const feedLang = lang ?? Astro.currentLocale ?? "en";
105
+ //
106
+ // ── `Astro.currentLocale` IS UNDEFINED HERE, ON EVERY PERSONA IN THIS FLEET ─────────────────────
107
+ //
108
+ // It was written as the fallback and it has never once fired. The fleet routes languages through a
109
+ // `[lang]` PARAMETER, not Astro's i18n config, so `currentLocale` is undefined in every persona that
110
+ // has one — `Sheet.astro` says exactly this, in this same package, and the two comments contradicted
111
+ // each other with the wrong one load-bearing.
112
+ //
113
+ // MEASURED 2026-08-21, and it is not theoretical: `time.app.zone/tr/` and `tabata.app.zone/tr/` were
114
+ // closing their feeds with *"made to matter"* — the ENGLISH house line, on a Turkish page — because
115
+ // neither passes `lang`. Fifteen of the twenty-five personas that render this cut are in that state.
116
+ //
117
+ // So there are two answers, one per surface, and neither is "ask fifteen repos to remember":
118
+ // the footer → rendered by the server, so it is RE-LABELLED at runtime from `<html lang>`, which
119
+ // is the pattern this package already uses for the words a cut owns
120
+ // the feed → fetched by the loader, which runs at runtime and can simply read `<html lang>`
121
+ // `lang` still wins wherever a persona states it: a stated fact beats an inferred one.
122
+ const feedLang = lang ?? "en";
106
123
  const foot = footer ?? tagline(feedLang);
124
+ // Only a STATED language rides on the section. An inferred "en" here would look identical to a
125
+ // persona that really is English, and the loader could no longer tell the difference.
126
+ const statedLang = lang ?? undefined;
127
+ // The house line is re-labelled at runtime ONLY when the persona did not state its language and did
128
+ // not override the sentence. A consumer's word always wins — the same rule `data-chrome` keeps.
129
+ const RELABEL = !lang && !footer
130
+ ? `(function(){try{var T=${JSON.stringify(TAGLINE)},l=(document.documentElement.lang||"en").toLowerCase().split("-")[0],e=document.querySelector("[data-house-line]");if(e&&T[l])e.textContent=T[l];}catch(_){}})();`
131
+ : "";
107
132
  const vars = [
108
133
  avatarBg && `--feed-av-bg:${avatarBg}`,
109
134
  avatarBgLight && `--feed-av-bg-light:${avatarBgLight}`,
@@ -115,7 +140,7 @@ const vars = [
115
140
  id="posts"
116
141
  data-persona={handle}
117
142
  data-name={name}
118
- data-lang={feedLang}
143
+ data-lang={statedLang}
119
144
  data-av={avatarSrc ?? "/icon.svg"}
120
145
  data-av-dark={avatarSrcDark}
121
146
  data-av-bare={avatarBare ? "" : undefined}
@@ -124,7 +149,7 @@ const vars = [
124
149
  <!-- filled at runtime by the loader below (lazy, on Posts-cut intersection) — single source: the console -->
125
150
  <div id="feed"></div>
126
151
  <footer class="z-foot">
127
- <a href="https://justai.pro">justai.pro</a> · {foot}
152
+ <a href="https://justai.pro">justai.pro</a> · <span data-house-line={!lang && !footer ? "" : undefined}>{foot}</span>
128
153
  {/* the change-your-mind door: hidden until the shell's consent script labels + reveals it
129
154
  (Base owns the behavior and the localized label; this cut only owns the placement). On a
130
155
  page with no analytics — and so no consent banner — it simply never appears. */}
@@ -132,6 +157,8 @@ const vars = [
132
157
  </footer>
133
158
  </section>
134
159
 
160
+ {RELABEL && <script is:inline set:html={RELABEL}></script>}
161
+
135
162
  <style>
136
163
  /* ---- POSTS cut — a conversation: ONE line descends from the post's avatar and
137
164
  connects every comment & reply (they're all replies to the post). ---- */
@@ -333,9 +360,12 @@ const vars = [
333
360
  // so it may carry markup (justai's ".pro" span). Every name that comes from the API is escaped.
334
361
  const PERSONA = section.dataset.persona || "";
335
362
  const NAME = section.dataset.name || "";
336
- // THE PAGE'S LANGUAGE, set by the cut above from the same value that picked the footer. Not
337
- // localStorage: on a localized home the language is in the URL and was settled before this ran.
338
- const LANG = section.dataset.lang || "en";
363
+ // THE PAGE'S LANGUAGE. `data-lang` is present only when the persona STATED it; otherwise the
364
+ // document's own `lang` is read, which is the one place every persona in this fleet agrees —
365
+ // `Astro.currentLocale` is undefined under `[lang]` routing and cannot be the fallback it looks
366
+ // like. Not localStorage either: on a localized home the language is in the URL, settled before
367
+ // this ran, and a link shared in Turkish must open in Turkish for whoever follows it.
368
+ const LANG = (section.dataset.lang || document.documentElement.lang || "en").toLowerCase().split("-")[0];
339
369
  if (!PERSONA) return;
340
370
  // Astro scopes this component's CSS by a data-astro-cid-* attribute; runtime nodes lack it, so copy it.
341
371
  const scopeAttr = section.getAttributeNames().find((n) => n.startsWith("data-astro-cid-")) || null;