reroute-js 0.45.12-beta.1 → 0.46.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 (239) hide show
  1. package/README.md +100 -2
  2. package/_/blog/src/client/routes/blog/[layout].tsx +45 -13
  3. package/_/blog/src/client/routes/blog/content/pt-BR/1-hello-world.tsx +27 -0
  4. package/_/blog/src/client/routes/index.tsx +4 -4
  5. package/_/search/src/client/routes/docs/content/content-collections.md +18 -0
  6. package/cli/bin.d.ts +2 -2
  7. package/cli/bin.js +980 -337
  8. package/cli/bin.js.map +29 -21
  9. package/cli/index.d.ts +2 -2
  10. package/cli/index.js +5 -5
  11. package/cli/index.js.map +1 -1
  12. package/cli/src/cli.d.ts +2 -2
  13. package/cli/src/commands/analyze.d.ts +2 -2
  14. package/cli/src/commands/build.d.ts +2 -2
  15. package/cli/src/commands/dev.d.ts +2 -2
  16. package/cli/src/commands/gen.d.ts +2 -2
  17. package/cli/src/commands/gen.d.ts.map +1 -1
  18. package/cli/src/commands/index.d.ts +2 -2
  19. package/cli/src/commands/init.d.ts +2 -2
  20. package/cli/src/commands/lib/assets.d.ts +2 -2
  21. package/cli/src/commands/lib/bundler.d.ts +2 -2
  22. package/cli/src/commands/lib/command.d.ts +2 -2
  23. package/cli/src/commands/lib/env.d.ts +2 -2
  24. package/cli/src/commands/lib/index.d.ts +2 -2
  25. package/cli/src/commands/lib/log.d.ts +2 -2
  26. package/cli/src/commands/lib/markdown/availability.d.ts +2 -2
  27. package/cli/src/commands/lib/markdown/index.d.ts +2 -2
  28. package/cli/src/commands/lib/markdown/processor.d.ts +2 -2
  29. package/cli/src/commands/lib/production.d.ts +2 -2
  30. package/cli/src/commands/lib/server.d.ts +2 -2
  31. package/cli/src/commands/lib/streaming/analyzer.d.ts +2 -2
  32. package/cli/src/commands/lib/streaming/suspense.d.ts +2 -2
  33. package/cli/src/commands/lib/tailwind.d.ts +2 -2
  34. package/cli/src/commands/lib/terminal-ui.d.ts +2 -2
  35. package/cli/src/commands/lib/version.d.ts +2 -2
  36. package/cli/src/commands/og.d.ts +2 -2
  37. package/cli/src/commands/start.d.ts +2 -2
  38. package/cli/src/index.d.ts +2 -2
  39. package/core/index.d.ts +2 -2
  40. package/core/index.js +667 -117
  41. package/core/index.js.map +28 -20
  42. package/core/src/bundler/hash.d.ts +2 -2
  43. package/core/src/bundler/index.d.ts +2 -2
  44. package/core/src/config.d.ts +6 -3
  45. package/core/src/config.d.ts.map +1 -1
  46. package/core/src/content/discovery.d.ts +2 -2
  47. package/core/src/content/index.d.ts +2 -2
  48. package/core/src/content/metadata.d.ts +2 -2
  49. package/core/src/i18n/catalog.d.ts +17 -0
  50. package/core/src/i18n/catalog.d.ts.map +1 -0
  51. package/core/src/i18n/discover.d.ts +19 -0
  52. package/core/src/i18n/discover.d.ts.map +1 -0
  53. package/core/src/i18n/index.d.ts +17 -0
  54. package/core/src/i18n/index.d.ts.map +1 -0
  55. package/core/src/i18n/messages.d.ts +18 -0
  56. package/core/src/i18n/messages.d.ts.map +1 -0
  57. package/core/src/i18n/negotiate.d.ts +18 -0
  58. package/core/src/i18n/negotiate.d.ts.map +1 -0
  59. package/core/src/i18n/pathname.d.ts +34 -0
  60. package/core/src/i18n/pathname.d.ts.map +1 -0
  61. package/core/src/i18n/resolve.d.ts +22 -0
  62. package/core/src/i18n/resolve.d.ts.map +1 -0
  63. package/core/src/i18n/types.d.ts +68 -0
  64. package/core/src/i18n/types.d.ts.map +1 -0
  65. package/core/src/index.d.ts +3 -2
  66. package/core/src/index.d.ts.map +1 -1
  67. package/core/src/llms/extractor.d.ts +2 -2
  68. package/core/src/llms/formatter.d.ts +2 -2
  69. package/core/src/llms/full-generator.d.ts +2 -2
  70. package/core/src/llms/index-generator.d.ts +2 -2
  71. package/core/src/llms/index.d.ts +2 -2
  72. package/core/src/og/discovery.d.ts +2 -2
  73. package/core/src/og/index.d.ts +2 -2
  74. package/core/src/og/meta.d.ts +2 -2
  75. package/core/src/og/render.d.ts +2 -2
  76. package/core/src/og/types.d.ts +2 -2
  77. package/core/src/robots/discovery.d.ts +2 -2
  78. package/core/src/robots/generator.d.ts +2 -2
  79. package/core/src/robots/index.d.ts +2 -2
  80. package/core/src/robots/policies.d.ts +2 -2
  81. package/core/src/rss/discovery.d.ts +4 -2
  82. package/core/src/rss/discovery.d.ts.map +1 -1
  83. package/core/src/rss/generator.d.ts +2 -2
  84. package/core/src/rss/index.d.ts +2 -2
  85. package/core/src/sitemap/discovery.d.ts +7 -2
  86. package/core/src/sitemap/discovery.d.ts.map +1 -1
  87. package/core/src/sitemap/generator.d.ts +2 -2
  88. package/core/src/sitemap/generator.d.ts.map +1 -1
  89. package/core/src/sitemap/index.d.ts +2 -2
  90. package/core/src/ssr/index.d.ts +2 -2
  91. package/core/src/ssr/lib/cache.d.ts +2 -2
  92. package/core/src/ssr/lib/cleanup.d.ts +2 -2
  93. package/core/src/ssr/lib/collections.d.ts +2 -2
  94. package/core/src/ssr/lib/compression.d.ts +2 -2
  95. package/core/src/ssr/lib/compute/content.d.ts +2 -9
  96. package/core/src/ssr/lib/compute/content.d.ts.map +1 -1
  97. package/core/src/ssr/lib/compute/index.d.ts +2 -2
  98. package/core/src/ssr/lib/compute/layouts.d.ts +2 -2
  99. package/core/src/ssr/lib/compute/routes.d.ts +2 -2
  100. package/core/src/ssr/lib/compute/routes.d.ts.map +1 -1
  101. package/core/src/ssr/lib/content-path.d.ts +22 -0
  102. package/core/src/ssr/lib/content-path.d.ts.map +1 -0
  103. package/core/src/ssr/lib/data.d.ts +2 -2
  104. package/core/src/ssr/lib/data.d.ts.map +1 -1
  105. package/core/src/ssr/lib/html.d.ts +2 -2
  106. package/core/src/ssr/lib/imports.d.ts +2 -2
  107. package/core/src/ssr/lib/index.d.ts +2 -2
  108. package/core/src/ssr/lib/layouts.d.ts +2 -2
  109. package/core/src/ssr/lib/metadata.d.ts +2 -2
  110. package/core/src/ssr/lib/metadata.d.ts.map +1 -1
  111. package/core/src/ssr/lib/mime.d.ts +2 -2
  112. package/core/src/ssr/lib/modules.d.ts +4 -4
  113. package/core/src/ssr/lib/modules.d.ts.map +1 -1
  114. package/core/src/ssr/lib/path.d.ts +2 -2
  115. package/core/src/ssr/lib/preload.d.ts +2 -2
  116. package/core/src/ssr/lib/preload.d.ts.map +1 -1
  117. package/core/src/ssr/lib/route-match.d.ts +2 -2
  118. package/core/src/ssr/lib/scripts/collections.d.ts +2 -2
  119. package/core/src/ssr/lib/scripts/data.d.ts +3 -3
  120. package/core/src/ssr/lib/scripts/data.d.ts.map +1 -1
  121. package/core/src/ssr/lib/scripts/escape.d.ts +2 -2
  122. package/core/src/ssr/lib/scripts/feeds.d.ts +2 -2
  123. package/core/src/ssr/lib/scripts/index.d.ts +2 -2
  124. package/core/src/ssr/lib/seed.d.ts +2 -2
  125. package/core/src/ssr/lib/seed.d.ts.map +1 -1
  126. package/core/src/ssr/lib/serialize.d.ts +2 -2
  127. package/core/src/ssr/lib/setup.d.ts +3 -3
  128. package/core/src/ssr/lib/setup.d.ts.map +1 -1
  129. package/core/src/ssr/lib/styles.d.ts +2 -2
  130. package/core/src/ssr/lib/template.d.ts +2 -2
  131. package/core/src/ssr/lib/types.d.ts +2 -2
  132. package/core/src/ssr/render.d.ts +4 -2
  133. package/core/src/ssr/render.d.ts.map +1 -1
  134. package/core/src/ssr/stream.d.ts +4 -2
  135. package/core/src/ssr/stream.d.ts.map +1 -1
  136. package/elysia/index.d.ts +2 -2
  137. package/elysia/index.js +872 -177
  138. package/elysia/index.js.map +32 -23
  139. package/elysia/src/index.d.ts +2 -2
  140. package/elysia/src/libs/assets.d.ts +2 -2
  141. package/elysia/src/libs/cache.d.ts +2 -2
  142. package/elysia/src/libs/caching.d.ts +2 -2
  143. package/elysia/src/libs/http.d.ts +2 -2
  144. package/elysia/src/libs/i18n.d.ts +26 -0
  145. package/elysia/src/libs/i18n.d.ts.map +1 -0
  146. package/elysia/src/libs/image.d.ts +2 -2
  147. package/elysia/src/libs/index.d.ts +2 -2
  148. package/elysia/src/libs/llms.d.ts +2 -2
  149. package/elysia/src/libs/response.d.ts +2 -2
  150. package/elysia/src/libs/serving.d.ts +2 -2
  151. package/elysia/src/plugin.d.ts +2 -2
  152. package/elysia/src/routes/artifacts.d.ts +2 -2
  153. package/elysia/src/routes/content.d.ts +2 -2
  154. package/elysia/src/routes/image.d.ts +2 -2
  155. package/elysia/src/routes/index.d.ts +2 -2
  156. package/elysia/src/routes/internal.d.ts +2 -2
  157. package/elysia/src/routes/llms.d.ts +2 -2
  158. package/elysia/src/routes/og.d.ts +2 -2
  159. package/elysia/src/routes/redirects.d.ts +2 -2
  160. package/elysia/src/routes/robots.d.ts +2 -2
  161. package/elysia/src/routes/rss.d.ts +2 -2
  162. package/elysia/src/routes/rss.d.ts.map +1 -1
  163. package/elysia/src/routes/search.d.ts +2 -2
  164. package/elysia/src/routes/search.d.ts.map +1 -1
  165. package/elysia/src/routes/sitemap.d.ts +2 -2
  166. package/elysia/src/routes/ssr.d.ts +2 -2
  167. package/elysia/src/routes/ssr.d.ts.map +1 -1
  168. package/elysia/src/routes/static.d.ts +2 -2
  169. package/elysia/src/types.d.ts +2 -2
  170. package/package.json +7 -6
  171. package/react/index.d.ts +2 -2
  172. package/react/index.js +560 -170
  173. package/react/index.js.map +12 -10
  174. package/react/src/components/ClientOnly.d.ts +2 -2
  175. package/react/src/components/ContentRoute.d.ts +3 -3
  176. package/react/src/components/ContentRoute.d.ts.map +1 -1
  177. package/react/src/components/Image.d.ts +2 -2
  178. package/react/src/components/LazyRoute.d.ts +2 -2
  179. package/react/src/components/Link.d.ts +2 -2
  180. package/react/src/components/Link.d.ts.map +1 -1
  181. package/react/src/components/Markdown.d.ts +2 -2
  182. package/react/src/components/Outlet.d.ts +2 -2
  183. package/react/src/components/index.d.ts +2 -2
  184. package/react/src/hooks/index.d.ts +2 -2
  185. package/react/src/hooks/useContent.d.ts +2 -2
  186. package/react/src/hooks/useContent.d.ts.map +1 -1
  187. package/react/src/hooks/useData.d.ts +2 -2
  188. package/react/src/hooks/useFeed.d.ts +2 -2
  189. package/react/src/hooks/useLayoutData.d.ts +2 -2
  190. package/react/src/hooks/useLlms.d.ts +2 -2
  191. package/react/src/hooks/useNavigate.d.ts +2 -2
  192. package/react/src/hooks/useParams.d.ts +2 -2
  193. package/react/src/hooks/useRouter.d.ts +2 -2
  194. package/react/src/hooks/useSearch.d.ts +2 -2
  195. package/react/src/hooks/useSearch.d.ts.map +1 -1
  196. package/react/src/hooks/useSearchParams.d.ts +2 -2
  197. package/react/src/hooks/useToc.d.ts +2 -2
  198. package/react/src/i18n/LocaleProvider.d.ts +49 -0
  199. package/react/src/i18n/LocaleProvider.d.ts.map +1 -0
  200. package/react/src/i18n/helpers.d.ts +24 -0
  201. package/react/src/i18n/helpers.d.ts.map +1 -0
  202. package/react/src/i18n/index.d.ts +13 -0
  203. package/react/src/i18n/index.d.ts.map +1 -0
  204. package/react/src/index.d.ts +3 -2
  205. package/react/src/index.d.ts.map +1 -1
  206. package/react/src/lib/collection.d.ts +2 -2
  207. package/react/src/lib/content.d.ts +4 -3
  208. package/react/src/lib/content.d.ts.map +1 -1
  209. package/react/src/lib/head.d.ts +2 -2
  210. package/react/src/lib/index.d.ts +2 -2
  211. package/react/src/lib/lazy-route.d.ts +2 -2
  212. package/react/src/lib/route-loader.d.ts +2 -2
  213. package/react/src/providers/ContentProvider.d.ts +3 -3
  214. package/react/src/providers/ContentProvider.d.ts.map +1 -1
  215. package/react/src/providers/RerouteProvider.d.ts +8 -6
  216. package/react/src/providers/RerouteProvider.d.ts.map +1 -1
  217. package/react/src/providers/RouterProvider.d.ts +2 -2
  218. package/react/src/providers/index.d.ts +2 -2
  219. package/react/src/types/any.d.ts +2 -2
  220. package/react/src/types/index.d.ts +2 -2
  221. package/react/src/types/router.d.ts +2 -2
  222. package/telemetry/react.d.ts +2 -2
  223. package/telemetry/react.js +3 -3
  224. package/telemetry/react.js.map +1 -1
  225. package/telemetry/server.d.ts +2 -2
  226. package/telemetry/server.js +56 -4
  227. package/telemetry/server.js.map +20 -15
  228. package/telemetry/src/react/api.d.ts +2 -2
  229. package/telemetry/src/react/context.d.ts +2 -2
  230. package/telemetry/src/react/index.d.ts +2 -2
  231. package/telemetry/src/react/telemetry.d.ts +2 -2
  232. package/telemetry/src/server/context.d.ts +2 -2
  233. package/telemetry/src/server/headers/extractor.d.ts +2 -2
  234. package/telemetry/src/server/headers/index.d.ts +2 -2
  235. package/telemetry/src/server/headers/presets.d.ts +2 -2
  236. package/telemetry/src/server/index.d.ts +2 -2
  237. package/telemetry/src/server/instrumentation.d.ts +2 -2
  238. package/telemetry/src/server/plugin.d.ts +2 -2
  239. package/telemetry/src/server/sourcemap.d.ts +2 -2
package/README.md CHANGED
@@ -22,6 +22,12 @@ Reroute is a feature-rich file-based routing framework for building fullstack Re
22
22
  - [Environment Files](#environment-files)
23
23
  - [Security](#security)
24
24
  - [TypeScript Support](#typescript-support)
25
+ - [🌍 Internationalization (i18n)](#-internationalization-i18n)
26
+ - [Enable](#enable)
27
+ - [URL Rules](#url-rules)
28
+ - [UI Strings](#ui-strings)
29
+ - [SEO & Feeds](#seo--feeds)
30
+ - [Config](#config)
25
31
  - [📝 Markdown Routes](#-markdown-routes)
26
32
  - [Installation](#installation)
27
33
  - [Creating Markdown Routes](#creating-markdown-routes)
@@ -74,6 +80,7 @@ Reroute is a feature-rich file-based routing framework for building fullstack Re
74
80
 
75
81
  ### 📄 Content Management
76
82
  - 📚 **Content Collections** - Organize content by collections (blog posts, docs, etc.)
83
+ - 🌍 **Internationalization** - Opt-in, collection-scoped i18n via `locales/` + `content/{locale}/`
77
84
  - 🔍 **Content Discovery** - Automatic scanning and indexing of content files
78
85
  - 🏷️ **Metadata Extraction** - Support for content metadata
79
86
  - 📑 **Content Registry** - Pre-generated content index for fast lookups
@@ -116,8 +123,11 @@ Reroute is a feature-rich file-based routing framework for building fullstack Re
116
123
  - `useLlms()` - Discover LLM-friendly content URLs for current route
117
124
  - `useSearch()` - Client-side content search with debouncing
118
125
  - `useToc()` - Auto-extract table of contents from markdown headings
126
+ - 🌍 **i18n**:
127
+ - `t(key, values?)` - Plain translator (ICU MessageFormat); not a hook
128
+ - `useLocale()` - Active locale, available locales, and `setLocale()`
119
129
  - 🧩 **Components**:
120
- - `<Link>` - Client-side navigation with automatic prefetching
130
+ - `<Link>` - Client-side navigation with automatic prefetching (localizes content hrefs)
121
131
  - `<Image>` - Optimized images with automatic format negotiation and lazy loading
122
132
  - `<Outlet>` - Render nested route components
123
133
  - `<ContentRoute>` - Dynamic content rendering with metadata injection
@@ -208,6 +218,7 @@ Reroute is a feature-rich file-based routing framework for building fullstack Re
208
218
  ### 🗺️ Sitemap Generation
209
219
  - 🔍 **Auto-Discovery** - Automatically discovers static routes, content collections, and ssr.data routes
210
220
  - 📄 **XML Generation** - Standards-compliant sitemap.xml following Google's specifications
221
+ - 🌍 **i18n Alternates** - `xhtml:link` hreflang entries for localized content
211
222
  - 💾 **Smart Caching** - Generated on first request and cached according to maxAge
212
223
  - 📊 **Auto-Pagination** - Automatically splits into multiple files for sites with 50k+ URLs
213
224
  - 🎨 **Custom Extractors** - Content-agnostic URL and date extraction via configuration
@@ -225,6 +236,7 @@ Reroute is a feature-rich file-based routing framework for building fullstack Re
225
236
  - 🔍 **Auto-Discovery** - Discovers content collections, route ssr.data, and layout ssr.data
226
237
  - 📄 **RSS & Atom Support** - Standards-compliant RSS 2.0 and Atom 1.0 formats
227
238
  - 📚 **Per-Collection Feeds** - Each collection gets its own feed (e.g., /blog/feed.xml)
239
+ - 🌍 **Locale Filter** - `?lang=` filters feed items by content locale
228
240
  - 💾 **Smart Caching** - Generated on first request and cached according to maxAge
229
241
  - 🎨 **Custom Extractors** - Content-agnostic extraction for title, description, author, pubDate
230
242
 
@@ -623,6 +635,92 @@ interface ImportMeta {
623
635
  }
624
636
  ```
625
637
 
638
+ ## 🌍 Internationalization (i18n)
639
+
640
+ Opt-in and **collection-scoped** — not site-wide locale prefixes. Enabled only when a `locales/` directory exists at the app root.
641
+
642
+ ### Enable
643
+
644
+ ```
645
+ locales/
646
+ en-US.json # default locale catalog
647
+ pt-BR.json
648
+ src/client/routes/blog/content/
649
+ hello-world.tsx # default locale (unprefixed URL)
650
+ pt-BR/
651
+ hello-world.tsx # /blog/pt-BR/hello-world
652
+ ```
653
+
654
+ ```json
655
+ // locales/en-US.json
656
+ {
657
+ "nav": { "home": "Home" },
658
+ "blog": {
659
+ "postsCount": "{count, plural, =0 {No posts} one {# post} other {# posts}}"
660
+ }
661
+ }
662
+ ```
663
+
664
+ ### URL Rules
665
+
666
+ | Locale | URL |
667
+ |--------|-----|
668
+ | Default (`en-US`) | `/blog/hello-world` |
669
+ | Other | `/blog/pt-BR/hello-world` |
670
+ | Non-content routes | unchanged (`/about`, `/`) |
671
+
672
+ - Flat files under `content/` are the default locale; nest under `content/{locale}/` for translations
673
+ - Collections without locale folders behave as before
674
+ - Default-locale prefix (`/blog/en-US/...`) 302s to the unprefixed URL
675
+ - Optional negotiate: `Accept-Language` / cookie can 302 default content URLs to a localized path (`i18n.redirectContentOnNegotiate`, default `true`)
676
+
677
+ ### UI Strings
678
+
679
+ ```tsx
680
+ import { t, useLocale, Link } from 'reroute-js/react';
681
+
682
+ function Nav() {
683
+ const { locale, locales, setLocale } = useLocale();
684
+ return (
685
+ <>
686
+ <Link to="/">{t('nav.home')}</Link>
687
+ <select value={locale} onChange={(e) => setLocale(e.target.value)}>
688
+ {locales.map((l) => (
689
+ <option key={l} value={l}>{l}</option>
690
+ ))}
691
+ </select>
692
+ <footer>{t('blog.postsCount', { count: 5 })}</footer>
693
+ </>
694
+ );
695
+ }
696
+ ```
697
+
698
+ - `t(key, values?)` — plain function (not a hook); ICU MessageFormat supported
699
+ - `useLocale()` — `{ locale, locales, defaultLocale, enabled, setLocale }`
700
+ - `Link` auto-localizes content hrefs; cookie (`reroute-locale`) + `Accept-Language` resolve UI locale
701
+
702
+ ### SEO & Feeds
703
+
704
+ - `hreflang` + `og:locale` on content pages
705
+ - Sitemap includes `xhtml:link` alternates
706
+ - RSS / search accept `?lang=` to filter by locale
707
+
708
+ ### Config
709
+
710
+ ```tsx
711
+ // reroute.config.ts
712
+ export default defineConfig({
713
+ i18n: {
714
+ defaultLocale: 'en-US', // unprefixed content URLs
715
+ localesDir: 'locales', // catalog directory
716
+ cookie: 'reroute-locale',
717
+ redirectContentOnNegotiate: true, // 302 default content → localized URL
718
+ },
719
+ });
720
+ ```
721
+
722
+ Feature still requires a `locales/` directory — config only overrides defaults.
723
+
626
724
  ## 📝 Markdown Routes
627
725
 
628
726
  Reroute supports native markdown and MDX files as routes with frontmatter support and syntax highlighting.
@@ -1693,7 +1791,7 @@ Built-in tracing for debugging SSR, 404s, and cache behavior. Automatically trac
1693
1791
 
1694
1792
  - [Examples](./examples) - Example projects to get started
1695
1793
  - [Packages](./packages) - Reroute entrypoints
1696
- - [GitHub](https://github.com/stewones/reroute) - Source code and issues
1794
+ - [GitHub](https://github.com/Intenseloop/reroute) - Source code and issues
1697
1795
 
1698
1796
  ## 🏗️ Build & Deployment
1699
1797
 
@@ -1,5 +1,5 @@
1
- import { Link, Outlet, useData } from 'reroute-js/react';
2
1
  import type { SSR } from 'reroute-js/core';
2
+ import { Link, Outlet, t, useData, useLocale } from 'reroute-js/react';
3
3
 
4
4
  // Layout data type
5
5
  type LayoutData = {
@@ -16,13 +16,17 @@ export const ssr: SSR<LayoutData> = {
16
16
  // Get last updated timestamp from package.json mtime
17
17
  let lastUpdated: string | undefined;
18
18
  try {
19
- const pkgPath = await import('node:path').then(p => p.join(process.cwd(), 'package.json'));
20
- const stats = await import('node:fs/promises').then(fs => fs.stat(pkgPath));
19
+ const pkgPath = await import('node:path').then((p) =>
20
+ p.join(process.cwd(), 'package.json'),
21
+ );
22
+ const stats = await import('node:fs/promises').then((fs) =>
23
+ fs.stat(pkgPath),
24
+ );
21
25
  lastUpdated = stats.mtime.toISOString();
22
26
  } catch {
23
27
  lastUpdated = new Date().toISOString();
24
28
  }
25
-
29
+
26
30
  return {
27
31
  siteTitle: 'Reroute Blog',
28
32
  tagline: 'Fast, Modern, File-Based Routing',
@@ -39,11 +43,11 @@ export const meta = {
39
43
  };
40
44
 
41
45
  export default function BlogLayout() {
42
- // Access layout data - it just works!
43
46
  const data = useData<LayoutData>();
47
+ const { locale, locales, setLocale, enabled } = useLocale();
48
+
44
49
  return (
45
50
  <div style={{ minHeight: '100vh', background: '#f9f9f9' }}>
46
- {/* Blog Header */}
47
51
  <header
48
52
  style={{
49
53
  background: '#fff',
@@ -57,6 +61,8 @@ export default function BlogLayout() {
57
61
  display: 'flex',
58
62
  alignItems: 'center',
59
63
  justifyContent: 'space-between',
64
+ gap: '1rem',
65
+ flexWrap: 'wrap',
60
66
  }}
61
67
  >
62
68
  <Link
@@ -68,7 +74,7 @@ export default function BlogLayout() {
68
74
  color: '#333',
69
75
  }}
70
76
  >
71
- 📝 {data?.siteTitle || 'Blog'}
77
+ 📝 {t('blog.title')}
72
78
  </Link>
73
79
  <div
74
80
  style={{ display: 'flex', gap: '1.5rem', alignItems: 'center' }}
@@ -81,7 +87,7 @@ export default function BlogLayout() {
81
87
  fontSize: '0.875rem',
82
88
  }}
83
89
  >
84
- Home
90
+ {t('nav.home')}
85
91
  </Link>
86
92
  <Link
87
93
  to='/about'
@@ -91,21 +97,43 @@ export default function BlogLayout() {
91
97
  fontSize: '0.875rem',
92
98
  }}
93
99
  >
94
- About
100
+ {t('nav.about')}
95
101
  </Link>
102
+ {enabled && locales.length > 1 && (
103
+ <label
104
+ style={{
105
+ display: 'flex',
106
+ alignItems: 'center',
107
+ gap: '0.35rem',
108
+ fontSize: '0.875rem',
109
+ color: '#666',
110
+ }}
111
+ >
112
+ {t('blog.language')}
113
+ <select
114
+ value={locale}
115
+ onChange={(e) => setLocale(e.target.value)}
116
+ style={{ fontSize: '0.875rem' }}
117
+ >
118
+ {locales.map((loc) => (
119
+ <option key={loc} value={loc}>
120
+ {loc}
121
+ </option>
122
+ ))}
123
+ </select>
124
+ </label>
125
+ )}
96
126
  </div>
97
127
  </nav>
98
128
  </div>
99
129
  </header>
100
130
 
101
- {/* Blog Content */}
102
131
  <main>
103
132
  <div style={{ maxWidth: '800px', margin: '0 auto' }}>
104
133
  <Outlet />
105
134
  </div>
106
135
  </main>
107
136
 
108
- {/* Blog Footer */}
109
137
  <footer
110
138
  style={{
111
139
  marginTop: '4rem',
@@ -117,10 +145,14 @@ export default function BlogLayout() {
117
145
  background: '#fff',
118
146
  }}
119
147
  >
120
- <p>© {new Date().getFullYear()} Reroute Blog. Built with Bun, Elysia, and React.</p>
148
+ <p>
149
+ © {new Date().getFullYear()} {t('blog.title')}. Built with Bun,
150
+ Elysia, and React.
151
+ </p>
121
152
  {data?.totalPosts && (
122
153
  <p style={{ marginTop: '0.5rem', fontSize: '0.75rem' }}>
123
- {data.totalPosts} posts • Last updated: {new Date(data.lastUpdated).toLocaleString()}
154
+ {t('blog.postsCount', { count: data.totalPosts })} • Last updated:{' '}
155
+ {new Date(data.lastUpdated).toLocaleString(locale)}
124
156
  </p>
125
157
  )}
126
158
  </footer>
@@ -0,0 +1,27 @@
1
+ // Page metadata and optional SSR extras. Reroute SSR will use these
2
+ // to generate <title>, <meta name="description"> and append any custom head.
3
+ const meta = {
4
+ title: 'Olá Mundo',
5
+ description: 'Este é o primeiro post usando Reroute 🎉',
6
+ excerpt: 'Este é um ótimo post',
7
+ date: '2025-10-20',
8
+ };
9
+
10
+ const ssr = {
11
+ head: [
12
+ '<meta property="og:type" content="article" />',
13
+ '<meta name="twitter:card" content="summary_large_image" />',
14
+ ],
15
+ };
16
+
17
+ function BlogPost() {
18
+ return (
19
+ <div>
20
+ <h1>Olá Mundo</h1>
21
+ <p>Bem-vindo ao meu blog!!!</p>
22
+ </div>
23
+ );
24
+ }
25
+
26
+ export { meta, ssr };
27
+ export default BlogPost;
@@ -1,10 +1,10 @@
1
- import { Link } from 'reroute-js/react';
1
+ import { Link, t } from 'reroute-js/react';
2
2
 
3
3
  export default function HomePage() {
4
4
  return (
5
5
  <main style={{ padding: '2rem', maxWidth: '1200px', margin: '0 auto' }}>
6
6
  <h1>🏠 Welcome to Reroute!</h1>
7
- <p>This is the home page of your custom file-based routing system.</p>
7
+ <p>{t('home.headline')}</p>
8
8
 
9
9
  <section style={{ marginTop: '2rem' }}>
10
10
  <h2>Navigation</h2>
@@ -25,7 +25,7 @@ export default function HomePage() {
25
25
  borderRadius: '4px',
26
26
  }}
27
27
  >
28
- About
28
+ {t('nav.about')}
29
29
  </Link>
30
30
  <Link
31
31
  to='/blog'
@@ -36,7 +36,7 @@ export default function HomePage() {
36
36
  borderRadius: '4px',
37
37
  }}
38
38
  >
39
- Blog
39
+ {t('home.cta')}
40
40
  </Link>
41
41
  <Link
42
42
  to='/docs'
@@ -35,6 +35,24 @@ src/client/routes/
35
35
  └── post-3.tsx
36
36
  ```
37
37
 
38
+ ### Multilingual content (opt-in)
39
+
40
+ Add a `locales/` folder at the app root with JSON catalogs (e.g. `en-US.json`, `pt-BR.json`) to enable i18n. Then nest translations under `content/{locale}/`:
41
+
42
+ ```
43
+ locales/
44
+ en-US.json
45
+ pt-BR.json
46
+ src/client/routes/blog/content/
47
+ en-US/post-1.md # or keep flat files as the default locale
48
+ pt-BR/post-1.md
49
+ ```
50
+
51
+ - Default locale URLs stay unprefixed: `/blog/post-1`
52
+ - Other locales: `/blog/pt-BR/post-1`
53
+ - Collections without locale folders are unchanged
54
+ - Use `t('nav.home')` for UI strings (ICU MessageFormat supported)
55
+
38
56
  ### Content Files
39
57
 
40
58
  #### Markdown Files
package/cli/bin.d.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  /**
2
- * reroute-js v0.45.11
2
+ * reroute-js v0.46.0
3
3
  *
4
4
  * @license MIT
5
5
  * @copyright 2026 stewones <hi@stewan.io>
6
- * @see https://github.com/stewones/reroute
6
+ * @see https://github.com/Intenseloop/reroute
7
7
  *
8
8
  * Built with Bun <3
9
9
  */