fimo 0.17.0 → 0.18.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 (159) hide show
  1. package/assets/astro/components/DateTime.astro +22 -0
  2. package/assets/astro/components/index.d.ts +1 -0
  3. package/assets/astro/components/index.js +1 -0
  4. package/assets/content-templates/shared/types.eta +2 -0
  5. package/assets/skills/fimo-cli/SKILL.md +3 -2
  6. package/assets/skills/fimo-cli/references/content.md +2 -2
  7. package/assets/skills/fimo-cli/references/deploy.md +2 -0
  8. package/assets/skills/fimo-cli/references/init.md +11 -4
  9. package/assets/skills/fimo-cli/references/locales.md +38 -14
  10. package/assets/skills/fimo-cli/references/pages.md +70 -0
  11. package/assets/skills/fimo-cli/references/webhooks.md +1 -1
  12. package/assets/skills/fimo-code/SKILL.md +11 -0
  13. package/assets/skills/fimo-code/assets/react-router-locales/LocaleLayout.tsx +12 -0
  14. package/assets/skills/fimo-code/assets/react-router-locales/routes.ts +7 -6
  15. package/assets/skills/fimo-code/references/best-practices/astro.md +47 -0
  16. package/assets/skills/fimo-code/references/best-practices/next.md +42 -0
  17. package/assets/skills/fimo-code/references/best-practices/sveltekit.md +17 -0
  18. package/assets/skills/fimo-code/references/content/richtext.md +5 -0
  19. package/assets/skills/fimo-code/references/content/schema.md +4 -1
  20. package/assets/skills/fimo-code/references/frameworks/astro.md +5 -3
  21. package/assets/skills/fimo-code/references/frameworks/hosting.md +5 -2
  22. package/assets/skills/fimo-code/references/frameworks/next/app-router.md +6 -0
  23. package/assets/skills/fimo-code/references/frameworks/next/locales.md +12 -2
  24. package/assets/skills/fimo-code/references/frameworks/next.md +7 -0
  25. package/assets/skills/fimo-code/references/frameworks/react-router.md +15 -7
  26. package/assets/skills/fimo-code/references/frameworks/sveltekit.md +15 -8
  27. package/assets/skills/fimo-code/references/labels.md +9 -1
  28. package/assets/skills/fimo-code/references/locales.md +8 -2
  29. package/assets/skills/fimo-code/references/migrations/react-router-route-ownership.md +93 -0
  30. package/assets/skills/fimo-code/references/ui.md +21 -2
  31. package/assets/skills/fimo-migration/SKILL.md +276 -51
  32. package/assets/skills/fimo-migration/references/content.md +119 -35
  33. package/assets/skills/fimo-migration/references/decision.md +72 -0
  34. package/assets/skills/fimo-migration/references/forms.md +38 -6
  35. package/assets/skills/fimo-migration/references/frameworks/nextjs.md +179 -23
  36. package/assets/skills/fimo-migration/references/import-contract.md +71 -19
  37. package/assets/skills/fimo-migration/references/manifest.md +11 -161
  38. package/assets/skills/fimo-migration/references/media.md +33 -1
  39. package/assets/skills/fimo-migration/references/platforms.md +26 -2
  40. package/assets/skills/fimo-migration/references/qa.md +167 -13
  41. package/assets/skills/fimo-migration/references/workers/content-execution.md +39 -0
  42. package/assets/skills/fimo-migration/references/workers/content-planner.md +64 -0
  43. package/assets/skills/fimo-migration/references/workers/framework.md +37 -0
  44. package/assets/skills/fimo-migration/references/workers/validator.md +25 -0
  45. package/assets/skills/fimo-migration/references/workers.md +82 -0
  46. package/assets/skills/fimo-migration/references/workflow.md +140 -192
  47. package/assets/skills/fimo-migration/scripts/apply-decision.mjs +534 -0
  48. package/assets/skills/fimo-migration/scripts/build-canonical-manifest.mjs +7 -4
  49. package/assets/skills/fimo-migration/scripts/write-migration-report.mjs +191 -4
  50. package/assets/skills/fimo-studio/references/cms.md +25 -7
  51. package/assets/skills/fimo-studio/references/webhooks.md +1 -1
  52. package/assets/sveltekit/components/DateTime.svelte +35 -0
  53. package/assets/sveltekit/components/FimoProvider.svelte +2 -2
  54. package/assets/sveltekit/components/index.d.ts +1 -0
  55. package/assets/sveltekit/components/index.js +1 -0
  56. package/dist/build/next/config.d.ts +4 -1
  57. package/dist/build/next/config.js +21 -5
  58. package/dist/build/sveltekit/vite.d.ts +3 -4
  59. package/dist/build/sveltekit/vite.js +3 -4
  60. package/dist/build/vite/plugins/runtime-env.d.ts +2 -1
  61. package/dist/build/vite/plugins/runtime-env.js +14 -10
  62. package/dist/cli/bundle.json +2 -2
  63. package/dist/cli/index.js +76 -78
  64. package/dist/runtime/app/FimoProviders.js +25 -14
  65. package/dist/runtime/app/prefetch.d.ts +3 -1
  66. package/dist/runtime/app/prefetch.js +11 -55
  67. package/dist/runtime/astro/preview.js +7 -9
  68. package/dist/runtime/content/client/internal.js +1 -0
  69. package/dist/runtime/i18n/locale.d.ts +4 -0
  70. package/dist/runtime/i18n/locale.js +14 -14
  71. package/dist/runtime/next/client-runtime.js +5 -1
  72. package/dist/runtime/next/client.d.ts +3 -2
  73. package/dist/runtime/next/client.js +2 -1
  74. package/dist/runtime/next/labels.d.ts +2 -2
  75. package/dist/runtime/next/labels.js +2 -2
  76. package/dist/runtime/next/preview.d.ts +13 -0
  77. package/dist/runtime/next/preview.js +34 -0
  78. package/dist/runtime/next/primitives/server.d.ts +2 -0
  79. package/dist/runtime/next/primitives/server.js +8 -0
  80. package/dist/runtime/next/provider.d.ts +5 -0
  81. package/dist/runtime/next/provider.js +17 -3
  82. package/dist/runtime/next/server-runtime.js +4 -1
  83. package/dist/runtime/next/server.d.ts +1 -1
  84. package/dist/runtime/next/server.js +1 -1
  85. package/dist/runtime/paths/get-fimo-paths.d.ts +6 -5
  86. package/dist/runtime/paths/get-fimo-paths.js +43 -42
  87. package/dist/runtime/preview/location.d.ts +19 -2
  88. package/dist/runtime/preview/location.js +16 -2
  89. package/dist/runtime/primitives/index.d.ts +1 -0
  90. package/dist/runtime/primitives/index.js +1 -0
  91. package/dist/runtime/react/primitives/editable/DateTime.d.ts +4 -0
  92. package/dist/runtime/react/primitives/editable/DateTime.js +13 -0
  93. package/dist/runtime/react/primitives/renderers/DateRenderer.d.ts +7 -1
  94. package/dist/runtime/react/primitives/renderers/DateRenderer.js +11 -8
  95. package/dist/runtime/react-router/{routes.d.ts → legacy/routes.d.ts} +6 -1
  96. package/dist/runtime/react-router/{routes.js → legacy/routes.js} +22 -7
  97. package/dist/runtime/routes/contract.d.ts +116 -0
  98. package/dist/runtime/routes/contract.js +377 -0
  99. package/dist/runtime/routes/index.d.ts +3 -0
  100. package/dist/runtime/routes/index.js +3 -0
  101. package/dist/runtime/routing/AppRoutesProvider.js +4 -3
  102. package/dist/runtime/seo/resolver.d.ts +5 -0
  103. package/dist/runtime/seo/resolver.js +10 -42
  104. package/dist/runtime/shared/fimo-config.types.d.ts +34 -8
  105. package/dist/runtime/shared/preview-location.d.ts +1 -22
  106. package/dist/runtime/shared/preview-location.js +5 -93
  107. package/dist/runtime/sveltekit/preview.d.ts +12 -3
  108. package/dist/runtime/sveltekit/preview.js +13 -8
  109. package/dist/scripts/sync-forms.js +1 -1
  110. package/dist/scripts/sync-schemas.js +1 -4
  111. package/dist/scripts/validate-fimo-config.js +5 -1
  112. package/dist/scripts/validate-page-registry.d.ts +2 -0
  113. package/dist/scripts/validate-page-registry.js +167 -0
  114. package/dist/scripts/validate-route-metadata.js +132 -41
  115. package/package.json +7 -3
  116. package/templates/astro/.fimo/config.json +13 -5
  117. package/templates/astro/AGENTS.md +5 -1
  118. package/templates/astro/astro.config.mjs +7 -0
  119. package/templates/astro/pnpm-workspace.yaml +0 -3
  120. package/templates/astro/src/components/ProjectOverview.astro +9 -6
  121. package/templates/astro/src/layouts/Base.astro +1 -1
  122. package/templates/astro/src/locales.ts +4 -0
  123. package/templates/astro/src/pages/[locale]/index.astro +19 -0
  124. package/templates/astro/src/pages/[locale]/projects/[slug].astro +35 -0
  125. package/templates/astro/src/pages/[locale]/projects/index.astro +19 -0
  126. package/templates/astro/src/pages/index.astro +5 -2
  127. package/templates/astro/src/pages/projects/[slug].astro +4 -2
  128. package/templates/astro/src/pages/projects/index.astro +5 -2
  129. package/templates/nextjs/.fimo/config.json +2 -1
  130. package/templates/nextjs/AGENTS.md +5 -0
  131. package/templates/nextjs/src/app/(default)/layout.tsx +10 -0
  132. package/templates/nextjs/src/app/[locale]/layout.tsx +22 -0
  133. package/templates/nextjs/src/app/[locale]/page.tsx +1 -0
  134. package/templates/nextjs/src/components/Document.tsx +26 -0
  135. package/templates/nextjs/src/components/FimoPreviewBridge.tsx +13 -0
  136. package/templates/nextjs/src/locales.ts +13 -0
  137. package/templates/react-router/.fimo/config.json +3 -6
  138. package/templates/react-router/AGENTS.md +4 -0
  139. package/templates/react-router/package.json +1 -1
  140. package/templates/react-router/pnpm-workspace.yaml +1 -3
  141. package/templates/react-router/react-router.config.ts +4 -10
  142. package/templates/react-router/src/pages/LocaleLayout.tsx +12 -0
  143. package/templates/react-router/src/root.tsx +2 -4
  144. package/templates/react-router/src/routes.ts +5 -3
  145. package/templates/sveltekit/.fimo/config.json +2 -1
  146. package/templates/sveltekit/AGENTS.md +5 -0
  147. package/templates/sveltekit/src/app.html +1 -1
  148. package/templates/sveltekit/src/hooks.server.ts +11 -0
  149. package/templates/sveltekit/src/locales.ts +8 -0
  150. package/templates/sveltekit/src/params/locale.ts +5 -0
  151. package/templates/sveltekit/src/routes/+layout.server.ts +6 -1
  152. package/templates/sveltekit/src/routes/+layout.svelte +5 -0
  153. package/assets/skills/fimo-migration/references/inventory/coordinator.md +0 -40
  154. package/assets/skills/fimo-migration/references/inventory/locales/next-intl.md +0 -39
  155. package/assets/skills/fimo-migration/references/inventory/locales.md +0 -41
  156. package/assets/skills/fimo-migration/scripts/inventory/locales/next-intl.mjs +0 -459
  157. package/templates/nextjs/src/app/layout.tsx +0 -17
  158. /package/templates/nextjs/src/app/{page.tsx → (default)/page.tsx} +0 -0
  159. /package/templates/sveltekit/src/routes/{+page.svelte → [[locale=locale]]/+page.svelte} +0 -0
@@ -82,6 +82,13 @@ Never write the registry by hand and never create alternate `*.schema.json` file
82
82
 
83
83
  ## Server and client boundaries
84
84
 
85
+ Next.js MUST receive generated serialized values across every Server-to-Client
86
+ Component prop boundary. Fimo values may be class-backed even when they look
87
+ JSON-shaped. Values that stay in Server Components may stay intact; values for
88
+ Client Components use the generated server `serialize()` and client
89
+ `hydrate()`. Plain-JSON outputs such as Markdown, RSS, and JSON-LD also use the
90
+ generated serialization rather than `JSON.stringify` as a conversion strategy.
91
+
85
92
  Forms follow the same boundary. Server actions and route handlers import the
86
93
  generated server form module; a Client Component imports its generated
87
94
  `.client.ts` module. Both expose `submitX(data)` and use the shared Fimo form
@@ -85,18 +85,24 @@ Keep the application's existing `Layout` details. Add only the Fimo provider and
85
85
 
86
86
  ## Routes and locales
87
87
 
88
- `fimoRoutes()` is an optional helper for Fimo's path-prefix locale convention:
88
+ React Router owns locale paths. Declare the optional locale segment directly so the default locale stays unprefixed:
89
89
 
90
90
  ```ts
91
91
  import type { RouteConfig } from '@react-router/dev/routes';
92
- import { index } from '@react-router/dev/routes';
93
- import { fimoRoutes } from 'fimo/react-router/routes';
94
-
95
- const routes = [index('./pages/Index.tsx', { id: 'home' })] satisfies RouteConfig;
96
- export default fimoRoutes(routes) satisfies RouteConfig;
92
+ import { layout, route } from '@react-router/dev/routes';
93
+
94
+ export default [
95
+ layout('./pages/LocaleLayout.tsx', [
96
+ route(':locale?', './pages/Index.tsx'),
97
+ route(':locale?/pricing', './pages/Pricing.tsx'),
98
+ route(':locale?/blog/:slug', './pages/BlogPost.tsx'),
99
+ ]),
100
+ ] satisfies RouteConfig;
97
101
  ```
98
102
 
99
- Custom locale routers can skip it and pass their resolved locale to `<FimoProviders locale={locale}>`. Use `FimoLink` only when the application adopts Fimo's locale-aware link behavior; otherwise preserve its links. Copyable path-prefix locale examples live in `assets/react-router-locales/`.
103
+ Read `locale` in an application layout and pass it to `<FimoProviders locale={locale}>`; omission resolves the configured default. Copy `assets/react-router-locales/routes.ts` and `LocaleLayout.tsx` for a complete boundary. For multilingual apps, move the root provider there instead of nesting providers. Preserve an existing locale library, and use `FimoLink` only when its locale-preserving behavior matches the app.
104
+
105
+ If an existing project imports `fimo/react-router/routes`, load `references/migrations/react-router-route-ownership.md` before changing it.
100
106
 
101
107
  ## Content and labels
102
108
 
@@ -122,6 +128,8 @@ Declare the runtime in `.fimo/config.json`:
122
128
 
123
129
  The optional `routes` object is Studio's semantic page catalog. Keep it aligned with application routes when the project uses Studio navigation, but do not treat it as the production router.
124
130
 
131
+ For new projects, apply `references/locales.md`, keep the starter's `:locale?` route, and describe it in Studio metadata as `/:locale` with `params.locale.optional: true`.
132
+
125
133
  ## Boundaries
126
134
 
127
135
  - Route modules and `meta` exports own routing and SEO.
@@ -74,24 +74,27 @@ do not import a Fimo environment variable or hardcode a tenant URL:
74
74
  // src/routes/+layout.server.ts
75
75
  import { getLabels } from 'fimo/sveltekit';
76
76
 
77
- export async function load(event) {
78
- // If the app resolves a locale from its URL or session, pass it:
79
- // const locale = resolveLocale(event.url); // your app's resolver
80
- // return { labels: await getLabels({ event, locale }) };
77
+ import { resolveLocale } from '../locales';
81
78
 
82
- // Otherwise, omit it and use the Fimo project default.
83
- return { labels: await getLabels({ event }) };
79
+ export async function load(event) {
80
+ const locale = resolveLocale(event.params);
81
+ return { locale, labels: await getLabels({ event, locale }) };
84
82
  }
85
83
  ```
86
84
 
87
85
  ```svelte
88
86
  <!-- src/routes/+layout.svelte -->
89
87
  <script lang="ts">
88
+ import { afterNavigate } from '$app/navigation';
90
89
  import { FimoProvider } from 'fimo/sveltekit/components';
91
90
  import type { LayoutData } from './$types';
92
91
  import type { Snippet } from 'svelte';
93
92
 
94
93
  let { data, children }: { data: LayoutData; children: Snippet } = $props();
94
+
95
+ afterNavigate(() => {
96
+ document.documentElement.lang = data.locale;
97
+ });
95
98
  </script>
96
99
 
97
100
  <FimoProvider labels={data.labels}>
@@ -101,7 +104,7 @@ export async function load(event) {
101
104
 
102
105
  Generated values are serialized at a `load` boundary and hydrated in the
103
106
  component that renders them. Use `Text`, `RichText`, `Image`, `Video`, `Date`,
104
- `Boolean`, `Json`, and `Number` from `fimo/sveltekit/components`. `Number`
107
+ `DateTime`, `Boolean`, `Json`, and `Number` from `fimo/sveltekit/components`. `Number`
105
108
  formats plain numeric values for display; numeric fields currently have no
106
109
  source metadata, so it is not a Studio-editable primitive.
107
110
 
@@ -128,7 +131,7 @@ export const actions = {
128
131
  `PUBLIC_FIMO_PREVIEW_SCRIPT_URL` from SvelteKit's dynamic public environment,
129
132
  loads that script once, delegates navigation to SvelteKit's `goto`, and
130
133
  refreshes data with `invalidateAll()`. Without that environment value it does
131
- nothing. Do not add a Fimo server hook or a second preview component.
134
+ nothing. Do not add a second preview component.
132
135
 
133
136
  ## Boundaries
134
137
 
@@ -136,3 +139,7 @@ nothing. Do not add a Fimo server hook or a second preview component.
136
139
  - `fimo/sveltekit/vite` owns dev source tagging only.
137
140
  - `FimoProvider` owns labels and the optional Studio preview bridge.
138
141
  - Do not add React, React Query, or a Vite SPA fallback to a SvelteKit project.
142
+
143
+ The starter uses SvelteKit's native `[[locale=locale]]` boundary and a matcher limited to configured, non-default locales, so unrelated top-level paths are not locales. `src/locales.ts` derives the default and prefixed set from `.fimo/config.json` and owns the shared locale resolver. Keep passing the tracked `event.params` object into that resolver from the root server layout so locale-crossing client navigation reruns labels.
144
+
145
+ For accessibility, SvelteKit's documented multilingual pattern renders `<html lang="%lang%">` through `src/hooks.server.ts#transformPageChunk`. The root layout updates the attribute after client navigation. Keep those seams aligned with the application's locale resolver. Keep `[[locale=locale]]` for an unprefixed default; use `[locale=locale]` only when every locale must be prefixed.
@@ -32,7 +32,7 @@ const items = [
32
32
 
33
33
  Do not use variables or interpolated expressions as label keys. Namespace literal keys by page/section/component, such as `hero.title`, `nav.signIn`, or `contact.form.submit`.
34
34
 
35
- Missing keys render as an empty tracked value. Run `fimo validate`, then create values with `fimo labels set` or `set-many`; do not add fallback copy to code.
35
+ Missing keys render as an empty tracked value. Run `fimo validate`, then create values with `fimo labels set` or `set-many`; do not add fallback copy to code (the one exception is a component that cannot mount under the provider — see "Provider mount" below).
36
36
 
37
37
  ## Framework adapters
38
38
 
@@ -46,6 +46,14 @@ The label contract is shared; acquisition differs by runtime:
46
46
 
47
47
  Load the matching framework reference before choosing a provider or server reader.
48
48
 
49
+ ## Provider mount
50
+
51
+ Components that render `Label` or call `useLabels()` MUST be mounted below the framework's `FimoProvider` (or the framework integration that supplies label context). Globally mounted components — cookie banners, toasts, consent dialogs injected near the document root — are the common escapees: outside the provider they render blank labels with no error.
52
+
53
+ If a component genuinely cannot be moved under the provider, use an explicit hardcoded, non-editable fallback and report that tradeoff to the user. Never ship silently blank copy.
54
+
55
+ When a label renders empty, check in order: (1) the key exists (`fimo validate`, `fimo labels list`), (2) the active locale has a value, (3) the component is under the provider. Add fallback copy only after those checks, and only in the cannot-mount case above.
56
+
49
57
  ## Locale behavior
50
58
 
51
59
  `.fimo/config.json#i18n.defaultLocale` selects the default (fallback `en`). The application resolves the active locale and gives it to the framework adapter. Create explicit label values for each configured locale the product supports.
@@ -13,7 +13,9 @@ The application owns locale resolution and routing. Fimo consumes the resolved l
13
13
  }
14
14
  ```
15
15
 
16
- Keep one locale unless the product asks for multilingual output. Locale tags should be structurally valid, such as `en`, `pt-BR`, or `zh-Hans`.
16
+ For new projects, derive the primary locale from the request; when several are explicit, the first one named is the default. Update `i18n.defaultLocale`, `i18n.locales`, the framework-native route boundary and matcher, and the document language default. If the user gives no locale signal, retain the starter default and state that choice.
17
+
18
+ Keep one locale unless the product asks for multilingual output. Keep it locale-ready without forcing `/en`, a language switcher, global path-prefix routing, or localized schemas. Locale tags should be structurally valid, such as `en`, `pt-BR`, or `zh-Hans`.
17
19
 
18
20
  For an already linked project, enable each locale in Fimo before writing non-default label or content variants. Load `fimo-cli` with its `locales` reference and run `fimo locales add <locale> --yes --json`; local config and `fimo validate` do not provision project locales. Do not change the application's route strategy to work around a missing locale.
19
21
 
@@ -22,6 +24,8 @@ For an already linked project, enable each locale in Fimo before writing non-def
22
24
  - Resolve locale from its router, route parameters, domain, request headers, middleware, cookie, existing i18n library, or user preference.
23
25
  - Keep its existing public URLs, redirects, links, `<html lang/dir>`, and SEO behavior.
24
26
  - Pass the resolved locale to Fimo's server reads and client provider.
27
+ - Keep the default locale separate from the URL prefix policy. `optional: true` means omit the configured default locale from the URL: with `defaultLocale: "en"`, `/pricing` is English and `/fr/pricing` is French. With `optional: false`, every locale is prefixed (`/en/pricing` and `/fr/pricing`).
28
+ - Treat routes without a `:locale` segment as application-owned. Fimo does not add or interpret a locale prefix for them.
25
29
  - Treat any optional Studio route catalog as framework-adapter-specific; load the framework reference before creating or changing one.
26
30
 
27
31
  ## Fimo responsibilities
@@ -39,4 +43,6 @@ For an already linked project, enable each locale in Fimo before writing non-def
39
43
  - React Router standard locale routing → load `references/frameworks/react-router.md`.
40
44
  - Vite + React/custom React router → load `references/frameworks/vite-react.md` and pass locale through its existing provider seam.
41
45
 
42
- Do not replace an existing locale system merely to add Fimo. Do not duplicate localized routes in the Studio catalog. Do not assume Fimo's route helpers are universal framework APIs.
46
+ Do not replace an existing locale system merely to add Fimo. Do not duplicate localized routes in the Studio catalog. Every framework resolves its active locale and passes it to Fimo through that framework's provider or server-read seam.
47
+
48
+ Astro and Next implement an optional locale boundary with paired native filesystem route trees: one unprefixed tree for the default locale and one prefixed tree for the other locales. Neither framework has an optional single-segment filesystem folder.
@@ -0,0 +1,93 @@
1
+ # React Router locale route ownership upgrade
2
+
3
+ Use this guide to move an existing project from the deprecated
4
+ `fimo/react-router/routes` compatibility adapter to application-owned React
5
+ Router routes. Existing projects can upgrade before completing this migration,
6
+ but new projects should not use the adapter and a future breaking release may
7
+ remove it.
8
+
9
+ ## Identify the installed contract
10
+
11
+ Run the project-local CLI with the package manager selected by the lockfile:
12
+
13
+ ```bash
14
+ pnpm exec fimo --version
15
+ ```
16
+
17
+ Then inspect `package.json`, the lockfile, `src/routes.ts`, the locale layout or
18
+ provider, `.fimo/config.json` (or legacy `fimo-config.json`), the language
19
+ selector, redirects, and SEO/static-generation setup. The installed package is
20
+ authoritative. Do not use a newer globally installed CLI to rewrite the app.
21
+
22
+ Choose the path by the installed and target contracts, not by a guessed
23
+ version number:
24
+
25
+ | Installed project | Target project | Action |
26
+ | ------------------------------------- | --------------- | ------------------------------------------------------------------------- |
27
+ | Uses `fimo/react-router/routes` | Current release | Upgrade safely, then follow this guide to leave the deprecated adapter. |
28
+ | Already uses application-owned routes | Later release | Keep the app-owned routes; no routing migration is needed. |
29
+ | Uses another router or framework | Any release | Keep that framework's locale system and pass its resolved locale to Fimo. |
30
+
31
+ The package export and `pnpm exec fimo --version` are the reliable boundary
32
+ until release notes assign concrete version numbers.
33
+
34
+ ## Replace the deprecated route wrapper
35
+
36
+ Remove the `fimo/react-router/routes` import and declare each localized path
37
+ directly. React Router uses `:locale?`; route metadata uses `/:locale` with an
38
+ optional locale descriptor:
39
+
40
+ ```ts
41
+ import type { RouteConfig } from '@react-router/dev/routes';
42
+ import { layout, route } from '@react-router/dev/routes';
43
+
44
+ export default [
45
+ layout('./pages/LocaleLayout.tsx', [
46
+ route(':locale?/pricing', './pages/Pricing.tsx'),
47
+ route(':locale?/blog/:slug', './pages/BlogPost.tsx'),
48
+ ]),
49
+ ] satisfies RouteConfig;
50
+ ```
51
+
52
+ Keep the public URL matrix unchanged:
53
+
54
+ | URL | route | active locale |
55
+ | --------------- | --------- | ------------------ |
56
+ | `/pricing` | pricing | configured default |
57
+ | `/es/pricing` | pricing | `es` |
58
+ | `/blog/hello` | blog post | configured default |
59
+ | `/es/blog/hola` | blog post | `es` |
60
+
61
+ Do not add a default-locale prefix. Read the optional route locale in an
62
+ application-owned layout and pass it to `<FimoProviders locale={locale}>`.
63
+ When it is omitted, FimoProviders resolves the configured default locale.
64
+ Preserve existing redirects, link behavior, document language/direction, and
65
+ locale validation.
66
+
67
+ The copyable boundary is:
68
+
69
+ ```tsx
70
+ import { FimoProviders } from 'fimo/react-router';
71
+ import { Outlet, useParams } from 'react-router';
72
+
73
+ export default function LocaleLayout() {
74
+ const { locale } = useParams();
75
+ return (
76
+ <FimoProviders locale={locale}>
77
+ <Outlet />
78
+ </FimoProviders>
79
+ );
80
+ }
81
+ ```
82
+
83
+ ## Verify before finishing
84
+
85
+ Run the project-local `fimo validate`, then verify all four URL shapes in the
86
+ preview. Switch languages in the application selector and in Studio, and check
87
+ that both report the same locale. Confirm canonical URLs, `hreflang`, sitemap or
88
+ prerender output, and locale-specific metadata/content remain correct.
89
+
90
+ If the installed version has no exact matching reference, preserve every
91
+ existing public URL and routing behavior. Report the installed version, the
92
+ pattern found, the checks completed, and any uncertainty instead of guessing a
93
+ new route shape.
@@ -9,7 +9,8 @@ Use Fimo components for source-tracked schema and label values so Studio can ide
9
9
  | media as `FimoMedia` | `Image` | schema media images |
10
10
  | non-schema URL | `StaticImage` | decorative/static image URLs |
11
11
  | media as `FimoMedia` | `Video` | schema media videos |
12
- | date as `FimoString` | `Date` | schema dates |
12
+ | date as `FimoString` | `Date` | schema dates; `<time datetime>` is the calendar day |
13
+ | datetime as `FimoString` | `DateTime` | schema instants; `<time datetime>` keeps the time |
13
14
  | boolean as `FimoBoolean` | `Boolean` | schema booleans |
14
15
  | source-tagged plain JSON | `Json` | schema JSON |
15
16
  | number | normal JSX; SvelteKit `Number` | numbers stay plain; SvelteKit `Number` formats display-only values |
@@ -21,6 +22,7 @@ Use Fimo components for source-tracked schema and label values so Studio can ide
21
22
  <RichText value={article.body} />
22
23
  <Image value={article.cover} width={1200} height={630} />
23
24
  <Date value={article.publishedAt} />
25
+ <DateTime value={article.lastReviewedAt} />
24
26
  ```
25
27
 
26
28
  Pass the tracked value directly. Do not replace `<Text>` with `<h1>{article.title}</h1>`, unwrap media into raw `<img>`, or hand-roll richtext rendering.
@@ -44,7 +46,24 @@ Blocks do not change this rule. Every visible nested scalar is source-tracked to
44
46
 
45
47
  Do not render those values as `{program.title}` or `{highlight.label}`. That displays text but bypasses the primitive that Studio uses to resolve the exact nested edit target.
46
48
 
47
- Use `<StaticImage>` only when the image is deliberately not editor-managed. Use `String(value)` for attributes/third-party APIs that cannot accept a `FimoString`; keep editable visible text in `<Text>`.
49
+ Use `<StaticImage>` only when the image is deliberately not editor-managed.
50
+
51
+ ## Wrapper values in JavaScript logic
52
+
53
+ `FimoString`, `FimoBoolean`, and the other tracked values are objects, not primitives: a plain string or boolean cannot carry the source field, locale, and edit-target metadata Fimo editing needs. That gives one two-sided rule:
54
+
55
+ - **MUST** pass the wrapper directly to Fimo rendering primitives (`Text`, `Boolean`, …). Unwrapping first removes the edit target.
56
+ - **MUST** normalize the wrapper before any JavaScript comparison, condition, attribute, or third-party API: `String(value)` for strings, `value.value` (or `value.valueOf()`) for booleans.
57
+
58
+ ```ts
59
+ fimoValue === 'build'; // false — an object never strict-equals a primitive
60
+ String(fimoValue) === 'build'; // true
61
+
62
+ if (fimoFlag) { … } // always runs — an object is truthy even when the value is false
63
+ if (fimoFlag.value) { … } // correct
64
+ ```
65
+
66
+ Keep editable visible text in `<Text>`; normalized primitives are for logic and APIs only, never a substitute for rendering through the primitive.
48
67
 
49
68
  Numeric fields stay plain JavaScript numbers, so they do not carry Studio source metadata. SvelteKit's `Number` component is an optional display/formatting helper; it is not source-editable. Other framework surfaces should render numeric fields normally until a shared tracked-number contract exists.
50
69