@tanstack/cta-framework-react-cra 0.44.1 → 0.44.3
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/add-ons/drizzle/assets/src/routes/demo/drizzle.tsx +1 -1
- package/add-ons/paraglide/README.md +7 -0
- package/add-ons/paraglide/assets/messages/de.json +9 -0
- package/add-ons/paraglide/assets/messages/en.json +9 -0
- package/add-ons/paraglide/assets/project.inlang/settings.json +12 -0
- package/add-ons/paraglide/assets/src/components/LocaleSwitcher.tsx.ejs +44 -0
- package/add-ons/paraglide/assets/src/routes/demo.i18n.tsx.ejs +34 -0
- package/add-ons/paraglide/info.json +25 -0
- package/add-ons/paraglide/package.json +5 -0
- package/add-ons/paraglide/small-logo.svg +4 -0
- package/add-ons/start/assets/src/router.tsx.ejs +9 -0
- package/add-ons/start/assets/src/server.ts.ejs +9 -0
- package/add-ons/start/assets/vite.config.ts.ejs +8 -1
- package/hosts/nitro/package.json +1 -1
- package/package.json +2 -2
- package/project/base/src/main.tsx.ejs +9 -2
- package/project/base/src/routes/__root.tsx.ejs +23 -2
- package/project/base/tsconfig.json.ejs +2 -1
- package/project/base/vite.config.ts.ejs +7 -2
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Paraglide i18n
|
|
2
|
+
|
|
3
|
+
This add-on wires up ParaglideJS for localized routing and message formatting.
|
|
4
|
+
|
|
5
|
+
- Messages live in `project.inlang/messages`.
|
|
6
|
+
- URLs are localized through the Paraglide Vite plugin and router `rewrite` hooks.
|
|
7
|
+
- Run the dev server or build to regenerate the `src/paraglide` outputs.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://inlang.com/schema/inlang-message-format",
|
|
3
|
+
"home_page": "Startseite",
|
|
4
|
+
"about_page": "Über uns",
|
|
5
|
+
"example_message": "Willkommen in deiner i18n-App.",
|
|
6
|
+
"language_label": "Sprache",
|
|
7
|
+
"current_locale": "Aktuelle Sprache: {locale}",
|
|
8
|
+
"learn_router": "Paraglide JS lernen"
|
|
9
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://inlang.com/schema/inlang-message-format",
|
|
3
|
+
"home_page": "Home page",
|
|
4
|
+
"about_page": "About page",
|
|
5
|
+
"example_message": "Welcome to your i18n app.",
|
|
6
|
+
"language_label": "Language",
|
|
7
|
+
"current_locale": "Current locale: {locale}",
|
|
8
|
+
"learn_router": "Learn Paraglide JS"
|
|
9
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://inlang.com/schema/project-settings",
|
|
3
|
+
"baseLocale": "en",
|
|
4
|
+
"locales": ["en", "de"],
|
|
5
|
+
"modules": [
|
|
6
|
+
"https://cdn.jsdelivr.net/npm/@inlang/plugin-message-format@4/dist/index.js",
|
|
7
|
+
"https://cdn.jsdelivr.net/npm/@inlang/plugin-m-function-matcher@2/dist/index.js"
|
|
8
|
+
],
|
|
9
|
+
"plugin.inlang.messageFormat": {
|
|
10
|
+
"pathPattern": "./messages/{locale}.json"
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// Locale switcher refs:
|
|
2
|
+
// - Paraglide docs: https://inlang.com/m/gerre34r/library-inlang-paraglideJs
|
|
3
|
+
// - Router example: https://github.com/TanStack/router/tree/main/examples/react/i18n-paraglide#switching-locale
|
|
4
|
+
import { getLocale, locales, setLocale } from '@/paraglide/runtime'
|
|
5
|
+
import { m } from '@/paraglide/messages'
|
|
6
|
+
|
|
7
|
+
export default function ParaglideLocaleSwitcher() {
|
|
8
|
+
const currentLocale = getLocale()
|
|
9
|
+
|
|
10
|
+
return (
|
|
11
|
+
<div
|
|
12
|
+
style={{
|
|
13
|
+
display: 'flex',
|
|
14
|
+
gap: '0.5rem',
|
|
15
|
+
alignItems: 'center',
|
|
16
|
+
color: 'inherit',
|
|
17
|
+
}}
|
|
18
|
+
aria-label={m.language_label()}
|
|
19
|
+
>
|
|
20
|
+
<span style={{ opacity: 0.85 }}>{m.current_locale({ locale: currentLocale })}</span>
|
|
21
|
+
<div style={{ display: 'flex', gap: '0.25rem' }}>
|
|
22
|
+
{locales.map((locale) => (
|
|
23
|
+
<button
|
|
24
|
+
key={locale}
|
|
25
|
+
onClick={() => setLocale(locale)}
|
|
26
|
+
aria-pressed={locale === currentLocale}
|
|
27
|
+
style={{
|
|
28
|
+
cursor: 'pointer',
|
|
29
|
+
padding: '0.35rem 0.75rem',
|
|
30
|
+
borderRadius: '999px',
|
|
31
|
+
border: '1px solid #d1d5db',
|
|
32
|
+
background: locale === currentLocale ? '#0f172a' : 'transparent',
|
|
33
|
+
color: locale === currentLocale ? '#f8fafc' : 'inherit',
|
|
34
|
+
fontWeight: locale === currentLocale ? 700 : 500,
|
|
35
|
+
letterSpacing: '0.01em',
|
|
36
|
+
}}
|
|
37
|
+
>
|
|
38
|
+
{locale.toUpperCase()}
|
|
39
|
+
</button>
|
|
40
|
+
))}
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
)
|
|
44
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { createFileRoute } from "@tanstack/react-router";
|
|
2
|
+
import logo from "../logo.svg";
|
|
3
|
+
import { m } from "@/paraglide/messages";
|
|
4
|
+
import LocaleSwitcher from "../components/LocaleSwitcher";
|
|
5
|
+
|
|
6
|
+
export const Route = createFileRoute("/demo/i18n")({
|
|
7
|
+
component: App,
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
function App() {
|
|
11
|
+
return (
|
|
12
|
+
<div className="text-center">
|
|
13
|
+
<header className="min-h-screen flex flex-col items-center justify-center bg-[#282c34] text-white text-[calc(10px+2vmin)] gap-4">
|
|
14
|
+
<img
|
|
15
|
+
src={logo}
|
|
16
|
+
className="h-[40vmin] pointer-events-none animate-[spin_20s_linear_infinite]"
|
|
17
|
+
alt="logo"
|
|
18
|
+
/>
|
|
19
|
+
<p>{m.example_message({ username: "TanStack Router" })}</p>
|
|
20
|
+
<a
|
|
21
|
+
className="text-[#61dafb] hover:underline"
|
|
22
|
+
href="https://inlang.com/m/gerre34r/library-inlang-paraglideJs"
|
|
23
|
+
target="_blank"
|
|
24
|
+
rel="noopener noreferrer"
|
|
25
|
+
>
|
|
26
|
+
{m.learn_router()}
|
|
27
|
+
</a>
|
|
28
|
+
<div className="mt-3">
|
|
29
|
+
<LocaleSwitcher />
|
|
30
|
+
</div>
|
|
31
|
+
</header>
|
|
32
|
+
</div>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Paraglide (i18n)",
|
|
3
|
+
"description": "i18n with localized routing",
|
|
4
|
+
"phase": "add-on",
|
|
5
|
+
"modes": ["file-router"],
|
|
6
|
+
"type": "add-on",
|
|
7
|
+
"priority": 30,
|
|
8
|
+
"link": "https://github.com/paraglidejs/paraglide-js",
|
|
9
|
+
"routes": [
|
|
10
|
+
{
|
|
11
|
+
"icon": "Languages",
|
|
12
|
+
"url": "/demo/i18n",
|
|
13
|
+
"name": "I18n example",
|
|
14
|
+
"path": "src/routes/demo.i18n.tsx",
|
|
15
|
+
"jsName": "I18nDemo"
|
|
16
|
+
}
|
|
17
|
+
],
|
|
18
|
+
"integrations": [
|
|
19
|
+
{
|
|
20
|
+
"type": "header-user",
|
|
21
|
+
"path": "src/components/LocaleSwitcher.tsx",
|
|
22
|
+
"jsName": "ParaglideLocaleSwitcher"
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
}
|
|
@@ -11,6 +11,8 @@ import { HttpLink } from "@apollo/client";
|
|
|
11
11
|
<% } %>
|
|
12
12
|
<% if (addOnEnabled.sentry) { %>
|
|
13
13
|
import * as Sentry from "@sentry/tanstackstart-react";
|
|
14
|
+
<% } %><% if (addOnEnabled.paraglide) { %>
|
|
15
|
+
import { deLocalizeUrl, localizeUrl } from "./paraglide/runtime";
|
|
14
16
|
<% } %>
|
|
15
17
|
|
|
16
18
|
// Import the generated route tree
|
|
@@ -41,6 +43,13 @@ export const getRouter = () => {
|
|
|
41
43
|
...rqContext,
|
|
42
44
|
<% } %>
|
|
43
45
|
},
|
|
46
|
+
<% if (addOnEnabled.paraglide) { %>
|
|
47
|
+
// Paraglide URL rewrite docs: https://github.com/TanStack/router/tree/main/examples/react/i18n-paraglide#rewrite-url
|
|
48
|
+
rewrite: {
|
|
49
|
+
input: ({ url }) => deLocalizeUrl(url),
|
|
50
|
+
output: ({ url }) => localizeUrl(url),
|
|
51
|
+
},
|
|
52
|
+
<% } %>
|
|
44
53
|
<% if (addOnEnabled['tanstack-query'] || addOnEnabled['apollo-client']) { %>
|
|
45
54
|
defaultPreload: "intent",
|
|
46
55
|
<% } else { %>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<% if (!addOnEnabled.paraglide) { ignoreFile() } %>import { paraglideMiddleware } from './paraglide/server'
|
|
2
|
+
import handler from '@tanstack/react-start/server-entry'
|
|
3
|
+
|
|
4
|
+
// Server-side URL localization/redirects for Paraglide
|
|
5
|
+
export default {
|
|
6
|
+
fetch(req: Request): Promise<Response> {
|
|
7
|
+
return paraglideMiddleware(req, () => handler.fetch(req))
|
|
8
|
+
},
|
|
9
|
+
}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { defineConfig } from 'vite'
|
|
2
2
|
import { devtools } from '@tanstack/devtools-vite'
|
|
3
|
+
<% if (addOnEnabled.paraglide) { -%>
|
|
4
|
+
import { paraglideVitePlugin } from "@inlang/paraglide-js"
|
|
5
|
+
<% } -%>
|
|
3
6
|
import { tanstackStart } from '@tanstack/react-start/plugin/vite';
|
|
4
7
|
import viteReact from '@vitejs/plugin-react'
|
|
5
8
|
import viteTsConfigPaths from 'vite-tsconfig-paths'<% if (tailwind) { %>
|
|
@@ -8,7 +11,11 @@ import tailwindcss from "@tailwindcss/vite"
|
|
|
8
11
|
<% } %>
|
|
9
12
|
|
|
10
13
|
const config = defineConfig({
|
|
11
|
-
plugins: [devtools(), <%
|
|
14
|
+
plugins: [devtools(), <% if (addOnEnabled.paraglide) { %>paraglideVitePlugin({
|
|
15
|
+
project: './project.inlang',
|
|
16
|
+
outdir: './src/paraglide',
|
|
17
|
+
strategy: ['url'],
|
|
18
|
+
}), <% } %><% for(const integration of integrations.filter(i => i.type === 'vite-plugin')) { %><%- integrationImportCode(integration) %>,<% } %>
|
|
12
19
|
// this is the plugin that enables path aliases
|
|
13
20
|
viteTsConfigPaths({
|
|
14
21
|
projects: ['./tsconfig.json'],
|
package/hosts/nitro/package.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/cta-framework-react-cra",
|
|
3
|
-
"version": "0.44.
|
|
3
|
+
"version": "0.44.3",
|
|
4
4
|
"description": "CTA Framework for React (Create React App)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"author": "Jack Herrington <jherr@pobox.com>",
|
|
24
24
|
"license": "MIT",
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@tanstack/cta-engine": "0.44.
|
|
26
|
+
"@tanstack/cta-engine": "0.44.3"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@types/node": "^24.6.0",
|
|
@@ -105,6 +105,8 @@ import ReactDOM from "react-dom/client";
|
|
|
105
105
|
import { RouterProvider, createRouter } from "@tanstack/react-router";
|
|
106
106
|
<% for(const integration of integrations.filter(i => i.type === 'root-provider')) { %>
|
|
107
107
|
import * as <%= integration.jsName %> from "<%= relativePath(integration.path) %>";
|
|
108
|
+
<% } %><% if (addOnEnabled.paraglide) { %>
|
|
109
|
+
import { deLocalizeUrl, localizeUrl } from "./paraglide/runtime";
|
|
108
110
|
<% } %>
|
|
109
111
|
|
|
110
112
|
// Import the generated route tree
|
|
@@ -122,7 +124,12 @@ const <%= integration.jsName %>Context = <%= integration.jsName %>.getContext();
|
|
|
122
124
|
<% for(const integration of integrations.filter(i => i.type === 'root-provider')) { %>
|
|
123
125
|
...<%= integration.jsName %>Context,
|
|
124
126
|
<% } %>
|
|
125
|
-
}
|
|
127
|
+
},<% if (addOnEnabled.paraglide) { %>
|
|
128
|
+
// Paraglide URL rewrite docs: https://github.com/TanStack/router/tree/main/examples/react/i18n-paraglide#rewrite-url
|
|
129
|
+
rewrite: {
|
|
130
|
+
input: ({ url }) => deLocalizeUrl(url),
|
|
131
|
+
output: ({ url }) => localizeUrl(url),
|
|
132
|
+
},<% } %>
|
|
126
133
|
defaultPreload: "intent",
|
|
127
134
|
scrollRestoration: true,
|
|
128
135
|
defaultStructuralSharing: true,
|
|
@@ -156,4 +163,4 @@ if (rootElement && !rootElement.innerHTML) {
|
|
|
156
163
|
// If you want to start measuring performance in your app, pass a function
|
|
157
164
|
// to log results (for example: reportWebVitals(console.log))
|
|
158
165
|
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
|
|
159
|
-
reportWebVitals();<% } %>
|
|
166
|
+
reportWebVitals();<% } %>
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
<% let hasContext = addOnEnabled["apollo-client"] || addOnEnabled["tanstack-query"]; %>
|
|
2
2
|
<% if (!fileRouter) { ignoreFile() } %>import { <% if (addOnEnabled.start) { %>
|
|
3
|
-
HeadContent<% } else { %>Outlet<% } %><% if (addOnEnabled.start) { %>, Scripts<% } %>, <% if (hasContext) { %>createRootRouteWithContext<% } else { %>createRootRoute<% } %> } from '@tanstack/react-router'
|
|
3
|
+
HeadContent<% } else { %>Outlet<% } %><% if (addOnEnabled.start) { %>, Scripts<% } %>, <% if (hasContext) { %>createRootRouteWithContext<% } else { %>createRootRoute<% } %><% if (addOnEnabled.paraglide) { %>, redirect<% } %> } from '@tanstack/react-router'
|
|
4
4
|
import { TanStackRouterDevtoolsPanel } from '@tanstack/react-router-devtools';
|
|
5
5
|
import { TanStackDevtools } from '@tanstack/react-devtools'
|
|
6
6
|
<% if (addOns.length) { %>
|
|
7
7
|
import Header from '../components/Header'
|
|
8
8
|
<% } %><% for(const integration of integrations.filter(i => i.type === 'layout' || i.type === 'provider' || i.type === 'devtools')) { %>
|
|
9
9
|
import <%= integration.jsName %> from '<%= relativePath(integration.path, true) %>'
|
|
10
|
+
<% } %><% if (addOnEnabled.paraglide) { %>
|
|
11
|
+
import { getLocale, shouldRedirect } from '@/paraglide/runtime'
|
|
10
12
|
<% } %>
|
|
11
13
|
<% if (addOnEnabled.start) { %>
|
|
12
14
|
import appCss from '../styles.css?url'
|
|
@@ -32,6 +34,25 @@ interface MyRouterContext <% if (addOnEnabled["apollo-client"]) {%> extends Apol
|
|
|
32
34
|
}<% } %>
|
|
33
35
|
|
|
34
36
|
export const Route = <% if (hasContext) { %>createRootRouteWithContext<MyRouterContext>()<% } else { %>createRootRoute<% } %>({
|
|
37
|
+
<% if (addOnEnabled.paraglide) { %>
|
|
38
|
+
beforeLoad: async () => {
|
|
39
|
+
// Other redirect strategies are possible; see
|
|
40
|
+
// https://github.com/TanStack/router/tree/main/examples/react/i18n-paraglide#offline-redirect
|
|
41
|
+
if (typeof document !== 'undefined') {
|
|
42
|
+
document.documentElement.setAttribute('lang', getLocale())
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
<% if (!addOnEnabled.start) { %>// Client-side fallback redirect for SPA/file-router builds. Start apps should
|
|
46
|
+
// prefer server-side paraglideMiddleware (see start template server.ts).
|
|
47
|
+
if (typeof window !== 'undefined') {
|
|
48
|
+
const decision = await shouldRedirect({ url: window.location.href })
|
|
49
|
+
|
|
50
|
+
if (decision.redirectUrl) {
|
|
51
|
+
throw redirect({ href: decision.redirectUrl.href })
|
|
52
|
+
}
|
|
53
|
+
}<% } %>
|
|
54
|
+
},
|
|
55
|
+
<% } %>
|
|
35
56
|
<% if (addOnEnabled.start) { %>
|
|
36
57
|
head: () => ({
|
|
37
58
|
meta: [
|
|
@@ -84,7 +105,7 @@ export const Route = <% if (hasContext) { %>createRootRouteWithContext<MyRouterC
|
|
|
84
105
|
<% if (addOnEnabled.start) { %>
|
|
85
106
|
function RootDocument({ children }: { children: React.ReactNode }) {
|
|
86
107
|
return (
|
|
87
|
-
|
|
108
|
+
<% if (addOnEnabled.paraglide) { %><html lang={getLocale()}><% } else { %><html lang="en"><% } %>
|
|
88
109
|
<head>
|
|
89
110
|
<HeadContent />
|
|
90
111
|
</head>
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
|
|
11
11
|
/* Bundler mode */
|
|
12
12
|
"moduleResolution": "bundler",
|
|
13
|
-
"allowImportingTsExtensions": true
|
|
13
|
+
"allowImportingTsExtensions": true,<% if (addOnEnabled.paraglide) { %>
|
|
14
|
+
"allowJs": true,<% } %>
|
|
14
15
|
"verbatimModuleSyntax": <%= addOnEnabled['start'] ? 'false' : 'true' %>,
|
|
15
16
|
"noEmit": true,
|
|
16
17
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<% if (addOnEnabled.start) { ignoreFile() } %>import { defineConfig } from "vite";
|
|
2
|
-
import { devtools } from '@tanstack/devtools-vite'
|
|
2
|
+
import { devtools } from '@tanstack/devtools-vite'<% if (addOnEnabled.paraglide) { %>
|
|
3
|
+
import { paraglideVitePlugin } from "@inlang/paraglide-js"<% } %>
|
|
3
4
|
import viteReact from "@vitejs/plugin-react";<% if (tailwind) { %>
|
|
4
5
|
import tailwindcss from "@tailwindcss/vite";
|
|
5
6
|
<% } %><%if (fileRouter) { %>
|
|
@@ -11,7 +12,11 @@ import federationConfig from "./module-federation.config.js";<% } %><% for(const
|
|
|
11
12
|
|
|
12
13
|
// https://vitejs.dev/config/
|
|
13
14
|
export default defineConfig({
|
|
14
|
-
plugins: [devtools(), <%
|
|
15
|
+
plugins: [devtools(), <% if (addOnEnabled.paraglide) { %>paraglideVitePlugin({
|
|
16
|
+
project: './project.inlang',
|
|
17
|
+
outdir: './src/paraglide',
|
|
18
|
+
strategy: ['url'],
|
|
19
|
+
}), <% } %><% for(const integration of integrations.filter(i => i.type === 'vite-plugin')) { %><%- integrationImportCode(integration) %>,<% } %> <% if(fileRouter) { %>tanstackRouter({
|
|
15
20
|
target: "react",
|
|
16
21
|
autoCodeSplitting: true,
|
|
17
22
|
}), <% } %>viteReact(<% if (addOnEnabled.compiler) { %>{
|