@linguanahq/cli 0.1.0 → 0.1.2

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 (163) hide show
  1. package/README.md +3 -3
  2. package/dist/index.js +42 -15
  3. package/dist/templates/blank/react/.env.example +15 -0
  4. package/dist/templates/blank/react/ASSETS.md +1 -0
  5. package/dist/templates/blank/react/DEPLOY.md +23 -0
  6. package/dist/templates/blank/react/LICENSE +21 -0
  7. package/dist/templates/blank/react/README.md +34 -0
  8. package/dist/templates/blank/react/_gitignore +11 -0
  9. package/dist/templates/blank/react/index.html +2 -0
  10. package/dist/templates/blank/react/linguana.json +10 -0
  11. package/dist/templates/blank/react/package.json +34 -0
  12. package/dist/templates/blank/react/public/favicon.ico +0 -0
  13. package/dist/templates/blank/react/public/logo.png +0 -0
  14. package/dist/templates/blank/react/src/App.tsx +72 -0
  15. package/dist/templates/blank/react/src/Copy.tsx +36 -0
  16. package/dist/templates/blank/react/src/demo-messages.ts +30 -0
  17. package/dist/templates/blank/react/src/i18n.ts +62 -0
  18. package/dist/templates/blank/react/src/main.tsx +11 -0
  19. package/dist/templates/blank/react/src/messages.ts +10 -0
  20. package/dist/templates/blank/react/src/styles.css +93 -0
  21. package/dist/templates/blank/react/src/vite-env.d.ts +1 -0
  22. package/dist/templates/blank/react/tsconfig.json +23 -0
  23. package/dist/templates/blank/react/vite.config.ts +36 -0
  24. package/dist/templates/blank/react/wrangler.jsonc +8 -0
  25. package/dist/templates/blank/solidjs/.env.example +15 -0
  26. package/dist/templates/blank/solidjs/ASSETS.md +1 -0
  27. package/dist/templates/blank/solidjs/DEPLOY.md +23 -0
  28. package/dist/templates/blank/solidjs/LICENSE +21 -0
  29. package/dist/templates/blank/solidjs/README.md +34 -0
  30. package/dist/templates/blank/solidjs/_gitignore +11 -0
  31. package/dist/templates/blank/solidjs/index.html +2 -0
  32. package/dist/templates/blank/solidjs/linguana.json +10 -0
  33. package/dist/templates/blank/solidjs/package.json +31 -0
  34. package/dist/templates/blank/solidjs/public/favicon.ico +0 -0
  35. package/dist/templates/blank/solidjs/public/logo.png +0 -0
  36. package/dist/templates/blank/solidjs/src/App.tsx +68 -0
  37. package/dist/templates/blank/solidjs/src/Copy.tsx +36 -0
  38. package/dist/templates/blank/solidjs/src/demo-messages.ts +30 -0
  39. package/dist/templates/blank/solidjs/src/i18n.ts +62 -0
  40. package/dist/templates/blank/solidjs/src/main.tsx +14 -0
  41. package/dist/templates/blank/solidjs/src/messages.ts +10 -0
  42. package/dist/templates/blank/solidjs/src/styles.css +93 -0
  43. package/dist/templates/blank/solidjs/src/vite-env.d.ts +1 -0
  44. package/dist/templates/blank/solidjs/tsconfig.json +24 -0
  45. package/dist/templates/blank/solidjs/vite.config.ts +36 -0
  46. package/dist/templates/blank/solidjs/wrangler.jsonc +8 -0
  47. package/dist/templates/blank/svelte/.env.example +15 -0
  48. package/dist/templates/blank/svelte/ASSETS.md +1 -0
  49. package/dist/templates/blank/svelte/DEPLOY.md +23 -0
  50. package/dist/templates/blank/svelte/LICENSE +21 -0
  51. package/dist/templates/blank/svelte/README.md +34 -0
  52. package/dist/templates/blank/svelte/_gitignore +11 -0
  53. package/dist/templates/blank/svelte/index.html +2 -0
  54. package/dist/templates/blank/svelte/linguana.json +10 -0
  55. package/dist/templates/blank/svelte/package.json +32 -0
  56. package/dist/templates/blank/svelte/public/favicon.ico +0 -0
  57. package/dist/templates/blank/svelte/public/logo.png +0 -0
  58. package/dist/templates/blank/svelte/src/App.svelte +40 -0
  59. package/dist/templates/blank/svelte/src/Copy.svelte +14 -0
  60. package/dist/templates/blank/svelte/src/Root.svelte +11 -0
  61. package/dist/templates/blank/svelte/src/demo-messages.ts +30 -0
  62. package/dist/templates/blank/svelte/src/i18n.ts +62 -0
  63. package/dist/templates/blank/svelte/src/main.ts +5 -0
  64. package/dist/templates/blank/svelte/src/messages.ts +10 -0
  65. package/dist/templates/blank/svelte/src/styles.css +93 -0
  66. package/dist/templates/blank/svelte/src/vite-env.d.ts +1 -0
  67. package/dist/templates/blank/svelte/svelte.config.js +2 -0
  68. package/dist/templates/blank/svelte/tsconfig.json +23 -0
  69. package/dist/templates/blank/svelte/vite.config.ts +36 -0
  70. package/dist/templates/blank/svelte/wrangler.jsonc +8 -0
  71. package/dist/templates/blank/tanstack-start/.env.example +15 -0
  72. package/dist/templates/blank/tanstack-start/ASSETS.md +1 -0
  73. package/dist/templates/blank/tanstack-start/DEPLOY.md +23 -0
  74. package/dist/templates/blank/tanstack-start/LICENSE +21 -0
  75. package/dist/templates/blank/tanstack-start/README.md +34 -0
  76. package/dist/templates/blank/tanstack-start/_gitignore +11 -0
  77. package/dist/templates/blank/tanstack-start/linguana.json +10 -0
  78. package/dist/templates/blank/tanstack-start/nitro.config.ts +2 -0
  79. package/dist/templates/blank/tanstack-start/package.json +42 -0
  80. package/dist/templates/blank/tanstack-start/public/favicon.ico +0 -0
  81. package/dist/templates/blank/tanstack-start/public/logo.png +0 -0
  82. package/dist/templates/blank/tanstack-start/src/App.tsx +72 -0
  83. package/dist/templates/blank/tanstack-start/src/Copy.tsx +36 -0
  84. package/dist/templates/blank/tanstack-start/src/demo-messages.ts +30 -0
  85. package/dist/templates/blank/tanstack-start/src/i18n.ts +62 -0
  86. package/dist/templates/blank/tanstack-start/src/locale-server.ts +54 -0
  87. package/dist/templates/blank/tanstack-start/src/messages.ts +10 -0
  88. package/dist/templates/blank/tanstack-start/src/router.tsx +10 -0
  89. package/dist/templates/blank/tanstack-start/src/routes/__root.tsx +53 -0
  90. package/dist/templates/blank/tanstack-start/src/routes/index.tsx +5 -0
  91. package/dist/templates/blank/tanstack-start/src/styles.css +93 -0
  92. package/dist/templates/blank/tanstack-start/src/vite-env.d.ts +1 -0
  93. package/dist/templates/blank/tanstack-start/tsconfig.json +23 -0
  94. package/dist/templates/blank/tanstack-start/vite.config.ts +50 -0
  95. package/dist/templates/blank/tanstack-start/wrangler.jsonc +12 -0
  96. package/dist/templates/blank/vue/.env.example +15 -0
  97. package/dist/templates/blank/vue/ASSETS.md +1 -0
  98. package/dist/templates/blank/vue/DEPLOY.md +23 -0
  99. package/dist/templates/blank/vue/LICENSE +21 -0
  100. package/dist/templates/blank/vue/README.md +34 -0
  101. package/dist/templates/blank/vue/_gitignore +11 -0
  102. package/dist/templates/blank/vue/index.html +2 -0
  103. package/dist/templates/blank/vue/linguana.json +10 -0
  104. package/dist/templates/blank/vue/package.json +34 -0
  105. package/dist/templates/blank/vue/public/favicon.ico +0 -0
  106. package/dist/templates/blank/vue/public/logo.png +0 -0
  107. package/dist/templates/blank/vue/src/App.vue +33 -0
  108. package/dist/templates/blank/vue/src/Copy.vue +13 -0
  109. package/dist/templates/blank/vue/src/demo-messages.ts +30 -0
  110. package/dist/templates/blank/vue/src/i18n.ts +62 -0
  111. package/dist/templates/blank/vue/src/main.ts +7 -0
  112. package/dist/templates/blank/vue/src/messages.ts +10 -0
  113. package/dist/templates/blank/vue/src/styles.css +93 -0
  114. package/dist/templates/blank/vue/src/vite-env.d.ts +1 -0
  115. package/dist/templates/blank/vue/tsconfig.json +23 -0
  116. package/dist/templates/blank/vue/vite.config.ts +36 -0
  117. package/dist/templates/blank/vue/wrangler.jsonc +8 -0
  118. package/dist/templates/blog/react/.env.example +2 -2
  119. package/dist/templates/blog/react/linguana.json +1 -1
  120. package/dist/templates/blog/react/src/App.tsx +1 -1
  121. package/dist/templates/blog/solidjs/.env.example +2 -2
  122. package/dist/templates/blog/solidjs/linguana.json +1 -1
  123. package/dist/templates/blog/solidjs/src/App.tsx +1 -1
  124. package/dist/templates/blog/svelte/.env.example +2 -2
  125. package/dist/templates/blog/svelte/linguana.json +1 -1
  126. package/dist/templates/blog/svelte/src/App.svelte +1 -1
  127. package/dist/templates/blog/tanstack-start/.env.example +2 -2
  128. package/dist/templates/blog/tanstack-start/linguana.json +1 -1
  129. package/dist/templates/blog/tanstack-start/src/App.tsx +1 -1
  130. package/dist/templates/blog/vue/.env.example +2 -2
  131. package/dist/templates/blog/vue/linguana.json +1 -1
  132. package/dist/templates/blog/vue/src/App.vue +1 -1
  133. package/dist/templates/saas/react/.env.example +2 -2
  134. package/dist/templates/saas/react/linguana.json +1 -1
  135. package/dist/templates/saas/react/src/App.tsx +1 -1
  136. package/dist/templates/saas/solidjs/.env.example +2 -2
  137. package/dist/templates/saas/solidjs/linguana.json +1 -1
  138. package/dist/templates/saas/solidjs/src/App.tsx +1 -1
  139. package/dist/templates/saas/svelte/.env.example +2 -2
  140. package/dist/templates/saas/svelte/linguana.json +1 -1
  141. package/dist/templates/saas/svelte/src/App.svelte +1 -1
  142. package/dist/templates/saas/tanstack-start/.env.example +2 -2
  143. package/dist/templates/saas/tanstack-start/linguana.json +1 -1
  144. package/dist/templates/saas/tanstack-start/src/App.tsx +1 -1
  145. package/dist/templates/saas/vue/.env.example +2 -2
  146. package/dist/templates/saas/vue/linguana.json +1 -1
  147. package/dist/templates/saas/vue/src/App.vue +1 -1
  148. package/dist/templates/storefront/react/.env.example +2 -2
  149. package/dist/templates/storefront/react/linguana.json +1 -1
  150. package/dist/templates/storefront/react/src/App.tsx +1 -1
  151. package/dist/templates/storefront/solidjs/.env.example +2 -2
  152. package/dist/templates/storefront/solidjs/linguana.json +1 -1
  153. package/dist/templates/storefront/solidjs/src/App.tsx +1 -1
  154. package/dist/templates/storefront/svelte/.env.example +2 -2
  155. package/dist/templates/storefront/svelte/linguana.json +1 -1
  156. package/dist/templates/storefront/svelte/src/App.svelte +1 -1
  157. package/dist/templates/storefront/tanstack-start/.env.example +2 -2
  158. package/dist/templates/storefront/tanstack-start/linguana.json +1 -1
  159. package/dist/templates/storefront/tanstack-start/src/App.tsx +1 -1
  160. package/dist/templates/storefront/vue/.env.example +2 -2
  161. package/dist/templates/storefront/vue/linguana.json +1 -1
  162. package/dist/templates/storefront/vue/src/App.vue +1 -1
  163. package/package.json +24 -36
@@ -0,0 +1,23 @@
1
+ # Deploy Blank
2
+
3
+ Demo mode needs no Linguana account. Hosting authentication is separate from the Linguana CLI.
4
+
5
+ ## Cloudflare Workers
6
+
7
+ Install dependencies, choose a unique Worker name in wrangler.jsonc, then:
8
+
9
+ ```sh
10
+ npx wrangler login
11
+ npm run build
12
+ npx wrangler deploy
13
+ ```
14
+
15
+ Wrangler serves dist as static assets with single-page navigation fallback. Unknown paths fall back to index.html.
16
+
17
+ ## Any static host
18
+
19
+ Run `npm run build` and publish dist/. Configure unknown paths to serve /index.html with status 200 (SPA fallback). A static preview can be started with `npm run preview`. Do not publish the project root.
20
+
21
+ ## Connected deployments
22
+
23
+ Pull the intended environment with `linguana env pull --environment production`. Configure the variables from .env.example in the build host, including the matching public project/environment values. Build tokens are secrets used by the compiler only. Never upload .env files or the CLI account session. LINGUANA_TRANSLATE remains false. Catalog publication is an explicit dashboard action.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Linguana contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,34 @@
1
+ # Blank
2
+
3
+ A minimal starting point: the Linguana logo, a translated hello world, a language picker, and hot reload.
4
+
5
+ A standalone vue app, generated from Linguana templates v0.1.0. Requires Node 22.12+ (or Bun).
6
+
7
+ ## Run
8
+
9
+ ```sh
10
+ npm install
11
+ npm run dev
12
+ ```
13
+
14
+ You can also use pnpm, Yarn, or Bun. English, French, Spanish, and Arabic catalogs are bundled in demo mode. No Linguana API requests are made. The language cookie persists between visits. Arabic switches the document to RTL.
15
+
16
+ ## Connect your own project
17
+
18
+ ```sh
19
+ npx @linguanahq/cli login
20
+ npx @linguanahq/cli link
21
+ npx @linguanahq/cli doctor
22
+ ```
23
+
24
+ Linking writes nonsecret `linguana.json` and ignored `.env.local`. The account session stays outside this project. Only the public project ID, environment, API URL, and publishable key reach the browser. Build tokens never belong in `VITE_*` variables.
25
+
26
+ Connected mode uses your published project catalogs and English source fallback. It does not load demo translations. Builds can upload the source manifest but do not start paid translations or publish catalogs. Review and publish translations in your dashboard. Existing project languages remain unchanged unless you pass `--locales`.
27
+
28
+ To target another environment, use `linguana env pull --environment staging`, then `npm run build -- --mode staging`. Production uses `.env.production.local` and Vite's default production build mode. Configure matching private and public values on your build host; see .env.example.
29
+
30
+ ## Customize
31
+
32
+ Start in src/App.vue. Vite hot reload applies your edits as you save, without losing the selected language. Add a message by giving it a stable ID in src/Copy.vue with its English text, a source fallback in src/messages.ts, and demo translations in src/demo-messages.ts.
33
+
34
+ Run `npm run check-types` and `npm run build` before deploying. Deployment instructions are in DEPLOY.md. See LICENSE and ASSETS.md.
@@ -0,0 +1,11 @@
1
+ node_modules/
2
+ dist/
3
+ .output/
4
+ .nitro/
5
+ .tanstack/
6
+ .wrangler/
7
+ .env
8
+ .env.local
9
+ .env.*.local
10
+ .linguana/
11
+ *.log
@@ -0,0 +1,2 @@
1
+ <!doctype html>
2
+ <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="description" content="A minimal starting point: the Linguana logo, a translated hello world, a language picker, and hot reload."><meta name="theme-color" content="#2f5bea"><link rel="icon" href="/favicon.ico" sizes="any"><title>Blank</title></head><body><div id="app"></div><script type="module" src="/src/main.ts"></script></body></html>
@@ -0,0 +1,10 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "framework": "vue",
4
+ "template": "blank",
5
+ "templateVersion": "0.1.0",
6
+ "mode": "demo",
7
+ "apiUrl": "https://api.linguana.dev",
8
+ "sourceLocale": "en",
9
+ "defaultEnvironment": "development"
10
+ }
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "blank-vue",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "engines": {
8
+ "node": ">=22.12.0"
9
+ },
10
+ "scripts": {
11
+ "dev": "vite --host 127.0.0.1",
12
+ "build": "vite build",
13
+ "preview": "vite preview",
14
+ "check-types": "vue-tsc --noEmit",
15
+ "deploy": "npm run build && wrangler deploy"
16
+ },
17
+ "dependencies": {
18
+ "@linguanahq/catalog": "0.1.1",
19
+ "@linguanahq/core": "0.1.1",
20
+ "@linguanahq/vue": "0.1.1",
21
+ "vue": "^3.5.24"
22
+ },
23
+ "devDependencies": {
24
+ "@linguanahq/vite": "0.1.1",
25
+ "typescript": "^6.0.0",
26
+ "vite": "^8.1.3",
27
+ "@types/node": "^24.0.0",
28
+ "wrangler": "^4.127.0",
29
+ "@vitejs/plugin-vue": "^6.0.2",
30
+ "@vue/compiler-dom": "^3.5.24",
31
+ "@vue/compiler-sfc": "^3.5.24",
32
+ "vue-tsc": "^3.1.0"
33
+ }
34
+ }
@@ -0,0 +1,33 @@
1
+ <script setup lang="ts">
2
+ import { useTranslation } from "@linguanahq/vue";
3
+ import { watchEffect } from "vue";
4
+ import Copy from "./Copy.vue";
5
+ import { demoLocales } from "./i18n";
6
+ import { messages } from "./messages";
7
+
8
+ const runtime = useTranslation();
9
+ const locale = () => runtime.locale.value;
10
+ const translate = runtime.translate;
11
+ const locales = () =>
12
+ runtime.availableLocales.value.length
13
+ ? runtime.availableLocales.value
14
+ : demoLocales.filter((item) => item.code === "en");
15
+ const changeLocale = (value: string) => void runtime.setLocale(value);
16
+ watchEffect(() => {
17
+ document.documentElement.lang = locale();
18
+ document.documentElement.dir = locale().startsWith("ar") ? "rtl" : "ltr";
19
+ });
20
+ const msg = (id: string, values?: Record<string, string | number>) =>
21
+ String(translate(id, messages[id] ?? id, values));
22
+ const value = (event: Event | { currentTarget: EventTarget | null }) =>
23
+ (event.currentTarget as HTMLSelectElement).value;
24
+ </script>
25
+ <template>
26
+ <main class="hello"><img src="/logo.png" :alt="msg('logoAlt')" class="hello-logo" width="96" height="96" />
27
+ <h1 ><Copy name="hello"></Copy></h1>
28
+ <p class="hello-intro"><Copy name="intro"></Copy></p>
29
+ <label class="locale-picker"><span class="sr-only"><Copy name="language"></Copy></span>
30
+ <select :value="locale()" :aria-label="msg('language')" @change="changeLocale(value($event))"><template v-for="language in locales()" :key="language.code"><option :value="language.code">{{ language.nativeName }}</option></template></select></label>
31
+ <p class="hello-hint"><Copy name="hotReload" :values="{ file: 'src/App.vue' }"></Copy></p>
32
+ <a href="https://docs.linguana.dev" class="hello-link" rel="noreferrer"><Copy name="docs"></Copy></a></main>
33
+ </template>
@@ -0,0 +1,13 @@
1
+ <script setup lang="ts">
2
+ import { T } from "@linguanahq/vue";
3
+
4
+ defineProps<{ name: string; values?: Record<string, string | number> }>();
5
+ </script>
6
+ <template>
7
+ <T v-if="name === 'language'" id="language" defaultMessage="Language" :values="values" />
8
+ <T v-else-if="name === 'hello'" id="hello" defaultMessage="Hello, world!" :values="values" />
9
+ <T v-else-if="name === 'intro'" id="intro" defaultMessage="Your multilingual app is ready. Pick a language to see it translated." :values="values" />
10
+ <T v-else-if="name === 'hotReload'" id="hotReload" defaultMessage="Edit {file} and save. The page updates instantly." :values="values" />
11
+ <T v-else-if="name === 'docs'" id="docs" defaultMessage="Read the docs" :values="values" />
12
+ <T v-else-if="name === 'logoAlt'" id="logoAlt" defaultMessage="Linguana logo" :values="values" />
13
+ </template>
@@ -0,0 +1,30 @@
1
+ // These catalogs are only used when linguana.json selects demo mode.
2
+ export const demoMessages = {
3
+ fr: {
4
+ language: "Langue",
5
+ hello: "Bonjour, le monde !",
6
+ intro:
7
+ "Votre application multilingue est prête. Choisissez une langue pour la voir traduite.",
8
+ hotReload:
9
+ "Modifiez {file} et enregistrez. La page se met à jour instantanément.",
10
+ docs: "Lire la documentation",
11
+ logoAlt: "Logo Linguana",
12
+ },
13
+ es: {
14
+ language: "Idioma",
15
+ hello: "¡Hola, mundo!",
16
+ intro:
17
+ "Tu aplicación multilingüe está lista. Elige un idioma para verla traducida.",
18
+ hotReload: "Edita {file} y guarda. La página se actualiza al instante.",
19
+ docs: "Leer la documentación",
20
+ logoAlt: "Logotipo de Linguana",
21
+ },
22
+ ar: {
23
+ language: "اللغة",
24
+ hello: "مرحبًا بالعالم!",
25
+ intro: "تطبيقك متعدد اللغات جاهز. اختر لغة لتراه مترجمًا.",
26
+ hotReload: "عدّل {file} واحفظه. تتحدّث الصفحة فورًا.",
27
+ docs: "اقرأ التوثيق",
28
+ logoAlt: "شعار Linguana",
29
+ },
30
+ };
@@ -0,0 +1,62 @@
1
+ import { createCatalog } from "@linguanahq/catalog";
2
+ import config from "../linguana.json";
3
+ import { demoMessages } from "./demo-messages";
4
+ export const demoLocales = [
5
+ { code: "en", displayName: "English", nativeName: "English" },
6
+ { code: "fr", displayName: "French", nativeName: "Français" },
7
+ { code: "es", displayName: "Spanish", nativeName: "Español" },
8
+ { code: "ar", displayName: "Arabic", nativeName: "العربية" },
9
+ ];
10
+ export const demo = config.mode === "demo";
11
+ export function cookieLocale(
12
+ cookie = typeof document === "undefined" ? "" : document.cookie,
13
+ ) {
14
+ try {
15
+ const value = decodeURIComponent(
16
+ cookie
17
+ .split(";")
18
+ .find((item) => item.trim().startsWith("linguana_locale="))
19
+ ?.split("=")[1] ?? "en",
20
+ );
21
+ return /^[a-z]{2,3}(?:-[A-Za-z0-9]{2,8})*$/.test(value) &&
22
+ (!demo || demoLocales.some((item) => item.code === value))
23
+ ? value
24
+ : "en";
25
+ } catch {
26
+ return "en";
27
+ }
28
+ }
29
+ export const demoCatalogs = demo
30
+ ? Object.entries(demoMessages).map(([locale, messages]) =>
31
+ createCatalog({
32
+ schemaVersion: "1.0",
33
+ projectId: "demo-blank",
34
+ environment: "development",
35
+ sourceLocale: "en",
36
+ locale,
37
+ manifestHash: "0".repeat(64),
38
+ version: 1,
39
+ messages,
40
+ }),
41
+ )
42
+ : [];
43
+ export function optionsFor(
44
+ locale = cookieLocale(),
45
+ ): import("@linguanahq/core").LinguanaClientOptions {
46
+ return {
47
+ projectId: demo ? "demo-blank" : import.meta.env.VITE_LINGUANA_PROJECT_ID,
48
+ environment: demo
49
+ ? "development"
50
+ : import.meta.env.VITE_LINGUANA_ENVIRONMENT,
51
+ initialLocale: locale,
52
+ fallbackLocale: config.sourceLocale,
53
+ catalogs: demoCatalogs,
54
+ ...(demo
55
+ ? { availableLocales: demoLocales }
56
+ : {
57
+ publishableKey: import.meta.env.VITE_LINGUANA_PUBLISHABLE_KEY,
58
+ catalogEndpoint: import.meta.env.VITE_LINGUANA_API_URL,
59
+ configEndpoint: import.meta.env.VITE_LINGUANA_API_URL,
60
+ }),
61
+ };
62
+ }
@@ -0,0 +1,7 @@
1
+ import { createLinguana } from "@linguanahq/vue";
2
+ import { createApp } from "vue";
3
+ import App from "./App.vue";
4
+ import { optionsFor } from "./i18n";
5
+ import "./styles.css";
6
+
7
+ createApp(App).use(createLinguana(optionsFor())).mount("#app");
@@ -0,0 +1,10 @@
1
+ // Source fallbacks; matching extractable literals live in Copy.vue.
2
+ export const messages: Record<string, string> = {
3
+ language: "Language",
4
+ hello: "Hello, world!",
5
+ intro:
6
+ "Your multilingual app is ready. Pick a language to see it translated.",
7
+ hotReload: "Edit {file} and save. The page updates instantly.",
8
+ docs: "Read the docs",
9
+ logoAlt: "Linguana logo",
10
+ };
@@ -0,0 +1,93 @@
1
+ * {
2
+ box-sizing: border-box;
3
+ }
4
+ body {
5
+ margin: 0;
6
+ min-height: 100vh;
7
+ display: grid;
8
+ place-items: center;
9
+ background: #f7f8fb;
10
+ color: #14213d;
11
+ font-family: system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
12
+ line-height: 1.6;
13
+ }
14
+ button,
15
+ select {
16
+ font: inherit;
17
+ }
18
+ .hello {
19
+ display: flex;
20
+ flex-direction: column;
21
+ align-items: center;
22
+ gap: 1rem;
23
+ max-width: 36rem;
24
+ padding: 3rem 1.5rem;
25
+ text-align: center;
26
+ }
27
+ .hello-logo {
28
+ width: 6rem;
29
+ height: 6rem;
30
+ }
31
+ .hello h1 {
32
+ margin: 0;
33
+ font-size: clamp(2.5rem, 8vw, 4rem);
34
+ line-height: 1.1;
35
+ letter-spacing: -0.02em;
36
+ }
37
+ .hello-intro {
38
+ margin: 0;
39
+ color: #46536b;
40
+ font-size: 1.125rem;
41
+ }
42
+ .locale-picker select {
43
+ min-height: 2.75rem;
44
+ padding: 0.5rem 2.5rem 0.5rem 1rem;
45
+ border: 1px solid #c9d1e0;
46
+ border-radius: 0.5rem;
47
+ background: #fff;
48
+ color: inherit;
49
+ cursor: pointer;
50
+ }
51
+ .locale-picker select:focus-visible,
52
+ .hello-link:focus-visible {
53
+ outline: 3px solid #2f5bea;
54
+ outline-offset: 2px;
55
+ }
56
+ .hello-hint {
57
+ margin: 0.5rem 0 0;
58
+ color: #46536b;
59
+ font-size: 0.9375rem;
60
+ }
61
+ .hello-link {
62
+ color: #2f5bea;
63
+ font-weight: 600;
64
+ text-underline-offset: 0.2em;
65
+ }
66
+ .sr-only {
67
+ position: absolute;
68
+ width: 1px;
69
+ height: 1px;
70
+ padding: 0;
71
+ margin: -1px;
72
+ overflow: hidden;
73
+ clip: rect(0, 0, 0, 0);
74
+ white-space: nowrap;
75
+ border: 0;
76
+ }
77
+ @media (prefers-color-scheme: dark) {
78
+ body {
79
+ background: #0f1420;
80
+ color: #eef1f7;
81
+ }
82
+ .hello-intro,
83
+ .hello-hint {
84
+ color: #aab4c8;
85
+ }
86
+ .locale-picker select {
87
+ background: #182033;
88
+ border-color: #33405c;
89
+ }
90
+ .hello-link {
91
+ color: #8ea8ff;
92
+ }
93
+ }
@@ -0,0 +1 @@
1
+ /// <reference types="vite/client" />
@@ -0,0 +1,23 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
6
+ "moduleResolution": "Bundler",
7
+ "strict": true,
8
+ "skipLibCheck": true,
9
+ "esModuleInterop": true,
10
+ "allowImportingTsExtensions": true,
11
+ "resolveJsonModule": true,
12
+ "noEmit": true,
13
+ "types": ["vite/client", "node"],
14
+ "jsx": "react-jsx"
15
+ },
16
+ "include": [
17
+ "src/**/*.ts",
18
+ "src/**/*.tsx",
19
+ "src/**/*.vue",
20
+ "src/**/*.svelte",
21
+ "vite.config.ts"
22
+ ]
23
+ }
@@ -0,0 +1,36 @@
1
+ import { linguana } from "@linguanahq/vite";
2
+ import { vue } from "@linguanahq/vite/vue";
3
+ import native from "@vitejs/plugin-vue";
4
+ import { defineConfig, loadEnv } from "vite";
5
+ import config from "./linguana.json" with { type: "json" };
6
+
7
+ export default defineConfig(({ mode }) => {
8
+ const env = { ...loadEnv(mode, process.cwd(), ""), ...process.env };
9
+ const connected = config.mode === "connected";
10
+ if (
11
+ connected &&
12
+ (!env.LINGUANA_PROJECT_ID ||
13
+ !env.VITE_LINGUANA_PUBLISHABLE_KEY ||
14
+ env.LINGUANA_PROJECT_ID !== env.VITE_LINGUANA_PROJECT_ID ||
15
+ env.LINGUANA_ENVIRONMENT !== env.VITE_LINGUANA_ENVIRONMENT ||
16
+ env.LINGUANA_API_URL !== env.VITE_LINGUANA_API_URL)
17
+ )
18
+ throw new Error(
19
+ "Linguana environment is incomplete or inconsistent. Run linguana env pull for this build mode.",
20
+ );
21
+ return {
22
+ plugins: [
23
+ linguana({
24
+ adapter: vue(),
25
+ projectId: connected ? env.LINGUANA_PROJECT_ID! : "demo-blank",
26
+ environment: connected ? env.LINGUANA_ENVIRONMENT : "development",
27
+ sourceLocale: config.sourceLocale,
28
+ apiUrl: connected ? env.LINGUANA_API_URL : undefined,
29
+ token: connected ? env.LINGUANA_PROJECT_TOKEN : undefined,
30
+ upload: connected && env.LINGUANA_UPLOAD === "true",
31
+ translation: false,
32
+ }),
33
+ native(),
34
+ ],
35
+ };
36
+ });
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "linguana-demo-blank-vue",
3
+ "compatibility_date": "2026-10-01",
4
+ "assets": {
5
+ "directory": "./dist",
6
+ "not_found_handling": "single-page-application"
7
+ }
8
+ }
@@ -3,7 +3,7 @@
3
3
  # Build/server only. NEVER prefix the project token with VITE_.
4
4
  LINGUANA_PROJECT_ID=
5
5
  LINGUANA_ENVIRONMENT=development
6
- LINGUANA_API_URL=https://linguana-api.mohammedibrahim.dev
6
+ LINGUANA_API_URL=https://api.linguana.dev
7
7
  LINGUANA_PROJECT_TOKEN=
8
8
  LINGUANA_UPLOAD=false
9
9
  # Paid translation is disabled; this template does not enable it automatically.
@@ -11,5 +11,5 @@ LINGUANA_TRANSLATE=false
11
11
  # Browser-safe values. A publishable key reads published catalogs only.
12
12
  VITE_LINGUANA_PROJECT_ID=
13
13
  VITE_LINGUANA_ENVIRONMENT=development
14
- VITE_LINGUANA_API_URL=https://linguana-api.mohammedibrahim.dev
14
+ VITE_LINGUANA_API_URL=https://api.linguana.dev
15
15
  VITE_LINGUANA_PUBLISHABLE_KEY=
@@ -4,7 +4,7 @@
4
4
  "template": "blog",
5
5
  "templateVersion": "0.1.0",
6
6
  "mode": "demo",
7
- "apiUrl": "https://linguana-api.mohammedibrahim.dev",
7
+ "apiUrl": "https://api.linguana.dev",
8
8
  "sourceLocale": "en",
9
9
  "defaultEnvironment": "development"
10
10
  }
@@ -455,7 +455,7 @@ export default function App({ path }: { path?: string }) {
455
455
  </div>
456
456
  <p className="fine">
457
457
  <Copy name="demo" />
458
- <a href="https://linguana.mohammedibrahim.dev" rel="noreferrer">
458
+ <a href="https://linguana.dev" rel="noreferrer">
459
459
  {"Linguana ↗"}
460
460
  </a>
461
461
  </p>
@@ -3,7 +3,7 @@
3
3
  # Build/server only. NEVER prefix the project token with VITE_.
4
4
  LINGUANA_PROJECT_ID=
5
5
  LINGUANA_ENVIRONMENT=development
6
- LINGUANA_API_URL=https://linguana-api.mohammedibrahim.dev
6
+ LINGUANA_API_URL=https://api.linguana.dev
7
7
  LINGUANA_PROJECT_TOKEN=
8
8
  LINGUANA_UPLOAD=false
9
9
  # Paid translation is disabled; this template does not enable it automatically.
@@ -11,5 +11,5 @@ LINGUANA_TRANSLATE=false
11
11
  # Browser-safe values. A publishable key reads published catalogs only.
12
12
  VITE_LINGUANA_PROJECT_ID=
13
13
  VITE_LINGUANA_ENVIRONMENT=development
14
- VITE_LINGUANA_API_URL=https://linguana-api.mohammedibrahim.dev
14
+ VITE_LINGUANA_API_URL=https://api.linguana.dev
15
15
  VITE_LINGUANA_PUBLISHABLE_KEY=
@@ -4,7 +4,7 @@
4
4
  "template": "blog",
5
5
  "templateVersion": "0.1.0",
6
6
  "mode": "demo",
7
- "apiUrl": "https://linguana-api.mohammedibrahim.dev",
7
+ "apiUrl": "https://api.linguana.dev",
8
8
  "sourceLocale": "en",
9
9
  "defaultEnvironment": "development"
10
10
  }
@@ -447,7 +447,7 @@ export default function App() {
447
447
  </div>
448
448
  <p class="fine">
449
449
  <Copy name="demo" />
450
- <a href="https://linguana.mohammedibrahim.dev" rel="noreferrer">
450
+ <a href="https://linguana.dev" rel="noreferrer">
451
451
  {"Linguana ↗"}
452
452
  </a>
453
453
  </p>
@@ -3,7 +3,7 @@
3
3
  # Build/server only. NEVER prefix the project token with VITE_.
4
4
  LINGUANA_PROJECT_ID=
5
5
  LINGUANA_ENVIRONMENT=development
6
- LINGUANA_API_URL=https://linguana-api.mohammedibrahim.dev
6
+ LINGUANA_API_URL=https://api.linguana.dev
7
7
  LINGUANA_PROJECT_TOKEN=
8
8
  LINGUANA_UPLOAD=false
9
9
  # Paid translation is disabled; this template does not enable it automatically.
@@ -11,5 +11,5 @@ LINGUANA_TRANSLATE=false
11
11
  # Browser-safe values. A publishable key reads published catalogs only.
12
12
  VITE_LINGUANA_PROJECT_ID=
13
13
  VITE_LINGUANA_ENVIRONMENT=development
14
- VITE_LINGUANA_API_URL=https://linguana-api.mohammedibrahim.dev
14
+ VITE_LINGUANA_API_URL=https://api.linguana.dev
15
15
  VITE_LINGUANA_PUBLISHABLE_KEY=
@@ -4,7 +4,7 @@
4
4
  "template": "blog",
5
5
  "templateVersion": "0.1.0",
6
6
  "mode": "demo",
7
- "apiUrl": "https://linguana-api.mohammedibrahim.dev",
7
+ "apiUrl": "https://api.linguana.dev",
8
8
  "sourceLocale": "en",
9
9
  "defaultEnvironment": "development"
10
10
  }
@@ -193,4 +193,4 @@ Elsewhere</a>
193
193
  <footer class="site-footer"><div ><a href="/" class="brand" onclick={(event) => { navigate(event); }}>Elsewhere</a>
194
194
  <p ><Copy name="about"></Copy></p></div>
195
195
  <p class="fine"><Copy name="demo"></Copy>
196
- <a href="https://linguana.mohammedibrahim.dev" rel="noreferrer">Linguana ↗</a></p></footer></div>
196
+ <a href="https://linguana.dev" rel="noreferrer">Linguana ↗</a></p></footer></div>
@@ -3,7 +3,7 @@
3
3
  # Build/server only. NEVER prefix the project token with VITE_.
4
4
  LINGUANA_PROJECT_ID=
5
5
  LINGUANA_ENVIRONMENT=development
6
- LINGUANA_API_URL=https://linguana-api.mohammedibrahim.dev
6
+ LINGUANA_API_URL=https://api.linguana.dev
7
7
  LINGUANA_PROJECT_TOKEN=
8
8
  LINGUANA_UPLOAD=false
9
9
  # Paid translation is disabled; this template does not enable it automatically.
@@ -11,5 +11,5 @@ LINGUANA_TRANSLATE=false
11
11
  # Browser-safe values. A publishable key reads published catalogs only.
12
12
  VITE_LINGUANA_PROJECT_ID=
13
13
  VITE_LINGUANA_ENVIRONMENT=development
14
- VITE_LINGUANA_API_URL=https://linguana-api.mohammedibrahim.dev
14
+ VITE_LINGUANA_API_URL=https://api.linguana.dev
15
15
  VITE_LINGUANA_PUBLISHABLE_KEY=
@@ -4,7 +4,7 @@
4
4
  "template": "blog",
5
5
  "templateVersion": "0.1.0",
6
6
  "mode": "demo",
7
- "apiUrl": "https://linguana-api.mohammedibrahim.dev",
7
+ "apiUrl": "https://api.linguana.dev",
8
8
  "sourceLocale": "en",
9
9
  "defaultEnvironment": "development"
10
10
  }
@@ -440,7 +440,7 @@ export default function App({ path }: { path?: string }) {
440
440
  </div>
441
441
  <p className="fine">
442
442
  <Copy name="demo" />
443
- <a href="https://linguana.mohammedibrahim.dev" rel="noreferrer">
443
+ <a href="https://linguana.dev" rel="noreferrer">
444
444
  {"Linguana ↗"}
445
445
  </a>
446
446
  </p>
@@ -3,7 +3,7 @@
3
3
  # Build/server only. NEVER prefix the project token with VITE_.
4
4
  LINGUANA_PROJECT_ID=
5
5
  LINGUANA_ENVIRONMENT=development
6
- LINGUANA_API_URL=https://linguana-api.mohammedibrahim.dev
6
+ LINGUANA_API_URL=https://api.linguana.dev
7
7
  LINGUANA_PROJECT_TOKEN=
8
8
  LINGUANA_UPLOAD=false
9
9
  # Paid translation is disabled; this template does not enable it automatically.
@@ -11,5 +11,5 @@ LINGUANA_TRANSLATE=false
11
11
  # Browser-safe values. A publishable key reads published catalogs only.
12
12
  VITE_LINGUANA_PROJECT_ID=
13
13
  VITE_LINGUANA_ENVIRONMENT=development
14
- VITE_LINGUANA_API_URL=https://linguana-api.mohammedibrahim.dev
14
+ VITE_LINGUANA_API_URL=https://api.linguana.dev
15
15
  VITE_LINGUANA_PUBLISHABLE_KEY=
@@ -4,7 +4,7 @@
4
4
  "template": "blog",
5
5
  "templateVersion": "0.1.0",
6
6
  "mode": "demo",
7
- "apiUrl": "https://linguana-api.mohammedibrahim.dev",
7
+ "apiUrl": "https://api.linguana.dev",
8
8
  "sourceLocale": "en",
9
9
  "defaultEnvironment": "development"
10
10
  }