@koehler8/cms 1.0.0-beta.23 β†’ 1.0.0-beta.24

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": "@koehler8/cms",
3
- "version": "1.0.0-beta.23",
3
+ "version": "1.0.0-beta.24",
4
4
  "description": "Vertex CMS β€” lightweight, config-driven Vue 3 framework with theming, extensions, and SSG support",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -97,7 +97,7 @@
97
97
  <li v-for="locale in availableLocales" :key="locale">
98
98
  <a
99
99
  class="locale-option"
100
- :href="`/${locale}`"
100
+ :href="localeHref(locale)"
101
101
  @click="handleLocaleLinkClick(locale)"
102
102
  >
103
103
  <span class="locale-flag" aria-hidden="true">{{ localeEmojis[locale] || '🌐' }}</span>
@@ -120,7 +120,7 @@ import { computed, inject, nextTick, onBeforeUnmount, onMounted, ref, useSlots,
120
120
  import { resolveAsset } from '../utils/assetResolver.js';
121
121
  import { trackEvent } from '../utils/analytics.js';
122
122
  import { getExtensionComponent } from '../extensions/extensionLoader.js';
123
- import { availableLocales as siteLocales } from '../utils/loadConfig.js';
123
+ import { availableLocales as siteLocales, baseLocale as siteBaseLocale } from '../utils/loadConfig.js';
124
124
 
125
125
  const slots = useSlots();
126
126
  const hasActionsSlot = computed(() => Boolean(slots.actions));
@@ -129,6 +129,14 @@ const isLangOpen = ref(false);
129
129
  const isHeaderCompact = ref(false);
130
130
  const currentLocale = ref('');
131
131
  const availableLocales = computed(() => siteLocales.map((code) => code.trim()).filter(Boolean));
132
+
133
+ // The base locale is served at the unprefixed root path (`/`) β€” clicking
134
+ // the dropdown item for it should NOT navigate to `/{baseLocale}` because
135
+ // that URL doesn't pre-render and would 404. Build the link path
136
+ // accordingly: base β†’ `/`, others β†’ `/{locale}`.
137
+ const localeHref = (locale) => {
138
+ return locale === siteBaseLocale ? '/' : `/${locale}`;
139
+ };
132
140
  const localeLabels = {
133
141
  en: 'English',
134
142
  fr: 'FranΓ§ais',
@@ -5,6 +5,19 @@ import Home from '../components/Home.vue';
5
5
 
6
6
  import { availableLocales, baseLocale } from '../utils/loadConfig.js';
7
7
 
8
+ // Test for `/{baseLocale}` or `/{baseLocale}/...` paths β€” these no longer
9
+ // pre-render or match the locale layout (the canonical URL for the base
10
+ // locale is unprefixed). Used by the router guard to redirect in-SPA
11
+ // navigation so external clicks land on the canonical URL instead of the
12
+ // SPA catch-all β†’ 404 path.
13
+ function stripBaseLocalePrefix(targetPath, base) {
14
+ if (!base || !targetPath) return null;
15
+ const root = `/${base}`;
16
+ if (targetPath === root) return '/';
17
+ if (targetPath.startsWith(`${root}/`)) return targetPath.slice(root.length) || '/';
18
+ return null;
19
+ }
20
+
8
21
  const LocaleLayout = {
9
22
  name: 'LocaleLayout',
10
23
  render() {
@@ -85,6 +98,17 @@ function normalizeLocale(value = '') {
85
98
 
86
99
  export function applyRouterGuards(router, localePrefixes = computeLocalePrefixes()) {
87
100
  router.beforeEach((to) => {
101
+ // SPA-side redirect for stale base-locale-prefixed URLs. When a user
102
+ // navigates inside the app to `/en/about` (and `en` is base), the URL
103
+ // doesn't pre-render and the catch-all renders the 404 page. Rewrite
104
+ // to the canonical unprefixed equivalent. Direct external hits to
105
+ // these URLs still need an Amplify customRule on the host side β€” see
106
+ // CLAUDE.md "URL hygiene".
107
+ const stripped = stripBaseLocalePrefix(to.path, baseLocale);
108
+ if (stripped !== null && stripped !== to.path) {
109
+ return { path: stripped, replace: true };
110
+ }
111
+
88
112
  const rawLocale = (to.params.locale || '').toString().trim();
89
113
 
90
114
  if (rawLocale) {