Context
Kychon's upcoming admin-content-management change adds per-locale block translations (a section_translations table that stores partial config overrides per language). The render path becomes:
- Detect the active locale (from URL prefix, cookie, or
Accept-Language).
- Fetch sections + LEFT JOIN section_translations on the active locale.
- Deep-merge translation over base config.
- Render HTML.
Every request, every page, every visitor pays for the JOIN. Cache layering today (build-time bake + localStorage + network fetch) does not key on locale, so a returning Spanish visitor still triggers a fresh network fetch even when the page hasn't changed.
Current friction
prefixDefaultLocale: false Astro routing works for the default locale, but other locales rely on app-side localStorage preference + runtime t() lookups — there is no edge-level locale routing.
- Run402's CDN cache key is path-based; serving
/about to an English visitor and a Spanish visitor returns the same cached HTML (then the app swaps content via runtime hydrate). This works but causes a noticeable cold-paint flash of English content for non-English visitors.
- Apps that want a fully locale-aware response (HTML pre-rendered with translated content) have to bypass the CDN or route through their own edge function.
Desired outcome
Run402 same-origin web routes could support locale-aware response caching natively:
# run402.deploy.json route entry
routes:
- path: /about
cache:
vary: ['accept-language'] # cache per Accept-Language
ttl: 300
Or a path-prefix locale model that Run402 normalizes:
i18n:
defaultLocale: en
locales: [en, es, fr, pt]
routing:
prefixDefaultLocale: false
detect: ['cookie:wl_locale', 'accept-language']
Then any /about request from a Spanish visitor is served from the /es/about cache entry (or origin-rendered with locale=es available in the function context), with the CDN keying per locale automatically.
Bonus: expose locale in the routed HTTP function context so app render code reads it without sniffing headers:
export default async (req, ctx) => {
const locale = ctx.locale; // resolved per request
// render with locale-aware data
};
Why it matters
- Multilingual portals are a Kychon differentiator vs Wild Apricot (which has limited localization). Making them fast at the edge is a big quality bump.
- Removes the cold-paint English-flash problem for non-English visitors.
- Halves origin load on multilingual portals (cache hits per locale instead of always-cold renders).
- The pattern generalizes to any Run402 app with localized content.
Workaround until shipped
Kychon's admin-content-management change implements the LEFT JOIN + deep-merge at the app render layer (Astro page-render.ts). Every request pays for the JOIN. Visitors continue to see a brief English flash before the runtime hydrate replaces content with their preferred locale.
Related Kychon change
/Users/talweiss/Developer/kychon/openspec/changes/admin-content-management/ — specifically specs/i18n/spec.md.
Context
Kychon's upcoming
admin-content-managementchange adds per-locale block translations (asection_translationstable that stores partial config overrides per language). The render path becomes:Accept-Language).Every request, every page, every visitor pays for the JOIN. Cache layering today (build-time bake + localStorage + network fetch) does not key on locale, so a returning Spanish visitor still triggers a fresh network fetch even when the page hasn't changed.
Current friction
prefixDefaultLocale: falseAstro routing works for the default locale, but other locales rely on app-side localStorage preference + runtimet()lookups — there is no edge-level locale routing./aboutto an English visitor and a Spanish visitor returns the same cached HTML (then the app swaps content via runtime hydrate). This works but causes a noticeable cold-paint flash of English content for non-English visitors.Desired outcome
Run402 same-origin web routes could support locale-aware response caching natively:
Or a path-prefix locale model that Run402 normalizes:
Then any
/aboutrequest from a Spanish visitor is served from the/es/aboutcache entry (or origin-rendered withlocale=esavailable in the function context), with the CDN keying per locale automatically.Bonus: expose
localein the routed HTTP function context so app render code reads it without sniffing headers:Why it matters
Workaround until shipped
Kychon's
admin-content-managementchange implements the LEFT JOIN + deep-merge at the app render layer (Astro page-render.ts). Every request pays for the JOIN. Visitors continue to see a brief English flash before the runtime hydrate replaces content with their preferred locale.Related Kychon change
/Users/talweiss/Developer/kychon/openspec/changes/admin-content-management/— specificallyspecs/i18n/spec.md.