diff --git a/examples/solid/start-i18n-paraglide/.gitignore b/examples/solid/start-i18n-paraglide/.gitignore new file mode 100644 index 00000000000..eb0412b5f5b --- /dev/null +++ b/examples/solid/start-i18n-paraglide/.gitignore @@ -0,0 +1,10 @@ +node_modules +.DS_Store +dist +dist-ssr +*.local +count.txt +.env +.nitro +.tanstack +.output diff --git a/examples/solid/start-i18n-paraglide/.vscode/extensions.json b/examples/solid/start-i18n-paraglide/.vscode/extensions.json new file mode 100644 index 00000000000..8cf06c2f61a --- /dev/null +++ b/examples/solid/start-i18n-paraglide/.vscode/extensions.json @@ -0,0 +1,3 @@ +{ + "recommendations": ["inlang.vs-code-extension"] +} diff --git a/examples/solid/start-i18n-paraglide/.vscode/settings.json b/examples/solid/start-i18n-paraglide/.vscode/settings.json new file mode 100644 index 00000000000..00b5278e580 --- /dev/null +++ b/examples/solid/start-i18n-paraglide/.vscode/settings.json @@ -0,0 +1,11 @@ +{ + "files.watcherExclude": { + "**/routeTree.gen.ts": true + }, + "search.exclude": { + "**/routeTree.gen.ts": true + }, + "files.readonlyInclude": { + "**/routeTree.gen.ts": true + } +} diff --git a/examples/solid/start-i18n-paraglide/README.md b/examples/solid/start-i18n-paraglide/README.md new file mode 100644 index 00000000000..eee202e3a13 --- /dev/null +++ b/examples/solid/start-i18n-paraglide/README.md @@ -0,0 +1,196 @@ +# TanStack Start example + +This example shows how to use Paraglide with TanStack Start. The source code can be found [here](https://github.com/opral/monorepo/tree/main/inlang/packages/paraglide/paraglide-js/examples/tanstack-start). + +## Getting started + +1. Init Paraglide JS + +```bash +npx @inlang/paraglide-js@latest init +``` + +2. Add the vite plugin to your `vite.config.ts`: + +```diff +import { defineConfig } from 'vite' +import { tanstackStart } from "@tanstack/solid-start/plugin/vite"; +import react from '@vitejs/plugin-react' ++import { paraglideVitePlugin } from "@inlang/paraglide-js"; + +export default defineConfig({ + plugins: [ + tanstackStart(), + react(), ++ paraglideVitePlugin({ ++ project: "./project.inlang", ++ outdir: "./app/paraglide", ++ outputStructure: "message-modules", ++ cookieName: "PARAGLIDE_LOCALE", ++ strategy: ["url", "cookie", "preferredLanguage", "baseLocale"], ++ urlPatterns: [ ++ { ++ pattern: "/:path(.*)?", ++ localized: [ ++ ["en", "/en/:path(.*)?"], ++ ], ++ }, ++ ], ++ }), + ], +}); +``` + +3. Done :) + +Run the app and start translating. See the [basics documentation](https://inlang.com/m/gerre34r/library-inlang-paraglideJs/basics) for information on how to use Paraglide's messages, parameters, and locale management. + +## Rewrite URL + +If you want to handle how the URL looks when the user changes the locale, you can rewrite the URL in the router. + +```diff +import { createRouter } from "@tanstack/solid-router"; +import { routeTree } from "./routeTree.gen"; ++import { deLocalizeUrl, localizeUrl } from "./paraglide/runtime.js"; + +const router = createRouter({ + routeTree, ++ rewrite: { ++ input: ({ url }) => deLocalizeUrl(url), ++ output: ({ url }) => localizeUrl(url), + }, +}); +``` + +In `server.ts` intercept the request with the paraglideMiddleware. + +```ts +import { paraglideMiddleware } from './paraglide/server.js' +import handler from '@tanstack/solid-start/server-entry' + +export default { + fetch(req: Request): Promise { + return paraglideMiddleware(req, ({ request }) => handler.fetch(request)) + }, +} +``` + +In `__root.tsx` add change the html lang attribute to the current locale. + +```tsx +import { getLocale } from '../paraglide/runtime.js' + +function RootDocument({ children }: { children: React.ReactNode }) { + return ( + + + + + + {children} + + + + ) +} +``` + +## Offline redirect + +If you have an application that needs to work offline, you will need to handle the redirect in the client like this. + +```ts +import { shouldRedirect } from "../paraglide/runtime"; + +export const Route = createRootRoute({ + beforeLoad: async () => { + const decision = await shouldRedirect({ url: window.location.href }); + + if (decision.redirectUrl) { + throw redirect({ href: decision.redirectUrl.href }); + } + }, + ... +}); +``` + +## Typesafe translated pathnames + +If you don't want to miss any translated path, you can create a `createTranslatedPathnames` function and pass it to the vite plugin. + +```ts +import { Locale } from '@/paraglide/runtime' +import { FileRoutesByTo } from '../routeTree.gen' + +type RoutePath = keyof FileRoutesByTo + +const excludedPaths = ['admin', 'docs', 'api'] as const + +type PublicRoutePath = Exclude< + RoutePath, + `${string}${(typeof excludedPaths)[number]}${string}` +> + +type TranslatedPathname = { + pattern: string + localized: Array<[Locale, string]> +} + +function toUrlPattern(path: string) { + return ( + path + // catch-all + .replace(/\/\$$/, '/:path(.*)?') + // optional parameters: {-$param} + .replace(/\{-\$([a-zA-Z0-9_]+)\}/g, ':$1?') + // named parameters: $param + .replace(/\$([a-zA-Z0-9_]+)/g, ':$1') + // remove trailing slash + .replace(/\/+$/, '') + ) +} + +function createTranslatedPathnames( + input: Record>, +): TranslatedPathname[] { + return Object.entries(input).map(([pattern, locales]) => ({ + pattern: toUrlPattern(pattern), + localized: Object.entries(locales).map( + ([locale, path]) => + [locale as Locale, `/${locale}${toUrlPattern(path)}`] satisfies [ + Locale, + string, + ], + ), + })) +} + +export const translatedPathnames = createTranslatedPathnames({ + '/': { + en: '/', + de: '/', + }, + '/about': { + en: '/about', + de: '/ueber', + }, +}) +``` + +And import into the Paraglide Vite plguin. + +# Prerender routes + +You can use use the `localizeHref` function to map the routes to localized versions and import into the pages option in the TanStack Start plugin. For this to work you will need to compile paraglide before the build with the CLI. + +```ts +import { localizeHref } from './paraglide/runtime' + +export const prerenderRoutes = ['/', '/about'].map((path) => ({ + path: localizeHref(path), + prerender: { + enabled: true, + }, +})) +``` diff --git a/examples/solid/start-i18n-paraglide/messages/de.json b/examples/solid/start-i18n-paraglide/messages/de.json new file mode 100644 index 00000000000..2c2167c3ca0 --- /dev/null +++ b/examples/solid/start-i18n-paraglide/messages/de.json @@ -0,0 +1,8 @@ +{ + "$schema": "https://inlang.com/schema/inlang-message-format", + "example_message": "Guten Tag {username}", + "server_message": "Server Nachricht {emoji}", + "about_message": "Über uns", + "home_page": "Startseite", + "about_page": "Über uns" +} diff --git a/examples/solid/start-i18n-paraglide/messages/en.json b/examples/solid/start-i18n-paraglide/messages/en.json new file mode 100644 index 00000000000..204789de75c --- /dev/null +++ b/examples/solid/start-i18n-paraglide/messages/en.json @@ -0,0 +1,8 @@ +{ + "$schema": "https://inlang.com/schema/inlang-message-format", + "example_message": "Hello world {username}", + "server_message": "Server message {emoji}", + "about_message": "About message", + "home_page": "Home page", + "about_page": "About page" +} diff --git a/examples/solid/start-i18n-paraglide/package.json b/examples/solid/start-i18n-paraglide/package.json new file mode 100644 index 00000000000..3258306e86a --- /dev/null +++ b/examples/solid/start-i18n-paraglide/package.json @@ -0,0 +1,28 @@ +{ + "name": "tanstack-solid-start-i18n-paraglide", + "private": true, + "type": "module", + "scripts": { + "dev": "vite dev --port 3000", + "start": "node .output/server/index.mjs", + "build": "vite build", + "serve": "vite preview" + }, + "dependencies": { + "@tanstack/solid-devtools": "^0.7.0", + "@tanstack/solid-router": "^1.135.2", + "@tanstack/solid-router-devtools": "^1.135.2", + "@tanstack/solid-start": "^1.135.2", + "solid-js": "^1.9.10" + }, + "devDependencies": { + "@types/node": "^22.18.6", + "vite-plugin-solid": "^2.11.10", + "typescript": "^5.9.2", + "vite": "^7.1.7", + "vite-tsconfig-paths": "^5.1.4", + "@tailwindcss/vite": "^4.1.13", + "tailwindcss": "^4.1.13", + "@inlang/paraglide-js": "2.4.0" + } +} diff --git a/examples/solid/start-i18n-paraglide/project.inlang/.gitignore b/examples/solid/start-i18n-paraglide/project.inlang/.gitignore new file mode 100644 index 00000000000..5e465967597 --- /dev/null +++ b/examples/solid/start-i18n-paraglide/project.inlang/.gitignore @@ -0,0 +1 @@ +cache \ No newline at end of file diff --git a/examples/solid/start-i18n-paraglide/project.inlang/project_id b/examples/solid/start-i18n-paraglide/project.inlang/project_id new file mode 100644 index 00000000000..a956b223fac --- /dev/null +++ b/examples/solid/start-i18n-paraglide/project.inlang/project_id @@ -0,0 +1 @@ +UoZ15Q8qSGIbImRS3Y \ No newline at end of file diff --git a/examples/solid/start-i18n-paraglide/project.inlang/settings.json b/examples/solid/start-i18n-paraglide/project.inlang/settings.json new file mode 100644 index 00000000000..9bdce4c8cc9 --- /dev/null +++ b/examples/solid/start-i18n-paraglide/project.inlang/settings.json @@ -0,0 +1,12 @@ +{ + "$schema": "https://inlang.com/schema/project-settings", + "baseLocale": "en", + "locales": ["en", "de"], + "modules": [ + "https://cdn.jsdelivr.net/npm/@inlang/plugin-message-format@4/dist/index.js", + "https://cdn.jsdelivr.net/npm/@inlang/plugin-m-function-matcher@2/dist/index.js" + ], + "plugin.inlang.messageFormat": { + "pathPattern": "./messages/{locale}.json" + } +} diff --git a/examples/solid/start-i18n-paraglide/public/favicon.ico b/examples/solid/start-i18n-paraglide/public/favicon.ico new file mode 100644 index 00000000000..a11777cc471 Binary files /dev/null and b/examples/solid/start-i18n-paraglide/public/favicon.ico differ diff --git a/examples/solid/start-i18n-paraglide/public/logo192.png b/examples/solid/start-i18n-paraglide/public/logo192.png new file mode 100644 index 00000000000..fc44b0a3796 Binary files /dev/null and b/examples/solid/start-i18n-paraglide/public/logo192.png differ diff --git a/examples/solid/start-i18n-paraglide/public/logo512.png b/examples/solid/start-i18n-paraglide/public/logo512.png new file mode 100644 index 00000000000..a4e47a6545b Binary files /dev/null and b/examples/solid/start-i18n-paraglide/public/logo512.png differ diff --git a/examples/solid/start-i18n-paraglide/public/manifest.json b/examples/solid/start-i18n-paraglide/public/manifest.json new file mode 100644 index 00000000000..078ef501162 --- /dev/null +++ b/examples/solid/start-i18n-paraglide/public/manifest.json @@ -0,0 +1,25 @@ +{ + "short_name": "TanStack App", + "name": "Create TanStack App Sample", + "icons": [ + { + "src": "favicon.ico", + "sizes": "64x64 32x32 24x24 16x16", + "type": "image/x-icon" + }, + { + "src": "logo192.png", + "type": "image/png", + "sizes": "192x192" + }, + { + "src": "logo512.png", + "type": "image/png", + "sizes": "512x512" + } + ], + "start_url": ".", + "display": "standalone", + "theme_color": "#000000", + "background_color": "#ffffff" +} diff --git a/examples/solid/start-i18n-paraglide/public/robots.txt b/examples/solid/start-i18n-paraglide/public/robots.txt new file mode 100644 index 00000000000..e9e57dc4d41 --- /dev/null +++ b/examples/solid/start-i18n-paraglide/public/robots.txt @@ -0,0 +1,3 @@ +# https://www.robotstxt.org/robotstxt.html +User-agent: * +Disallow: diff --git a/examples/solid/start-i18n-paraglide/src/logo.svg b/examples/solid/start-i18n-paraglide/src/logo.svg new file mode 100644 index 00000000000..fe53fe8d0d2 --- /dev/null +++ b/examples/solid/start-i18n-paraglide/src/logo.svg @@ -0,0 +1,12 @@ + + + logo + + \ No newline at end of file diff --git a/examples/solid/start-i18n-paraglide/src/routeTree.gen.ts b/examples/solid/start-i18n-paraglide/src/routeTree.gen.ts new file mode 100644 index 00000000000..3cc45c071ea --- /dev/null +++ b/examples/solid/start-i18n-paraglide/src/routeTree.gen.ts @@ -0,0 +1,86 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +import { Route as rootRouteImport } from './routes/__root' +import { Route as AboutRouteImport } from './routes/about' +import { Route as IndexRouteImport } from './routes/index' + +const AboutRoute = AboutRouteImport.update({ + id: '/about', + path: '/about', + getParentRoute: () => rootRouteImport, +} as any) +const IndexRoute = IndexRouteImport.update({ + id: '/', + path: '/', + getParentRoute: () => rootRouteImport, +} as any) + +export interface FileRoutesByFullPath { + '/': typeof IndexRoute + '/about': typeof AboutRoute +} +export interface FileRoutesByTo { + '/': typeof IndexRoute + '/about': typeof AboutRoute +} +export interface FileRoutesById { + __root__: typeof rootRouteImport + '/': typeof IndexRoute + '/about': typeof AboutRoute +} +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: '/' | '/about' + fileRoutesByTo: FileRoutesByTo + to: '/' | '/about' + id: '__root__' | '/' | '/about' + fileRoutesById: FileRoutesById +} +export interface RootRouteChildren { + IndexRoute: typeof IndexRoute + AboutRoute: typeof AboutRoute +} + +declare module '@tanstack/solid-router' { + interface FileRoutesByPath { + '/about': { + id: '/about' + path: '/about' + fullPath: '/about' + preLoaderRoute: typeof AboutRouteImport + parentRoute: typeof rootRouteImport + } + '/': { + id: '/' + path: '/' + fullPath: '/' + preLoaderRoute: typeof IndexRouteImport + parentRoute: typeof rootRouteImport + } + } +} + +const rootRouteChildren: RootRouteChildren = { + IndexRoute: IndexRoute, + AboutRoute: AboutRoute, +} +export const routeTree = rootRouteImport + ._addFileChildren(rootRouteChildren) + ._addFileTypes() + +import type { getRouter } from './router.tsx' +import type { createStart } from '@tanstack/solid-start' +declare module '@tanstack/solid-start' { + interface Register { + ssr: true + router: Awaited> + } +} diff --git a/examples/solid/start-i18n-paraglide/src/router.tsx b/examples/solid/start-i18n-paraglide/src/router.tsx new file mode 100644 index 00000000000..917e4afefe3 --- /dev/null +++ b/examples/solid/start-i18n-paraglide/src/router.tsx @@ -0,0 +1,18 @@ +import { createRouter } from '@tanstack/solid-router' + +// Import the generated route tree +import { routeTree } from './routeTree.gen' +import { deLocalizeUrl, localizeUrl } from './paraglide/runtime' + +// Create a new router instance +export const getRouter = () => { + return createRouter({ + routeTree, + scrollRestoration: true, + defaultPreloadStaleTime: 0, + rewrite: { + input: ({ url }) => deLocalizeUrl(url), + output: ({ url }) => localizeUrl(url), + }, + }) +} diff --git a/examples/solid/start-i18n-paraglide/src/routes/__root.tsx b/examples/solid/start-i18n-paraglide/src/routes/__root.tsx new file mode 100644 index 00000000000..39875ee9fe4 --- /dev/null +++ b/examples/solid/start-i18n-paraglide/src/routes/__root.tsx @@ -0,0 +1,97 @@ +import { + HeadContent, + Link, + Scripts, + createRootRoute, +} from '@tanstack/solid-router' +import { TanStackRouterDevtoolsPanel } from '@tanstack/solid-router-devtools' +import { TanStackDevtools } from '@tanstack/solid-devtools' +import { HydrationScript } from 'solid-js/web' +import styles from '../styles.css?url' +import type { JSX } from 'solid-js/jsx-runtime' +import { getLocale, locales, setLocale } from '@/paraglide/runtime' +import { m } from '@/paraglide/messages' + +export const Route = createRootRoute({ + head: () => ({ + meta: [ + { + charSet: 'utf-8', + }, + { + name: 'viewport', + content: 'width=device-width, initial-scale=1', + }, + { + title: 'TanStack Start Starter', + }, + ], + links: [{ rel: 'stylesheet', href: styles }], + }), + + shellComponent: RootDocument, +}) + +function RootDocument({ children }: { children: JSX.Element }) { + return ( + + + + + + +
+
+ + {m.home_page()} + + + + {m.about_page()} + +
+ +
+ {locales.map((locale) => ( + + ))} +
+
+ +
+ +
{children}
+ + , + }, + ]} + /> + + + + ) +} diff --git a/examples/solid/start-i18n-paraglide/src/routes/about.tsx b/examples/solid/start-i18n-paraglide/src/routes/about.tsx new file mode 100644 index 00000000000..a9a44226363 --- /dev/null +++ b/examples/solid/start-i18n-paraglide/src/routes/about.tsx @@ -0,0 +1,10 @@ +import { createFileRoute } from '@tanstack/solid-router' +import { m } from '@/paraglide/messages' + +export const Route = createFileRoute('/about')({ + component: RouteComponent, +}) + +function RouteComponent() { + return
{m.about_message()}
+} diff --git a/examples/solid/start-i18n-paraglide/src/routes/index.tsx b/examples/solid/start-i18n-paraglide/src/routes/index.tsx new file mode 100644 index 00000000000..48f092c7549 --- /dev/null +++ b/examples/solid/start-i18n-paraglide/src/routes/index.tsx @@ -0,0 +1,31 @@ +import { createFileRoute } from '@tanstack/solid-router' +import { createServerFn } from '@tanstack/solid-start' +import { m } from '@/paraglide/messages.js' +// import { getLocale } from '@/paraglide/runtime.js' + +const getServerMessage = createServerFn() + .inputValidator((emoji: string) => emoji) + .handler((ctx) => { + return m.server_message({ emoji: ctx.data }) + }) + +export const Route = createFileRoute('/')({ + component: Home, + loader: async () => { + return { + messageFromLoader: m.example_message({ username: 'John Doe' }), + serverFunctionMessage: await getServerMessage({ data: '📩' }), + } + }, +}) + +function Home() { + const loaderData = Route.useLoaderData() + return ( +
+

Message from loader: {loaderData().messageFromLoader}

+

Server function message: {loaderData().serverFunctionMessage}:

+

{m.example_message({ username: 'John Doe' })}

+
+ ) +} diff --git a/examples/solid/start-i18n-paraglide/src/server.ts b/examples/solid/start-i18n-paraglide/src/server.ts new file mode 100644 index 00000000000..fffdaf3ca1b --- /dev/null +++ b/examples/solid/start-i18n-paraglide/src/server.ts @@ -0,0 +1,8 @@ +import { paraglideMiddleware } from './paraglide/server.js' +import handler from '@tanstack/solid-start/server-entry' + +export default { + fetch(req: Request): Promise { + return paraglideMiddleware(req, ({ request }) => handler.fetch(request)) + }, +} diff --git a/examples/solid/start-i18n-paraglide/src/styles.css b/examples/solid/start-i18n-paraglide/src/styles.css new file mode 100644 index 00000000000..d4b5078586e --- /dev/null +++ b/examples/solid/start-i18n-paraglide/src/styles.css @@ -0,0 +1 @@ +@import 'tailwindcss'; diff --git a/examples/solid/start-i18n-paraglide/src/utils/prerender.ts b/examples/solid/start-i18n-paraglide/src/utils/prerender.ts new file mode 100644 index 00000000000..0cb1630595f --- /dev/null +++ b/examples/solid/start-i18n-paraglide/src/utils/prerender.ts @@ -0,0 +1,8 @@ +import { localizeHref } from '../paraglide/runtime' + +export const prerenderRoutes = ['/', '/about'].map((path) => ({ + path: localizeHref(path), + prerender: { + enabled: true, + }, +})) diff --git a/examples/solid/start-i18n-paraglide/src/utils/seo.ts b/examples/solid/start-i18n-paraglide/src/utils/seo.ts new file mode 100644 index 00000000000..d18ad84b74e --- /dev/null +++ b/examples/solid/start-i18n-paraglide/src/utils/seo.ts @@ -0,0 +1,33 @@ +export const seo = ({ + title, + description, + keywords, + image, +}: { + title: string + description?: string + image?: string + keywords?: string +}) => { + const tags = [ + { title }, + { name: 'description', content: description }, + { name: 'keywords', content: keywords }, + { name: 'twitter:title', content: title }, + { name: 'twitter:description', content: description }, + { name: 'twitter:creator', content: '@tannerlinsley' }, + { name: 'twitter:site', content: '@tannerlinsley' }, + { name: 'og:type', content: 'website' }, + { name: 'og:title', content: title }, + { name: 'og:description', content: description }, + ...(image + ? [ + { name: 'twitter:image', content: image }, + { name: 'twitter:card', content: 'summary_large_image' }, + { name: 'og:image', content: image }, + ] + : []), + ] + + return tags +} diff --git a/examples/solid/start-i18n-paraglide/src/utils/translated-pathnames.ts b/examples/solid/start-i18n-paraglide/src/utils/translated-pathnames.ts new file mode 100644 index 00000000000..bb8649ff4e0 --- /dev/null +++ b/examples/solid/start-i18n-paraglide/src/utils/translated-pathnames.ts @@ -0,0 +1,56 @@ +import { Locale } from '@/paraglide/runtime' +import { FileRoutesByTo } from '../routeTree.gen' + +type RoutePath = keyof FileRoutesByTo + +const excludedPaths = ['admin', 'docs', 'api'] as const + +type PublicRoutePath = Exclude< + RoutePath, + `${string}${(typeof excludedPaths)[number]}${string}` +> + +type TranslatedPathname = { + pattern: string + localized: Array<[Locale, string]> +} + +function toUrlPattern(path: string) { + return ( + path + // catch-all + .replace(/\/\$$/, '/:path(.*)?') + // optional parameters: {-$param} + .replace(/\{-\$([a-zA-Z0-9_]+)\}/g, ':$1?') + // named parameters: $param + .replace(/\$([a-zA-Z0-9_]+)/g, ':$1') + // remove trailing slash + .replace(/\/+$/, '') + ) +} + +function createTranslatedPathnames( + input: Record>, +): TranslatedPathname[] { + return Object.entries(input).map(([pattern, locales]) => ({ + pattern: toUrlPattern(pattern), + localized: Object.entries(locales).map( + ([locale, path]) => + [locale as Locale, `/${locale}${toUrlPattern(path)}`] satisfies [ + Locale, + string, + ], + ), + })) +} + +export const translatedPathnames = createTranslatedPathnames({ + '/': { + en: '/', + de: '/', + }, + '/about': { + en: '/about', + de: '/ueber', + }, +}) diff --git a/examples/solid/start-i18n-paraglide/tsconfig.json b/examples/solid/start-i18n-paraglide/tsconfig.json new file mode 100644 index 00000000000..522b26852d0 --- /dev/null +++ b/examples/solid/start-i18n-paraglide/tsconfig.json @@ -0,0 +1,30 @@ +{ + "include": ["**/*.ts", "**/*.tsx"], + "compilerOptions": { + "target": "ES2022", + "jsx": "preserve", + "jsxImportSource": "solid-js", + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "allowJs": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": false, + "noEmit": true, + + /* Linting */ + "skipLibCheck": true, + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true, + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + } +} diff --git a/examples/solid/start-i18n-paraglide/vite.config.ts b/examples/solid/start-i18n-paraglide/vite.config.ts new file mode 100644 index 00000000000..77d18ac8327 --- /dev/null +++ b/examples/solid/start-i18n-paraglide/vite.config.ts @@ -0,0 +1,47 @@ +import { paraglideVitePlugin } from '@inlang/paraglide-js' +import { defineConfig } from 'vite' +import { tanstackStart } from '@tanstack/solid-start/plugin/vite' +import viteSolid from 'vite-plugin-solid' +import viteTsConfigPaths from 'vite-tsconfig-paths' +import tailwindcss from '@tailwindcss/vite' + +const config = defineConfig({ + plugins: [ + paraglideVitePlugin({ + project: './project.inlang', + outdir: './src/paraglide', + outputStructure: 'message-modules', + cookieName: 'PARAGLIDE_LOCALE', + strategy: ['url', 'cookie', 'preferredLanguage', 'baseLocale'], + urlPatterns: [ + { + pattern: '/', + localized: [ + ['en', '/en'], + ['de', '/de'], + ], + }, + { + pattern: '/about', + localized: [ + ['en', '/en/about'], + ['de', '/de/ueber'], + ], + }, + { + pattern: '/:path(.*)?', + localized: [ + ['en', '/en/:path(.*)?'], + ['de', '/de/:path(.*)?'], + ], + }, + ], + }), + viteTsConfigPaths(), + tanstackStart(), + viteSolid({ ssr: true }), + tailwindcss(), + ], +}) + +export default config diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9371966fb14..fade56178ec 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8389,6 +8389,49 @@ importers: specifier: ^5.1.4 version: 5.1.4(typescript@5.9.2)(vite@7.1.7(@types/node@22.10.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.37.0)(tsx@4.20.3)(yaml@2.8.1)) + examples/solid/start-i18n-paraglide: + dependencies: + '@tanstack/solid-devtools': + specifier: ^0.7.0 + version: 0.7.14(csstype@3.1.3)(solid-js@1.9.10) + '@tanstack/solid-router': + specifier: ^1.135.2 + version: link:../../../packages/solid-router + '@tanstack/solid-router-devtools': + specifier: workspace:^ + version: link:../../../packages/solid-router-devtools + '@tanstack/solid-start': + specifier: workspace:* + version: link:../../../packages/solid-start + solid-js: + specifier: 1.9.10 + version: 1.9.10 + devDependencies: + '@inlang/paraglide-js': + specifier: 2.4.0 + version: 2.4.0(babel-plugin-macros@3.1.0) + '@tailwindcss/vite': + specifier: ^4.1.13 + version: 4.1.17(vite@7.1.7(@types/node@22.10.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.37.0)(tsx@4.20.3)(yaml@2.8.1)) + '@types/node': + specifier: 22.10.2 + version: 22.10.2 + tailwindcss: + specifier: ^4.1.13 + version: 4.1.17 + typescript: + specifier: ^5.9.2 + version: 5.9.2 + vite: + specifier: ^7.1.7 + version: 7.1.7(@types/node@22.10.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.37.0)(tsx@4.20.3)(yaml@2.8.1) + vite-plugin-solid: + specifier: ^2.11.10 + version: 2.11.10(@testing-library/jest-dom@6.6.3)(solid-js@1.9.10)(vite@7.1.7(@types/node@22.10.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.37.0)(tsx@4.20.3)(yaml@2.8.1)) + vite-tsconfig-paths: + specifier: ^5.1.4 + version: 5.1.4(typescript@5.9.2)(vite@7.1.7(@types/node@22.10.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.37.0)(tsx@4.20.3)(yaml@2.8.1)) + examples/solid/start-streaming-data-from-server-functions: dependencies: '@tanstack/solid-router':