diff --git a/GROK-PROVIDER-INTEGRATION-PLAN.md b/GROK-PROVIDER-INTEGRATION-PLAN.md
index 744d6d37..2d318880 100644
--- a/GROK-PROVIDER-INTEGRATION-PLAN.md
+++ b/GROK-PROVIDER-INTEGRATION-PLAN.md
@@ -15,26 +15,32 @@ now and executed only after every other workstream in the current post-recovery
---
-## 0. Executive summary — verified current state (corrects the original draft's premise)
+## 0. Executive summary — verified current state (corrects the original draft's premise, twice)
-The original request assumed both Grok and Claude were simply "not yet implemented." Verification
-against the actual code shows two **structurally different** problems:
+The original request assumed both Grok and Claude were simply "not yet implemented." A first
+verification pass (below, still accurate for Grok) found Claude's backend deliberately stubbed for
+a real reason (CORS) rather than just unwired. **A second, more careful pass — re-checking
+`AiProviderCard.tsx` for the literal string `anthropic`, not `claude` (a search-term mistake in the
+first pass) — found the picture is more nuanced still:**
| | Grok (xAI) | Claude (Anthropic) |
|---|---|---|
| `AIProvider` / `AiModel` types | Already present (`'grok'`, `'grok-3'`, `'grok-3-mini'`) | Already present (`'anthropic'`, Claude model ids) |
| README | Lists as Cloud 4 | Lists as Cloud 3 |
-| Legacy provider service (`services/aiProviderService.ts`) | **Real, working implementation** — `streamGrok()` does an actual `fetch('https://api.x.ai/v1/chat/completions', ...)`, key lookup via `storageService.getApiKey('grok')`, and a real `/v1/models` connectivity test (lines 260, 314, 380, 827) | **Deliberately stubbed** — `streamAnthropic()` (line 244) unconditionally throws: *"Claude/Anthropic: Direct browser requests are blocked by Anthropic (CORS). Please use a backend proxy or switch to Gemini/OpenAI/Ollama."* Same pattern at the image-generation and connection-test call sites (lines 590, 821-824). |
+| Legacy provider service (`services/aiProviderService.ts`) | **Real, working implementation** — `streamGrok()` does an actual `fetch('https://api.x.ai/v1/chat/completions', ...)`, key lookup via `storageService.getApiKey('grok')`, and a real `/v1/models` connectivity test (lines 260, 314, 380, 827) | `streamAnthropic()` (line 244) **unconditionally throws on every platform, including desktop**: *"Claude/Anthropic: Direct browser requests are blocked by Anthropic (CORS). Please use a backend proxy or switch to Gemini/OpenAI/Ollama."* Same pattern at the image-generation and connection-test call sites (lines 590, 821-824). **This is the actual bug** — CORS is a *browser* security mechanism; it does not apply to Tauri's native HTTP plugin (`@tauri-apps/plugin-http`, `services/localServerHttp.ts`, ADR-0012), which already exists in this codebase for exactly this class of problem (local server discovery). `streamAnthropic()` never even tries the native path — it throws before checking `isTauriRuntime()` at all. |
| New Vercel AI SDK layer (`services/ai/providerFactory.ts`) | `providerToKind()` has no `'grok'` case — falls through to `'unsupported'`. Comment: *"anthropic/grok are reserved in the type union but not yet implemented here."* | Same — no `'anthropic'` case, falls through to `'unsupported'`. |
-| Settings UI (`components/settings/AiProviderCard.tsx`) | **Not in the primary provider dropdown** (`{gemini, openai, ollama, webllm}` only, lines 174-177). Reachable only as a **hybrid-fallback-chain** option in `AiSections.tsx` (lines 149, 178) — never as a primary selection with its own API-key field. | **Not in the primary provider dropdown either.** No fallback-chain entry, no dedicated UI anywhere. |
-| CSP — Tauri desktop (`src-tauri/tauri.conf.json`) | `https://api.x.ai` **already present** in `connect-src` | `https://api.anthropic.com` **absent** |
-| CSP — web (`index.html`, `vercel.json`) | Already permissive: `connect-src` includes a bare `https:` scheme-source by design (ADR-0004, BYOK custom-base-URL tradeoff) — any HTTPS origin is already allowed on web builds. | Same — already permissive on web. |
-| Root cause | **UI wiring gap only.** The backend already works; it's simply unreachable from the Settings UI. | **Architectural constraint, not a wiring gap.** Anthropic's API does not send CORS headers permitting direct browser `fetch()`. This app has zero backend/serverless infrastructure today (no `api/` directory, no Vercel Functions, no Cloudflare Workers) — it is a purely static SPA across all three of its deployment targets (GitHub Pages, Vercel, Cloudflare Pages) plus a Tauri desktop bundle. Claude genuinely cannot work without adding a server-side relay. |
-
-**Decision (made 2026-07-30, by the maintainer, mid-audit-sprint):** do both in one plan/PR —
-Grok gets the straightforward UI-wiring fix; Claude gets a purpose-built serverless CORS-proxy
-**in addition to** the same UI wiring, since this is the app's first backend dependency and needs
-its own architectural treatment, not just a UI patch.
+| Settings UI (`components/settings/AiProviderCard.tsx`) | **Not in the primary provider dropdown** (`{gemini, openai, ollama, webllm, onnx, transformers}`, lines 174-179). Reachable only as a **hybrid-fallback-chain** option in `AiSections.tsx` (lines 149, 178) — never as a primary selection with its own API-key field. | **Already in the primary provider dropdown** (`{ id: 'anthropic', label: 'Anthropic Claude' }`, line 180) — this part is *not* missing. Selecting it renders a dedicated warning block (line 587) with existing, already-shipped i18n strings (`settings.ai.corsRestriction`, `settings.ai.anthropicCorsNote` — the latter's copy *already says* "...or use the Tauri desktop app for Anthropic calls", a promise the code doesn't yet keep). There is no API-key input for it today — the block is warning-only. |
+| CSP — Tauri desktop (`src-tauri/tauri.conf.json`) | `https://api.x.ai` **already present** in `connect-src` | `https://api.anthropic.com` **absent** — needed once desktop calls it directly |
+| CSP — web (`index.html`, `vercel.json`) | Already permissive: `connect-src` includes a bare `https:` scheme-source by design (ADR-0004, BYOK custom-base-URL tradeoff) — any HTTPS origin is already allowed on web builds. | Same — already permissive on web (irrelevant either way, since the proxy call from the browser is same-origin). |
+| Root cause | **UI wiring gap only.** The backend already works; it's simply unreachable from the Settings UI. | **Two separate gaps, one per platform.** Desktop: `streamAnthropic()` never attempts the native-HTTP escape hatch that ADR-0012 already built for exactly this CORS class of problem — a **narrow bug fix**, not new architecture. Web/PWA: browser `fetch()` has no such escape hatch; Anthropic's API sends no CORS headers permitting it, so the **only** way to make Claude work in a browser tab is a server-side relay — this app's first backend dependency. |
+
+**Decision (made 2026-07-30, by the maintainer, mid-audit-sprint):** do both providers in one
+plan/PR. Grok gets the straightforward UI-wiring fix. Claude gets **two independent tracks**: a
+small native-HTTP fix for desktop (reusing ADR-0012's established pattern — ships first, no new
+infrastructure) and a purpose-built serverless CORS-proxy for web/PWA (the actual new architecture,
+ships second, larger and riskier). Treating these as one lump "Claude proxy" task — as the first
+draft of this plan did — would have meant the *easier, already-half-promised* desktop fix waited
+behind the *harder* web fix for no real reason.
---
@@ -72,7 +78,7 @@ its own architectural treatment, not just a UI patch.
**Goal:** make Grok selectable as a primary provider with its own API-key field, exactly like
Gemini/OpenAI.
-1. **`components/settings/AiProviderCard.tsx`**: add `{ id: 'grok', label: t('settings.ai.provider.grok') }` (translation key, never a hardcoded literal — see §5 below) to the
+1. **`components/settings/AiProviderCard.tsx`**: add `{ id: 'grok', label: t('settings.ai.provider.grok') }` (translation key, never a hardcoded literal — see item 5 below) to the
primary options array (currently `gemini | openai | ollama | webllm`, lines 174-177). Add a
`provider === 'grok'` UI block mirroring the existing `provider === 'openai'` block (lines
257+): API-key input (`storageService.saveApiKey('grok', ...)` / `clearApiKey('grok')` — the
@@ -118,40 +124,91 @@ Gemini/OpenAI.
---
-## 4. Phase 2 — Claude: serverless CORS proxy (new architecture)
-
-This is the substantial new piece. **Read this whole phase before starting** — the deployment-target
-constraint below affects the entire design.
-
-### 4.1 The deployment-target problem
-
-WorldScript Studio ships to **four** targets, and a serverless function is not equally available
-on all of them:
+## 4. Phase 2 — Claude: two independent tracks, desktop first
+
+Claude splits cleanly into two tracks with very different sizes, because CORS is a **browser**
+security mechanism — it does not apply to Tauri's native HTTP plugin at all. **Ship Track A first**:
+it is a narrow bug fix reusing infrastructure that already exists (ADR-0012), not new architecture,
+and it fulfills a promise the shipped UI copy already makes (`settings.ai.anthropicCorsNote`: *"...or
+use the Tauri desktop app for Anthropic calls"*). Track B (the actual new architecture) follows.
+
+### 4.0 Track A — Desktop: native-HTTP fix (small, ships first, no new infrastructure)
+
+1. **`services/aiProviderService.ts`**: `streamAnthropic()` (and the image-generation / connection-test
+ call sites at lines 590, 821-824) currently throw unconditionally, before ever checking the
+ runtime. Branch on `isTauriRuntime()` (`services/tauriRuntime.ts`) first:
+ - **Desktop**: call `https://api.anthropic.com/v1/messages` directly via a Tauri-native fetch —
+ the same `@tauri-apps/plugin-http` escape hatch `services/localServerHttp.ts` already uses for
+ Ollama/LM Studio/vLLM (ADR-0012). That module is scoped and named for *local* servers
+ specifically (`LocalServerError`, `DEFAULT_OLLAMA_BASE_URL`); reusing it as-is for a cloud
+ endpoint would be a naming/scope mismatch. Extract the ~10-line `isTauriRuntime() ? dynamic
+ plugin-http import : global fetch` resolution into a small shared helper (or duplicate it
+ narrowly here with a comment pointing at `localServerHttp.ts` as the sibling pattern) — decide
+ which at execution time based on how it reads in context; either is defensible, over-abstracting
+ two call sites into a shared module is not required.
+ - **Web/browser** (including the Tauri WebView's own dev-mode web preview, if distinct from the
+ packaged app — verify `isTauriRuntime()`'s detection covers exactly the packaged case): still
+ throws, now pointing at Track B once it ships (or the existing message if Track B isn't done
+ yet — sequence the throw message's wording to whichever is true at the time this ships).
+2. **CSP**: add `https://api.anthropic.com` to `src-tauri/tauri.conf.json`'s `connect-src` (mirrors
+ the existing `https://api.x.ai` entry for Grok). No web CSP change needed (native fetch isn't
+ subject to it; irrelevant for the desktop-only path anyway).
+3. **UI**: on desktop, `AiProviderCard.tsx`'s existing `provider === 'anthropic'` warning block
+ (line 587) becomes conditional on `!isTauriRuntime()` — desktop instead renders the same
+ API-key + model-selector + Test Connection pattern as every other cloud provider, calling straight
+ through to the now-fixed `streamAnthropic()`. Web/PWA keeps the existing warning block (updated
+ per Track B's actual shipped state — see §4.2 below).
+4. **i18n**: no *new* strings needed for the desktop UI block itself — reuse the API-key/model-selector
+ copy already shared with Gemini/OpenAI/Grok. The existing `anthropicCorsNote` string's wording may
+ need a small revision once desktop actually works (it currently frames desktop as a suggestion,
+ not a fact) — treat this as a content update, not a new key, across all 19 locales.
+5. **Tests**: unit tests for `streamAnthropic()`'s new `isTauriRuntime()` branch (both sides mocked),
+ and for the UI's desktop-vs-web conditional rendering.
+
+**Track A Definition of Done:**
+- [ ] `streamAnthropic()` (+ image-gen + connection-test) branch on `isTauriRuntime()`; desktop calls Anthropic natively, no CORS error
+- [ ] `src-tauri/tauri.conf.json` CSP includes `https://api.anthropic.com`
+- [ ] Desktop Settings UI shows a real API-key/model-selector flow for Claude instead of the warning block
+- [ ] Web/PWA UI unchanged by this track (still shows the warning, pointing at Track B once it exists)
+- [ ] i18n: any copy changes across all 19 locales; no hardcoded literals
+- [ ] Unit tests for both runtime branches
+- [ ] This is explicitly **not** gated behind Track B — it can ship and be useful on its own even if Track B is deferred
+
+### 4.1 Track B — Web/PWA: serverless CORS proxy (the actual new architecture)
+
+This is the substantial new piece, and the only one that needs a backend. **Read this whole
+section before starting** — the deployment-target constraint below affects the entire design, and
+it is now **narrower than the first draft assumed**: Track A already covers desktop, so this track
+only needs to reach browser tabs (Vercel, Cloudflare Pages, GitHub Pages).
+
+#### 4.1.1 The deployment-target problem
+
+A serverless function is not equally available across WorldScript Studio's three *web* deploy
+targets:
| Target | Can host a serverless function? | Consequence for Claude |
|---|---|---|
| **Vercel** (primary) | Yes — Vercel Functions (`api/*.ts`) | Claude works when the app is served from Vercel |
| **Cloudflare Pages** | Yes — Cloudflare Pages Functions (`functions/*.ts`) | Claude works when served from Cloudflare, but needs a **second, separately-written** function (different runtime/handler shape from Vercel's) |
| **GitHub Pages** | **No** — pure static hosting, no server-side execution at all | Claude **cannot** work on the GitHub Pages mirror, ever, without pointing at an externally-hosted proxy |
-| **Tauri desktop** | No — static bundled app, no local server | Claude on desktop would have to call out to a **hosted** proxy (e.g., the maintainer's own Vercel deployment) — a materially different trust/privacy story than "your key never leaves your device except to the provider you configure," since now a request also transits the maintainer's infrastructure |
**This is the crux of the decision the maintainer needs to be aware of at execution time, restated
-clearly in this plan rather than glossed over:** enabling Claude means either (a) accepting that it
-silently doesn't work on 2 of 4 targets (GitHub Pages, desktop) unless those builds are configured
-to point at a hosted proxy URL, with clear UI messaging about that, or (b) writing and maintaining
-proxy functions for both Vercel *and* Cloudflare Pages, and deciding whether desktop/GitHub-Pages
-builds get a hardcoded fallback proxy URL (introducing a real dependency on a specific external
-host that isn't "your own deployment" for those users) or simply show Claude as unavailable there.
+clearly in this plan rather than glossed over:** enabling Claude on the web means either (a)
+accepting that it silently doesn't work on GitHub Pages unless that build is configured to point at
+a hosted proxy URL, with clear UI messaging about that, or (b) hardcoding a fallback proxy URL for
+the GitHub Pages build specifically (introducing a real dependency on a specific external host that
+isn't "this exact deployment" for those users, and a genuine trust-model question worth flagging to
+the maintainer rather than deciding silently).
**Recommended default for this plan:** implement the Vercel Function (primary target) first;
-Cloudflare Pages Function as a fast-follow using the same relay logic; GitHub Pages and Tauri
-desktop show Claude as **unavailable** with a clear, honest message (reusing the existing
-`settings.ai.providerStatusUnavailableBrowser` i18n key's *pattern* — a new, more specific key —
-rather than silently failing or defaulting to a hosted proxy the user didn't choose). Revisit
-hardcoding a fallback proxy URL only if the maintainer explicitly wants GitHub-Pages/desktop users
-to have Claude too, understanding the trust-model change that implies.
+Cloudflare Pages Function as a fast-follow using the same relay logic; GitHub Pages shows Claude as
+**unavailable** with a clear, honest message (a new, precise i18n key — not a reuse of
+`settings.ai.providerStatusUnavailableBrowser`, since that key's existing use case is a different
+reason) rather than silently failing or defaulting to a hosted proxy the user didn't choose. Revisit
+a hardcoded fallback proxy URL only if the maintainer explicitly wants GitHub-Pages users to have
+Claude too, understanding the trust-model change that implies.
-### 4.2 Proxy design
+#### 4.1.2 Proxy design
- **New file:** `api/claude-proxy.ts` (Vercel Function, Node.js runtime — check whether Vercel's
Edge Runtime or Node runtime is the better fit; Edge is lighter but has stricter API surface).
@@ -189,31 +246,34 @@ to have Claude too, understanding the trust-model change that implies.
routing convention differs from Vercel's `api/` — check Cloudflare Pages Functions docs for the
exact handler signature at execution time, since this plan predates writing the code).
-### 4.3 UI wiring (same pattern as Grok, once the proxy exists)
-
-1. `components/settings/AiProviderCard.tsx`: add `{ id: 'anthropic', label: t('settings.ai.provider.anthropic') }` —
- **use the existing `'anthropic'` identifier consistently** (the `AIProvider` type, `aiProviderService.ts`'s
- `case 'anthropic':`, and every other switch/lookup already use `'anthropic'`; do not introduce a
- parallel `'claude'` id anywhere — selection, key storage, service dispatch, and factory routing
- must all key off the same identifier),
- with the same API-key + model-selector + test-connection pattern as Grok — but the "backend" the
- Test Connection button calls is now the proxy endpoint, not a direct Anthropic call.
-2. **Availability detection:** on GitHub Pages / Tauri desktop builds (however that's detected at
- runtime — check `services/tauriRuntime.ts` and any existing hostname-based deploy-target
- detection), show Claude as disabled/unavailable per §4.1's recommended default, with a
- `settings.ai.providerStatusUnavailableProxy`-style i18n string explaining why (not just a generic
- "unavailable in browser" reuse — this is a different reason than the existing key's original
- use case, so a new, precise key is more honest).
-3. `services/aiProviderService.ts`: replace `streamAnthropic()`'s unconditional throw with a real
- implementation that calls the proxy endpoint (`fetch('/api/claude-proxy', ...)`) instead of
- `https://api.anthropic.com` directly. Same for the image-generation and connection-test call
- sites (lines 590, 821-824) — decide whether Claude image generation is in scope at all (Anthropic
- may not offer an image-gen endpoint; verify before wiring UI for something that doesn't exist).
-4. `services/ai/providerFactory.ts`: add an `'anthropic'` case if the new Vercel-AI-SDK layer should
- also support Claude — likely wants its own `'anthropicProxy'` kind rather than reusing
- `'openaiCompatible'`, since the request/response shape differs from OpenAI's.
-
-### 4.4 Security & privacy documentation (mandatory, not optional)
+### 4.2 UI wiring (web/PWA — the dropdown entry and warning block already exist, see §0)
+
+Unlike Grok, **no new dropdown entry is needed** — `{ id: 'anthropic', label: 'Anthropic Claude' }`
+and its warning block already ship (`AiProviderCard.tsx` lines 180, 587). The identifier is already
+correctly `'anthropic'` throughout (`AIProvider` type, `aiProviderService.ts`'s `case 'anthropic':`)
+— just don't introduce a parallel `'claude'` id anywhere while touching this.
+
+1. **On web builds where the proxy is reachable** (Vercel, Cloudflare Pages): replace the existing
+ warning-only block with the same API-key + model-selector + Test Connection pattern every other
+ cloud provider gets — but the "backend" the Test Connection button calls is the proxy endpoint,
+ not a direct Anthropic call. Existing labels are already real strings, not hardcoded literals
+ (verify `t('settings.ai.provider.anthropic')`-equivalent is actually used, per the mandatory
+ i18n rule in §3.5 — the current line reads `label: 'Anthropic Claude'`, a literal; fix this as
+ part of the same change even though it predates this plan).
+2. **On GitHub Pages** (no proxy possible — §4.1.1): keep a warning block, but update its copy to
+ the new, precise "no proxy on this deployment" reasoning rather than the current generic CORS
+ note, once Track A ships and the note's "use the desktop app" half becomes literally true.
+3. **`services/aiProviderService.ts`**: replace `streamAnthropic()`'s web-path throw (the desktop
+ path was already fixed in Track A) with a real implementation that calls the proxy endpoint
+ (`fetch('/api/claude-proxy', ...)`) instead of `https://api.anthropic.com` directly. Same for the
+ image-generation and connection-test call sites (lines 590, 821-824) — decide whether Claude
+ image generation is in scope at all (Anthropic may not offer an image-gen endpoint; verify before
+ wiring UI for something that doesn't exist).
+4. **`services/ai/providerFactory.ts`**: add an `'anthropic'` case if the new Vercel-AI-SDK layer
+ should also support Claude on the web — likely wants its own `'anthropicProxy'` kind rather than
+ reusing `'openaiCompatible'`, since the request/response shape differs from OpenAI's.
+
+### 4.3 Security & privacy documentation (mandatory, not optional)
- `docs/SECURITY-THREAT-MODEL.md`: add a new row/section for the Claude proxy — it is the **first**
place in this app's architecture where a BYOK key transits infrastructure the user doesn't
@@ -227,7 +287,7 @@ to have Claude too, understanding the trust-model change that implies.
- Settings UI: the Claude API-key input should carry a brief, honest inline note about this
distinction — not hidden in docs only.
-### 4.5 Testing
+### 4.4 Testing
- Unit tests for the proxy handler logic (request forwarding, no logging of secrets) — likely needs
a lightweight Vercel Function test harness or at minimum a pure-function extraction of the relay
@@ -238,20 +298,29 @@ to have Claude too, understanding the trust-model change that implies.
mock the proxy endpoint, verify the Settings UI flow end-to-end. Cannot realistically hit the
real Anthropic API in CI (costs money, needs a real key) — mock-only, consistent with how other
cloud-provider E2E specs in this repo already avoid real API calls.
-- Manual smoke test matrix: Vercel (real proxy, real Anthropic key) — Cloudflare Pages (real proxy)
- — GitHub Pages (confirm Claude shows unavailable, doesn't silently break) — Tauri desktop (same).
+- Manual smoke test matrix: Tauri desktop (Track A, real Anthropic key, no proxy) — Vercel (Track B,
+ real proxy, real Anthropic key) — Cloudflare Pages (Track B, real proxy) — GitHub Pages (Track B
+ unavailable state, confirm it doesn't silently break).
-**Claude Definition of Done:**
+**Claude Definition of Done (Track A — desktop, ships first):**
+- [ ] `streamAnthropic()` (+ image-gen + connection-test) branch on `isTauriRuntime()`; desktop calls Anthropic natively, no CORS error
+- [ ] `src-tauri/tauri.conf.json` CSP includes `https://api.anthropic.com`
+- [ ] Desktop Settings UI shows a real API-key/model-selector flow for Claude instead of the warning block
+- [ ] Unit tests for both runtime branches
+
+**Claude Definition of Done (Track B — web/PWA, ships second):**
- [ ] Vercel Function proxy deployed and relaying requests statelessly (no key/prompt logging)
-- [ ] Proxy enforces schema validation, body-size limit, origin policy, rate limiting, and timeouts (§4.2) — tested
+- [ ] Proxy enforces schema validation, body-size limit, origin policy, rate limiting, and timeouts (§4.1.2) — tested
- [ ] Cloudflare Pages Function equivalent (or explicit decision to defer, documented in the ADR)
-- [ ] Claude selectable as primary provider in Settings → AI Provider on proxy-capable deployments
-- [ ] GitHub Pages and Tauri desktop show an honest "unavailable" state, not a silent failure
+- [ ] Claude's existing warning-only block replaced with a real API-key/model-selector flow on proxy-capable web deployments
+- [ ] GitHub Pages shows an honest "unavailable" state, not a silent failure
- [ ] `docs/SECURITY-THREAT-MODEL.md` and README's privacy framing updated with the proxy caveat
-- [ ] i18n: all provider/model/status/error strings use translation keys (no hardcoded literals); all 19 locales
-- [ ] No new feature flag
- [ ] Unit + E2E tests (mocked, no real Anthropic calls in CI)
-- [ ] New ADR 0016 covers both Grok and Claude decisions
+
+**Both tracks:**
+- [ ] i18n: all provider/model/status/error strings use translation keys (no hardcoded literals) — including fixing the pre-existing `label: 'Anthropic Claude'` literal; all 19 locales
+- [ ] No new feature flag
+- [ ] New ADR 0016 covers both Grok and Claude decisions (and the Track A/B split)
- [ ] README/CHANGELOG updated; TODO.md/AUDIT.md reconciled
---
@@ -287,11 +356,11 @@ to have Claude too, understanding the trust-model change that implies.
## 7. Addendum — opt-in browser-fetch Ollama for the PWA (Issue #266 follow-up)
-**This is a separate initiative from §§1-7 above** — different issue, different mechanism, no
+**This is a separate initiative from §§0-6 above** — different issue, different mechanism, no
backend involved — bundled into this same plan file at the maintainer's request rather than as a
second document.
-### 8.1 Why this is *not* the same pattern as the Claude proxy
+### 7.1 Why this is *not* the same pattern as the Claude proxy
A hosted serverless proxy (§4) works for Claude because the proxy's *destination* —
`api.anthropic.com` — is a fixed host reachable from anywhere on the internet, including from
@@ -301,7 +370,7 @@ is `http://localhost:11434` **on the end user's own machine**. A serverless func
bridges "an internet server reaching into a user's private machine." This is a hard networking
fact, not a policy choice, and it's why no part of this addendum proposes a proxy.
-### 8.2 What actually exists: the maintainer's own "technically: yes" answer in Issue #266
+### 7.2 What actually exists: the maintainer's own "technically: yes" answer in Issue #266
[Issue #266](https://github.com/qnbs/WorldScript-Studio/issues/266) already contains a full,
correct analysis (comment thread, 2026-07-28/29) of why the PWA doesn't attempt Ollama connections
@@ -322,7 +391,7 @@ plan operationalizes exactly that answer, not a new invention:
reason this was never made the *default* — but that's an argument against defaulting it on, not
against offering it as an explicit, clearly-labeled opt-in for users who understand the tradeoff.
-### 8.3 Implementation sketch
+### 7.3 Implementation sketch
1. **New feature flag** — e.g. `enableBrowserOllama` — default **off**, opt-in, added through the
normal `featureFlagsSlice.ts` + `featureCatalog.ts` process this sprint's WS-2 already
@@ -360,11 +429,11 @@ plan operationalizes exactly that answer, not a new invention:
7. **Docs**: update the existing "desktop app required" banner copy, README, TODO.md, and the
in-app help article to mention the new opt-in path without implying it's the recommended one —
desktop remains the recommended, zero-config path for local servers.
-8. **i18n**: same mandatory-translation-key requirement as §5/§8 above — the toggle label, the
- `OLLAMA_ORIGINS` instructional copy, and the new `cors`-suspected error state all need real
- `t()` keys across all 19 locales; no hardcoded literals.
+8. **i18n**: same mandatory-translation-key requirement as Phase 1's i18n item (§3.5) above — the
+ toggle label, the `OLLAMA_ORIGINS` instructional copy, and the new `cors`-suspected error state
+ all need real `t()` keys across all 19 locales; no hardcoded literals.
-### 8.4 Definition of Done
+### 7.4 Definition of Done
- [ ] New feature flag, default off, follows this repo's existing flag conventions (`pnpm exec tsx scripts/audit-feature-parity.ts` reports 0 drifts)
- [ ] PWA can optionally attempt a direct Ollama fetch when the flag is on, clearly labeled experimental/unsupported in the UI
diff --git a/README.md b/README.md
index 16da7fce..5446c0fa 100644
--- a/README.md
+++ b/README.md
@@ -12,7 +12,7 @@
-
+
@@ -383,7 +383,7 @@ Infrastructure-level features that keep the app fast and extensible as projects
### 🌐 Full Multi-Language Support
-Shipped UI locales with **2849 i18n keys** across all 19 languages — zero hardcoded user-facing strings:
+Shipped UI locales with **2855 i18n keys** across all 19 languages — zero hardcoded user-facing strings:
- 🇩🇪 **German** (Deutsch)
- 🇬🇧 **English**
@@ -492,7 +492,7 @@ The Settings → AI panel shows a live GPU status badge with adapter details and
| **PDF Export** | jsPDF | Client-side, configurable PDF document generation |
| **Document Export** | docx + jszip | Word-compatible `.docx` generation (lazy-loaded) |
| **PWA** | Service Worker + Web App Manifest v3 | Offline support, installability, Workbox chunking |
-| **i18n** | Custom React Context (`I18nContext.tsx`) | 2849 keys × 19 locales (de/en/es/fr/it + ar/he/fa RTL Beta + ja/zh/pt/el/fi/sv/hu/is/eu Beta); EN fallback; `localStorage` persistence |
+| **i18n** | Custom React Context (`I18nContext.tsx`) | 2855 keys × 19 locales (de/en/es/fr/it + ar/he/fa RTL Beta + ja/zh/pt/el/fi/sv/hu/is/eu Beta); EN fallback; `localStorage` persistence |
| **Testing** | Vitest 4.x (6477 tests / 529 files) + Playwright E2E | Unit/integration + cross-browser E2E; Stryker mutation (manual workflow) |
| **Code Quality** | Biome (lint + format) + TypeScript 7 (tsgo) strict | `--error-on-warnings` in CI; zero `any` policy |
| **Visualization** | Force-directed graph | Interactive character relationship network |
@@ -694,7 +694,7 @@ The main pipeline is [`.github/workflows/ci.yml`](.github/workflows/ci.yml). Opt
**Current test metrics (2026-07-30, CI-reported):**
- **6477 unit tests** across **529 test files** — all passing
- Coverage thresholds: lines ≥ 74 · branches ≥ 60 · functions ≥ 67 · statements ≥ 72 — enforced in CI (see Codecov badge for live metrics)
-- i18n: **2849 keys × 19 locales** (en/de/fr/es/it + ar/he/fa RTL Beta + ja/zh/pt/el/fi/sv/hu/is/eu Beta)
+- i18n: **2855 keys × 19 locales** (en/de/fr/es/it + ar/he/fa RTL Beta + ja/zh/pt/el/fi/sv/hu/is/eu Beta)
**CI-cloud-first workflow (recommended):** On constrained hardware run **`pnpm run lint && pnpm run i18n:check && pnpm run typecheck`** locally, then push and let CI handle coverage, E2E, Lighthouse, and Stryker. Authoritative numbers come from CI artifacts (Codecov, JUnit). After CI goes green, update the README badges and `AUDIT.md` quality-gate line from the reported metrics. See **[`docs/CI.md`](docs/CI.md) § Cloud CI-first vs local development** for the full post-merge doc-update checklist.
diff --git a/components/settings/AiProviderCard.tsx b/components/settings/AiProviderCard.tsx
index 7a1543c7..57707f66 100644
--- a/components/settings/AiProviderCard.tsx
+++ b/components/settings/AiProviderCard.tsx
@@ -46,6 +46,9 @@ export const AiProviderCard: FC = ({
// imply a verified connection next to the "desktop app required" banner.
const ollamaUntestable = provider === 'ollama' && !isDesktop;
const [openaiKey, setOpenaiKey] = useState('');
+ // QNBS-v3: Grok's own key input state, mirroring OpenAI's pattern above.
+ const [grokKey, setGrokKey] = useState('');
+ const [isSavingGrokKey, setIsSavingGrokKey] = useState(false);
const [ollamaModels, setOllamaModels] = useState([]);
const [testStatus, setTestStatus] = useState<'idle' | 'loading' | 'ok' | 'error'>('idle');
const [testError, setTestError] = useState('');
@@ -66,8 +69,26 @@ export const AiProviderCard: FC = ({
.getApiKey('openai')
.then((k) => setOpenaiKey(k ?? ''))
.catch(() => {});
+ storageService
+ .getApiKey('grok')
+ .then((k) => setGrokKey(k ?? ''))
+ .catch(() => {});
}, []);
+ // QNBS-v3: save/clear via storageService, matching every other provider's key persistence.
+ const handleSaveGrokKey = useCallback(async () => {
+ setIsSavingGrokKey(true);
+ try {
+ if (grokKey.trim()) {
+ await storageService.saveApiKey('grok', grokKey.trim());
+ } else {
+ await storageService.clearApiKey('grok');
+ }
+ } finally {
+ setIsSavingGrokKey(false);
+ }
+ }, [grokKey]);
+
const handleSaveOpenAiKey = useCallback(async () => {
setIsSavingKey(true);
try {
@@ -171,13 +192,14 @@ export const AiProviderCard: FC = ({
}, [provider, isDesktop, handleLoadOllamaModels, handleTest]);
const providers: { id: AIProvider; label: string }[] = [
- { id: 'gemini', label: 'Google Gemini' },
- { id: 'openai', label: 'OpenAI' },
- { id: 'ollama', label: 'Ollama (lokal)' },
+ { id: 'gemini', label: t('settings.ai.provider.gemini') },
+ { id: 'openai', label: t('settings.ai.provider.openai') },
+ { id: 'ollama', label: t('settings.ai.provider.ollama') },
{ id: 'webllm', label: t('settings.ai.providerWebllm') },
{ id: 'onnx', label: t('settings.ai.providerOnnx') },
{ id: 'transformers', label: t('settings.ai.providerTransformers') },
- { id: 'anthropic', label: 'Anthropic Claude' },
+ { id: 'anthropic', label: t('settings.ai.provider.anthropic') },
+ { id: 'grok', label: t('settings.ai.provider.grok') },
];
const presetOptions: { id: LocalBackendPreset; labelKey: string }[] = [
@@ -322,6 +344,46 @@ export const AiProviderCard: FC = ({
)}
+ {provider === 'grok' && (
+
{!isDesktop && (
diff --git a/docs/adr/0016-native-grok-and-claude-providers.md b/docs/adr/0016-native-grok-and-claude-providers.md
new file mode 100644
index 00000000..18281054
--- /dev/null
+++ b/docs/adr/0016-native-grok-and-claude-providers.md
@@ -0,0 +1,118 @@
+# ADR 0016 — Native Grok provider + split Claude fix (desktop native-HTTP, web serverless proxy)
+
+- **Status:** Accepted
+- **Date:** 2026-07-30
+- **Deciders:** Maintainer + Claude Code
+- **Context tags:** ai, grok, anthropic, claude, cors, tauri, proxy, backend
+- **Related:** [`GROK-PROVIDER-INTEGRATION-PLAN.md`](../../GROK-PROVIDER-INTEGRATION-PLAN.md) (execution plan this ADR formalizes) · extends [ADR 0012](0012-local-server-connectivity-tauri-http.md) · see also [ADR 0004](0004-csp-connect-src-byok-tradeoff.md)
+
+## Context
+
+README documents Grok (xAI, "Cloud 4") and Claude (Anthropic, "Cloud 3") as working cloud AI
+providers. Neither was actually selectable as a primary provider with its own API key in
+`components/settings/AiProviderCard.tsx`'s main flow, prompting an investigation into why.
+
+Verification found **two structurally different problems**, not one:
+
+- **Grok**: `services/aiProviderService.ts`'s `streamGrok()` already has a real, working
+ implementation — a genuine `fetch('https://api.x.ai/v1/chat/completions', ...)`, BYOK key
+ storage, and a working `/v1/models` connection test. It simply was never added to
+ `AiProviderCard.tsx`'s primary provider dropdown (only reachable as a hybrid-fallback-chain
+ option) or to the newer Vercel-AI-SDK layer (`services/ai/providerFactory.ts`'s
+ `providerToKind()`). **Pure UI/wiring gap.**
+- **Claude**: `streamAnthropic()` unconditionally throws — *"Direct browser requests are blocked by
+ Anthropic (CORS). Please use a backend proxy or switch to Gemini/OpenAI/Ollama."* — on **every**
+ platform, including desktop, without ever checking which platform it's running on. A first
+ investigation pass concluded this needed a serverless proxy everywhere. **A second, more careful
+ pass corrected that**: `AiProviderCard.tsx` already has an `'anthropic'` entry in its primary
+ dropdown with a dedicated warning block, whose own shipped i18n copy already says *"...or use the
+ Tauri desktop app for Anthropic calls"* — a promise the code doesn't keep. CORS is a **browser**
+ security mechanism. It does not apply to Tauri's native HTTP plugin
+ (`@tauri-apps/plugin-http`), which `services/localServerHttp.ts` already uses to bypass exactly
+ this class of restriction for Ollama/LM Studio/vLLM (ADR-0012). `streamAnthropic()` never
+ attempts that escape hatch before throwing.
+
+## Decision
+
+### Grok — native UI wiring (no new architecture)
+
+Add Grok to `AiProviderCard.tsx`'s primary provider dropdown with its own API-key field and model
+selector, wired to the existing, already-functional `streamGrok()` backend. Add a `case 'grok'` to
+`providerFactory.ts`'s `providerToKind()` (xAI's API is OpenAI-compatible) so the newer
+Vercel-AI-SDK Writer-streaming path gets Grok too, not just legacy thunks. No new feature flag —
+Grok becomes a regular provider option exactly like Gemini/OpenAI. No CSP change needed:
+`https://api.x.ai` is already present in `src-tauri/tauri.conf.json`, and the web CSP's `https:`
+scheme-source (ADR-0004) already covers it.
+
+### Claude — two independent tracks, not one
+
+**Track A (desktop, ships first, no new infrastructure):** fix `streamAnthropic()` to branch on
+`isTauriRuntime()` before throwing. On desktop, call `https://api.anthropic.com` directly via the
+same native-HTTP pattern ADR-0012 established for local servers — native networking is not subject
+to browser CORS at all. Add `https://api.anthropic.com` to the Tauri CSP's `connect-src` (mirrors
+the existing Grok entry). Desktop Settings UI swaps the warning-only block for a real API-key/model
+flow. This is a narrow bug fix, not new architecture, and ships independently of Track B.
+
+**Track B (web/PWA, ships second, the actual new architecture):** browser `fetch()` has no
+native-HTTP escape hatch — Anthropic's API sends no CORS headers permitting direct browser access,
+so the only way to make Claude work in a browser tab is a server-side relay. This is the app's
+**first backend dependency** ever (previously a purely static SPA across GitHub Pages, Vercel, and
+Cloudflare Pages, plus a Tauri desktop bundle with no local server of its own). A Vercel Function
+(`api/claude-proxy.ts`) relays `{ apiKey, model, messages }` to `https://api.anthropic.com/v1/messages`
+statelessly — it must never log, persist, or cache the API key or message content. A Cloudflare
+Pages Function equivalent follows for that deploy target. **GitHub Pages cannot host a serverless
+function at all** (pure static hosting) — Claude shows an honest "unavailable on this deployment"
+state there rather than silently failing or defaulting to a hosted proxy the user didn't choose.
+
+The proxy is public and unauthenticated by construction (it relays whatever API key the caller
+supplies) — this makes it an externally-reachable resource-exhaustion surface (CWE-400) if shipped
+without controls. Schema validation, a request body size limit, an origin check, rate limiting, and
+timeouts on both legs (inbound and the outbound call to Anthropic) are **mandatory**, not optional
+hardening to consider later.
+
+### Trust-model consequence (Track B only)
+
+Every other cloud provider in this app is a direct browser→provider call — the user's API key
+never transits infrastructure WorldScript controls. Track B's proxy is the **first exception**: a
+Claude request on the web now flows browser → WorldScript's Vercel/Cloudflare deployment →
+Anthropic. The proxy is stateless (nothing is persisted or logged), but the key still passes
+through code the maintainer runs, for the duration of that one request. This is documented
+explicitly in `docs/SECURITY-THREAT-MODEL.md` and in README's privacy framing — it is not hidden
+behind "just like BYOK for other providers," because it isn't quite the same guarantee.
+
+### Ollama-in-PWA (adjacent follow-up, Issue #266, not part of this decision's core scope)
+
+A related but separate question came up during this work: could the same proxy pattern let the PWA
+reach the user's own local Ollama server? **No** — a hosted proxy can only reach itself, never a
+user's private `localhost`, so this is not a variant of Track B. The actual answer (already
+described by the maintainer in Issue #266's own comment thread) is an opt-in feature flag using
+direct browser `fetch()`, matching NovelCrafter's real (non-magic) model: it works only when the
+user configures their own Ollama server's `OLLAMA_ORIGINS` to the exact PWA origin. This narrowly
+widens ADR-0012's "PWA stays desktop-only" decision for users who explicitly opt in and accept the
+setup burden — it does not reverse that decision as the default. See the plan document's addendum
+for the full design.
+
+## Consequences
+
+- **Positive:** Grok becomes fully usable with zero new infrastructure. Claude becomes usable on
+ desktop immediately (Track A) with a small, low-risk fix reusing an established pattern, and on
+ the web (Track B) once the proxy ships — closing a real gap between README's claims and actual
+ behavior for both providers.
+- **Negative (accepted):** Track B introduces this app's first backend dependency, a genuine
+ architectural shift from "purely static SPA" — deliberately scoped as narrowly as possible (one
+ relay endpoint, no general backend-for-frontend layer) and documented as a trust-model change,
+ not glossed over.
+- **Deliberately deferred:** a hardcoded fallback proxy URL for GitHub Pages (so that deployment
+ could have Claude too, at the cost of routing every such request through a fixed external host
+ the user didn't choose) is not part of this decision — it's called out in the plan as a choice
+ for the maintainer to make explicitly later, not a default.
+- **Not yet resolved:** whether Claude's image-generation call site should get an equivalent fix
+ depends on whether Anthropic's API even offers image generation — verify before wiring UI for a
+ capability that may not exist.
+
+## References
+
+- [`GROK-PROVIDER-INTEGRATION-PLAN.md`](../../GROK-PROVIDER-INTEGRATION-PLAN.md) — full phased execution plan
+- [[0012-local-server-connectivity-tauri-http]] — the native-HTTP pattern Track A reuses
+- [[0004-csp-connect-src-byok-tradeoff]] — why the web CSP's `https:` scheme-source already covers Grok
+- [Issue #266](https://github.com/qnbs/WorldScript-Studio/issues/266) — origin of both the ADR-0012 pattern and the Ollama-in-PWA follow-up
diff --git a/docs/adr/README.md b/docs/adr/README.md
index 14e4d557..c13421d6 100644
--- a/docs/adr/README.md
+++ b/docs/adr/README.md
@@ -21,6 +21,7 @@ than editing history.
| [0013](0013-csp-wasm-and-blob-frames.md) | CSP `'wasm-unsafe-eval'` and `frame-src blob:` | Accepted |
| [0014](0014-worker-generation-duplication.md) | Two live worker generations (v1 and WorkerBus v2) | Superseded by 0015 |
| [0015](0015-worker-generation-consolidation.md) | Worker-generation consolidation: v1 retired, WorkerBus v2 is the sole generation | Accepted |
+| [0016](0016-native-grok-and-claude-providers.md) | Native Grok provider + split Claude fix (desktop native-HTTP, web serverless proxy) | Accepted |
**Format:** Context → Decision → Consequences (incl. rejected alternatives). Keep each ADR to one
decision. Link related records with `[[slug]]`.
diff --git a/docs/i18n/AUDIT_AND_IMPROVEMENT_PLAN.md b/docs/i18n/AUDIT_AND_IMPROVEMENT_PLAN.md
index 5297d2ce..7f0027e9 100644
--- a/docs/i18n/AUDIT_AND_IMPROVEMENT_PLAN.md
+++ b/docs/i18n/AUDIT_AND_IMPROVEMENT_PLAN.md
@@ -7,7 +7,7 @@
## 1. Current state (as audited)
-- **19 locales × 21 modules**, ~2849 keys, full **key parity** enforced by
+- **19 locales × 21 modules**, ~2855 keys, full **key parity** enforced by
`scripts/check-i18n-keys.mjs` (CI `quality` job) + bundled to `public/locales//bundle.json`.
- Runtime: custom `contexts/I18nContext.tsx` — lazy `bundle.json` fetch, `localStorage` persistence
(`worldscript-language`), English fallback chain, cached `Intl.*` helpers, `Intl.Segmenter` word
diff --git a/locales/ar/settings.json b/locales/ar/settings.json
index b1d78832..883f9c15 100644
--- a/locales/ar/settings.json
+++ b/locales/ar/settings.json
@@ -134,6 +134,7 @@
"settings.ai.gpu.troubleshootLowEnd": "جهازك ذو موارد محدودة. سيستخدم الذكاء الاصطناعي المحلي نماذج أصغر. لأداء أفضل، أغلق علامات تبويب المتصفّح الأخرى أو فعّل الوضع الاقتصادي.",
"settings.ai.gpu.troubleshootQueue": "هناك مهام ذكاء اصطناعي متعدّدة في الطابور. تعمل واحدة فقط في كل مرة لتجنّب تصادمات ذاكرة الرسوميات. انتظر انتهاء المهمة الحالية.",
"settings.ai.gpu.waitingConsumers": "في الانتظار",
+ "settings.ai.grokKey": "Grok API Key",
"settings.ai.hybridFallbackHint": "إذا فشل المزوّد الأساسي، يجرّب WorldScript الاحتياطيات المدرجة (مولّدات المشاهد، أدوات الفهرس). يستخدم بثّ الكاتب مزوّدك الأساسي فقط.",
"settings.ai.hybridFallbackTitle": "الاحتياطي الهجين (أدوات الذكاء الاصطناعي للمشروع)",
"settings.ai.hybridFallbackToggle": "تفعيل سلسلة الاحتياطي",
@@ -214,6 +215,11 @@
"settings.ai.preset.lmStudio": "LM Studio",
"settings.ai.preset.ollamaDefault": "Ollama (المنفذ الافتراضي)",
"settings.ai.preset.vllm": "vLLM",
+ "settings.ai.provider.anthropic": "Anthropic Claude",
+ "settings.ai.provider.gemini": "Google Gemini",
+ "settings.ai.provider.grok": "xAI Grok",
+ "settings.ai.provider.ollama": "Ollama (local)",
+ "settings.ai.provider.openai": "OpenAI",
"settings.ai.providerDescription": "اختر مزوّد الذكاء الاصطناعي الذي يجب أن يستخدمه WorldScript Studio.",
"settings.ai.providerOnnx": "ONNX (WASM)",
"settings.ai.providerStatusConnected": "متصل",
diff --git a/locales/de/settings.json b/locales/de/settings.json
index 54ba181a..69c7188f 100644
--- a/locales/de/settings.json
+++ b/locales/de/settings.json
@@ -134,6 +134,7 @@
"settings.ai.gpu.troubleshootLowEnd": "Ihr Gerät hat begrenzte Ressourcen. Lokale KI verwendet kleinere Modelle. Schließen Sie andere Browser-Tabs oder aktivieren Sie den Eco-Modus.",
"settings.ai.gpu.troubleshootQueue": "Mehrere KI-Aufgaben sind in der Warteschlange. Nur eine läuft gleichzeitig, um VRAM-Kollisionen zu vermeiden. Warten Sie, bis die aktuelle Aufgabe fertig ist.",
"settings.ai.gpu.waitingConsumers": "Wartend",
+ "settings.ai.grokKey": "Grok API-Schlüssel",
"settings.ai.hybridFallbackHint": "Wenn der primäre Anbieter fehlschlägt, versucht WorldScript die aufgelisteten Fallbacks (Szenen-Generator, Codex-Tools). Das Writer-Streaming nutzt ausschließlich den primären Anbieter.",
"settings.ai.hybridFallbackTitle": "Hybrides Fallback (Projekt-KI-Tools)",
"settings.ai.hybridFallbackToggle": "Fallback-Kette aktivieren",
@@ -214,6 +215,11 @@
"settings.ai.preset.lmStudio": "LM Studio",
"settings.ai.preset.ollamaDefault": "Ollama (Standardport)",
"settings.ai.preset.vllm": "vLLM",
+ "settings.ai.provider.anthropic": "Anthropic Claude",
+ "settings.ai.provider.gemini": "Google Gemini",
+ "settings.ai.provider.grok": "xAI Grok",
+ "settings.ai.provider.ollama": "Ollama (lokal)",
+ "settings.ai.provider.openai": "OpenAI",
"settings.ai.providerDescription": "Wähle, welchen KI-Anbieter WorldScript Studio verwenden soll.",
"settings.ai.providerOnnx": "ONNX (WASM)",
"settings.ai.providerStatusConnected": "Verbunden",
diff --git a/locales/el/settings.json b/locales/el/settings.json
index 508922ec..f0225af9 100644
--- a/locales/el/settings.json
+++ b/locales/el/settings.json
@@ -134,6 +134,7 @@
"settings.ai.gpu.troubleshootLowEnd": "Η συσκευή σας έχει περιορισμένους πόρους. Η τοπική τεχνητή νοημοσύνη θα χρησιμοποιεί μικρότερα μοντέλα. Για καλύτερη απόδοση, κλείστε άλλες καρτέλες του προγράμματος περιήγησης ή ενεργοποιήστε τη λειτουργία Eco Mode.",
"settings.ai.gpu.troubleshootQueue": "Πολλές εργασίες AI βρίσκονται στην ουρά. Μόνο ένα τρέχει κάθε φορά για να αποφευχθούν συγκρούσεις VRAM. Περιμένετε να ολοκληρωθεί η τρέχουσα εργασία.",
"settings.ai.gpu.waitingConsumers": "Αναμονή",
+ "settings.ai.grokKey": "Grok API Key",
"settings.ai.hybridFallbackHint": "Εάν ο κύριος πάροχος αποτύχει, το WorldScript δοκιμάζει τα αναγραφόμενα εναλλακτικά (δημιουργοί σκηνής, εργαλεία κώδικα). Η ροή του Writer χρησιμοποιεί μόνο τον κύριο πάροχο σας.",
"settings.ai.hybridFallbackTitle": "Υβριδικό εναλλακτικό (εργαλεία AI έργου)",
"settings.ai.hybridFallbackToggle": "Ενεργοποίηση εναλλακτικής αλυσίδας",
@@ -214,6 +215,11 @@
"settings.ai.preset.lmStudio": "LM Studio",
"settings.ai.preset.ollamaDefault": "Ollama (προεπιλεγμένη θύρα)",
"settings.ai.preset.vllm": "vLLM",
+ "settings.ai.provider.anthropic": "Anthropic Claude",
+ "settings.ai.provider.gemini": "Google Gemini",
+ "settings.ai.provider.grok": "xAI Grok",
+ "settings.ai.provider.ollama": "Ollama (local)",
+ "settings.ai.provider.openai": "OpenAI",
"settings.ai.providerDescription": "Επιλέξτε ποιον πάροχο τεχνητής νοημοσύνης θα χρησιμοποιεί το WorldScript Studio.",
"settings.ai.providerOnnx": "ONNX (WASM)",
"settings.ai.providerStatusConnected": "Συνδεδεμένος",
diff --git a/locales/en/settings.json b/locales/en/settings.json
index 2df90e31..067c2648 100644
--- a/locales/en/settings.json
+++ b/locales/en/settings.json
@@ -119,6 +119,7 @@
"settings.ai.geminiKeyBelow": "below.",
"settings.ai.geminiKeySection": "API Key",
"settings.ai.geminiSelected": "Google Gemini is selected. Configure the API key in the section",
+ "settings.ai.grokKey": "Grok API Key",
"settings.ai.gpu.currentConsumer": "GPU held by",
"settings.ai.gpu.deviceHighEnd": "High-end",
"settings.ai.gpu.deviceLowEnd": "Low-end",
@@ -214,6 +215,11 @@
"settings.ai.preset.lmStudio": "LM Studio",
"settings.ai.preset.ollamaDefault": "Ollama (default port)",
"settings.ai.preset.vllm": "vLLM",
+ "settings.ai.provider.anthropic": "Anthropic Claude",
+ "settings.ai.provider.gemini": "Google Gemini",
+ "settings.ai.provider.grok": "xAI Grok",
+ "settings.ai.provider.ollama": "Ollama (local)",
+ "settings.ai.provider.openai": "OpenAI",
"settings.ai.providerDescription": "Choose which AI provider WorldScript Studio should use.",
"settings.ai.providerOnnx": "ONNX (WASM)",
"settings.ai.providerStatusConnected": "Connected",
diff --git a/locales/es/settings.json b/locales/es/settings.json
index 4db6a854..6edaa300 100644
--- a/locales/es/settings.json
+++ b/locales/es/settings.json
@@ -134,6 +134,7 @@
"settings.ai.gpu.troubleshootLowEnd": "Su dispositivo tiene recursos limitados. La IA local usará modelos más pequeños. Cierre otras pestañas o active el modo eco.",
"settings.ai.gpu.troubleshootQueue": "Varias tareas de IA están en cola. Solo una se ejecuta a la vez para evitar colisiones de VRAM. Espere a que termine la tarea actual.",
"settings.ai.gpu.waitingConsumers": "En espera",
+ "settings.ai.grokKey": "Clave API de Grok",
"settings.ai.hybridFallbackHint": "Si el proveedor principal falla, WorldScript prueba los respaldos enumerados (generadores de escenas, herramientas de codex). La transmisión del escritor usa solo tu proveedor principal.",
"settings.ai.hybridFallbackTitle": "Respaldo híbrido (herramientas de IA del proyecto)",
"settings.ai.hybridFallbackToggle": "Activar cadena de respaldo",
@@ -214,6 +215,11 @@
"settings.ai.preset.lmStudio": "LM Studio",
"settings.ai.preset.ollamaDefault": "Ollama (puerto predeterminado)",
"settings.ai.preset.vllm": "vLLM",
+ "settings.ai.provider.anthropic": "Anthropic Claude",
+ "settings.ai.provider.gemini": "Google Gemini",
+ "settings.ai.provider.grok": "xAI Grok",
+ "settings.ai.provider.ollama": "Ollama (local)",
+ "settings.ai.provider.openai": "OpenAI",
"settings.ai.providerDescription": "Elige qué proveedor de IA debe usar WorldScript Studio.",
"settings.ai.providerOnnx": "ONNX (WASM)",
"settings.ai.providerStatusConnected": "Conectado",
diff --git a/locales/eu/settings.json b/locales/eu/settings.json
index 17ae6dd9..87f706d4 100644
--- a/locales/eu/settings.json
+++ b/locales/eu/settings.json
@@ -134,6 +134,7 @@
"settings.ai.gpu.troubleshootLowEnd": "Zure gailuak baliabide mugatuak ditu. Tokiko AI eredu txikiagoak erabiliko ditu. Errendimendu hobea lortzeko, itxi beste arakatzailearen fitxak edo gaitu Eco modua.",
"settings.ai.gpu.troubleshootQueue": "AI ataza anitz daude ilaran. Bat bakarrik exekutatzen da aldi berean VRAM talkak saihesteko. Itxaron uneko zeregina amaitu arte.",
"settings.ai.gpu.waitingConsumers": "Zain",
+ "settings.ai.grokKey": "Grok API Key",
"settings.ai.hybridFallbackHint": "Hornitzaile nagusiak huts egiten badu, WorldScript-ek zerrendatutako ordezkapenak probatzen ditu (eszena-sortzaileak, kodex-tresnak). Writer-ek zure hornitzaile nagusia soilik erabiltzen du.",
"settings.ai.hybridFallbackTitle": "Erreplika hibridoa (proiektuaren AI tresnak)",
"settings.ai.hybridFallbackToggle": "Gaitu ordezko katea",
@@ -214,6 +215,11 @@
"settings.ai.preset.lmStudio": "LM estudioa",
"settings.ai.preset.ollamaDefault": "Ollama (ataka lehenetsia)",
"settings.ai.preset.vllm": "vLLM",
+ "settings.ai.provider.anthropic": "Anthropic Claude",
+ "settings.ai.provider.gemini": "Google Gemini",
+ "settings.ai.provider.grok": "xAI Grok",
+ "settings.ai.provider.ollama": "Ollama (local)",
+ "settings.ai.provider.openai": "OpenAI",
"settings.ai.providerDescription": "Aukeratu zein AI hornitzaile erabili behar duen WorldScript Studio-k.",
"settings.ai.providerOnnx": "ONNX (WASM)",
"settings.ai.providerStatusConnected": "Konektatuta",
diff --git a/locales/fa/settings.json b/locales/fa/settings.json
index 5a9cab56..cc1a169a 100644
--- a/locales/fa/settings.json
+++ b/locales/fa/settings.json
@@ -134,6 +134,7 @@
"settings.ai.gpu.troubleshootLowEnd": "دستگاه شما منابع محدودی دارد. هوش مصنوعی محلی از مدل های کوچکتر استفاده خواهد کرد. برای عملکرد بهتر، سایر تب های مرورگر را ببندید یا حالت Eco Mode را فعال کنید.",
"settings.ai.gpu.troubleshootQueue": "چندین کار هوش مصنوعی در صف قرار می گیرند. فقط یکی در یک زمان اجرا می شود تا از برخورد VRAM جلوگیری شود. منتظر بمانید تا کار فعلی تمام شود.",
"settings.ai.gpu.waitingConsumers": "در انتظار",
+ "settings.ai.grokKey": "Grok API Key",
"settings.ai.hybridFallbackHint": "اگر ارائهدهنده اصلی شکست بخورد، WorldScript موارد بازگشتی فهرست شده (مولد صحنه، ابزار کدکس) را امتحان میکند. پخش جریانی نویسنده فقط از ارائه دهنده اصلی شما استفاده می کند.",
"settings.ai.hybridFallbackTitle": "بازگشت ترکیبی (ابزارهای هوش مصنوعی پروژه)",
"settings.ai.hybridFallbackToggle": "فعال کردن زنجیره بازگشتی",
@@ -214,6 +215,11 @@
"settings.ai.preset.lmStudio": "LM Studio",
"settings.ai.preset.ollamaDefault": "اولاما (درگاه پیش فرض)",
"settings.ai.preset.vllm": "vLLM",
+ "settings.ai.provider.anthropic": "Anthropic Claude",
+ "settings.ai.provider.gemini": "Google Gemini",
+ "settings.ai.provider.grok": "xAI Grok",
+ "settings.ai.provider.ollama": "Ollama (local)",
+ "settings.ai.provider.openai": "OpenAI",
"settings.ai.providerDescription": "انتخاب کنید که WorldScript Studio از کدام ارائه دهنده هوش مصنوعی استفاده کند.",
"settings.ai.providerOnnx": "ONNX (WASM)",
"settings.ai.providerStatusConnected": "متصل شد",
diff --git a/locales/fi/settings.json b/locales/fi/settings.json
index 8a5f4e5b..b71ffb47 100644
--- a/locales/fi/settings.json
+++ b/locales/fi/settings.json
@@ -134,6 +134,7 @@
"settings.ai.gpu.troubleshootLowEnd": "Laitteesi resurssit ovat rajalliset. Paikallinen tekoäly käyttää pienempiä malleja. Suorituskyvyn parantamiseksi sulje muut selaimen välilehdet tai ota Eco Mode käyttöön.",
"settings.ai.gpu.troubleshootQueue": "Useita tekoälytehtäviä on jonossa. Vain yksi toimii kerrallaan VRAM-törmäysten välttämiseksi. Odota nykyisen tehtävän valmistumista.",
"settings.ai.gpu.waitingConsumers": "Odottaa",
+ "settings.ai.grokKey": "Grok API Key",
"settings.ai.hybridFallbackHint": "Jos ensisijainen toimittaja epäonnistuu, WorldScript yrittää lueteltuja varavaihtoehtoja (kohtausgeneraattorit, codex-työkalut). Writer-suoratoisto käyttää vain ensisijaista palveluntarjoajaasi.",
"settings.ai.hybridFallbackTitle": "Hybridivaraus (projektin tekoälytyökalut)",
"settings.ai.hybridFallbackToggle": "Ota varaketju käyttöön",
@@ -214,6 +215,11 @@
"settings.ai.preset.lmStudio": "LM Studio",
"settings.ai.preset.ollamaDefault": "Ollama (oletusportti)",
"settings.ai.preset.vllm": "vLLM",
+ "settings.ai.provider.anthropic": "Anthropic Claude",
+ "settings.ai.provider.gemini": "Google Gemini",
+ "settings.ai.provider.grok": "xAI Grok",
+ "settings.ai.provider.ollama": "Ollama (local)",
+ "settings.ai.provider.openai": "OpenAI",
"settings.ai.providerDescription": "Valitse, mitä tekoälyn tarjoajaa WorldScript Studion tulee käyttää.",
"settings.ai.providerOnnx": "ONNX (WASM)",
"settings.ai.providerStatusConnected": "Yhdistetty",
diff --git a/locales/fr/settings.json b/locales/fr/settings.json
index 4892b12f..38cfee4d 100644
--- a/locales/fr/settings.json
+++ b/locales/fr/settings.json
@@ -134,6 +134,7 @@
"settings.ai.gpu.troubleshootLowEnd": "Votre appareil dispose de ressources limitées. L'IA locale utilisera des modèles plus petits. Fermez d'autres onglets ou activez le mode éco.",
"settings.ai.gpu.troubleshootQueue": "Plusieurs tâches IA sont en file d'attente. Une seule s'exécute à la fois pour éviter les collisions VRAM. Attendez la fin de la tâche en cours.",
"settings.ai.gpu.waitingConsumers": "En attente",
+ "settings.ai.grokKey": "Clé API Grok",
"settings.ai.hybridFallbackHint": "Si le fournisseur principal échoue, WorldScript essaie les replis listés. La diffusion en continu de l'écrivain utilise uniquement votre fournisseur principal.",
"settings.ai.hybridFallbackTitle": "Repli hybride (outils IA du projet)",
"settings.ai.hybridFallbackToggle": "Activer la chaîne de repli",
@@ -214,6 +215,11 @@
"settings.ai.preset.lmStudio": "LM Studio",
"settings.ai.preset.ollamaDefault": "Ollama (port par défaut)",
"settings.ai.preset.vllm": "vLLM",
+ "settings.ai.provider.anthropic": "Anthropic Claude",
+ "settings.ai.provider.gemini": "Google Gemini",
+ "settings.ai.provider.grok": "xAI Grok",
+ "settings.ai.provider.ollama": "Ollama (local)",
+ "settings.ai.provider.openai": "OpenAI",
"settings.ai.providerDescription": "Choisissez quel fournisseur d'IA WorldScript Studio doit utiliser.",
"settings.ai.providerOnnx": "ONNX (WASM)",
"settings.ai.providerStatusConnected": "Connecté",
diff --git a/locales/he/settings.json b/locales/he/settings.json
index 03836944..5a02f305 100644
--- a/locales/he/settings.json
+++ b/locales/he/settings.json
@@ -134,6 +134,7 @@
"settings.ai.gpu.troubleshootLowEnd": "למכשיר שלכם משאבים מוגבלים. ה‑AI המקומי ישתמש במודלים קטנים יותר. לביצועים טובים יותר, סגרו לשוניות דפדפן אחרות או הפעילו מצב חיסכון.",
"settings.ai.gpu.troubleshootQueue": "מספר משימות AI בתור. רק אחת רצה בכל פעם כדי להימנע מהתנגשויות VRAM. המתינו לסיום המשימה הנוכחית.",
"settings.ai.gpu.waitingConsumers": "ממתין",
+ "settings.ai.grokKey": "Grok API Key",
"settings.ai.hybridFallbackHint": "אם הספק הראשי נכשל, WorldScript מנסה את החלופות הרשומות (מחוללי סצנות, כלי קודקס). הזרמת הכותב משתמשת בספק הראשי שלכם בלבד.",
"settings.ai.hybridFallbackTitle": "חלופה היברידית (כלי AI של הפרויקט)",
"settings.ai.hybridFallbackToggle": "הפעלת שרשרת חלופות",
@@ -214,6 +215,11 @@
"settings.ai.preset.lmStudio": "LM Studio",
"settings.ai.preset.ollamaDefault": "Ollama (פורט ברירת מחדל)",
"settings.ai.preset.vllm": "vLLM",
+ "settings.ai.provider.anthropic": "Anthropic Claude",
+ "settings.ai.provider.gemini": "Google Gemini",
+ "settings.ai.provider.grok": "xAI Grok",
+ "settings.ai.provider.ollama": "Ollama (local)",
+ "settings.ai.provider.openai": "OpenAI",
"settings.ai.providerDescription": "בחרו באיזה ספק AI WorldScript Studio ישתמש.",
"settings.ai.providerOnnx": "ONNX (WASM)",
"settings.ai.providerStatusConnected": "מחובר",
diff --git a/locales/hu/settings.json b/locales/hu/settings.json
index 94afe2f4..88eddf9c 100644
--- a/locales/hu/settings.json
+++ b/locales/hu/settings.json
@@ -134,6 +134,7 @@
"settings.ai.gpu.troubleshootLowEnd": "Az eszköz korlátozott erőforrásokkal rendelkezik. A helyi AI kisebb modelleket fog használni. A jobb teljesítmény érdekében zárja be a böngésző többi lapját, vagy engedélyezze az Eco módot.",
"settings.ai.gpu.troubleshootQueue": "Több mesterségesintelligencia-feladat van sorban. Egyszerre csak egy fut a VRAM ütközések elkerülése érdekében. Várja meg, amíg az aktuális feladat befejeződik.",
"settings.ai.gpu.waitingConsumers": "Várakozás",
+ "settings.ai.grokKey": "Grok API Key",
"settings.ai.hybridFallbackHint": "Ha az elsődleges szolgáltató meghibásodik, a WorldScript megpróbálja a felsorolt tartalékokat (jelenetgenerátorok, kódexeszközök). A Writer streaming csak az elsődleges szolgáltatót használja.",
"settings.ai.hybridFallbackTitle": "Hibrid tartalék (projekt AI-eszközök)",
"settings.ai.hybridFallbackToggle": "Tartaléklánc engedélyezése",
@@ -214,6 +215,11 @@
"settings.ai.preset.lmStudio": "LM Stúdió",
"settings.ai.preset.ollamaDefault": "Ollama (alapértelmezett port)",
"settings.ai.preset.vllm": "vLLM",
+ "settings.ai.provider.anthropic": "Anthropic Claude",
+ "settings.ai.provider.gemini": "Google Gemini",
+ "settings.ai.provider.grok": "xAI Grok",
+ "settings.ai.provider.ollama": "Ollama (local)",
+ "settings.ai.provider.openai": "OpenAI",
"settings.ai.providerDescription": "Válassza ki, hogy a WorldScript Studio melyik AI-szolgáltatót használja.",
"settings.ai.providerOnnx": "ONNX (WASM)",
"settings.ai.providerStatusConnected": "Csatlakozva",
diff --git a/locales/is/settings.json b/locales/is/settings.json
index b53f975f..c5fcfcb9 100644
--- a/locales/is/settings.json
+++ b/locales/is/settings.json
@@ -134,6 +134,7 @@
"settings.ai.gpu.troubleshootLowEnd": "Tækið þitt hefur takmarkað fjármagn. Staðbundin gervigreind mun nota smærri gerðir. Til að fá betri frammistöðu skaltu loka öðrum vafraflipa eða virkja umhverfisstillingu.",
"settings.ai.gpu.troubleshootQueue": "Mörg gervigreind verkefni eru í biðröð. Aðeins einn keyrir í einu til að forðast VRAM árekstra. Bíddu þar til núverandi verkefni lýkur.",
"settings.ai.gpu.waitingConsumers": "Bíður",
+ "settings.ai.grokKey": "Grok API Key",
"settings.ai.hybridFallbackHint": "Ef aðalveitan mistakast, reynir WorldScript upptaldar fallbacks (senuframleiðendur, kóðaxverkfæri). Writer streymi notar eingöngu aðalveituna þína.",
"settings.ai.hybridFallbackTitle": "Hybrid fallback (verkfæri gervigreindarverkefnis)",
"settings.ai.hybridFallbackToggle": "Virkja afturkeðju",
@@ -214,6 +215,11 @@
"settings.ai.preset.lmStudio": "LM stúdíó",
"settings.ai.preset.ollamaDefault": "Ollama (sjálfgefin höfn)",
"settings.ai.preset.vllm": "vLLM",
+ "settings.ai.provider.anthropic": "Anthropic Claude",
+ "settings.ai.provider.gemini": "Google Gemini",
+ "settings.ai.provider.grok": "xAI Grok",
+ "settings.ai.provider.ollama": "Ollama (local)",
+ "settings.ai.provider.openai": "OpenAI",
"settings.ai.providerDescription": "Veldu hvaða gervigreindarfyrirtæki WorldScript Studio ætti að nota.",
"settings.ai.providerOnnx": "ONNX (WASM)",
"settings.ai.providerStatusConnected": "Tengdur",
diff --git a/locales/it/settings.json b/locales/it/settings.json
index 073c1423..0e8fb5b9 100644
--- a/locales/it/settings.json
+++ b/locales/it/settings.json
@@ -134,6 +134,7 @@
"settings.ai.gpu.troubleshootLowEnd": "Il tuo dispositivo ha risorse limitate. L'IA locale utilizzerà modelli più piccoli. Chiudi altre schede o attiva la modalità eco.",
"settings.ai.gpu.troubleshootQueue": "Più attività IA sono in coda. Solo una viene eseguita alla volta per evitare collisioni VRAM. Attendi il completamento dell'attività corrente.",
"settings.ai.gpu.waitingConsumers": "In attesa",
+ "settings.ai.grokKey": "Chiave API Grok",
"settings.ai.hybridFallbackHint": "Se il provider principale fallisce, WorldScript prova i fallback elencati. Lo streaming dello scrittore usa solo il tuo provider principale.",
"settings.ai.hybridFallbackTitle": "Fallback ibrido (strumenti IA del progetto)",
"settings.ai.hybridFallbackToggle": "Abilita catena di fallback",
@@ -214,6 +215,11 @@
"settings.ai.preset.lmStudio": "LM Studio",
"settings.ai.preset.ollamaDefault": "Ollama (porta predefinita)",
"settings.ai.preset.vllm": "vLLM",
+ "settings.ai.provider.anthropic": "Anthropic Claude",
+ "settings.ai.provider.gemini": "Google Gemini",
+ "settings.ai.provider.grok": "xAI Grok",
+ "settings.ai.provider.ollama": "Ollama (locale)",
+ "settings.ai.provider.openai": "OpenAI",
"settings.ai.providerDescription": "Scegli quale provider IA WorldScript Studio deve utilizzare.",
"settings.ai.providerOnnx": "ONNX (WASM)",
"settings.ai.providerStatusConnected": "Connesso",
diff --git a/locales/ja/settings.json b/locales/ja/settings.json
index ff8aafbd..3b475cea 100644
--- a/locales/ja/settings.json
+++ b/locales/ja/settings.json
@@ -134,6 +134,7 @@
"settings.ai.gpu.troubleshootLowEnd": "デバイスのリソースは限られています。ローカル AI はより小さなモデルを使用します。パフォーマンスを向上させるには、他のブラウザ タブを閉じるか、エコ モードを有効にしてください。",
"settings.ai.gpu.troubleshootQueue": "複数の AI タスクがキューに入れられます。 VRAM の衝突を避けるために、一度に 1 つだけが実行されます。現在のタスクが完了するまで待ちます。",
"settings.ai.gpu.waitingConsumers": "待っている",
+ "settings.ai.grokKey": "Grok API Key",
"settings.ai.hybridFallbackHint": "プライマリ プロバイダーが失敗した場合、WorldScript はリストされているフォールバック (シーン ジェネレーター、コーデックス ツール) を試行します。ライター ストリーミングでは、プライマリ プロバイダーのみが使用されます。",
"settings.ai.hybridFallbackTitle": "ハイブリッド フォールバック (プロジェクト AI ツール)",
"settings.ai.hybridFallbackToggle": "フォールバック チェーンを有効にする",
@@ -214,6 +215,11 @@
"settings.ai.preset.lmStudio": "LMスタジオ",
"settings.ai.preset.ollamaDefault": "オラマ (デフォルトのポート)",
"settings.ai.preset.vllm": "vLLM",
+ "settings.ai.provider.anthropic": "Anthropic Claude",
+ "settings.ai.provider.gemini": "Google Gemini",
+ "settings.ai.provider.grok": "xAI Grok",
+ "settings.ai.provider.ollama": "Ollama (local)",
+ "settings.ai.provider.openai": "OpenAI",
"settings.ai.providerDescription": "WorldScript Studio が使用する AI プロバイダーを選択します。",
"settings.ai.providerOnnx": "ONNX (WASM)",
"settings.ai.providerStatusConnected": "接続済み",
diff --git a/locales/ko/settings.json b/locales/ko/settings.json
index a7b019f6..356201fe 100644
--- a/locales/ko/settings.json
+++ b/locales/ko/settings.json
@@ -134,6 +134,7 @@
"settings.ai.gpu.troubleshootLowEnd": "귀하의 장치에는 리소스가 제한되어 있습니다. 로컬 AI는 더 작은 모델을 사용합니다. 성능을 향상하려면 다른 브라우저 탭을 닫거나 에코 모드를 활성화하세요.",
"settings.ai.gpu.troubleshootQueue": "여러 AI 작업이 대기열에 추가됩니다. VRAM 충돌을 피하기 위해 한 번에 하나만 실행됩니다. 현재 작업이 완료될 때까지 기다립니다.",
"settings.ai.gpu.waitingConsumers": "대기 중",
+ "settings.ai.grokKey": "Grok API Key",
"settings.ai.hybridFallbackHint": "기본 공급자가 실패하면 WorldScript는 나열된 폴백(장면 생성기, 코덱스 도구)을 시도합니다. 작성자 스트리밍은 기본 공급자만 사용합니다.",
"settings.ai.hybridFallbackTitle": "하이브리드 폴백(프로젝트 AI 도구)",
"settings.ai.hybridFallbackToggle": "대체 체인 활성화",
@@ -214,6 +215,11 @@
"settings.ai.preset.lmStudio": "LM 스튜디오",
"settings.ai.preset.ollamaDefault": "올라마(기본 포트)",
"settings.ai.preset.vllm": "vLLM",
+ "settings.ai.provider.anthropic": "Anthropic Claude",
+ "settings.ai.provider.gemini": "Google Gemini",
+ "settings.ai.provider.grok": "xAI Grok",
+ "settings.ai.provider.ollama": "Ollama (local)",
+ "settings.ai.provider.openai": "OpenAI",
"settings.ai.providerDescription": "WorldScript Studio가 사용해야 할 AI 제공자를 선택하세요.",
"settings.ai.providerOnnx": "ONNX(WASM)",
"settings.ai.providerStatusConnected": "연결됨",
diff --git a/locales/pt/settings.json b/locales/pt/settings.json
index ae1d3c90..dd1d26cd 100644
--- a/locales/pt/settings.json
+++ b/locales/pt/settings.json
@@ -134,6 +134,7 @@
"settings.ai.gpu.troubleshootLowEnd": "Your device has limited resources. Local IA will use smaller models. For better performance, close other browser tabs or enable Eco Mode.",
"settings.ai.gpu.troubleshootQueue": "Multiple IA tasks are queued. Only one runs at a time to avoid VRAM collisions. Wait for the current task to finish.",
"settings.ai.gpu.waitingConsumers": "Esperando",
+ "settings.ai.grokKey": "Grok API Key",
"settings.ai.hybridFallbackHint": "Se o provedor primário falhar, o WorldScript tenta os substitutos listados (geradores de cena, ferramentas de códice). O streaming do gravador usa apenas seu provedor principal.",
"settings.ai.hybridFallbackTitle": "Hybrid fallback (project IA tools)",
"settings.ai.hybridFallbackToggle": "Ativar cadeia de fallback",
@@ -214,6 +215,11 @@
"settings.ai.preset.lmStudio": "Estúdio LM",
"settings.ai.preset.ollamaDefault": "Ollama (porta padrão)",
"settings.ai.preset.vllm": "vLLM",
+ "settings.ai.provider.anthropic": "Anthropic Claude",
+ "settings.ai.provider.gemini": "Google Gemini",
+ "settings.ai.provider.grok": "xAI Grok",
+ "settings.ai.provider.ollama": "Ollama (local)",
+ "settings.ai.provider.openai": "OpenAI",
"settings.ai.providerDescription": "Choose which IA provider WorldScript Studio should use.",
"settings.ai.providerOnnx": "ONNX (WASM)",
"settings.ai.providerStatusConnected": "Conectado",
diff --git a/locales/ru/settings.json b/locales/ru/settings.json
index 9d8fde22..f559ac40 100644
--- a/locales/ru/settings.json
+++ b/locales/ru/settings.json
@@ -134,6 +134,7 @@
"settings.ai.gpu.troubleshootLowEnd": "Ваше устройство имеет ограниченные ресурсы. Местный ИИ будет использовать модели меньшего размера. Для повышения производительности закройте другие вкладки браузера или включите экономичный режим.",
"settings.ai.gpu.troubleshootQueue": "Несколько задач ИИ ставятся в очередь. Одновременно запускается только один, чтобы избежать коллизий VRAM. Дождитесь завершения текущей задачи.",
"settings.ai.gpu.waitingConsumers": "Ожидающий",
+ "settings.ai.grokKey": "Grok API Key",
"settings.ai.hybridFallbackHint": "Если основной поставщик дает сбой, WorldScript пробует использовать перечисленные резервные варианты (генераторы сцен, инструменты кодекса). Потоковая передача Writer использует только вашего основного провайдера.",
"settings.ai.hybridFallbackTitle": "Гибридный запасной вариант (инструменты искусственного интеллекта проекта)",
"settings.ai.hybridFallbackToggle": "Включить резервную цепочку",
@@ -214,6 +215,11 @@
"settings.ai.preset.lmStudio": "ЛМ Студия",
"settings.ai.preset.ollamaDefault": "Оллама (порт по умолчанию)",
"settings.ai.preset.vllm": "vLLM",
+ "settings.ai.provider.anthropic": "Anthropic Claude",
+ "settings.ai.provider.gemini": "Google Gemini",
+ "settings.ai.provider.grok": "xAI Grok",
+ "settings.ai.provider.ollama": "Ollama (local)",
+ "settings.ai.provider.openai": "OpenAI",
"settings.ai.providerDescription": "Выберите, какой поставщик искусственного интеллекта будет использовать WorldScript Studio.",
"settings.ai.providerOnnx": "ОННКС (ВАСМ)",
"settings.ai.providerStatusConnected": "Подключено",
diff --git a/locales/sv/settings.json b/locales/sv/settings.json
index 3dd3c2de..af8d2194 100644
--- a/locales/sv/settings.json
+++ b/locales/sv/settings.json
@@ -134,6 +134,7 @@
"settings.ai.gpu.troubleshootLowEnd": "Din enhet har begränsade resurser. Lokal AI kommer att använda mindre modeller. För bättre prestanda, stäng andra webbläsarflikar eller aktivera Eco Mode.",
"settings.ai.gpu.troubleshootQueue": "Flera AI-uppgifter står i kö. Endast en kör åt gången för att undvika VRAM-kollisioner. Vänta tills den aktuella uppgiften är klar.",
"settings.ai.gpu.waitingConsumers": "Väntan",
+ "settings.ai.grokKey": "Grok API Key",
"settings.ai.hybridFallbackHint": "Om den primära leverantören misslyckas, försöker WorldScript de listade fallbacks (scengeneratorer, codexverktyg). Writer-strömning använder endast din primära leverantör.",
"settings.ai.hybridFallbackTitle": "Hybrid fallback (projekt AI-verktyg)",
"settings.ai.hybridFallbackToggle": "Aktivera reservkedja",
@@ -214,6 +215,11 @@
"settings.ai.preset.lmStudio": "LM Studio",
"settings.ai.preset.ollamaDefault": "Ollama (standardport)",
"settings.ai.preset.vllm": "vLLM",
+ "settings.ai.provider.anthropic": "Anthropic Claude",
+ "settings.ai.provider.gemini": "Google Gemini",
+ "settings.ai.provider.grok": "xAI Grok",
+ "settings.ai.provider.ollama": "Ollama (local)",
+ "settings.ai.provider.openai": "OpenAI",
"settings.ai.providerDescription": "Välj vilken AI-leverantör WorldScript Studio ska använda.",
"settings.ai.providerOnnx": "ONNX (WASM)",
"settings.ai.providerStatusConnected": "Ansluten",
diff --git a/locales/zh/settings.json b/locales/zh/settings.json
index 13e90189..c608047f 100644
--- a/locales/zh/settings.json
+++ b/locales/zh/settings.json
@@ -134,6 +134,7 @@
"settings.ai.gpu.troubleshootLowEnd": "您的设备资源有限。本地人工智能将使用更小的模型。为了获得更好的性能,请关闭其他浏览器选项卡或启用 Eco 模式。",
"settings.ai.gpu.troubleshootQueue": "多个 AI 任务排队。一次仅运行一个以避免 VRAM 冲突。等待当前任务完成。",
"settings.ai.gpu.waitingConsumers": "等待",
+ "settings.ai.grokKey": "Grok API Key",
"settings.ai.hybridFallbackHint": "如果主要提供程序失败,WorldScript 会尝试列出的后备方案(场景生成器、法典工具)。作家流媒体仅使用您的主要提供商。",
"settings.ai.hybridFallbackTitle": "混合后备(项目 AI 工具)",
"settings.ai.hybridFallbackToggle": "启用后备链",
@@ -214,6 +215,11 @@
"settings.ai.preset.lmStudio": "LM工作室",
"settings.ai.preset.ollamaDefault": "奥拉马(默认端口)",
"settings.ai.preset.vllm": "法学硕士",
+ "settings.ai.provider.anthropic": "Anthropic Claude",
+ "settings.ai.provider.gemini": "Google Gemini",
+ "settings.ai.provider.grok": "xAI Grok",
+ "settings.ai.provider.ollama": "Ollama (local)",
+ "settings.ai.provider.openai": "OpenAI",
"settings.ai.providerDescription": "选择 WorldScript Studio 应使用的 AI 提供商。",
"settings.ai.providerOnnx": "ONNX (WASM)",
"settings.ai.providerStatusConnected": "已连接",
diff --git a/public/locales/ar/bundle.json b/public/locales/ar/bundle.json
index 03226450..bface19a 100644
--- a/public/locales/ar/bundle.json
+++ b/public/locales/ar/bundle.json
@@ -90,6 +90,14 @@
"characters.edit.relationships": "العلاقات",
"characters.editorTabsAriaLabel": "علامات تبويب محرّر الشخصية",
"characters.error.portraitFailed": "فشل توليد الصورة. حاول إضافة المزيد من التفاصيل إلى وصف المظهر.",
+ "characters.heuristic.appearance": "Describe how they present themselves — let their look hint at {{concept}}.",
+ "characters.heuristic.backstory": "Shaped by formative experiences, this character carries a past tied to {{concept}}.",
+ "characters.heuristic.characterArc": "They begin guarded and, through the story, are changed by {{concept}}.",
+ "characters.heuristic.flaws": "A weakness that complicates their goals.",
+ "characters.heuristic.motivation": "A core desire connected to {{concept}} drives their choices.",
+ "characters.heuristic.name": "New Character",
+ "characters.heuristic.personalityTraits": "Resourceful, guarded, determined.",
+ "characters.heuristic.relationships": "Note the key bonds and rivalries that define them.",
"characters.loading.profile": "جارٍ توليد ملف تعريف مفصّل...",
"characters.newCharacterName": "شخصية جديدة",
"characters.noCharacters": "لم تُنشأ شخصيات بعد.",
@@ -107,14 +115,6 @@
"characters.title": "ملفات الشخصيات",
"characters.uploadImage": "رفع صورة",
"characters.yourCharacters": "شخصياتك",
- "characters.heuristic.name": "New Character",
- "characters.heuristic.backstory": "Shaped by formative experiences, this character carries a past tied to {{concept}}.",
- "characters.heuristic.motivation": "A core desire connected to {{concept}} drives their choices.",
- "characters.heuristic.appearance": "Describe how they present themselves — let their look hint at {{concept}}.",
- "characters.heuristic.personalityTraits": "Resourceful, guarded, determined.",
- "characters.heuristic.flaws": "A weakness that complicates their goals.",
- "characters.heuristic.characterArc": "They begin guarded and, through the story, are changed by {{concept}}.",
- "characters.heuristic.relationships": "Note the key bonds and rivalries that define them.",
"apiKey.connectionFailed": "فشل اختبار الاتصال.",
"apiKey.connectionSuccess": "نجح الاتصال! واجهة API تستجيب بشكل صحيح.",
"apiKey.decryptFailed": "تعذّر فك تشفير مفتاح API",
@@ -125,6 +125,11 @@
"apiKey.test": "اختبار الاتصال",
"apiKey.testConnection": "اختبار اتصال API",
"apiKey.testing": "جارٍ الاختبار…",
+ "assisted.badge.label": "Assisted",
+ "assisted.badge.srLabel": "Assisted mode — generated without AI",
+ "assisted.enhance": "Enhance with AI",
+ "assisted.toast.description": "Used built-in assistance. Enhance with AI when a model is available.",
+ "assisted.toast.title": "AI unavailable",
"charGraph.characters": "الشخصيات",
"charGraph.noCharacters": "لا توجد شخصيات بعد",
"charGraph.noCharactersHint": "أضف شخصيات في عرض الشخصيات لتصوّر علاقاتها هنا.",
@@ -286,6 +291,8 @@
"error.db.unknown": "خطأ غير معروف أثناء الوصول إلى قاعدة البيانات.",
"error.deepLink.title": "Failed to open project file",
"error.deepLink.unknown": "Unknown error",
+ "error.fallback.generic": "AI is unavailable — used built-in assistance.",
+ "error.fallback.offline": "You're offline — used built-in assistance.",
"error.fileImportError": "خطأ في استيراد الملف",
"error.mic.denied": "تم رفض الوصول إلى الميكروفون. يرجى منح الإذن في إعدادات متصفّحك.",
"error.mic.generic": "خطأ في التعرّف على الكلام: {{error}}",
@@ -382,6 +389,16 @@
"palette.voice.listeningLive": "الإدخال الصوتي نشط",
"palette.voice.start": "بدء البحث الصوتي",
"palette.voice.stop": "إيقاف البحث الصوتي",
+ "plotBoard.heuristic.complicate.description": "Add an obstacle or reveal that forces a change of plan.",
+ "plotBoard.heuristic.complicate.rationale": "A fresh complication tests the characters and opens new threads.",
+ "plotBoard.heuristic.complicate.title": "Introduce a complication",
+ "plotBoard.heuristic.escalate.description": "Increase the pressure on your protagonist so the next choice costs more.",
+ "plotBoard.heuristic.escalate.rationale": "Escalation keeps momentum when the middle sags.",
+ "plotBoard.heuristic.escalate.title": "Raise the stakes",
+ "plotBoard.heuristic.position": "Right after the selected scene",
+ "plotBoard.heuristic.reverse.description": "Flip an expectation — an ally falters, a win turns sour, or a hidden truth surfaces.",
+ "plotBoard.heuristic.reverse.rationale": "Reversals refresh tension and deepen the arc.",
+ "plotBoard.heuristic.reverse.title": "Add a reversal",
"preview.controls.ariaLabel": "ضوابط المعاينة",
"preview.controls.decreaseFontSize": "تصغير حجم الخط",
"preview.controls.exitFullscreen": "الخروج من ملء الشاشة",
@@ -449,10 +466,6 @@
"proforge.progress.awaitingReviewHint": "⚠️ This stage is awaiting your review. Click the stage button above to review items.",
"proforge.progress.completedStages": "Completed Stages",
"proforge.progress.currentStatus": "Current Status",
- "proforge.progress.overall": "Overall progress",
- "proforge.progress.preparing": "Preparing…",
- "proforge.progress.stageOfTotal": "Stage {{current}} of {{total}}",
- "proforge.progress.percentComplete": "{{percent}}% complete",
"proforge.progress.itemsCount": "{{count}} items",
"proforge.progress.metric.aiCalls": "AI Calls",
"proforge.progress.metric.duration": "Duration",
@@ -463,7 +476,11 @@
"proforge.progress.metric.totalTime": "Total Time",
"proforge.progress.metric.totalTokens": "Total Tokens",
"proforge.progress.noneRunning": "No pipeline running.",
+ "proforge.progress.overall": "Overall progress",
+ "proforge.progress.percentComplete": "{{percent}}% complete",
+ "proforge.progress.preparing": "Preparing…",
"proforge.progress.stageDetails": "Stage Details: {{stage}}",
+ "proforge.progress.stageOfTotal": "Stage {{current}} of {{total}}",
"proforge.progress.statusLabel": "Status",
"proforge.progress.totals": "Pipeline Totals",
"proforge.review.accept": "Accept",
@@ -777,9 +794,9 @@
"vc.title": "سجلّ الإصدارات",
"vc.words": "كلمات",
"voice.cancelSpeech": "إلغاء النطق",
+ "voice.feedback.confidence": "الثقة {{percent}}%",
"voice.modeChip.commands": "أوامر",
"voice.modeChip.dictation": "إملاء",
- "voice.feedback.confidence": "الثقة {{percent}}%",
"voice.panelLabel": "التحكم الصوتي",
"voice.permissionDenied": "تم رفض الوصول إلى الميكروفون. يرجى السماح بالوصول إلى الميكروفون في إعدادات متصفّحك لاستخدام الميزات الصوتية.",
"voice.startDictation": "بدء الإملاء",
@@ -793,23 +810,6 @@
"voice.stopListening": "إيقاف الاستماع",
"worlds.emptyState.description": "ابنِ الأماكن والقواعد والتواريخ التي تعيش فيها قصتك. ابدأ بموقع.",
"worlds.emptyState.title": "العالم بانتظارك",
- "error.fallback.generic": "AI is unavailable — used built-in assistance.",
- "error.fallback.offline": "You're offline — used built-in assistance.",
- "assisted.badge.label": "Assisted",
- "assisted.badge.srLabel": "Assisted mode — generated without AI",
- "assisted.toast.title": "AI unavailable",
- "assisted.toast.description": "Used built-in assistance. Enhance with AI when a model is available.",
- "assisted.enhance": "Enhance with AI",
- "plotBoard.heuristic.position": "Right after the selected scene",
- "plotBoard.heuristic.escalate.title": "Raise the stakes",
- "plotBoard.heuristic.escalate.description": "Increase the pressure on your protagonist so the next choice costs more.",
- "plotBoard.heuristic.escalate.rationale": "Escalation keeps momentum when the middle sags.",
- "plotBoard.heuristic.complicate.title": "Introduce a complication",
- "plotBoard.heuristic.complicate.description": "Add an obstacle or reveal that forces a change of plan.",
- "plotBoard.heuristic.complicate.rationale": "A fresh complication tests the characters and opens new threads.",
- "plotBoard.heuristic.reverse.title": "Add a reversal",
- "plotBoard.heuristic.reverse.description": "Flip an expectation — an ally falters, a win turns sour, or a hidden truth surfaces.",
- "plotBoard.heuristic.reverse.rationale": "Reversals refresh tension and deepen the arc.",
"copilot.annotationCount": "{{count}} insight for this chapter",
"copilot.announceClosed": "AI Copilot closed",
"copilot.announceOpened": "AI Copilot opened",
@@ -1090,10 +1090,10 @@
"export.pasteSection.importAsChapter": "استيراد كفصل",
"export.pasteSection.textPlaceholder": "الصق نصًا من Google Docs أو Notion هنا (Ctrl+V)...",
"export.pasteSection.titlePlaceholder": "عنوان الفصل (اختياري)",
- "export.preview.noContent": "اختر محتوى لرؤية معاينة.",
"export.preview.modeLabel": "وضع المعاينة",
- "export.preview.modeText": "نص",
"export.preview.modeRendered": "معروض",
+ "export.preview.modeText": "نص",
+ "export.preview.noContent": "اختر محتوى لرؤية معاينة.",
"export.preview.title": "معاينة حيّة",
"export.title": "جناح النشر والتصدير",
"export.toggleSection": "تبديل ظهور {{title}}",
@@ -1519,6 +1519,23 @@
"outline.deleteConfirm": "هل أنت متأكد من حذف قسم المخطط هذا؟",
"outline.description": "صِف فكرة قصتك ودع الذكاء الاصطناعي ينشئ لك مخططًا منظّمًا قابلًا للتحرير.",
"outline.error.generationFailed": "فشل توليد المحتوى. يرجى المحاولة مرة أخرى.",
+ "outline.heuristic.beat.climax.desc": "The central conflict comes to a head in the story's defining confrontation.",
+ "outline.heuristic.beat.climax.title": "Climax",
+ "outline.heuristic.beat.complications.desc": "Setbacks and conflicts deepen; the path forward narrows.",
+ "outline.heuristic.beat.complications.title": "Complications",
+ "outline.heuristic.beat.incitingIncident.desc": "The event that sets the story in motion: {{idea}}.",
+ "outline.heuristic.beat.incitingIncident.title": "Inciting Incident",
+ "outline.heuristic.beat.midpoint.desc": "A turning point shifts the direction of the story and raises the stakes.",
+ "outline.heuristic.beat.midpoint.title": "Midpoint",
+ "outline.heuristic.beat.resolution.desc": "Loose ends are tied up and a new status quo emerges.",
+ "outline.heuristic.beat.resolution.title": "Resolution",
+ "outline.heuristic.beat.risingAction.desc": "Complications escalate and the stakes grow as the characters pursue their goal.",
+ "outline.heuristic.beat.risingAction.title": "Rising Action",
+ "outline.heuristic.beat.setup.desc": "Introduce the world and the main characters, and establish the status quo before everything changes.",
+ "outline.heuristic.beat.setup.title": "Setup",
+ "outline.heuristic.beat.twist.desc": "An unexpected revelation upends what the characters believed to be true.",
+ "outline.heuristic.beat.twist.title": "Twist",
+ "outline.heuristic.fallbackIdea": "the central idea",
"outline.idea.generateButton": "توليد المخطط",
"outline.idea.genreLabel": "النوع الأدبي",
"outline.idea.genrePlaceholder": "مثل: خيال علمي، فانتازيا، غموض",
@@ -1541,23 +1558,6 @@
"outline.result.twistTooltip": "منعطف حبكة مُولَّد بالذكاء الاصطناعي",
"outline.selectSection": "Select section '{{title}}'",
"outline.title": "مُولِّد مخطط القصة بالذكاء الاصطناعي",
- "outline.heuristic.fallbackIdea": "the central idea",
- "outline.heuristic.beat.setup.title": "Setup",
- "outline.heuristic.beat.setup.desc": "Introduce the world and the main characters, and establish the status quo before everything changes.",
- "outline.heuristic.beat.incitingIncident.title": "Inciting Incident",
- "outline.heuristic.beat.incitingIncident.desc": "The event that sets the story in motion: {{idea}}.",
- "outline.heuristic.beat.risingAction.title": "Rising Action",
- "outline.heuristic.beat.risingAction.desc": "Complications escalate and the stakes grow as the characters pursue their goal.",
- "outline.heuristic.beat.midpoint.title": "Midpoint",
- "outline.heuristic.beat.midpoint.desc": "A turning point shifts the direction of the story and raises the stakes.",
- "outline.heuristic.beat.complications.title": "Complications",
- "outline.heuristic.beat.complications.desc": "Setbacks and conflicts deepen; the path forward narrows.",
- "outline.heuristic.beat.twist.title": "Twist",
- "outline.heuristic.beat.twist.desc": "An unexpected revelation upends what the characters believed to be true.",
- "outline.heuristic.beat.climax.title": "Climax",
- "outline.heuristic.beat.climax.desc": "The central conflict comes to a head in the story's defining confrontation.",
- "outline.heuristic.beat.resolution.title": "Resolution",
- "outline.heuristic.beat.resolution.desc": "Loose ends are tied up and a new status quo emerges.",
"portal.back": "رجوع",
"portal.demo.chapterContent": "تشبّث ضباب الصباح بالأرصفة بينما فردت ليرا خريطة المدينة القديمة. كانت دائرة باهتة تحدّد الركن الشمالي الغربي — البرج الذي لا يذكره أحد.\n\nطوت الورقة وتبعت الممر الضيق حتى ارتفعت أمامها الشبكة الحديدية. كان القفل دافئًا تحت الشمس؛ أما المعدن فظلّ باردًا.",
"portal.demo.chapterTitle": "الفصل الأول — أمام البوابة",
@@ -1752,6 +1752,7 @@
"settings.ai.gpu.troubleshootLowEnd": "جهازك ذو موارد محدودة. سيستخدم الذكاء الاصطناعي المحلي نماذج أصغر. لأداء أفضل، أغلق علامات تبويب المتصفّح الأخرى أو فعّل الوضع الاقتصادي.",
"settings.ai.gpu.troubleshootQueue": "هناك مهام ذكاء اصطناعي متعدّدة في الطابور. تعمل واحدة فقط في كل مرة لتجنّب تصادمات ذاكرة الرسوميات. انتظر انتهاء المهمة الحالية.",
"settings.ai.gpu.waitingConsumers": "في الانتظار",
+ "settings.ai.grokKey": "Grok API Key",
"settings.ai.hybridFallbackHint": "إذا فشل المزوّد الأساسي، يجرّب WorldScript الاحتياطيات المدرجة (مولّدات المشاهد، أدوات الفهرس). يستخدم بثّ الكاتب مزوّدك الأساسي فقط.",
"settings.ai.hybridFallbackTitle": "الاحتياطي الهجين (أدوات الذكاء الاصطناعي للمشروع)",
"settings.ai.hybridFallbackToggle": "تفعيل سلسلة الاحتياطي",
@@ -1832,6 +1833,11 @@
"settings.ai.preset.lmStudio": "LM Studio",
"settings.ai.preset.ollamaDefault": "Ollama (المنفذ الافتراضي)",
"settings.ai.preset.vllm": "vLLM",
+ "settings.ai.provider.anthropic": "Anthropic Claude",
+ "settings.ai.provider.gemini": "Google Gemini",
+ "settings.ai.provider.grok": "xAI Grok",
+ "settings.ai.provider.ollama": "Ollama (local)",
+ "settings.ai.provider.openai": "OpenAI",
"settings.ai.providerDescription": "اختر مزوّد الذكاء الاصطناعي الذي يجب أن يستخدمه WorldScript Studio.",
"settings.ai.providerOnnx": "ONNX (WASM)",
"settings.ai.providerStatusConnected": "متصل",
@@ -2711,6 +2717,11 @@
"worlds.edit.notes": "ملاحظات",
"worlds.editorTabsAriaLabel": "علامات تبويب محرّر العالم",
"worlds.error.imageFailed": "فشل توليد صورة الأجواء. حاول إضافة المزيد من التفاصيل إلى وصف العالم أو تحقّق من اتصالك.",
+ "worlds.heuristic.culture": "Describe the peoples, beliefs, and daily life shaped by {{concept}}.",
+ "worlds.heuristic.description": "A world defined by its central premise: {{concept}}.",
+ "worlds.heuristic.geography": "Outline the major regions, climates, and natural features of {{concept}}.",
+ "worlds.heuristic.magicSystem": "Define the rules, costs, and limits of power in {{concept}}.",
+ "worlds.heuristic.name": "New World",
"worlds.loading.profile": "جارٍ توليد ملف تعريف مفصّل للعالم...",
"worlds.newWorldName": "عالم جديد",
"worlds.noWorlds": "لم تُنشأ عوالم بعد.",
@@ -2729,11 +2740,6 @@
"worlds.title": "أطلس العالم",
"worlds.uploadImage": "رفع صورة",
"worlds.yourWorlds": "عوالمك",
- "worlds.heuristic.name": "New World",
- "worlds.heuristic.description": "A world defined by its central premise: {{concept}}.",
- "worlds.heuristic.geography": "Outline the major regions, climates, and natural features of {{concept}}.",
- "worlds.heuristic.magicSystem": "Define the rules, costs, and limits of power in {{concept}}.",
- "worlds.heuristic.culture": "Describe the peoples, beliefs, and daily life shaped by {{concept}}.",
"writer.cancelledTag": "Cancelled",
"writer.chapter.label": "الفصل: {{title}}",
"writer.coachmark.dismiss": "Got it",
@@ -2755,6 +2761,20 @@
"writer.focusMode.enterLabel": "وضع التركيز",
"writer.focusMode.exit": "الخروج من وضع التركيز",
"writer.focusMode.exitLabel": "إنهاء التركيز",
+ "writer.grammar.addToDictionary": "Add to dictionary",
+ "writer.grammar.apply": "Apply",
+ "writer.grammar.checkButton": "Check this scene",
+ "writer.grammar.checking": "Checking…",
+ "writer.grammar.disabled": "Enable LanguageTool in Settings → Connections to check this scene.",
+ "writer.grammar.error": "The LanguageTool server returned an error.",
+ "writer.grammar.ignore": "Ignore",
+ "writer.grammar.issuesFound": "{{count}} issues found",
+ "writer.grammar.noIssues": "No issues found.",
+ "writer.grammar.noSuggestions": "No suggestions",
+ "writer.grammar.offline": "Couldn't reach the LanguageTool server. Is it running?",
+ "writer.grammar.selectScene": "Select a scene to check.",
+ "writer.grammar.title": "Grammar & Spelling",
+ "writer.grammar.unsupported": "Grammar check isn't available for this language.",
"writer.imagePrompt.description": "يولّد موجّهًا محسّنًا لـ DALL·E 3 / Midjourney من المشهد الحالي أو النص المحدّد.",
"writer.imagePrompt.note": "يعمل الموجّه المُولَّد مباشرة في DALL·E 3 و Midjourney.",
"writer.imagePrompt.tip": "نصيحة: حدّد قسمًا نصيًا محدّدًا للحصول على موجّه مشهد مركّز.",
@@ -2787,12 +2807,10 @@
"writer.studio.controls.tones.poetic": "أكثر شاعرية",
"writer.studio.controls.tones.suspenseful": "أكثر تشويقًا",
"writer.studio.description": "مؤلّفك المشارك بالذكاء الاصطناعي. ولّد وحسّن وعصف الأفكار بسياق المشروع الكامل.",
+ "writer.studio.rag.chunkScore": "الصلة {{score}}",
"writer.studio.rag.chunksBadge": "تم العثور على {{count}} مقطعًا من القصة",
"writer.studio.rag.chunksHint": "مقتطفات ذات صلة من مخطوطتك — المزيد من المقاطع يعني سياقًا أغنى للذكاء الاصطناعي",
"writer.studio.rag.inspectorLabel": "السياق المُسترجَع",
- "writer.studio.rag.chunkScore": "الصلة {{score}}",
- "writer.studio.tokens.badge": "~{{count}} رمز",
- "writer.studio.tokens.hint": "عدد الرموز التقريبي المُستخدَم في آخر طلب للذكاء الاصطناعي",
"writer.studio.rag.useContext": "اسحب من قصتي",
"writer.studio.result.insert": "إدراج",
"writer.studio.result.next": "التالي",
@@ -2802,6 +2820,8 @@
"writer.studio.result.retry": "إعادة المحاولة",
"writer.studio.result.title": "مسوّدة الذكاء الاصطناعي",
"writer.studio.title": "استوديو الكتابة بالذكاء الاصطناعي",
+ "writer.studio.tokens.badge": "~{{count}} رمز",
+ "writer.studio.tokens.hint": "عدد الرموز التقريبي المُستخدَم في آخر طلب للذكاء الاصطناعي",
"writer.studio.tools.brainstorm.contextLabel": "سياق العصف الذهني (اختياري)",
"writer.studio.tools.brainstorm.contextPlaceholder": "قدّم موقفًا موجزًا، أو سيستخدم الذكاء الاصطناعي قسم المخطوطة الحالي.",
"writer.studio.tools.brainstorm.title": "عصف الأفكار",
@@ -2833,19 +2853,5 @@
"writer.tts.start": "قراءة بصوت عالٍ",
"writer.tts.stop": "إيقاف القراءة",
"writer.versionControl.label": "الإصدارات",
- "writer.versionControl.tooltip": "التحكم بالإصدارات (الفروع واللقطات)",
- "writer.grammar.title": "Grammar & Spelling",
- "writer.grammar.checkButton": "Check this scene",
- "writer.grammar.checking": "Checking…",
- "writer.grammar.issuesFound": "{{count}} issues found",
- "writer.grammar.noIssues": "No issues found.",
- "writer.grammar.selectScene": "Select a scene to check.",
- "writer.grammar.unsupported": "Grammar check isn't available for this language.",
- "writer.grammar.disabled": "Enable LanguageTool in Settings → Connections to check this scene.",
- "writer.grammar.offline": "Couldn't reach the LanguageTool server. Is it running?",
- "writer.grammar.error": "The LanguageTool server returned an error.",
- "writer.grammar.apply": "Apply",
- "writer.grammar.ignore": "Ignore",
- "writer.grammar.addToDictionary": "Add to dictionary",
- "writer.grammar.noSuggestions": "No suggestions"
+ "writer.versionControl.tooltip": "التحكم بالإصدارات (الفروع واللقطات)"
}
diff --git a/public/locales/de/bundle.json b/public/locales/de/bundle.json
index c3e7c90d..f09ca0a0 100644
--- a/public/locales/de/bundle.json
+++ b/public/locales/de/bundle.json
@@ -90,6 +90,14 @@
"characters.edit.relationships": "Beziehungen",
"characters.editorTabsAriaLabel": "Charaktereditor-Reiter",
"characters.error.portraitFailed": "Porträtgenerierung fehlgeschlagen. Versuchen Sie, der Beschreibung des Aussehens mehr Details hinzuzufügen.",
+ "characters.heuristic.appearance": "Beschreibe, wie sie sich präsentiert — lass ihr Aussehen auf {{concept}} hindeuten.",
+ "characters.heuristic.backstory": "Geprägt von prägenden Erfahrungen trägt diese Figur eine Vergangenheit, die mit {{concept}} verbunden ist.",
+ "characters.heuristic.characterArc": "Sie beginnt zurückhaltend und wird im Verlauf der Geschichte durch {{concept}} verändert.",
+ "characters.heuristic.flaws": "Eine Schwäche, die ihre Ziele erschwert.",
+ "characters.heuristic.motivation": "Ein zentrales Verlangen, das mit {{concept}} verknüpft ist, bestimmt ihre Entscheidungen.",
+ "characters.heuristic.name": "Neue Figur",
+ "characters.heuristic.personalityTraits": "Einfallsreich, zurückhaltend, entschlossen.",
+ "characters.heuristic.relationships": "Notiere die wichtigsten Bindungen und Rivalitäten, die sie ausmachen.",
"characters.loading.profile": "Detailliertes Profil wird generiert...",
"characters.newCharacterName": "Neuer Charakter",
"characters.noCharacters": "Noch keine Charaktere erstellt.",
@@ -107,14 +115,6 @@
"characters.title": "Charakter-Dossiers",
"characters.uploadImage": "Bild hochladen",
"characters.yourCharacters": "Ihre Charaktere",
- "characters.heuristic.name": "Neue Figur",
- "characters.heuristic.backstory": "Geprägt von prägenden Erfahrungen trägt diese Figur eine Vergangenheit, die mit {{concept}} verbunden ist.",
- "characters.heuristic.motivation": "Ein zentrales Verlangen, das mit {{concept}} verknüpft ist, bestimmt ihre Entscheidungen.",
- "characters.heuristic.appearance": "Beschreibe, wie sie sich präsentiert — lass ihr Aussehen auf {{concept}} hindeuten.",
- "characters.heuristic.personalityTraits": "Einfallsreich, zurückhaltend, entschlossen.",
- "characters.heuristic.flaws": "Eine Schwäche, die ihre Ziele erschwert.",
- "characters.heuristic.characterArc": "Sie beginnt zurückhaltend und wird im Verlauf der Geschichte durch {{concept}} verändert.",
- "characters.heuristic.relationships": "Notiere die wichtigsten Bindungen und Rivalitäten, die sie ausmachen.",
"apiKey.connectionFailed": "Verbindungstest fehlgeschlagen.",
"apiKey.connectionSuccess": "Verbindung erfolgreich! API antwortet korrekt.",
"apiKey.decryptFailed": "API-Key konnte nicht entschlüsselt werden",
@@ -125,6 +125,11 @@
"apiKey.test": "Verbindung testen",
"apiKey.testConnection": "API-Verbindung testen",
"apiKey.testing": "Testen…",
+ "assisted.badge.label": "Assistiert",
+ "assisted.badge.srLabel": "Assistierter Modus – ohne KI erstellt",
+ "assisted.enhance": "Mit KI verbessern",
+ "assisted.toast.description": "Integrierte Hilfe verwendet. Mit KI verbessern, sobald ein Modell verfügbar ist.",
+ "assisted.toast.title": "KI nicht verfügbar",
"charGraph.characters": "Charaktere",
"charGraph.noCharacters": "Noch keine Charaktere",
"charGraph.noCharactersHint": "Füge Charaktere in der Charakteransicht hinzu, um ihre Beziehungen hier zu visualisieren.",
@@ -185,8 +190,8 @@
"common.add": "Hinzufügen",
"common.appLoading": "Anwendung wird geladen",
"common.back": "Zurück",
- "common.badge.experimental": "Experimentell",
"common.badge.beta": "Beta",
+ "common.badge.experimental": "Experimentell",
"common.badge.new": "Neu",
"common.cancel": "Abbrechen",
"common.close": "Schließen",
@@ -217,16 +222,16 @@
"common.words": "Wörter",
"consistencyChecker.checkButton": "Konsistenz prüfen",
"consistencyChecker.description": "Prüfen Sie Ihre Charaktere auf Widersprüche mit der etablierten Lore, anderen Charakteren und Ihrem Manuskript.",
+ "consistencyChecker.noFindings": "Keine Widersprüche gefunden — diese Figur wirkt konsistent.",
"consistencyChecker.noResults": "Noch keine Ergebnisse",
"consistencyChecker.noResultsHint": "Wählen Sie links einen Charakter aus und klicken Sie auf Konsistenz prüfen, um das Manuskript zu scannen.",
- "consistencyChecker.results": "Ergebnisse",
- "consistencyChecker.severity.info": "Info",
- "consistencyChecker.severity.warn": "Warnung",
- "consistencyChecker.severity.error": "Konflikt",
"consistencyChecker.refLabel": "Bezug",
- "consistencyChecker.noFindings": "Keine Widersprüche gefunden — diese Figur wirkt konsistent.",
+ "consistencyChecker.results": "Ergebnisse",
"consistencyChecker.selectCharacter": "Charakter auswählen",
"consistencyChecker.selectPlaceholder": "Wählen Sie einen Charakter zum Prüfen",
+ "consistencyChecker.severity.error": "Konflikt",
+ "consistencyChecker.severity.info": "Info",
+ "consistencyChecker.severity.warn": "Warnung",
"consistencyChecker.storyBible.edgesTitle": "Entity-Kookkurrenz (Top)",
"consistencyChecker.storyBible.empty": "Aktivieren Sie „Story Bible erweitert“ unter Einstellungen → KI → Feature-Flags und bearbeiten Sie das Manuskript, um Codex-Graphendaten zu extrahieren.",
"consistencyChecker.storyBible.hintsTitle": "Konsistenz-Hinweise",
@@ -286,6 +291,8 @@
"error.db.unknown": "Unbekannter Fehler beim Zugriff auf die Datenbank.",
"error.deepLink.title": "Fehler beim Öffnen der Projektdatei",
"error.deepLink.unknown": "Unbekannter Fehler",
+ "error.fallback.generic": "KI nicht verfügbar – integrierte Hilfe verwendet.",
+ "error.fallback.offline": "Offline – integrierte Hilfe verwendet.",
"error.fileImportError": "Importfehler",
"error.mic.denied": "Mikrofon-Zugriff verweigert. Bitte Berechtigung in den Browser-Einstellungen erteilen.",
"error.mic.generic": "Spracherkennungsfehler: {{error}}",
@@ -382,22 +389,32 @@
"palette.voice.listeningLive": "Spracheingabe ist aktiv",
"palette.voice.start": "Sprachsuche starten",
"palette.voice.stop": "Sprachsuche beenden",
+ "plotBoard.heuristic.complicate.description": "Füge ein Hindernis oder eine Enthüllung hinzu, die einen Planwechsel erzwingt.",
+ "plotBoard.heuristic.complicate.rationale": "Eine neue Komplikation fordert die Figuren und eröffnet neue Stränge.",
+ "plotBoard.heuristic.complicate.title": "Eine Komplikation einführen",
+ "plotBoard.heuristic.escalate.description": "Erhöhe den Druck auf deine Hauptfigur, damit die nächste Entscheidung mehr kostet.",
+ "plotBoard.heuristic.escalate.rationale": "Eskalation hält das Tempo, wenn der Mittelteil durchhängt.",
+ "plotBoard.heuristic.escalate.title": "Den Einsatz erhöhen",
+ "plotBoard.heuristic.position": "Direkt nach der ausgewählten Szene",
+ "plotBoard.heuristic.reverse.description": "Kehre eine Erwartung um — ein Verbündeter versagt, ein Sieg wird bitter oder eine verborgene Wahrheit kommt ans Licht.",
+ "plotBoard.heuristic.reverse.rationale": "Wendungen erneuern die Spannung und vertiefen den Bogen.",
+ "plotBoard.heuristic.reverse.title": "Eine Wendung hinzufügen",
"preview.controls.ariaLabel": "Vorschau-Steuerung",
"preview.controls.decreaseFontSize": "Schriftgröße verringern",
"preview.controls.exitFullscreen": "Vollbild beenden",
"preview.controls.export": "Exportieren (EPUB)",
- "preview.controls.pagedMode": "Seitenansicht",
- "preview.progress.ariaLabel": "Lesefortschritt",
"preview.controls.fontFamily": "Schriftart",
"preview.controls.fontMono": "Monospace",
"preview.controls.fontSerif": "Serif",
"preview.controls.fontSystemUi": "System",
"preview.controls.fullscreen": "Vollbild",
"preview.controls.increaseFontSize": "Schriftgröße erhöhen",
+ "preview.controls.pagedMode": "Seitenansicht",
"preview.controls.wordCount": "Wortanzahl",
"preview.emptyScene": "Noch kein Inhalt.",
"preview.noScenes": "Das Manuskript ist leer",
"preview.noScenesHint": "Gehe zur Manuskript-Ansicht und füge deine erste Szene hinzu, um hier eine Vorschau zu sehen.",
+ "preview.progress.ariaLabel": "Lesefortschritt",
"preview.title": "Buchvorschau",
"preview.toc.ariaLabel": "Inhaltsverzeichnis",
"preview.toc.close": "Inhaltsverzeichnis schließen",
@@ -449,10 +466,6 @@
"proforge.progress.awaitingReviewHint": "⚠️ Diese Phase wartet auf Ihre Prüfung. Klicken Sie oben auf die Phasenschaltfläche, um die Einträge zu prüfen.",
"proforge.progress.completedStages": "Abgeschlossene Phasen",
"proforge.progress.currentStatus": "Aktueller Status",
- "proforge.progress.overall": "Gesamtfortschritt",
- "proforge.progress.preparing": "Wird vorbereitet…",
- "proforge.progress.stageOfTotal": "Phase {{current}} von {{total}}",
- "proforge.progress.percentComplete": "{{percent}} % abgeschlossen",
"proforge.progress.itemsCount": "{{count}} Einträge",
"proforge.progress.metric.aiCalls": "KI-Aufrufe",
"proforge.progress.metric.duration": "Dauer",
@@ -463,7 +476,11 @@
"proforge.progress.metric.totalTime": "Gesamtzeit",
"proforge.progress.metric.totalTokens": "Tokens gesamt",
"proforge.progress.noneRunning": "Keine Pipeline aktiv.",
+ "proforge.progress.overall": "Gesamtfortschritt",
+ "proforge.progress.percentComplete": "{{percent}} % abgeschlossen",
+ "proforge.progress.preparing": "Wird vorbereitet…",
"proforge.progress.stageDetails": "Phasendetails: {{stage}}",
+ "proforge.progress.stageOfTotal": "Phase {{current}} von {{total}}",
"proforge.progress.statusLabel": "Status",
"proforge.progress.totals": "Pipeline-Gesamtwerte",
"proforge.review.accept": "Übernehmen",
@@ -631,9 +648,9 @@
"sceneboard.act3.label": "Akt 3 – Auflösung",
"sceneboard.addScene": "Szene hinzufügen",
"sceneboard.addSceneToAct": "Szene in diesem Akt hinzufügen",
+ "sceneboard.ai.contextNote": "Die Analyse nutzt Szenentitel und Anfangszeilen, bis zu ~2.000 Zeichen.",
"sceneboard.ai.empty": "Noch keine Vorschläge. Erneut ausführen nach Szenen-Inhalt.",
"sceneboard.ai.panelTitle": "KI-Plot-Vorschläge",
- "sceneboard.ai.contextNote": "Die Analyse nutzt Szenentitel und Anfangszeilen, bis zu ~2.000 Zeichen.",
"sceneboard.ai.ragChunks": "{{count}} Story-Passagen",
"sceneboard.ai.retry": "Erneut vorschlagen",
"sceneboard.ai.suggestBeat": "KI Beat vorschlagen",
@@ -777,9 +794,9 @@
"vc.title": "Versionsverlauf",
"vc.words": "Wörter",
"voice.cancelSpeech": "Sprache abbrechen",
+ "voice.feedback.confidence": "Konfidenz {{percent}}%",
"voice.modeChip.commands": "Befehle",
"voice.modeChip.dictation": "Diktat",
- "voice.feedback.confidence": "Konfidenz {{percent}}%",
"voice.panelLabel": "Sprachsteuerung",
"voice.permissionDenied": "Mikrofonzugriff verweigert. Bitte erlaube den Mikrofonzugriff in deinen Browsereinstellungen.",
"voice.startDictation": "Diktat starten",
@@ -793,23 +810,6 @@
"voice.stopListening": "Zuhören stoppen",
"worlds.emptyState.description": "Baue die Orte, Regeln und Geschichten auf, in denen deine Geschichte lebt. Beginne mit einem Ort.",
"worlds.emptyState.title": "Die Welt wartet",
- "error.fallback.generic": "KI nicht verfügbar – integrierte Hilfe verwendet.",
- "error.fallback.offline": "Offline – integrierte Hilfe verwendet.",
- "assisted.badge.label": "Assistiert",
- "assisted.badge.srLabel": "Assistierter Modus – ohne KI erstellt",
- "assisted.toast.title": "KI nicht verfügbar",
- "assisted.toast.description": "Integrierte Hilfe verwendet. Mit KI verbessern, sobald ein Modell verfügbar ist.",
- "assisted.enhance": "Mit KI verbessern",
- "plotBoard.heuristic.position": "Direkt nach der ausgewählten Szene",
- "plotBoard.heuristic.escalate.title": "Den Einsatz erhöhen",
- "plotBoard.heuristic.escalate.description": "Erhöhe den Druck auf deine Hauptfigur, damit die nächste Entscheidung mehr kostet.",
- "plotBoard.heuristic.escalate.rationale": "Eskalation hält das Tempo, wenn der Mittelteil durchhängt.",
- "plotBoard.heuristic.complicate.title": "Eine Komplikation einführen",
- "plotBoard.heuristic.complicate.description": "Füge ein Hindernis oder eine Enthüllung hinzu, die einen Planwechsel erzwingt.",
- "plotBoard.heuristic.complicate.rationale": "Eine neue Komplikation fordert die Figuren und eröffnet neue Stränge.",
- "plotBoard.heuristic.reverse.title": "Eine Wendung hinzufügen",
- "plotBoard.heuristic.reverse.description": "Kehre eine Erwartung um — ein Verbündeter versagt, ein Sieg wird bitter oder eine verborgene Wahrheit kommt ans Licht.",
- "plotBoard.heuristic.reverse.rationale": "Wendungen erneuern die Spannung und vertiefen den Bogen.",
"copilot.annotationCount": "{{count}} insight for this chapter",
"copilot.announceClosed": "KI-Copilot geschlossen",
"copilot.announceOpened": "KI-Copilot geöffnet",
@@ -877,11 +877,9 @@
"copilot.you": "Du",
"dashboard.authorInsights.readability": "Lesbarkeit (Flesch/Amstad, DE-Heuristik)",
"dashboard.authorInsights.readabilityFootnote": "Höhere Werte wirken oft leichter lesbar; Genre bewusst steuern.",
- "dashboard.authorInsights.readabilityTooltip": "Flesch-Lesbarkeitsskala 0–100: höher = leichter lesbar (60–70 ist Alltagssprache). Ein grober Richtwert, keine normative Note.",
- "dashboard.authorInsights.readabilityScaleSuffix": "/100",
- "dashboard.logline.updated": "Logline aktualisiert",
- "dashboard.logline.updatedUndo": "Mit Strg+Z rückgängig machen.",
"dashboard.authorInsights.readabilityNeedMore": "Noch etwas schreiben — stabiler Wert ab ca. 40+ Wörtern.",
+ "dashboard.authorInsights.readabilityScaleSuffix": "/100",
+ "dashboard.authorInsights.readabilityTooltip": "Flesch-Lesbarkeitsskala 0–100: höher = leichter lesbar (60–70 ist Alltagssprache). Ein grober Richtwert, keine normative Note.",
"dashboard.authorInsights.timeline": "Szenen-Zeitleiste",
"dashboard.authorInsights.timelineClear": "Keine Warnungen aus Szenen-Metadaten.",
"dashboard.authorInsights.timelineWarnBadge": "{{count}} Warnungen — Daten auf dem Szenenboard prüfen.",
@@ -953,6 +951,8 @@
"dashboard.healthScore.title": "Projekt-Gesundheit",
"dashboard.healthScore.world": "Weltenbau",
"dashboard.healthScore.writing": "Schreibfortschritt",
+ "dashboard.logline.updated": "Logline aktualisiert",
+ "dashboard.logline.updatedUndo": "Mit Strg+Z rückgängig machen.",
"dashboard.loglineModal.loading": "Generiere brillante Loglines...",
"dashboard.loglineModal.title": "KI-Logline-Vorschläge",
"dashboard.momentum.activity": "Letzte 14 Tage",
@@ -986,23 +986,23 @@
"initialProject.chapter1": "Kapitel 1",
"initialProject.logline": "Eine Reise von tausend Meilen beginnt mit einem einzigen Schritt...",
"initialProject.title": "Meine unbenannte Geschichte",
- "desktop.menu.file": "Datei",
+ "desktop.menu.commandPalette": "Befehlspalette",
+ "desktop.menu.edit": "Bearbeiten",
"desktop.menu.export": "Projekt exportieren…",
+ "desktop.menu.file": "Datei",
+ "desktop.menu.help": "Hilfe",
+ "desktop.menu.helpCenter": "Hilfe-Center",
"desktop.menu.settings": "Einstellungen",
- "desktop.menu.edit": "Bearbeiten",
"desktop.menu.view": "Ansicht",
- "desktop.menu.commandPalette": "Befehlspalette",
"desktop.menu.window": "Fenster",
- "desktop.menu.help": "Hilfe",
- "desktop.menu.helpCenter": "Hilfe-Center",
- "desktop.tray.tooltip": "WorldScript Studio",
- "desktop.tray.show": "WorldScript Studio anzeigen",
- "desktop.tray.settings": "Einstellungen",
- "desktop.tray.commandPalette": "Befehlspalette",
- "desktop.tray.quit": "Beenden",
- "desktop.settings.sectionTitle": "Desktop",
"desktop.settings.minimizeToTray": "Beim Schließen in den Infobereich minimieren",
"desktop.settings.minimizeToTrayHint": "WorldScript Studio beim Schließen des Fensters im Infobereich weiterlaufen lassen, statt zu beenden.",
+ "desktop.settings.sectionTitle": "Desktop",
+ "desktop.tray.commandPalette": "Befehlspalette",
+ "desktop.tray.quit": "Beenden",
+ "desktop.tray.settings": "Einstellungen",
+ "desktop.tray.show": "WorldScript Studio anzeigen",
+ "desktop.tray.tooltip": "WorldScript Studio",
"export.ai.generateButton": "Synopse generieren",
"export.ai.generating": "Generiere...",
"export.ai.synopsis": "KI-Synopse generieren",
@@ -1090,10 +1090,10 @@
"export.pasteSection.importAsChapter": "Als Kapitel importieren",
"export.pasteSection.textPlaceholder": "Text aus Google Docs oder Notion hier einfügen (Strg+V)…",
"export.pasteSection.titlePlaceholder": "Kapiteltitel (optional)",
- "export.preview.noContent": "Wählen Sie Inhalte aus, um eine Vorschau zu sehen.",
"export.preview.modeLabel": "Vorschaumodus",
- "export.preview.modeText": "Text",
"export.preview.modeRendered": "Gerendert",
+ "export.preview.modeText": "Text",
+ "export.preview.noContent": "Wählen Sie Inhalte aus, um eine Vorschau zu sehen.",
"export.preview.title": "Live-Vorschau",
"export.title": "Publishing-Suite",
"export.toggleSection": "Sichtbarkeit für {{title}} umschalten",
@@ -1519,6 +1519,23 @@
"outline.deleteConfirm": "Sind Sie sicher, dass Sie diesen Gliederungsabschnitt löschen möchten?",
"outline.description": "Beschreiben Sie Ihre Story-Idee und lassen Sie die KI eine strukturierte, bearbeitbare Gliederung für Sie erstellen.",
"outline.error.generationFailed": "Inhalt konnte nicht generiert werden. Bitte versuchen Sie es erneut.",
+ "outline.heuristic.beat.climax.desc": "Der zentrale Konflikt spitzt sich in der entscheidenden Konfrontation der Geschichte zu.",
+ "outline.heuristic.beat.climax.title": "Höhepunkt",
+ "outline.heuristic.beat.complications.desc": "Rückschläge und Konflikte verschärfen sich; der Weg nach vorn wird enger.",
+ "outline.heuristic.beat.complications.title": "Komplikationen",
+ "outline.heuristic.beat.incitingIncident.desc": "Das Ereignis, das die Geschichte in Gang setzt: {{idea}}.",
+ "outline.heuristic.beat.incitingIncident.title": "Auslösendes Ereignis",
+ "outline.heuristic.beat.midpoint.desc": "Ein Wendepunkt verändert die Richtung der Geschichte und erhöht den Einsatz.",
+ "outline.heuristic.beat.midpoint.title": "Wendepunkt",
+ "outline.heuristic.beat.resolution.desc": "Lose Enden werden zusammengeführt und ein neuer Ausgangszustand entsteht.",
+ "outline.heuristic.beat.resolution.title": "Auflösung",
+ "outline.heuristic.beat.risingAction.desc": "Die Komplikationen nehmen zu und der Einsatz steigt, während die Figuren ihr Ziel verfolgen.",
+ "outline.heuristic.beat.risingAction.title": "Steigende Handlung",
+ "outline.heuristic.beat.setup.desc": "Stelle die Welt und die Hauptfiguren vor und etabliere den Ausgangszustand, bevor sich alles ändert.",
+ "outline.heuristic.beat.setup.title": "Einführung",
+ "outline.heuristic.beat.twist.desc": "Eine unerwartete Enthüllung stellt alles auf den Kopf, woran die Figuren geglaubt haben.",
+ "outline.heuristic.beat.twist.title": "Wendung",
+ "outline.heuristic.fallbackIdea": "die zentrale Idee",
"outline.idea.generateButton": "Gliederung generieren",
"outline.idea.genreLabel": "Genre",
"outline.idea.genrePlaceholder": "z.B. Sci-Fi, Fantasy, Krimi",
@@ -1541,23 +1558,6 @@
"outline.result.twistTooltip": "KI-generierte Wendung",
"outline.selectSection": "Abschnitt '{{title}}' auswählen",
"outline.title": "KI Story-Gliederungsgenerator",
- "outline.heuristic.fallbackIdea": "die zentrale Idee",
- "outline.heuristic.beat.setup.title": "Einführung",
- "outline.heuristic.beat.setup.desc": "Stelle die Welt und die Hauptfiguren vor und etabliere den Ausgangszustand, bevor sich alles ändert.",
- "outline.heuristic.beat.incitingIncident.title": "Auslösendes Ereignis",
- "outline.heuristic.beat.incitingIncident.desc": "Das Ereignis, das die Geschichte in Gang setzt: {{idea}}.",
- "outline.heuristic.beat.risingAction.title": "Steigende Handlung",
- "outline.heuristic.beat.risingAction.desc": "Die Komplikationen nehmen zu und der Einsatz steigt, während die Figuren ihr Ziel verfolgen.",
- "outline.heuristic.beat.midpoint.title": "Wendepunkt",
- "outline.heuristic.beat.midpoint.desc": "Ein Wendepunkt verändert die Richtung der Geschichte und erhöht den Einsatz.",
- "outline.heuristic.beat.complications.title": "Komplikationen",
- "outline.heuristic.beat.complications.desc": "Rückschläge und Konflikte verschärfen sich; der Weg nach vorn wird enger.",
- "outline.heuristic.beat.twist.title": "Wendung",
- "outline.heuristic.beat.twist.desc": "Eine unerwartete Enthüllung stellt alles auf den Kopf, woran die Figuren geglaubt haben.",
- "outline.heuristic.beat.climax.title": "Höhepunkt",
- "outline.heuristic.beat.climax.desc": "Der zentrale Konflikt spitzt sich in der entscheidenden Konfrontation der Geschichte zu.",
- "outline.heuristic.beat.resolution.title": "Auflösung",
- "outline.heuristic.beat.resolution.desc": "Lose Enden werden zusammengeführt und ein neuer Ausgangszustand entsteht.",
"portal.back": "Zurück",
"portal.demo.chapterContent": "Die Morgennebel hingen über den Kais, als Lyra den alten Plan der Stadtbibliothek entrollte. Ein Kreis, kaum lesbar, markierte den Platz Nordwest — dort stand der Turm, von dem niemand sprach.\n\nSie steckte den Zettel ein und ging den schmalen Pfad entlang, bis das Gitter vor ihr aufragte. Das Schloss war warm vom Sonnenlicht; das Metall jedoch kalt.",
"portal.demo.chapterTitle": "Erstes Kapitel — Vor dem Tor",
@@ -1752,6 +1752,7 @@
"settings.ai.gpu.troubleshootLowEnd": "Ihr Gerät hat begrenzte Ressourcen. Lokale KI verwendet kleinere Modelle. Schließen Sie andere Browser-Tabs oder aktivieren Sie den Eco-Modus.",
"settings.ai.gpu.troubleshootQueue": "Mehrere KI-Aufgaben sind in der Warteschlange. Nur eine läuft gleichzeitig, um VRAM-Kollisionen zu vermeiden. Warten Sie, bis die aktuelle Aufgabe fertig ist.",
"settings.ai.gpu.waitingConsumers": "Wartend",
+ "settings.ai.grokKey": "Grok API-Schlüssel",
"settings.ai.hybridFallbackHint": "Wenn der primäre Anbieter fehlschlägt, versucht WorldScript die aufgelisteten Fallbacks (Szenen-Generator, Codex-Tools). Das Writer-Streaming nutzt ausschließlich den primären Anbieter.",
"settings.ai.hybridFallbackTitle": "Hybrides Fallback (Projekt-KI-Tools)",
"settings.ai.hybridFallbackToggle": "Fallback-Kette aktivieren",
@@ -1832,6 +1833,11 @@
"settings.ai.preset.lmStudio": "LM Studio",
"settings.ai.preset.ollamaDefault": "Ollama (Standardport)",
"settings.ai.preset.vllm": "vLLM",
+ "settings.ai.provider.anthropic": "Anthropic Claude",
+ "settings.ai.provider.gemini": "Google Gemini",
+ "settings.ai.provider.grok": "xAI Grok",
+ "settings.ai.provider.ollama": "Ollama (lokal)",
+ "settings.ai.provider.openai": "OpenAI",
"settings.ai.providerDescription": "Wähle, welchen KI-Anbieter WorldScript Studio verwenden soll.",
"settings.ai.providerOnnx": "ONNX (WASM)",
"settings.ai.providerStatusConnected": "Verbunden",
@@ -2711,6 +2717,11 @@
"worlds.edit.notes": "Notizen",
"worlds.editorTabsAriaLabel": "Welteditor-Reiter",
"worlds.error.imageFailed": "Generierung des Stimmungsbildes fehlgeschlagen. Bitte fügen Sie der Weltbeschreibung mehr Details hinzu oder überprüfen Sie Ihre Verbindung.",
+ "worlds.heuristic.culture": "Beschreibe die Völker, Überzeugungen und das tägliche Leben, die von {{concept}} geprägt sind.",
+ "worlds.heuristic.description": "Eine Welt, die durch ihre zentrale Prämisse bestimmt wird: {{concept}}.",
+ "worlds.heuristic.geography": "Skizziere die wichtigsten Regionen, Klimazonen und natürlichen Merkmale von {{concept}}.",
+ "worlds.heuristic.magicSystem": "Lege die Regeln, Kosten und Grenzen der Macht in {{concept}} fest.",
+ "worlds.heuristic.name": "Neue Welt",
"worlds.loading.profile": "Detailliertes Weltprofil wird generiert...",
"worlds.newWorldName": "Neue Welt",
"worlds.noWorlds": "Noch keine Welten erstellt.",
@@ -2729,32 +2740,19 @@
"worlds.title": "Welt-Atlas",
"worlds.uploadImage": "Bild hochladen",
"worlds.yourWorlds": "Ihre Welten",
- "worlds.heuristic.name": "Neue Welt",
- "worlds.heuristic.description": "Eine Welt, die durch ihre zentrale Prämisse bestimmt wird: {{concept}}.",
- "worlds.heuristic.geography": "Skizziere die wichtigsten Regionen, Klimazonen und natürlichen Merkmale von {{concept}}.",
- "worlds.heuristic.magicSystem": "Lege die Regeln, Kosten und Grenzen der Macht in {{concept}} fest.",
- "worlds.heuristic.culture": "Beschreibe die Völker, Überzeugungen und das tägliche Leben, die von {{concept}} geprägt sind.",
"writer.cancelledTag": "Abgebrochen",
"writer.chapter.label": "Kapitel: {{title}}",
- "writer.context.hide": "Kontext ausblenden",
- "writer.context.label": "Kontext",
- "writer.context.show": "Kontext einblenden",
- "writer.flowMode.enterLabel": "Flow-Modus",
- "writer.modeBadge.label": "Aktive Modi:",
- "writer.modeBadge.flow": "Flow",
- "writer.modeBadge.focus": "Fokus",
- "writer.modeBadge.proforge": "ProForge",
- "writer.modeBadge.contextHidden": "Kontext ausgeblendet",
- "writer.modeBadge.toolsHidden": "Werkzeuge ausgeblendet",
- "writer.modeBadge.reset": "Standardlayout wiederherstellen",
- "writer.modeBadge.resetTitle": "Auf das dreispaltige Standardlayout zurücksetzen",
"writer.coachmark.dismiss": "Verstanden",
- "writer.coachmark.flow.title": "Flow-Modus",
"writer.coachmark.flow.body": "Nur das Schreibfeld wird angezeigt – alles andere ist ausgeblendet. Mit Esc oder \"Standardlayout wiederherstellen\" kehrst du zurück.",
- "writer.coachmark.focus.title": "Fokus-Modus",
+ "writer.coachmark.flow.title": "Flow-Modus",
"writer.coachmark.focus.body": "Zeigt Manuskript und Kontext nebeneinander und blendet die Werkzeugspalte aus. Über die Kopfzeile jederzeit abschaltbar.",
- "writer.coachmark.proforge.title": "ProForge-Pipeline",
+ "writer.coachmark.focus.title": "Fokus-Modus",
"writer.coachmark.proforge.body": "Die Werkzeugspalte führt jetzt die mehrstufige Editing-Pipeline aus. Dein Manuskript wird nie ohne deine Prüfung verändert.",
+ "writer.coachmark.proforge.title": "ProForge-Pipeline",
+ "writer.context.hide": "Kontext ausblenden",
+ "writer.context.label": "Kontext",
+ "writer.context.show": "Kontext einblenden",
+ "writer.flowMode.enterLabel": "Flow-Modus",
"writer.flowMode.exit": "Flow-Modus beenden",
"writer.flowMode.exitLabel": "Flow beenden",
"writer.flowMode.hint": "Schreib ohne Unterbrechung. Drücke Esc zum Beenden.",
@@ -2763,9 +2761,31 @@
"writer.focusMode.enterLabel": "Fokus-Modus",
"writer.focusMode.exit": "Fokus-Modus beenden",
"writer.focusMode.exitLabel": "Fokus beenden",
+ "writer.grammar.addToDictionary": "Zum Wörterbuch hinzufügen",
+ "writer.grammar.apply": "Übernehmen",
+ "writer.grammar.checkButton": "Diese Szene prüfen",
+ "writer.grammar.checking": "Prüfe…",
+ "writer.grammar.disabled": "Aktiviere LanguageTool in Einstellungen → Verbindungen, um diese Szene zu prüfen.",
+ "writer.grammar.error": "Der LanguageTool-Server hat einen Fehler zurückgegeben.",
+ "writer.grammar.ignore": "Ignorieren",
+ "writer.grammar.issuesFound": "{{count}} Probleme gefunden",
+ "writer.grammar.noIssues": "Keine Probleme gefunden.",
+ "writer.grammar.noSuggestions": "Keine Vorschläge",
+ "writer.grammar.offline": "LanguageTool-Server nicht erreichbar. Läuft er?",
+ "writer.grammar.selectScene": "Wähle eine Szene zum Prüfen.",
+ "writer.grammar.title": "Grammatik & Rechtschreibung",
+ "writer.grammar.unsupported": "Die Grammatikprüfung ist für diese Sprache nicht verfügbar.",
"writer.imagePrompt.description": "Generiert einen optimierten DALL·E 3 / Midjourney-Prompt aus der aktuellen Szene oder Textauswahl.",
"writer.imagePrompt.note": "Der generierte Prompt funktioniert direkt in DALL·E 3 und Midjourney.",
"writer.imagePrompt.tip": "Tipp: Markiere einen bestimmten Textabschnitt für einen fokussierten Szenen-Prompt.",
+ "writer.modeBadge.contextHidden": "Kontext ausgeblendet",
+ "writer.modeBadge.flow": "Flow",
+ "writer.modeBadge.focus": "Fokus",
+ "writer.modeBadge.label": "Aktive Modi:",
+ "writer.modeBadge.proforge": "ProForge",
+ "writer.modeBadge.reset": "Standardlayout wiederherstellen",
+ "writer.modeBadge.resetTitle": "Auf das dreispaltige Standardlayout zurücksetzen",
+ "writer.modeBadge.toolsHidden": "Werkzeuge ausgeblendet",
"writer.stopGenerating": "Generierung stoppen",
"writer.studio.context.contentPlaceholder": "Wählen oder erstellen Sie einen Abschnitt, um zu beginnen.",
"writer.studio.context.sectionLabel": "Aktiver Abschnitt",
@@ -2787,12 +2807,10 @@
"writer.studio.controls.tones.poetic": "Poetischer",
"writer.studio.controls.tones.suspenseful": "Spannender",
"writer.studio.description": "Ihr KI-Co-Autor. Generieren, verbessern und brainstormen Sie mit vollem Projektkontext.",
+ "writer.studio.rag.chunkScore": "Relevanz {{score}}",
"writer.studio.rag.chunksBadge": "{{count}} Passagen gefunden",
"writer.studio.rag.chunksHint": "Relevante Auszüge aus deinem Manuskript – mehr Passagen bedeuten reichhaltigeren KI-Kontext",
"writer.studio.rag.inspectorLabel": "Abgerufener Kontext",
- "writer.studio.rag.chunkScore": "Relevanz {{score}}",
- "writer.studio.tokens.badge": "~{{count}} Tokens",
- "writer.studio.tokens.hint": "Ungefähre Tokenzahl deiner letzten KI-Anfrage",
"writer.studio.rag.useContext": "Aus meiner Geschichte schöpfen",
"writer.studio.result.insert": "Einfügen",
"writer.studio.result.next": "Weiter",
@@ -2802,6 +2820,8 @@
"writer.studio.result.retry": "Erneut",
"writer.studio.result.title": "KI-Notizblock",
"writer.studio.title": "KI-Schreibstudio",
+ "writer.studio.tokens.badge": "~{{count}} Tokens",
+ "writer.studio.tokens.hint": "Ungefähre Tokenzahl deiner letzten KI-Anfrage",
"writer.studio.tools.brainstorm.contextLabel": "Kontext (Optional)",
"writer.studio.tools.brainstorm.contextPlaceholder": "Beschreiben Sie die Situation für die KI.",
"writer.studio.tools.brainstorm.title": "Ideenfindung",
@@ -2833,19 +2853,5 @@
"writer.tts.start": "Vorlesen",
"writer.tts.stop": "Vorlesen stoppen",
"writer.versionControl.label": "Versionen",
- "writer.versionControl.tooltip": "Versionskontrolle (Zweige & Schnappschüsse)",
- "writer.grammar.title": "Grammatik & Rechtschreibung",
- "writer.grammar.checkButton": "Diese Szene prüfen",
- "writer.grammar.checking": "Prüfe…",
- "writer.grammar.issuesFound": "{{count}} Probleme gefunden",
- "writer.grammar.noIssues": "Keine Probleme gefunden.",
- "writer.grammar.selectScene": "Wähle eine Szene zum Prüfen.",
- "writer.grammar.unsupported": "Die Grammatikprüfung ist für diese Sprache nicht verfügbar.",
- "writer.grammar.disabled": "Aktiviere LanguageTool in Einstellungen → Verbindungen, um diese Szene zu prüfen.",
- "writer.grammar.offline": "LanguageTool-Server nicht erreichbar. Läuft er?",
- "writer.grammar.error": "Der LanguageTool-Server hat einen Fehler zurückgegeben.",
- "writer.grammar.apply": "Übernehmen",
- "writer.grammar.ignore": "Ignorieren",
- "writer.grammar.addToDictionary": "Zum Wörterbuch hinzufügen",
- "writer.grammar.noSuggestions": "Keine Vorschläge"
+ "writer.versionControl.tooltip": "Versionskontrolle (Zweige & Schnappschüsse)"
}
diff --git a/public/locales/el/bundle.json b/public/locales/el/bundle.json
index 6dd91d27..f7b4fc6e 100644
--- a/public/locales/el/bundle.json
+++ b/public/locales/el/bundle.json
@@ -90,6 +90,14 @@
"characters.edit.relationships": "Σχέσεις",
"characters.editorTabsAriaLabel": "Χαρακτήρας editor tabs",
"characters.error.portraitFailed": "Η δημιουργία πορτρέτου απέτυχε. Δοκιμάστε να προσθέσετε περισσότερες λεπτομέρειες στην περιγραφή της εμφάνισης.",
+ "characters.heuristic.appearance": "Describe how they present themselves — let their look hint at {{concept}}.",
+ "characters.heuristic.backstory": "Shaped by formative experiences, this character carries a past tied to {{concept}}.",
+ "characters.heuristic.characterArc": "They begin guarded and, through the story, are changed by {{concept}}.",
+ "characters.heuristic.flaws": "A weakness that complicates their goals.",
+ "characters.heuristic.motivation": "A core desire connected to {{concept}} drives their choices.",
+ "characters.heuristic.name": "New Character",
+ "characters.heuristic.personalityTraits": "Resourceful, guarded, determined.",
+ "characters.heuristic.relationships": "Note the key bonds and rivalries that define them.",
"characters.loading.profile": "Δημιουργία λεπτομερούς προφίλ...",
"characters.newCharacterName": "New Χαρακτήρας",
"characters.noCharacters": "Δεν έχουν δημιουργηθεί ακόμη χαρακτήρες.",
@@ -107,14 +115,6 @@
"characters.title": "Χαρακτήρας Dossiers",
"characters.uploadImage": "Μεταφόρτωση εικόνας",
"characters.yourCharacters": "Οι χαρακτήρες σας",
- "characters.heuristic.name": "New Character",
- "characters.heuristic.backstory": "Shaped by formative experiences, this character carries a past tied to {{concept}}.",
- "characters.heuristic.motivation": "A core desire connected to {{concept}} drives their choices.",
- "characters.heuristic.appearance": "Describe how they present themselves — let their look hint at {{concept}}.",
- "characters.heuristic.personalityTraits": "Resourceful, guarded, determined.",
- "characters.heuristic.flaws": "A weakness that complicates their goals.",
- "characters.heuristic.characterArc": "They begin guarded and, through the story, are changed by {{concept}}.",
- "characters.heuristic.relationships": "Note the key bonds and rivalries that define them.",
"apiKey.connectionFailed": "Η δοκιμή σύνδεσης απέτυχε.",
"apiKey.connectionSuccess": "Επιτυχής σύνδεση! Το API ανταποκρίνεται σωστά.",
"apiKey.decryptFailed": "Δεν ήταν δυνατή η αποκρυπτογράφηση του κλειδιού API",
@@ -125,6 +125,11 @@
"apiKey.test": "Δοκιμαστική σύνδεση",
"apiKey.testConnection": "Δοκιμή σύνδεσης API",
"apiKey.testing": "Δοκιμή…",
+ "assisted.badge.label": "Assisted",
+ "assisted.badge.srLabel": "Assisted mode — generated without AI",
+ "assisted.enhance": "Enhance with AI",
+ "assisted.toast.description": "Used built-in assistance. Enhance with AI when a model is available.",
+ "assisted.toast.title": "AI unavailable",
"charGraph.characters": "Χαρακτήρες",
"charGraph.noCharacters": "Δεν υπάρχουν ακόμη χαρακτήρες",
"charGraph.noCharactersHint": "Προσθήκη characters in the Characters view to visualize their relationships here.",
@@ -286,6 +291,8 @@
"error.db.unknown": "Άγνωστο σφάλμα κατά την πρόσβαση στη βάση δεδομένων.",
"error.deepLink.title": "Απέτυχε το άνοιγμα του αρχείου έργου",
"error.deepLink.unknown": "Άγνωστο σφάλμα",
+ "error.fallback.generic": "AI is unavailable — used built-in assistance.",
+ "error.fallback.offline": "You're offline — used built-in assistance.",
"error.fileImportError": "Σφάλμα εισαγωγής αρχείου",
"error.mic.denied": "Δεν επιτρέπεται η πρόσβαση στο μικρόφωνο. Παρακαλούμε χορηγήστε άδεια στις ρυθμίσεις του προγράμματος περιήγησής σας.",
"error.mic.generic": "Σφάλμα αναγνώρισης ομιλίας: {{error}}",
@@ -382,6 +389,16 @@
"palette.voice.listeningLive": "Η φωνητική είσοδος είναι ενεργή",
"palette.voice.start": "Ξεκινήστε τη φωνητική αναζήτηση",
"palette.voice.stop": "Διακοπή φωνητικής αναζήτησης",
+ "plotBoard.heuristic.complicate.description": "Add an obstacle or reveal that forces a change of plan.",
+ "plotBoard.heuristic.complicate.rationale": "A fresh complication tests the characters and opens new threads.",
+ "plotBoard.heuristic.complicate.title": "Introduce a complication",
+ "plotBoard.heuristic.escalate.description": "Increase the pressure on your protagonist so the next choice costs more.",
+ "plotBoard.heuristic.escalate.rationale": "Escalation keeps momentum when the middle sags.",
+ "plotBoard.heuristic.escalate.title": "Raise the stakes",
+ "plotBoard.heuristic.position": "Right after the selected scene",
+ "plotBoard.heuristic.reverse.description": "Flip an expectation — an ally falters, a win turns sour, or a hidden truth surfaces.",
+ "plotBoard.heuristic.reverse.rationale": "Reversals refresh tension and deepen the arc.",
+ "plotBoard.heuristic.reverse.title": "Add a reversal",
"preview.controls.ariaLabel": "Στοιχεία ελέγχου προεπισκόπησης",
"preview.controls.decreaseFontSize": "Μειώστε το μέγεθος της γραμματοσειράς",
"preview.controls.exitFullscreen": "Έξοδος από πλήρη οθόνη",
@@ -449,10 +466,6 @@
"proforge.progress.awaitingReviewHint": "⚠️ Αυτό το στάδιο περιμένει την κριτική σας. Κάντε κλικ στο κουμπί του σταδίου παραπάνω για να ελέγξετε τα στοιχεία.",
"proforge.progress.completedStages": "Ολοκληρωμένα Στάδια",
"proforge.progress.currentStatus": "Τρέχουσα κατάσταση",
- "proforge.progress.overall": "Overall progress",
- "proforge.progress.preparing": "Preparing…",
- "proforge.progress.stageOfTotal": "Stage {{current}} of {{total}}",
- "proforge.progress.percentComplete": "{{percent}}% complete",
"proforge.progress.itemsCount": "{{count}} αντικείμενα",
"proforge.progress.metric.aiCalls": "Κλήσεις AI",
"proforge.progress.metric.duration": "Διάρκεια",
@@ -463,7 +476,11 @@
"proforge.progress.metric.totalTime": "Συνολικός χρόνος",
"proforge.progress.metric.totalTokens": "Σύνολο Μαρκών",
"proforge.progress.noneRunning": "Δεν λειτουργεί αγωγός.",
+ "proforge.progress.overall": "Overall progress",
+ "proforge.progress.percentComplete": "{{percent}}% complete",
+ "proforge.progress.preparing": "Preparing…",
"proforge.progress.stageDetails": "Λεπτομέρειες σταδίου: {{stage}}",
+ "proforge.progress.stageOfTotal": "Stage {{current}} of {{total}}",
"proforge.progress.statusLabel": "Κατάσταση",
"proforge.progress.totals": "Σύνολα αγωγών",
"proforge.review.accept": "Αποδέχομαι",
@@ -777,9 +794,9 @@
"vc.title": "Ιστορικό έκδοσης",
"vc.words": "λόγια",
"voice.cancelSpeech": "Ακύρωση speech",
+ "voice.feedback.confidence": "Βεβαιότητα {{percent}}%",
"voice.modeChip.commands": "Εντολές",
"voice.modeChip.dictation": "Υπαγόρευση",
- "voice.feedback.confidence": "Βεβαιότητα {{percent}}%",
"voice.panelLabel": "Φωνητικός έλεγχος",
"voice.permissionDenied": "Δεν επιτρέπεται η πρόσβαση στο μικρόφωνο. Επιτρέψτε την πρόσβαση στο μικρόφωνο στις ρυθμίσεις του προγράμματος περιήγησής σας για χρήση φωνητικών λειτουργιών.",
"voice.startDictation": "Έναρξη υπαγόρευσης",
@@ -793,23 +810,6 @@
"voice.stopListening": "Σταμάτα να ακούς",
"worlds.emptyState.description": "Δημιουργήστε τα μέρη, τους κανόνες και τις ιστορίες στα οποία ζει η ιστορία σας. Ξεκινήστε με μια τοποθεσία.",
"worlds.emptyState.title": "Ο κόσμος περιμένει",
- "error.fallback.generic": "AI is unavailable — used built-in assistance.",
- "error.fallback.offline": "You're offline — used built-in assistance.",
- "assisted.badge.label": "Assisted",
- "assisted.badge.srLabel": "Assisted mode — generated without AI",
- "assisted.toast.title": "AI unavailable",
- "assisted.toast.description": "Used built-in assistance. Enhance with AI when a model is available.",
- "assisted.enhance": "Enhance with AI",
- "plotBoard.heuristic.position": "Right after the selected scene",
- "plotBoard.heuristic.escalate.title": "Raise the stakes",
- "plotBoard.heuristic.escalate.description": "Increase the pressure on your protagonist so the next choice costs more.",
- "plotBoard.heuristic.escalate.rationale": "Escalation keeps momentum when the middle sags.",
- "plotBoard.heuristic.complicate.title": "Introduce a complication",
- "plotBoard.heuristic.complicate.description": "Add an obstacle or reveal that forces a change of plan.",
- "plotBoard.heuristic.complicate.rationale": "A fresh complication tests the characters and opens new threads.",
- "plotBoard.heuristic.reverse.title": "Add a reversal",
- "plotBoard.heuristic.reverse.description": "Flip an expectation — an ally falters, a win turns sour, or a hidden truth surfaces.",
- "plotBoard.heuristic.reverse.rationale": "Reversals refresh tension and deepen the arc.",
"copilot.annotationCount": "{{count}} πληροφορίες για αυτό το κεφάλαιο",
"copilot.announceClosed": "Το AI Copilot έκλεισε",
"copilot.announceOpened": "Άνοιξε το AI Copilot",
@@ -1090,10 +1090,10 @@
"export.pasteSection.importAsChapter": "Εισαγωγή ως κεφάλαιο",
"export.pasteSection.textPlaceholder": "Επικολλήστε εδώ κείμενο από τα Έγγραφα Google ή το Notion (Ctrl+V)...",
"export.pasteSection.titlePlaceholder": "Τίτλος κεφαλαίου (προαιρετικό)",
- "export.preview.noContent": "Επιλέξτε περιεχόμενο για να δείτε μια προεπισκόπηση.",
"export.preview.modeLabel": "Λειτουργία προεπισκόπησης",
- "export.preview.modeText": "Κείμενο",
"export.preview.modeRendered": "Αποδοθέν",
+ "export.preview.modeText": "Κείμενο",
+ "export.preview.noContent": "Επιλέξτε περιεχόμενο για να δείτε μια προεπισκόπηση.",
"export.preview.title": "Ζωντανή προεπισκόπηση",
"export.title": "Εξαγωγή Publishing Suite",
"export.toggleSection": "Εναλλαγή ορατότητας για {{title}}",
@@ -1519,6 +1519,23 @@
"outline.deleteConfirm": "Είστε βέβαιοι ότι θέλετε να διαγράψετε αυτήν την ενότητα περιλήψεων;",
"outline.description": "Περιγράψτε την ιδέα της ιστορίας σας και αφήστε το AI να δημιουργήσει ένα δομημένο, επεξεργάσιμο περίγραμμα για εσάς.",
"outline.error.generationFailed": "Αποτυχία δημιουργίας περιεχομένου. Δοκιμάστε ξανά.",
+ "outline.heuristic.beat.climax.desc": "The central conflict comes to a head in the story's defining confrontation.",
+ "outline.heuristic.beat.climax.title": "Climax",
+ "outline.heuristic.beat.complications.desc": "Setbacks and conflicts deepen; the path forward narrows.",
+ "outline.heuristic.beat.complications.title": "Complications",
+ "outline.heuristic.beat.incitingIncident.desc": "The event that sets the story in motion: {{idea}}.",
+ "outline.heuristic.beat.incitingIncident.title": "Inciting Incident",
+ "outline.heuristic.beat.midpoint.desc": "A turning point shifts the direction of the story and raises the stakes.",
+ "outline.heuristic.beat.midpoint.title": "Midpoint",
+ "outline.heuristic.beat.resolution.desc": "Loose ends are tied up and a new status quo emerges.",
+ "outline.heuristic.beat.resolution.title": "Resolution",
+ "outline.heuristic.beat.risingAction.desc": "Complications escalate and the stakes grow as the characters pursue their goal.",
+ "outline.heuristic.beat.risingAction.title": "Rising Action",
+ "outline.heuristic.beat.setup.desc": "Introduce the world and the main characters, and establish the status quo before everything changes.",
+ "outline.heuristic.beat.setup.title": "Setup",
+ "outline.heuristic.beat.twist.desc": "An unexpected revelation upends what the characters believed to be true.",
+ "outline.heuristic.beat.twist.title": "Twist",
+ "outline.heuristic.fallbackIdea": "the central idea",
"outline.idea.generateButton": "Δημιουργία Σχεδιάγραμμα",
"outline.idea.genreLabel": "Είδος",
"outline.idea.genrePlaceholder": "π.χ., Sci-Fi, Fantasy, Mystery",
@@ -1541,23 +1558,6 @@
"outline.result.twistTooltip": "Twist πλοκής που δημιουργήθηκε με AI",
"outline.selectSection": "Επιλέξτε ενότητα \"{{title}}\"",
"outline.title": "AI Story Σχεδιάγραμμα Generator",
- "outline.heuristic.fallbackIdea": "the central idea",
- "outline.heuristic.beat.setup.title": "Setup",
- "outline.heuristic.beat.setup.desc": "Introduce the world and the main characters, and establish the status quo before everything changes.",
- "outline.heuristic.beat.incitingIncident.title": "Inciting Incident",
- "outline.heuristic.beat.incitingIncident.desc": "The event that sets the story in motion: {{idea}}.",
- "outline.heuristic.beat.risingAction.title": "Rising Action",
- "outline.heuristic.beat.risingAction.desc": "Complications escalate and the stakes grow as the characters pursue their goal.",
- "outline.heuristic.beat.midpoint.title": "Midpoint",
- "outline.heuristic.beat.midpoint.desc": "A turning point shifts the direction of the story and raises the stakes.",
- "outline.heuristic.beat.complications.title": "Complications",
- "outline.heuristic.beat.complications.desc": "Setbacks and conflicts deepen; the path forward narrows.",
- "outline.heuristic.beat.twist.title": "Twist",
- "outline.heuristic.beat.twist.desc": "An unexpected revelation upends what the characters believed to be true.",
- "outline.heuristic.beat.climax.title": "Climax",
- "outline.heuristic.beat.climax.desc": "The central conflict comes to a head in the story's defining confrontation.",
- "outline.heuristic.beat.resolution.title": "Resolution",
- "outline.heuristic.beat.resolution.desc": "Loose ends are tied up and a new status quo emerges.",
"portal.back": "Πίσω",
"portal.demo.chapterContent": "Η πρωινή ομίχλη κόλλησε στις αποβάθρες καθώς η Lyra ξετύλιξε τον παλιό χάρτη της πόλης. Ένας αμυδρός κύκλος σημάδεψε τη βορειοδυτική γωνία - τον πύργο που κανείς δεν ανέφερε.\n\nΤράβηξε το χαρτί και ακολούθησε το στενό μονοπάτι μέχρι που το σιδερένιο πλέγμα σηκώθηκε μπροστά της. Το λουκέτο ήταν ζεστό στον ήλιο. το μέταλλο είναι ακόμα κρύο.",
"portal.demo.chapterTitle": "Κεφάλαιο 1 — Πριν από την Πύλη",
@@ -1752,6 +1752,7 @@
"settings.ai.gpu.troubleshootLowEnd": "Η συσκευή σας έχει περιορισμένους πόρους. Η τοπική τεχνητή νοημοσύνη θα χρησιμοποιεί μικρότερα μοντέλα. Για καλύτερη απόδοση, κλείστε άλλες καρτέλες του προγράμματος περιήγησης ή ενεργοποιήστε τη λειτουργία Eco Mode.",
"settings.ai.gpu.troubleshootQueue": "Πολλές εργασίες AI βρίσκονται στην ουρά. Μόνο ένα τρέχει κάθε φορά για να αποφευχθούν συγκρούσεις VRAM. Περιμένετε να ολοκληρωθεί η τρέχουσα εργασία.",
"settings.ai.gpu.waitingConsumers": "Αναμονή",
+ "settings.ai.grokKey": "Grok API Key",
"settings.ai.hybridFallbackHint": "Εάν ο κύριος πάροχος αποτύχει, το WorldScript δοκιμάζει τα αναγραφόμενα εναλλακτικά (δημιουργοί σκηνής, εργαλεία κώδικα). Η ροή του Writer χρησιμοποιεί μόνο τον κύριο πάροχο σας.",
"settings.ai.hybridFallbackTitle": "Υβριδικό εναλλακτικό (εργαλεία AI έργου)",
"settings.ai.hybridFallbackToggle": "Ενεργοποίηση εναλλακτικής αλυσίδας",
@@ -1832,6 +1833,11 @@
"settings.ai.preset.lmStudio": "LM Studio",
"settings.ai.preset.ollamaDefault": "Ollama (προεπιλεγμένη θύρα)",
"settings.ai.preset.vllm": "vLLM",
+ "settings.ai.provider.anthropic": "Anthropic Claude",
+ "settings.ai.provider.gemini": "Google Gemini",
+ "settings.ai.provider.grok": "xAI Grok",
+ "settings.ai.provider.ollama": "Ollama (local)",
+ "settings.ai.provider.openai": "OpenAI",
"settings.ai.providerDescription": "Επιλέξτε ποιον πάροχο τεχνητής νοημοσύνης θα χρησιμοποιεί το WorldScript Studio.",
"settings.ai.providerOnnx": "ONNX (WASM)",
"settings.ai.providerStatusConnected": "Συνδεδεμένος",
@@ -2711,6 +2717,11 @@
"worlds.edit.notes": "Σημειώσεις",
"worlds.editorTabsAriaLabel": "Κόσμος editor tabs",
"worlds.error.imageFailed": "Η δημιουργία εικόνας περιβάλλοντος απέτυχε. Δοκιμάστε να προσθέσετε περισσότερες λεπτομέρειες στην περιγραφή του κόσμου ή ελέγξτε τη σύνδεσή σας.",
+ "worlds.heuristic.culture": "Describe the peoples, beliefs, and daily life shaped by {{concept}}.",
+ "worlds.heuristic.description": "A world defined by its central premise: {{concept}}.",
+ "worlds.heuristic.geography": "Outline the major regions, climates, and natural features of {{concept}}.",
+ "worlds.heuristic.magicSystem": "Define the rules, costs, and limits of power in {{concept}}.",
+ "worlds.heuristic.name": "New World",
"worlds.loading.profile": "Δημιουργία λεπτομερούς παγκόσμιου προφίλ...",
"worlds.newWorldName": "New Κόσμος",
"worlds.noWorlds": "Δεν έχουν δημιουργηθεί ακόμη κόσμοι.",
@@ -2729,11 +2740,6 @@
"worlds.title": "Κόσμος Atlas",
"worlds.uploadImage": "Μεταφόρτωση εικόνας",
"worlds.yourWorlds": "Οι Κόσμοι σας",
- "worlds.heuristic.name": "New World",
- "worlds.heuristic.description": "A world defined by its central premise: {{concept}}.",
- "worlds.heuristic.geography": "Outline the major regions, climates, and natural features of {{concept}}.",
- "worlds.heuristic.magicSystem": "Define the rules, costs, and limits of power in {{concept}}.",
- "worlds.heuristic.culture": "Describe the peoples, beliefs, and daily life shaped by {{concept}}.",
"writer.cancelledTag": "Ακυρώθηκε",
"writer.chapter.label": "Κεφάλαιο: {{title}}",
"writer.coachmark.dismiss": "Got it",
@@ -2755,6 +2761,20 @@
"writer.focusMode.enterLabel": "Λειτουργία εστίασης",
"writer.focusMode.exit": "Έξοδος από τη λειτουργία εστίασης",
"writer.focusMode.exitLabel": "Έξοδος από την εστίαση",
+ "writer.grammar.addToDictionary": "Add to dictionary",
+ "writer.grammar.apply": "Apply",
+ "writer.grammar.checkButton": "Check this scene",
+ "writer.grammar.checking": "Checking…",
+ "writer.grammar.disabled": "Enable LanguageTool in Settings → Connections to check this scene.",
+ "writer.grammar.error": "The LanguageTool server returned an error.",
+ "writer.grammar.ignore": "Ignore",
+ "writer.grammar.issuesFound": "{{count}} issues found",
+ "writer.grammar.noIssues": "No issues found.",
+ "writer.grammar.noSuggestions": "No suggestions",
+ "writer.grammar.offline": "Couldn't reach the LanguageTool server. Is it running?",
+ "writer.grammar.selectScene": "Select a scene to check.",
+ "writer.grammar.title": "Grammar & Spelling",
+ "writer.grammar.unsupported": "Grammar check isn't available for this language.",
"writer.imagePrompt.description": "Δημιουργεί ένα βελτιστοποιημένο μήνυμα DALL·E 3 / Midjourney από την τρέχουσα επιλογή σκηνής ή κειμένου.",
"writer.imagePrompt.note": "Η προτροπή που δημιουργείται λειτουργεί απευθείας στο DALL·E 3 και στο Midjourney.",
"writer.imagePrompt.tip": "Συμβουλή: Επιλέξτε μια συγκεκριμένη ενότητα κειμένου για μια προτροπή εστιασμένης σκηνής.",
@@ -2787,12 +2807,10 @@
"writer.studio.controls.tones.poetic": "Πιο ποιητικό",
"writer.studio.controls.tones.suspenseful": "Πιο σασπένς",
"writer.studio.description": "Your AI co-author. Δημιουργία, improve, and brainstorm with full project context.",
+ "writer.studio.rag.chunkScore": "συνάφεια {{score}}",
"writer.studio.rag.chunksBadge": "Βρέθηκαν {{count}} αποσπάσματα ιστορίας",
"writer.studio.rag.chunksHint": "Σχετικά αποσπάσματα από το χειρόγραφό σας — περισσότερα αποσπάσματα σημαίνουν πλουσιότερο περιβάλλον τεχνητής νοημοσύνης",
"writer.studio.rag.inspectorLabel": "Ανακτημένο πλαίσιο",
- "writer.studio.rag.chunkScore": "συνάφεια {{score}}",
- "writer.studio.tokens.badge": "~{{count}} διακριτικά",
- "writer.studio.tokens.hint": "Κατά προσέγγιση διακριτικά στο τελευταίο αίτημα AI",
"writer.studio.rag.useContext": "Βγάλε από την ιστορία μου",
"writer.studio.result.insert": "Εισάγω",
"writer.studio.result.next": "Επόμενο",
@@ -2802,6 +2820,8 @@
"writer.studio.result.retry": "Δοκιμάζω πάλι",
"writer.studio.result.title": "AI Scratchpad",
"writer.studio.title": "AI Writing Studio",
+ "writer.studio.tokens.badge": "~{{count}} διακριτικά",
+ "writer.studio.tokens.hint": "Κατά προσέγγιση διακριτικά στο τελευταίο αίτημα AI",
"writer.studio.tools.brainstorm.contextLabel": "Πλαίσιο καταιγισμού ιδεών (Προαιρετικό)",
"writer.studio.tools.brainstorm.contextPlaceholder": "Δώστε μια σύντομη κατάσταση, διαφορετικά η τεχνητή νοημοσύνη θα χρησιμοποιήσει την τρέχουσα ενότητα χειρογράφου.",
"writer.studio.tools.brainstorm.title": "Ιδέες καταιγισμού ιδεών",
@@ -2833,19 +2853,5 @@
"writer.tts.start": "Διαβάστε δυνατά",
"writer.tts.stop": "Σταμάτα να διαβάζεις",
"writer.versionControl.label": "εκδόσεις",
- "writer.versionControl.tooltip": "Έλεγχος έκδοσης (Κλάδοι και στιγμιότυπα)",
- "writer.grammar.title": "Grammar & Spelling",
- "writer.grammar.checkButton": "Check this scene",
- "writer.grammar.checking": "Checking…",
- "writer.grammar.issuesFound": "{{count}} issues found",
- "writer.grammar.noIssues": "No issues found.",
- "writer.grammar.selectScene": "Select a scene to check.",
- "writer.grammar.unsupported": "Grammar check isn't available for this language.",
- "writer.grammar.disabled": "Enable LanguageTool in Settings → Connections to check this scene.",
- "writer.grammar.offline": "Couldn't reach the LanguageTool server. Is it running?",
- "writer.grammar.error": "The LanguageTool server returned an error.",
- "writer.grammar.apply": "Apply",
- "writer.grammar.ignore": "Ignore",
- "writer.grammar.addToDictionary": "Add to dictionary",
- "writer.grammar.noSuggestions": "No suggestions"
+ "writer.versionControl.tooltip": "Έλεγχος έκδοσης (Κλάδοι και στιγμιότυπα)"
}
diff --git a/public/locales/en/bundle.json b/public/locales/en/bundle.json
index 18818fa2..0202fdaa 100644
--- a/public/locales/en/bundle.json
+++ b/public/locales/en/bundle.json
@@ -1737,6 +1737,7 @@
"settings.ai.geminiKeyBelow": "below.",
"settings.ai.geminiKeySection": "API Key",
"settings.ai.geminiSelected": "Google Gemini is selected. Configure the API key in the section",
+ "settings.ai.grokKey": "Grok API Key",
"settings.ai.gpu.currentConsumer": "GPU held by",
"settings.ai.gpu.deviceHighEnd": "High-end",
"settings.ai.gpu.deviceLowEnd": "Low-end",
@@ -1832,6 +1833,11 @@
"settings.ai.preset.lmStudio": "LM Studio",
"settings.ai.preset.ollamaDefault": "Ollama (default port)",
"settings.ai.preset.vllm": "vLLM",
+ "settings.ai.provider.anthropic": "Anthropic Claude",
+ "settings.ai.provider.gemini": "Google Gemini",
+ "settings.ai.provider.grok": "xAI Grok",
+ "settings.ai.provider.ollama": "Ollama (local)",
+ "settings.ai.provider.openai": "OpenAI",
"settings.ai.providerDescription": "Choose which AI provider WorldScript Studio should use.",
"settings.ai.providerOnnx": "ONNX (WASM)",
"settings.ai.providerStatusConnected": "Connected",
diff --git a/public/locales/es/bundle.json b/public/locales/es/bundle.json
index 485327f2..536a5131 100644
--- a/public/locales/es/bundle.json
+++ b/public/locales/es/bundle.json
@@ -90,6 +90,14 @@
"characters.edit.relationships": "Relaciones",
"characters.editorTabsAriaLabel": "Pestañas del editor de personaje",
"characters.error.portraitFailed": "Error al generar el retrato. Intenta añadir más detalles a la descripción de la apariencia.",
+ "characters.heuristic.appearance": "Describe cómo se presenta — deja que su aspecto insinúe {{concept}}.",
+ "characters.heuristic.backstory": "Moldeado por experiencias formativas, este personaje carga un pasado ligado a {{concept}}.",
+ "characters.heuristic.characterArc": "Empieza reservado y, a lo largo de la historia, cambia por {{concept}}.",
+ "characters.heuristic.flaws": "Una debilidad que complica sus objetivos.",
+ "characters.heuristic.motivation": "Un deseo central conectado con {{concept}} guía sus decisiones.",
+ "characters.heuristic.name": "Nuevo personaje",
+ "characters.heuristic.personalityTraits": "Ingenioso, reservado, decidido.",
+ "characters.heuristic.relationships": "Anota los vínculos y rivalidades clave que lo definen.",
"characters.loading.profile": "Generando perfil detallado...",
"characters.newCharacterName": "Nuevo personaje",
"characters.noCharacters": "Ningún personaje creado aún.",
@@ -107,14 +115,6 @@
"characters.title": "Dossiers de personajes",
"characters.uploadImage": "Subir imagen",
"characters.yourCharacters": "Tus personajes",
- "characters.heuristic.name": "Nuevo personaje",
- "characters.heuristic.backstory": "Moldeado por experiencias formativas, este personaje carga un pasado ligado a {{concept}}.",
- "characters.heuristic.motivation": "Un deseo central conectado con {{concept}} guía sus decisiones.",
- "characters.heuristic.appearance": "Describe cómo se presenta — deja que su aspecto insinúe {{concept}}.",
- "characters.heuristic.personalityTraits": "Ingenioso, reservado, decidido.",
- "characters.heuristic.flaws": "Una debilidad que complica sus objetivos.",
- "characters.heuristic.characterArc": "Empieza reservado y, a lo largo de la historia, cambia por {{concept}}.",
- "characters.heuristic.relationships": "Anota los vínculos y rivalidades clave que lo definen.",
"apiKey.connectionFailed": "Error en la prueba de conexión.",
"apiKey.connectionSuccess": "¡Conexión exitosa! La API responde correctamente.",
"apiKey.decryptFailed": "No se pudo descifrar la clave API",
@@ -125,6 +125,11 @@
"apiKey.test": "Probar conexión",
"apiKey.testConnection": "Probar conexión API",
"apiKey.testing": "Probando…",
+ "assisted.badge.label": "Asistido",
+ "assisted.badge.srLabel": "Modo asistido: generado sin IA",
+ "assisted.enhance": "Mejorar con IA",
+ "assisted.toast.description": "Se usó la asistencia integrada. Mejora con IA cuando haya un modelo disponible.",
+ "assisted.toast.title": "IA no disponible",
"charGraph.characters": "Personajes",
"charGraph.noCharacters": "Aún no hay personajes",
"charGraph.noCharactersHint": "Añade personajes en la vista Personajes para visualizar sus relaciones aquí.",
@@ -185,8 +190,8 @@
"common.add": "Añadir",
"common.appLoading": "La aplicación se está cargando",
"common.back": "Atrás",
- "common.badge.experimental": "Experimental",
"common.badge.beta": "Beta",
+ "common.badge.experimental": "Experimental",
"common.badge.new": "Nuevo",
"common.cancel": "Cancelar",
"common.close": "Cerrar",
@@ -217,16 +222,16 @@
"common.words": "palabras",
"consistencyChecker.checkButton": "Verificar coherencia",
"consistencyChecker.description": "Verifica la coherencia de tus personajes con el lore establecido, otros personajes y tu manuscrito.",
+ "consistencyChecker.noFindings": "No se encontraron inconsistencias — este personaje parece coherente.",
"consistencyChecker.noResults": "Sin resultados",
"consistencyChecker.noResultsHint": "Selecciona un personaje de la lista de la izquierda y haz clic en Verificar coherencia para analizar tu manuscrito.",
- "consistencyChecker.results": "Resultados",
- "consistencyChecker.severity.info": "Info",
- "consistencyChecker.severity.warn": "Advertencia",
- "consistencyChecker.severity.error": "Conflicto",
"consistencyChecker.refLabel": "Relacionado",
- "consistencyChecker.noFindings": "No se encontraron inconsistencias — este personaje parece coherente.",
+ "consistencyChecker.results": "Resultados",
"consistencyChecker.selectCharacter": "Seleccionar personaje",
"consistencyChecker.selectPlaceholder": "Elige un personaje a verificar",
+ "consistencyChecker.severity.error": "Conflicto",
+ "consistencyChecker.severity.info": "Info",
+ "consistencyChecker.severity.warn": "Advertencia",
"consistencyChecker.storyBible.edgesTitle": "Co-ocurrencia de entidades (top)",
"consistencyChecker.storyBible.empty": "Activa «Story Bible avanzado» en Ajustes → IA → Indicadores de funciones, luego edita el manuscrito para extraer datos del grafo Codex.",
"consistencyChecker.storyBible.hintsTitle": "Sugerencias de coherencia",
@@ -286,6 +291,8 @@
"error.db.unknown": "Error desconocido al acceder a la base de datos.",
"error.deepLink.title": "Error al abrir el archivo del proyecto",
"error.deepLink.unknown": "Error desconocido",
+ "error.fallback.generic": "La IA no está disponible: se usó la asistencia integrada.",
+ "error.fallback.offline": "Estás sin conexión: se usó la asistencia integrada.",
"error.fileImportError": "Error de importación de archivo",
"error.mic.denied": "Acceso al micrófono denegado. Otorga permiso en los ajustes de tu navegador.",
"error.mic.generic": "Error de reconocimiento de voz: {{error}}",
@@ -382,22 +389,32 @@
"palette.voice.listeningLive": "Entrada de voz activa",
"palette.voice.start": "Iniciar búsqueda por voz",
"palette.voice.stop": "Detener búsqueda por voz",
+ "plotBoard.heuristic.complicate.description": "Añade un obstáculo o una revelación que obligue a cambiar de plan.",
+ "plotBoard.heuristic.complicate.rationale": "Una complicación nueva pone a prueba a los personajes y abre tramas.",
+ "plotBoard.heuristic.complicate.title": "Introducir una complicación",
+ "plotBoard.heuristic.escalate.description": "Incrementa la presión sobre tu protagonista para que la próxima decisión cueste más.",
+ "plotBoard.heuristic.escalate.rationale": "La escalada mantiene el ritmo cuando el desarrollo decae.",
+ "plotBoard.heuristic.escalate.title": "Aumentar lo que está en juego",
+ "plotBoard.heuristic.position": "Justo después de la escena seleccionada",
+ "plotBoard.heuristic.reverse.description": "Invierte una expectativa: un aliado falla, una victoria se amarga o una verdad oculta sale a la luz.",
+ "plotBoard.heuristic.reverse.rationale": "Los giros renuevan la tensión y profundizan el arco.",
+ "plotBoard.heuristic.reverse.title": "Añadir un giro",
"preview.controls.ariaLabel": "Controles de vista previa",
"preview.controls.decreaseFontSize": "Reducir tamaño de fuente",
"preview.controls.exitFullscreen": "Salir de pantalla completa",
"preview.controls.export": "Exportar (EPUB)",
- "preview.controls.pagedMode": "Vista de página",
- "preview.progress.ariaLabel": "Progreso de lectura",
"preview.controls.fontFamily": "Tipo de letra",
"preview.controls.fontMono": "Monoespaciado",
"preview.controls.fontSerif": "Serif",
"preview.controls.fontSystemUi": "Sistema",
"preview.controls.fullscreen": "Pantalla completa",
"preview.controls.increaseFontSize": "Aumentar tamaño de fuente",
+ "preview.controls.pagedMode": "Vista de página",
"preview.controls.wordCount": "Recuento de palabras",
"preview.emptyScene": "Sin contenido aún.",
"preview.noScenes": "El manuscrito está vacío",
"preview.noScenesHint": "Ve a la vista Manuscrito y añade tu primera escena para ver una vista previa aquí.",
+ "preview.progress.ariaLabel": "Progreso de lectura",
"preview.title": "Vista previa del libro",
"preview.toc.ariaLabel": "Tabla de contenidos",
"preview.toc.close": "Cerrar tabla de contenidos",
@@ -449,10 +466,6 @@
"proforge.progress.awaitingReviewHint": "⚠️ Esta etapa está esperando tu revisión. Haz clic en el botón de la etapa de arriba para revisar los elementos.",
"proforge.progress.completedStages": "Etapas completadas",
"proforge.progress.currentStatus": "Estado actual",
- "proforge.progress.overall": "Progreso general",
- "proforge.progress.preparing": "Preparando…",
- "proforge.progress.stageOfTotal": "Etapa {{current}} de {{total}}",
- "proforge.progress.percentComplete": "{{percent}} % completado",
"proforge.progress.itemsCount": "{{count}} elementos",
"proforge.progress.metric.aiCalls": "Llamadas a IA",
"proforge.progress.metric.duration": "Duración",
@@ -463,7 +476,11 @@
"proforge.progress.metric.totalTime": "Tiempo total",
"proforge.progress.metric.totalTokens": "Total de tokens",
"proforge.progress.noneRunning": "Ninguna canalización en ejecución.",
+ "proforge.progress.overall": "Progreso general",
+ "proforge.progress.percentComplete": "{{percent}} % completado",
+ "proforge.progress.preparing": "Preparando…",
"proforge.progress.stageDetails": "Detalles de la etapa: {{stage}}",
+ "proforge.progress.stageOfTotal": "Etapa {{current}} de {{total}}",
"proforge.progress.statusLabel": "Estado",
"proforge.progress.totals": "Totales de la canalización",
"proforge.review.accept": "Aceptar",
@@ -631,9 +648,9 @@
"sceneboard.act3.label": "Acto 3 – Resolución",
"sceneboard.addScene": "Añadir escena",
"sceneboard.addSceneToAct": "Añadir escena a este acto",
+ "sceneboard.ai.contextNote": "El análisis usa títulos de escena y líneas iniciales, hasta ~2.000 caracteres.",
"sceneboard.ai.empty": "Sin sugerencias. Vuelve a ejecutar con contenido.",
"sceneboard.ai.panelTitle": "Sugerencias de trama IA",
- "sceneboard.ai.contextNote": "El análisis usa títulos de escena y líneas iniciales, hasta ~2.000 caracteres.",
"sceneboard.ai.ragChunks": "{{count}} pasajes de la historia",
"sceneboard.ai.retry": "Sugerir de nuevo",
"sceneboard.ai.suggestBeat": "Sugerir beat IA",
@@ -777,9 +794,9 @@
"vc.title": "Historial de versiones",
"vc.words": "palabras",
"voice.cancelSpeech": "Cancelar voz",
+ "voice.feedback.confidence": "Confianza {{percent}}%",
"voice.modeChip.commands": "Comandos",
"voice.modeChip.dictation": "Dictado",
- "voice.feedback.confidence": "Confianza {{percent}}%",
"voice.panelLabel": "Control de voz",
"voice.permissionDenied": "Acceso al micrófono denegado. Permite el acceso al micrófono en la configuración de tu navegador.",
"voice.startDictation": "Iniciar dictado",
@@ -793,23 +810,6 @@
"voice.stopListening": "Detener escucha",
"worlds.emptyState.description": "Construye los lugares, reglas e historias en los que vive tu historia. Comienza con una ubicación.",
"worlds.emptyState.title": "El mundo te espera",
- "error.fallback.generic": "La IA no está disponible: se usó la asistencia integrada.",
- "error.fallback.offline": "Estás sin conexión: se usó la asistencia integrada.",
- "assisted.badge.label": "Asistido",
- "assisted.badge.srLabel": "Modo asistido: generado sin IA",
- "assisted.toast.title": "IA no disponible",
- "assisted.toast.description": "Se usó la asistencia integrada. Mejora con IA cuando haya un modelo disponible.",
- "assisted.enhance": "Mejorar con IA",
- "plotBoard.heuristic.position": "Justo después de la escena seleccionada",
- "plotBoard.heuristic.escalate.title": "Aumentar lo que está en juego",
- "plotBoard.heuristic.escalate.description": "Incrementa la presión sobre tu protagonista para que la próxima decisión cueste más.",
- "plotBoard.heuristic.escalate.rationale": "La escalada mantiene el ritmo cuando el desarrollo decae.",
- "plotBoard.heuristic.complicate.title": "Introducir una complicación",
- "plotBoard.heuristic.complicate.description": "Añade un obstáculo o una revelación que obligue a cambiar de plan.",
- "plotBoard.heuristic.complicate.rationale": "Una complicación nueva pone a prueba a los personajes y abre tramas.",
- "plotBoard.heuristic.reverse.title": "Añadir un giro",
- "plotBoard.heuristic.reverse.description": "Invierte una expectativa: un aliado falla, una victoria se amarga o una verdad oculta sale a la luz.",
- "plotBoard.heuristic.reverse.rationale": "Los giros renuevan la tensión y profundizan el arco.",
"copilot.annotationCount": "{{count}} insight for this chapter",
"copilot.announceClosed": "Copiloto IA cerrado",
"copilot.announceOpened": "Copiloto IA abierto",
@@ -877,11 +877,9 @@
"copilot.you": "Tú",
"dashboard.authorInsights.readability": "Legibilidad (Fernández Huerta, heurística ES)",
"dashboard.authorInsights.readabilityFootnote": "Puntuaciones más altas suelen leerse más fácil; afina según el género.",
- "dashboard.authorInsights.readabilityTooltip": "Escala de facilidad de lectura Flesch 0–100: más alto = más fácil de leer (60–70 es lenguaje sencillo). Es un indicador aproximado, no una nota normativa.",
- "dashboard.authorInsights.readabilityScaleSuffix": "/100",
- "dashboard.logline.updated": "Logline actualizada",
- "dashboard.logline.updatedUndo": "Pulsa Ctrl+Z para deshacer.",
"dashboard.authorInsights.readabilityNeedMore": "Escribe un poco más — se necesitan ~40+ palabras para un valor estable.",
+ "dashboard.authorInsights.readabilityScaleSuffix": "/100",
+ "dashboard.authorInsights.readabilityTooltip": "Escala de facilidad de lectura Flesch 0–100: más alto = más fácil de leer (60–70 es lenguaje sencillo). Es un indicador aproximado, no una nota normativa.",
"dashboard.authorInsights.timeline": "Comprobaciones de línea temporal",
"dashboard.authorInsights.timelineClear": "Sin avisos desde los metadatos de escena.",
"dashboard.authorInsights.timelineWarnBadge": "{{count}} avisos — revisa fechas/duraciones en el tablero.",
@@ -953,6 +951,8 @@
"dashboard.healthScore.title": "Salud del proyecto",
"dashboard.healthScore.world": "Construcción del mundo",
"dashboard.healthScore.writing": "Progreso de escritura",
+ "dashboard.logline.updated": "Logline actualizada",
+ "dashboard.logline.updatedUndo": "Pulsa Ctrl+Z para deshacer.",
"dashboard.loglineModal.loading": "Generando loglines brillantes...",
"dashboard.loglineModal.title": "Sugerencias de loglines IA",
"dashboard.momentum.activity": "Últimos 14 días",
@@ -986,23 +986,23 @@
"initialProject.chapter1": "Capítulo 1",
"initialProject.logline": "Un viaje de mil millas comienza con un solo paso...",
"initialProject.title": "Mi historia sin título",
- "desktop.menu.file": "Archivo",
+ "desktop.menu.commandPalette": "Paleta de comandos",
+ "desktop.menu.edit": "Editar",
"desktop.menu.export": "Exportar proyecto…",
+ "desktop.menu.file": "Archivo",
+ "desktop.menu.help": "Ayuda",
+ "desktop.menu.helpCenter": "Centro de ayuda",
"desktop.menu.settings": "Ajustes",
- "desktop.menu.edit": "Editar",
"desktop.menu.view": "Ver",
- "desktop.menu.commandPalette": "Paleta de comandos",
"desktop.menu.window": "Ventana",
- "desktop.menu.help": "Ayuda",
- "desktop.menu.helpCenter": "Centro de ayuda",
- "desktop.tray.tooltip": "WorldScript Studio",
- "desktop.tray.show": "Mostrar WorldScript Studio",
- "desktop.tray.settings": "Ajustes",
- "desktop.tray.commandPalette": "Paleta de comandos",
- "desktop.tray.quit": "Salir",
- "desktop.settings.sectionTitle": "Escritorio",
"desktop.settings.minimizeToTray": "Minimizar a la bandeja al cerrar",
"desktop.settings.minimizeToTrayHint": "Mantén WorldScript Studio en la bandeja del sistema en lugar de salir al cerrar la ventana.",
+ "desktop.settings.sectionTitle": "Escritorio",
+ "desktop.tray.commandPalette": "Paleta de comandos",
+ "desktop.tray.quit": "Salir",
+ "desktop.tray.settings": "Ajustes",
+ "desktop.tray.show": "Mostrar WorldScript Studio",
+ "desktop.tray.tooltip": "WorldScript Studio",
"export.ai.generateButton": "Generar sinopsis",
"export.ai.generating": "Generando...",
"export.ai.synopsis": "Generar sinopsis IA",
@@ -1090,10 +1090,10 @@
"export.pasteSection.importAsChapter": "Importar como capítulo",
"export.pasteSection.textPlaceholder": "Pega texto de Google Docs o Notion aquí (Ctrl+V)...",
"export.pasteSection.titlePlaceholder": "Título del capítulo (opcional)",
- "export.preview.noContent": "Selecciona contenido para ver una vista previa.",
"export.preview.modeLabel": "Modo de vista previa",
- "export.preview.modeText": "Texto",
"export.preview.modeRendered": "Renderizado",
+ "export.preview.modeText": "Texto",
+ "export.preview.noContent": "Selecciona contenido para ver una vista previa.",
"export.preview.title": "Vista previa en vivo",
"export.title": "Suite de publicación Export",
"export.toggleSection": "Alternar visibilidad para {{title}}",
@@ -1519,6 +1519,23 @@
"outline.deleteConfirm": "¿Estás seguro de querer eliminar esta sección del esquema?",
"outline.description": "Describe tu idea de historia y deja que la IA cree un esquema estructurado y editable para ti.",
"outline.error.generationFailed": "Error al generar el contenido. Por favor, inténtalo de nuevo.",
+ "outline.heuristic.beat.climax.desc": "El conflicto central llega a su punto culminante en la confrontación decisiva de la historia.",
+ "outline.heuristic.beat.climax.title": "Clímax",
+ "outline.heuristic.beat.complications.desc": "Los reveses y los conflictos se intensifican; el camino a seguir se estrecha.",
+ "outline.heuristic.beat.complications.title": "Complicaciones",
+ "outline.heuristic.beat.incitingIncident.desc": "El acontecimiento que pone en marcha la historia: {{idea}}.",
+ "outline.heuristic.beat.incitingIncident.title": "Incidente incitador",
+ "outline.heuristic.beat.midpoint.desc": "Un punto de inflexión cambia el rumbo de la historia y eleva lo que está en juego.",
+ "outline.heuristic.beat.midpoint.title": "Punto medio",
+ "outline.heuristic.beat.resolution.desc": "Se atan los cabos sueltos y surge un nuevo statu quo.",
+ "outline.heuristic.beat.resolution.title": "Resolución",
+ "outline.heuristic.beat.risingAction.desc": "Las complicaciones aumentan y lo que está en juego crece mientras los personajes persiguen su objetivo.",
+ "outline.heuristic.beat.risingAction.title": "Acción ascendente",
+ "outline.heuristic.beat.setup.desc": "Presenta el mundo y los personajes principales, y establece el statu quo antes de que todo cambie.",
+ "outline.heuristic.beat.setup.title": "Planteamiento",
+ "outline.heuristic.beat.twist.desc": "Una revelación inesperada trastoca lo que los personajes creían cierto.",
+ "outline.heuristic.beat.twist.title": "Giro",
+ "outline.heuristic.fallbackIdea": "la idea central",
"outline.idea.generateButton": "Generar esquema",
"outline.idea.genreLabel": "Género",
"outline.idea.genrePlaceholder": "ej. Ciencia ficción, Fantasía, Misterio",
@@ -1541,23 +1558,6 @@
"outline.result.twistTooltip": "Giro de trama generado por IA",
"outline.selectSection": "Seleccionar sección «{{title}}»",
"outline.title": "Generador de esquema de historia IA",
- "outline.heuristic.fallbackIdea": "la idea central",
- "outline.heuristic.beat.setup.title": "Planteamiento",
- "outline.heuristic.beat.setup.desc": "Presenta el mundo y los personajes principales, y establece el statu quo antes de que todo cambie.",
- "outline.heuristic.beat.incitingIncident.title": "Incidente incitador",
- "outline.heuristic.beat.incitingIncident.desc": "El acontecimiento que pone en marcha la historia: {{idea}}.",
- "outline.heuristic.beat.risingAction.title": "Acción ascendente",
- "outline.heuristic.beat.risingAction.desc": "Las complicaciones aumentan y lo que está en juego crece mientras los personajes persiguen su objetivo.",
- "outline.heuristic.beat.midpoint.title": "Punto medio",
- "outline.heuristic.beat.midpoint.desc": "Un punto de inflexión cambia el rumbo de la historia y eleva lo que está en juego.",
- "outline.heuristic.beat.complications.title": "Complicaciones",
- "outline.heuristic.beat.complications.desc": "Los reveses y los conflictos se intensifican; el camino a seguir se estrecha.",
- "outline.heuristic.beat.twist.title": "Giro",
- "outline.heuristic.beat.twist.desc": "Una revelación inesperada trastoca lo que los personajes creían cierto.",
- "outline.heuristic.beat.climax.title": "Clímax",
- "outline.heuristic.beat.climax.desc": "El conflicto central llega a su punto culminante en la confrontación decisiva de la historia.",
- "outline.heuristic.beat.resolution.title": "Resolución",
- "outline.heuristic.beat.resolution.desc": "Se atan los cabos sueltos y surge un nuevo statu quo.",
"portal.back": "Volver",
"portal.demo.chapterContent": "La niebla matinal cubría los muelles cuando Lyra desplegó el viejo plano de la ciudad. Un círculo apenas visible marcaba el noroeste — la torre de la que nadie hablaba.\n\nGuardó el papel y siguió el sendero hasta que la verja de hierro se alzó ante ella. El candado estaba cálido al sol; el metal seguía frío.",
"portal.demo.chapterTitle": "Capítulo 1 — Ante la verja",
@@ -1752,6 +1752,7 @@
"settings.ai.gpu.troubleshootLowEnd": "Su dispositivo tiene recursos limitados. La IA local usará modelos más pequeños. Cierre otras pestañas o active el modo eco.",
"settings.ai.gpu.troubleshootQueue": "Varias tareas de IA están en cola. Solo una se ejecuta a la vez para evitar colisiones de VRAM. Espere a que termine la tarea actual.",
"settings.ai.gpu.waitingConsumers": "En espera",
+ "settings.ai.grokKey": "Clave API de Grok",
"settings.ai.hybridFallbackHint": "Si el proveedor principal falla, WorldScript prueba los respaldos enumerados (generadores de escenas, herramientas de codex). La transmisión del escritor usa solo tu proveedor principal.",
"settings.ai.hybridFallbackTitle": "Respaldo híbrido (herramientas de IA del proyecto)",
"settings.ai.hybridFallbackToggle": "Activar cadena de respaldo",
@@ -1832,6 +1833,11 @@
"settings.ai.preset.lmStudio": "LM Studio",
"settings.ai.preset.ollamaDefault": "Ollama (puerto predeterminado)",
"settings.ai.preset.vllm": "vLLM",
+ "settings.ai.provider.anthropic": "Anthropic Claude",
+ "settings.ai.provider.gemini": "Google Gemini",
+ "settings.ai.provider.grok": "xAI Grok",
+ "settings.ai.provider.ollama": "Ollama (local)",
+ "settings.ai.provider.openai": "OpenAI",
"settings.ai.providerDescription": "Elige qué proveedor de IA debe usar WorldScript Studio.",
"settings.ai.providerOnnx": "ONNX (WASM)",
"settings.ai.providerStatusConnected": "Conectado",
@@ -2711,6 +2717,11 @@
"worlds.edit.notes": "Notas",
"worlds.editorTabsAriaLabel": "Pestañas del editor de mundo",
"worlds.error.imageFailed": "Error al generar la imagen de ambiente. Intenta añadir más detalles a la descripción del mundo.",
+ "worlds.heuristic.culture": "Describe los pueblos, creencias y la vida cotidiana moldeados por {{concept}}.",
+ "worlds.heuristic.description": "Un mundo definido por su premisa central: {{concept}}.",
+ "worlds.heuristic.geography": "Esboza las principales regiones, climas y rasgos naturales de {{concept}}.",
+ "worlds.heuristic.magicSystem": "Define las reglas, los costes y los límites del poder en {{concept}}.",
+ "worlds.heuristic.name": "Nuevo mundo",
"worlds.loading.profile": "Generando perfil de mundo detallado...",
"worlds.newWorldName": "Nuevo mundo",
"worlds.noWorlds": "Ningún mundo creado aún.",
@@ -2729,32 +2740,19 @@
"worlds.title": "Atlas de mundos",
"worlds.uploadImage": "Subir imagen",
"worlds.yourWorlds": "Tus mundos",
- "worlds.heuristic.name": "Nuevo mundo",
- "worlds.heuristic.description": "Un mundo definido por su premisa central: {{concept}}.",
- "worlds.heuristic.geography": "Esboza las principales regiones, climas y rasgos naturales de {{concept}}.",
- "worlds.heuristic.magicSystem": "Define las reglas, los costes y los límites del poder en {{concept}}.",
- "worlds.heuristic.culture": "Describe los pueblos, creencias y la vida cotidiana moldeados por {{concept}}.",
"writer.cancelledTag": "Cancelado",
"writer.chapter.label": "Capítulo: {{title}}",
- "writer.context.hide": "Ocultar contexto",
- "writer.context.label": "Contexto",
- "writer.context.show": "Mostrar contexto",
- "writer.flowMode.enterLabel": "Modo flujo",
- "writer.modeBadge.label": "Modos activos:",
- "writer.modeBadge.flow": "Flujo",
- "writer.modeBadge.focus": "Enfoque",
- "writer.modeBadge.proforge": "ProForge",
- "writer.modeBadge.contextHidden": "Contexto oculto",
- "writer.modeBadge.toolsHidden": "Herramientas ocultas",
- "writer.modeBadge.reset": "Restaurar diseño estándar",
- "writer.modeBadge.resetTitle": "Restablecer el diseño estándar de tres columnas",
"writer.coachmark.dismiss": "Entendido",
- "writer.coachmark.flow.title": "Modo flujo",
"writer.coachmark.flow.body": "Solo se muestra el panel de escritura; todo lo demás queda oculto. Pulsa Esc o \"Restaurar diseño estándar\" para volver.",
- "writer.coachmark.focus.title": "Modo enfoque",
+ "writer.coachmark.flow.title": "Modo flujo",
"writer.coachmark.focus.body": "Muestra el manuscrito y el contexto en paralelo, ocultando la columna de herramientas. Desactívalo cuando quieras desde la cabecera.",
- "writer.coachmark.proforge.title": "Canalización ProForge",
+ "writer.coachmark.focus.title": "Modo enfoque",
"writer.coachmark.proforge.body": "La columna de herramientas ahora ejecuta la canalización de edición de varias etapas. Tu manuscrito nunca se modifica sin tu revisión.",
+ "writer.coachmark.proforge.title": "Canalización ProForge",
+ "writer.context.hide": "Ocultar contexto",
+ "writer.context.label": "Contexto",
+ "writer.context.show": "Mostrar contexto",
+ "writer.flowMode.enterLabel": "Modo flujo",
"writer.flowMode.exit": "Salir del modo flujo",
"writer.flowMode.exitLabel": "Salir del flujo",
"writer.flowMode.hint": "Escribe sin interrupciones. Pulsa Esc para volver.",
@@ -2763,9 +2761,31 @@
"writer.focusMode.enterLabel": "Modo enfoque",
"writer.focusMode.exit": "Salir del modo enfoque",
"writer.focusMode.exitLabel": "Salir del enfoque",
+ "writer.grammar.addToDictionary": "Añadir al diccionario",
+ "writer.grammar.apply": "Aplicar",
+ "writer.grammar.checkButton": "Revisar esta escena",
+ "writer.grammar.checking": "Revisando…",
+ "writer.grammar.disabled": "Activa LanguageTool en Ajustes → Conexiones para revisar esta escena.",
+ "writer.grammar.error": "El servidor de LanguageTool devolvió un error.",
+ "writer.grammar.ignore": "Ignorar",
+ "writer.grammar.issuesFound": "{{count}} problemas encontrados",
+ "writer.grammar.noIssues": "No se encontraron problemas.",
+ "writer.grammar.noSuggestions": "Sin sugerencias",
+ "writer.grammar.offline": "No se pudo conectar con el servidor de LanguageTool. ¿Está en marcha?",
+ "writer.grammar.selectScene": "Selecciona una escena para revisar.",
+ "writer.grammar.title": "Gramática y ortografía",
+ "writer.grammar.unsupported": "La revisión gramatical no está disponible para este idioma.",
"writer.imagePrompt.description": "Genera un prompt optimizado para DALL·E 3 / Midjourney a partir de la escena actual o la selección de texto.",
"writer.imagePrompt.note": "El prompt generado funciona directamente en DALL·E 3 y Midjourney.",
"writer.imagePrompt.tip": "Consejo: Selecciona una sección de texto específica para un prompt de escena enfocado.",
+ "writer.modeBadge.contextHidden": "Contexto oculto",
+ "writer.modeBadge.flow": "Flujo",
+ "writer.modeBadge.focus": "Enfoque",
+ "writer.modeBadge.label": "Modos activos:",
+ "writer.modeBadge.proforge": "ProForge",
+ "writer.modeBadge.reset": "Restaurar diseño estándar",
+ "writer.modeBadge.resetTitle": "Restablecer el diseño estándar de tres columnas",
+ "writer.modeBadge.toolsHidden": "Herramientas ocultas",
"writer.stopGenerating": "Detener generación",
"writer.studio.context.contentPlaceholder": "Selecciona o crea una sección del manuscrito para comenzar.",
"writer.studio.context.sectionLabel": "Sección de trabajo",
@@ -2787,12 +2807,10 @@
"writer.studio.controls.tones.poetic": "Más poético",
"writer.studio.controls.tones.suspenseful": "Más suspensivo",
"writer.studio.description": "Tu coautor IA. Genera, mejora y haz brainstorming con el contexto completo del proyecto.",
+ "writer.studio.rag.chunkScore": "relevancia {{score}}",
"writer.studio.rag.chunksBadge": "{{count}} pasajes encontrados",
"writer.studio.rag.chunksHint": "Fragmentos relevantes de tu manuscrito — más pasajes significa un contexto de IA más rico",
"writer.studio.rag.inspectorLabel": "Contexto recuperado",
- "writer.studio.rag.chunkScore": "relevancia {{score}}",
- "writer.studio.tokens.badge": "~{{count}} tokens",
- "writer.studio.tokens.hint": "Tokens aproximados usados por tu última solicitud de IA",
"writer.studio.rag.useContext": "Extraer de mi historia",
"writer.studio.result.insert": "Insertar",
"writer.studio.result.next": "Siguiente",
@@ -2802,6 +2820,8 @@
"writer.studio.result.retry": "Reintentar",
"writer.studio.result.title": "Borrador IA",
"writer.studio.title": "Estudio de escritura IA",
+ "writer.studio.tokens.badge": "~{{count}} tokens",
+ "writer.studio.tokens.hint": "Tokens aproximados usados por tu última solicitud de IA",
"writer.studio.tools.brainstorm.contextLabel": "Contexto de brainstorming (opcional)",
"writer.studio.tools.brainstorm.contextPlaceholder": "Proporciona una breve situación, o la IA usará la sección del manuscrito actual.",
"writer.studio.tools.brainstorm.title": "Hacer brainstorming",
@@ -2833,19 +2853,5 @@
"writer.tts.start": "Leer en voz alta",
"writer.tts.stop": "Detener lectura",
"writer.versionControl.label": "Versiones",
- "writer.versionControl.tooltip": "Control de versiones (ramas e instantáneas)",
- "writer.grammar.title": "Gramática y ortografía",
- "writer.grammar.checkButton": "Revisar esta escena",
- "writer.grammar.checking": "Revisando…",
- "writer.grammar.issuesFound": "{{count}} problemas encontrados",
- "writer.grammar.noIssues": "No se encontraron problemas.",
- "writer.grammar.selectScene": "Selecciona una escena para revisar.",
- "writer.grammar.unsupported": "La revisión gramatical no está disponible para este idioma.",
- "writer.grammar.disabled": "Activa LanguageTool en Ajustes → Conexiones para revisar esta escena.",
- "writer.grammar.offline": "No se pudo conectar con el servidor de LanguageTool. ¿Está en marcha?",
- "writer.grammar.error": "El servidor de LanguageTool devolvió un error.",
- "writer.grammar.apply": "Aplicar",
- "writer.grammar.ignore": "Ignorar",
- "writer.grammar.addToDictionary": "Añadir al diccionario",
- "writer.grammar.noSuggestions": "Sin sugerencias"
+ "writer.versionControl.tooltip": "Control de versiones (ramas e instantáneas)"
}
diff --git a/public/locales/eu/bundle.json b/public/locales/eu/bundle.json
index 9bfb5856..36cc87f4 100644
--- a/public/locales/eu/bundle.json
+++ b/public/locales/eu/bundle.json
@@ -90,6 +90,14 @@
"characters.edit.relationships": "Harremanak",
"characters.editorTabsAriaLabel": "Karaktere-editorearen fitxak",
"characters.error.portraitFailed": "Erretratuak sortzeak huts egin du. Saiatu itxuraren deskribapenari xehetasun gehiago gehitzen.",
+ "characters.heuristic.appearance": "Describe how they present themselves — let their look hint at {{concept}}.",
+ "characters.heuristic.backstory": "Shaped by formative experiences, this character carries a past tied to {{concept}}.",
+ "characters.heuristic.characterArc": "They begin guarded and, through the story, are changed by {{concept}}.",
+ "characters.heuristic.flaws": "A weakness that complicates their goals.",
+ "characters.heuristic.motivation": "A core desire connected to {{concept}} drives their choices.",
+ "characters.heuristic.name": "New Character",
+ "characters.heuristic.personalityTraits": "Resourceful, guarded, determined.",
+ "characters.heuristic.relationships": "Note the key bonds and rivalries that define them.",
"characters.loading.profile": "Profil zehatza sortzen...",
"characters.newCharacterName": "Pertsonaia berria",
"characters.noCharacters": "Ez dago pertsonaiarik sortu oraindik.",
@@ -107,14 +115,6 @@
"characters.title": "Pertsonaien Dosierra",
"characters.uploadImage": "Igo irudia",
"characters.yourCharacters": "Zure Pertsonaiak",
- "characters.heuristic.name": "New Character",
- "characters.heuristic.backstory": "Shaped by formative experiences, this character carries a past tied to {{concept}}.",
- "characters.heuristic.motivation": "A core desire connected to {{concept}} drives their choices.",
- "characters.heuristic.appearance": "Describe how they present themselves — let their look hint at {{concept}}.",
- "characters.heuristic.personalityTraits": "Resourceful, guarded, determined.",
- "characters.heuristic.flaws": "A weakness that complicates their goals.",
- "characters.heuristic.characterArc": "They begin guarded and, through the story, are changed by {{concept}}.",
- "characters.heuristic.relationships": "Note the key bonds and rivalries that define them.",
"apiKey.connectionFailed": "Konexio-probak huts egin du.",
"apiKey.connectionSuccess": "Konexioa arrakastatsua da! APIak behar bezala erantzuten du.",
"apiKey.decryptFailed": "Ezin izan da deszifratu API gakoa",
@@ -125,6 +125,11 @@
"apiKey.test": "Probatu konexioa",
"apiKey.testConnection": "Probatu API konexioa",
"apiKey.testing": "Proba egiten…",
+ "assisted.badge.label": "Assisted",
+ "assisted.badge.srLabel": "Assisted mode — generated without AI",
+ "assisted.enhance": "Enhance with AI",
+ "assisted.toast.description": "Used built-in assistance. Enhance with AI when a model is available.",
+ "assisted.toast.title": "AI unavailable",
"charGraph.characters": "Pertsonaiak",
"charGraph.noCharacters": "Oraindik ez dago pertsonaiarik",
"charGraph.noCharactersHint": "Gehitu karaktereak Pertsonaiak ikuspegian haien harremanak hemen ikusteko.",
@@ -286,6 +291,8 @@
"error.db.unknown": "Errore ezezaguna datu-basera sartzean.",
"error.deepLink.title": "Ezin izan da proiektuaren fitxategia ireki",
"error.deepLink.unknown": "Errore ezezaguna",
+ "error.fallback.generic": "AI is unavailable — used built-in assistance.",
+ "error.fallback.offline": "You're offline — used built-in assistance.",
"error.fileImportError": "Fitxategia inportatzeko errorea",
"error.mic.denied": "Mikrofonorako sarbidea ukatu da. Mesedez, eman baimena arakatzailearen ezarpenetan.",
"error.mic.generic": "Ahots-ezagutze errorea: {{error}}",
@@ -382,6 +389,16 @@
"palette.voice.listeningLive": "Ahots-sarrera aktibo dago",
"palette.voice.start": "Hasi ahots bidezko bilaketa",
"palette.voice.stop": "Gelditu ahots bidezko bilaketa",
+ "plotBoard.heuristic.complicate.description": "Add an obstacle or reveal that forces a change of plan.",
+ "plotBoard.heuristic.complicate.rationale": "A fresh complication tests the characters and opens new threads.",
+ "plotBoard.heuristic.complicate.title": "Introduce a complication",
+ "plotBoard.heuristic.escalate.description": "Increase the pressure on your protagonist so the next choice costs more.",
+ "plotBoard.heuristic.escalate.rationale": "Escalation keeps momentum when the middle sags.",
+ "plotBoard.heuristic.escalate.title": "Raise the stakes",
+ "plotBoard.heuristic.position": "Right after the selected scene",
+ "plotBoard.heuristic.reverse.description": "Flip an expectation — an ally falters, a win turns sour, or a hidden truth surfaces.",
+ "plotBoard.heuristic.reverse.rationale": "Reversals refresh tension and deepen the arc.",
+ "plotBoard.heuristic.reverse.title": "Add a reversal",
"preview.controls.ariaLabel": "Aurrebista kontrolak",
"preview.controls.decreaseFontSize": "Murriztu letra-tamaina",
"preview.controls.exitFullscreen": "Irten pantaila osotik",
@@ -449,10 +466,6 @@
"proforge.progress.awaitingReviewHint": "⚠️ Etapa hau zure iritziaren zain dago. Egin klik goiko faseko botoian elementuak berrikusteko.",
"proforge.progress.completedStages": "Etapa amaituta",
"proforge.progress.currentStatus": "Egungo egoera",
- "proforge.progress.overall": "Overall progress",
- "proforge.progress.preparing": "Preparing…",
- "proforge.progress.stageOfTotal": "Stage {{current}} of {{total}}",
- "proforge.progress.percentComplete": "{{percent}}% complete",
"proforge.progress.itemsCount": "{{count}} elementuak",
"proforge.progress.metric.aiCalls": "AI Deiak",
"proforge.progress.metric.duration": "Iraupena",
@@ -463,7 +476,11 @@
"proforge.progress.metric.totalTime": "Denbora osoa",
"proforge.progress.metric.totalTokens": "Tokens guztira",
"proforge.progress.noneRunning": "Ez dago kanalizaziorik martxan.",
+ "proforge.progress.overall": "Overall progress",
+ "proforge.progress.percentComplete": "{{percent}}% complete",
+ "proforge.progress.preparing": "Preparing…",
"proforge.progress.stageDetails": "Etapa xehetasunak: {{stage}}",
+ "proforge.progress.stageOfTotal": "Stage {{current}} of {{total}}",
"proforge.progress.statusLabel": "Egoera",
"proforge.progress.totals": "Pipeline Totalak",
"proforge.review.accept": "Onartu",
@@ -777,9 +794,9 @@
"vc.title": "Bertsioen Historia",
"vc.words": "hitzak",
"voice.cancelSpeech": "Hitzaldia bertan behera utzi",
+ "voice.feedback.confidence": "Konfiantza: {{percent}}%",
"voice.modeChip.commands": "Komandoak",
"voice.modeChip.dictation": "Diktaketa",
- "voice.feedback.confidence": "Konfiantza: {{percent}}%",
"voice.panelLabel": "Ahots kontrola",
"voice.permissionDenied": "Mikrofonorako sarbidea ukatu da. Mesedez, baimendu mikrofonorako sarbidea zure arakatzailearen ezarpenetan ahots-eginbideak erabiltzeko.",
"voice.startDictation": "Hasi diktaketa",
@@ -793,23 +810,6 @@
"voice.stopListening": "Utzi entzuteari",
"worlds.emptyState.description": "Eraiki zure istorioa bizi den lekuak, arauak eta historiak. Hasi kokapen batekin.",
"worlds.emptyState.title": "Mundua zain dago",
- "error.fallback.generic": "AI is unavailable — used built-in assistance.",
- "error.fallback.offline": "You're offline — used built-in assistance.",
- "assisted.badge.label": "Assisted",
- "assisted.badge.srLabel": "Assisted mode — generated without AI",
- "assisted.toast.title": "AI unavailable",
- "assisted.toast.description": "Used built-in assistance. Enhance with AI when a model is available.",
- "assisted.enhance": "Enhance with AI",
- "plotBoard.heuristic.position": "Right after the selected scene",
- "plotBoard.heuristic.escalate.title": "Raise the stakes",
- "plotBoard.heuristic.escalate.description": "Increase the pressure on your protagonist so the next choice costs more.",
- "plotBoard.heuristic.escalate.rationale": "Escalation keeps momentum when the middle sags.",
- "plotBoard.heuristic.complicate.title": "Introduce a complication",
- "plotBoard.heuristic.complicate.description": "Add an obstacle or reveal that forces a change of plan.",
- "plotBoard.heuristic.complicate.rationale": "A fresh complication tests the characters and opens new threads.",
- "plotBoard.heuristic.reverse.title": "Add a reversal",
- "plotBoard.heuristic.reverse.description": "Flip an expectation — an ally falters, a win turns sour, or a hidden truth surfaces.",
- "plotBoard.heuristic.reverse.rationale": "Reversals refresh tension and deepen the arc.",
"copilot.annotationCount": "{{count}} kapitulu honetarako ikuspegia",
"copilot.announceClosed": "AI Copilot itxita",
"copilot.announceOpened": "AI Copilot ireki da",
@@ -1090,10 +1090,10 @@
"export.pasteSection.importAsChapter": "Inportatu kapitulu gisa",
"export.pasteSection.textPlaceholder": "Itsatsi Google Docs edo Notion-eko testua hemen (Ktrl+V)...",
"export.pasteSection.titlePlaceholder": "Kapituluaren izenburua (aukerakoa)",
- "export.preview.noContent": "Hautatu edukia aurrebista ikusteko.",
"export.preview.modeLabel": "Aurrebista modua",
- "export.preview.modeText": "Testua",
"export.preview.modeRendered": "Errendatua",
+ "export.preview.modeText": "Testua",
+ "export.preview.noContent": "Hautatu edukia aurrebista ikusteko.",
"export.preview.title": "Zuzeneko aurrebista",
"export.title": "Esportatu Argitalpen Suite",
"export.toggleSection": "Aldatu ikusgaitasuna {{title}}",
@@ -1519,6 +1519,23 @@
"outline.deleteConfirm": "Ziur eskema-atal hau ezabatu nahi duzula?",
"outline.description": "Deskribatu zure istorioaren ideia eta utzi AI-ri eskema egituratu eta editagarria sortzen zuretzako.",
"outline.error.generationFailed": "Ezin izan da edukia sortu. Mesedez, saiatu berriro.",
+ "outline.heuristic.beat.climax.desc": "The central conflict comes to a head in the story's defining confrontation.",
+ "outline.heuristic.beat.climax.title": "Climax",
+ "outline.heuristic.beat.complications.desc": "Setbacks and conflicts deepen; the path forward narrows.",
+ "outline.heuristic.beat.complications.title": "Complications",
+ "outline.heuristic.beat.incitingIncident.desc": "The event that sets the story in motion: {{idea}}.",
+ "outline.heuristic.beat.incitingIncident.title": "Inciting Incident",
+ "outline.heuristic.beat.midpoint.desc": "A turning point shifts the direction of the story and raises the stakes.",
+ "outline.heuristic.beat.midpoint.title": "Midpoint",
+ "outline.heuristic.beat.resolution.desc": "Loose ends are tied up and a new status quo emerges.",
+ "outline.heuristic.beat.resolution.title": "Resolution",
+ "outline.heuristic.beat.risingAction.desc": "Complications escalate and the stakes grow as the characters pursue their goal.",
+ "outline.heuristic.beat.risingAction.title": "Rising Action",
+ "outline.heuristic.beat.setup.desc": "Introduce the world and the main characters, and establish the status quo before everything changes.",
+ "outline.heuristic.beat.setup.title": "Setup",
+ "outline.heuristic.beat.twist.desc": "An unexpected revelation upends what the characters believed to be true.",
+ "outline.heuristic.beat.twist.title": "Twist",
+ "outline.heuristic.fallbackIdea": "the central idea",
"outline.idea.generateButton": "Sortu eskema",
"outline.idea.genreLabel": "Generoa",
"outline.idea.genrePlaceholder": "adibidez, Zientzia-Fikzioa, Fantasia, Misterioa",
@@ -1541,23 +1558,6 @@
"outline.result.twistTooltip": "AI-k sortutako trama bira",
"outline.selectSection": "Hautatu '{{title}}' atala",
"outline.title": "AI Story Outline Generator",
- "outline.heuristic.fallbackIdea": "the central idea",
- "outline.heuristic.beat.setup.title": "Setup",
- "outline.heuristic.beat.setup.desc": "Introduce the world and the main characters, and establish the status quo before everything changes.",
- "outline.heuristic.beat.incitingIncident.title": "Inciting Incident",
- "outline.heuristic.beat.incitingIncident.desc": "The event that sets the story in motion: {{idea}}.",
- "outline.heuristic.beat.risingAction.title": "Rising Action",
- "outline.heuristic.beat.risingAction.desc": "Complications escalate and the stakes grow as the characters pursue their goal.",
- "outline.heuristic.beat.midpoint.title": "Midpoint",
- "outline.heuristic.beat.midpoint.desc": "A turning point shifts the direction of the story and raises the stakes.",
- "outline.heuristic.beat.complications.title": "Complications",
- "outline.heuristic.beat.complications.desc": "Setbacks and conflicts deepen; the path forward narrows.",
- "outline.heuristic.beat.twist.title": "Twist",
- "outline.heuristic.beat.twist.desc": "An unexpected revelation upends what the characters believed to be true.",
- "outline.heuristic.beat.climax.title": "Climax",
- "outline.heuristic.beat.climax.desc": "The central conflict comes to a head in the story's defining confrontation.",
- "outline.heuristic.beat.resolution.title": "Resolution",
- "outline.heuristic.beat.resolution.desc": "Loose ends are tied up and a new status quo emerges.",
"portal.back": "Atzera",
"portal.demo.chapterContent": "Goizeko lainoa kaietan itsatsita zegoen Lyrak hiriko mapa zaharra zabaldu zuenean. Zirkulu ahul batek ipar-mendebaldeko izkina markatzen zuen — inork aipatzen ez zuen dorrea.\n\nPapera gorde eta bide estuari jarraitu zion burdinazko sareta haren aurrean altxatu zen arte. Giltzarrapoa epela zegoen eguzkitan; metala, berriz, hotza oraindik.",
"portal.demo.chapterTitle": "1. kapitulua — Atearen aurrean",
@@ -1752,6 +1752,7 @@
"settings.ai.gpu.troubleshootLowEnd": "Zure gailuak baliabide mugatuak ditu. Tokiko AI eredu txikiagoak erabiliko ditu. Errendimendu hobea lortzeko, itxi beste arakatzailearen fitxak edo gaitu Eco modua.",
"settings.ai.gpu.troubleshootQueue": "AI ataza anitz daude ilaran. Bat bakarrik exekutatzen da aldi berean VRAM talkak saihesteko. Itxaron uneko zeregina amaitu arte.",
"settings.ai.gpu.waitingConsumers": "Zain",
+ "settings.ai.grokKey": "Grok API Key",
"settings.ai.hybridFallbackHint": "Hornitzaile nagusiak huts egiten badu, WorldScript-ek zerrendatutako ordezkapenak probatzen ditu (eszena-sortzaileak, kodex-tresnak). Writer-ek zure hornitzaile nagusia soilik erabiltzen du.",
"settings.ai.hybridFallbackTitle": "Erreplika hibridoa (proiektuaren AI tresnak)",
"settings.ai.hybridFallbackToggle": "Gaitu ordezko katea",
@@ -1832,6 +1833,11 @@
"settings.ai.preset.lmStudio": "LM estudioa",
"settings.ai.preset.ollamaDefault": "Ollama (ataka lehenetsia)",
"settings.ai.preset.vllm": "vLLM",
+ "settings.ai.provider.anthropic": "Anthropic Claude",
+ "settings.ai.provider.gemini": "Google Gemini",
+ "settings.ai.provider.grok": "xAI Grok",
+ "settings.ai.provider.ollama": "Ollama (local)",
+ "settings.ai.provider.openai": "OpenAI",
"settings.ai.providerDescription": "Aukeratu zein AI hornitzaile erabili behar duen WorldScript Studio-k.",
"settings.ai.providerOnnx": "ONNX (WASM)",
"settings.ai.providerStatusConnected": "Konektatuta",
@@ -2711,6 +2717,11 @@
"worlds.edit.notes": "Oharrak",
"worlds.editorTabsAriaLabel": "Munduko editorearen fitxak",
"worlds.error.imageFailed": "Huts egin du giroko irudiak sortzea. Mesedez, saiatu munduaren deskribapenari xehetasun gehiago gehitzen edo egiaztatu zure konexioa.",
+ "worlds.heuristic.culture": "Describe the peoples, beliefs, and daily life shaped by {{concept}}.",
+ "worlds.heuristic.description": "A world defined by its central premise: {{concept}}.",
+ "worlds.heuristic.geography": "Outline the major regions, climates, and natural features of {{concept}}.",
+ "worlds.heuristic.magicSystem": "Define the rules, costs, and limits of power in {{concept}}.",
+ "worlds.heuristic.name": "New World",
"worlds.loading.profile": "Munduko profil zehatza sortzen...",
"worlds.newWorldName": "Mundu Berria",
"worlds.noWorlds": "Oraindik ez dago mundurik sortu.",
@@ -2729,11 +2740,6 @@
"worlds.title": "Munduko Atlasa",
"worlds.uploadImage": "Igo irudia",
"worlds.yourWorlds": "Zure Munduak",
- "worlds.heuristic.name": "New World",
- "worlds.heuristic.description": "A world defined by its central premise: {{concept}}.",
- "worlds.heuristic.geography": "Outline the major regions, climates, and natural features of {{concept}}.",
- "worlds.heuristic.magicSystem": "Define the rules, costs, and limits of power in {{concept}}.",
- "worlds.heuristic.culture": "Describe the peoples, beliefs, and daily life shaped by {{concept}}.",
"writer.cancelledTag": "Bertan behera utzita",
"writer.chapter.label": "Kapitulua: {{title}}",
"writer.coachmark.dismiss": "Got it",
@@ -2755,6 +2761,20 @@
"writer.focusMode.enterLabel": "Foku modua",
"writer.focusMode.exit": "Irten foku modutik",
"writer.focusMode.exitLabel": "Irten fokua",
+ "writer.grammar.addToDictionary": "Add to dictionary",
+ "writer.grammar.apply": "Apply",
+ "writer.grammar.checkButton": "Check this scene",
+ "writer.grammar.checking": "Checking…",
+ "writer.grammar.disabled": "Enable LanguageTool in Settings → Connections to check this scene.",
+ "writer.grammar.error": "The LanguageTool server returned an error.",
+ "writer.grammar.ignore": "Ignore",
+ "writer.grammar.issuesFound": "{{count}} issues found",
+ "writer.grammar.noIssues": "No issues found.",
+ "writer.grammar.noSuggestions": "No suggestions",
+ "writer.grammar.offline": "Couldn't reach the LanguageTool server. Is it running?",
+ "writer.grammar.selectScene": "Select a scene to check.",
+ "writer.grammar.title": "Grammar & Spelling",
+ "writer.grammar.unsupported": "Grammar check isn't available for this language.",
"writer.imagePrompt.description": "DALL·E 3 / Midjourney gonbita optimizatua sortzen du uneko eszena edo testu hautapenetik.",
"writer.imagePrompt.note": "Sortutako gonbita zuzenean funtzionatzen du DALL·E 3 eta Midjourney-n.",
"writer.imagePrompt.tip": "Aholkua: hautatu testu-atal zehatz bat eszena fokatutako gonbita baterako.",
@@ -2787,12 +2807,10 @@
"writer.studio.controls.tones.poetic": "Poetikoagoa",
"writer.studio.controls.tones.suspenseful": "Suspense gehiago",
"writer.studio.description": "Zure AI egilekidea. Sortu, hobetu eta ideia-jasa proiektuaren testuinguru osoarekin.",
+ "writer.studio.rag.chunkScore": "garrantzia {{score}}",
"writer.studio.rag.chunksBadge": "{{count}} istorioko pasarteak aurkitu dira",
"writer.studio.rag.chunksHint": "Zure eskuizkribuaren pasarte garrantzitsuak: pasarte gehiago AI testuinguru aberatsagoa dakar",
"writer.studio.rag.inspectorLabel": "Berreskuratutako testuingurua",
- "writer.studio.rag.chunkScore": "garrantzia {{score}}",
- "writer.studio.tokens.badge": "~{{count}} token",
- "writer.studio.tokens.hint": "Azken AI eskaeran erabilitako gutxi gorabeherako tokenak",
"writer.studio.rag.useContext": "Tira nire istoriotik",
"writer.studio.result.insert": "Txertatu",
"writer.studio.result.next": "Hurrengoa",
@@ -2802,6 +2820,8 @@
"writer.studio.result.retry": "Saiatu berriro",
"writer.studio.result.title": "AI Scratchpad",
"writer.studio.title": "AI Writing Studio",
+ "writer.studio.tokens.badge": "~{{count}} token",
+ "writer.studio.tokens.hint": "Azken AI eskaeran erabilitako gutxi gorabeherako tokenak",
"writer.studio.tools.brainstorm.contextLabel": "Brainstorming testuingurua (aukerakoa)",
"writer.studio.tools.brainstorm.contextPlaceholder": "Eman egoera labur bat, edo AIak eskuizkribuen atala erabiliko du.",
"writer.studio.tools.brainstorm.title": "Brainstorm Ideiak",
@@ -2833,19 +2853,5 @@
"writer.tts.start": "Irakurri ozen",
"writer.tts.stop": "Utzi irakurtzeari",
"writer.versionControl.label": "Bertsioak",
- "writer.versionControl.tooltip": "Bertsio-kontrola (adarrak eta argazkiak)",
- "writer.grammar.title": "Grammar & Spelling",
- "writer.grammar.checkButton": "Check this scene",
- "writer.grammar.checking": "Checking…",
- "writer.grammar.issuesFound": "{{count}} issues found",
- "writer.grammar.noIssues": "No issues found.",
- "writer.grammar.selectScene": "Select a scene to check.",
- "writer.grammar.unsupported": "Grammar check isn't available for this language.",
- "writer.grammar.disabled": "Enable LanguageTool in Settings → Connections to check this scene.",
- "writer.grammar.offline": "Couldn't reach the LanguageTool server. Is it running?",
- "writer.grammar.error": "The LanguageTool server returned an error.",
- "writer.grammar.apply": "Apply",
- "writer.grammar.ignore": "Ignore",
- "writer.grammar.addToDictionary": "Add to dictionary",
- "writer.grammar.noSuggestions": "No suggestions"
+ "writer.versionControl.tooltip": "Bertsio-kontrola (adarrak eta argazkiak)"
}
diff --git a/public/locales/fa/bundle.json b/public/locales/fa/bundle.json
index ce2e417d..f45a93be 100644
--- a/public/locales/fa/bundle.json
+++ b/public/locales/fa/bundle.json
@@ -90,6 +90,14 @@
"characters.edit.relationships": "روابط",
"characters.editorTabsAriaLabel": "برگه های ویرایشگر کاراکتر",
"characters.error.portraitFailed": "تولید پرتره شکست خورد. سعی کنید جزئیات بیشتری را به توضیحات ظاهر اضافه کنید.",
+ "characters.heuristic.appearance": "Describe how they present themselves — let their look hint at {{concept}}.",
+ "characters.heuristic.backstory": "Shaped by formative experiences, this character carries a past tied to {{concept}}.",
+ "characters.heuristic.characterArc": "They begin guarded and, through the story, are changed by {{concept}}.",
+ "characters.heuristic.flaws": "A weakness that complicates their goals.",
+ "characters.heuristic.motivation": "A core desire connected to {{concept}} drives their choices.",
+ "characters.heuristic.name": "New Character",
+ "characters.heuristic.personalityTraits": "Resourceful, guarded, determined.",
+ "characters.heuristic.relationships": "Note the key bonds and rivalries that define them.",
"characters.loading.profile": "ایجاد نمایه دقیق...",
"characters.newCharacterName": "شخصیت جدید",
"characters.noCharacters": "هنوز هیچ شخصیتی ایجاد نشده است.",
@@ -107,14 +115,6 @@
"characters.title": "پرونده شخصیت",
"characters.uploadImage": "آپلود تصویر",
"characters.yourCharacters": "شخصیت های شما",
- "characters.heuristic.name": "New Character",
- "characters.heuristic.backstory": "Shaped by formative experiences, this character carries a past tied to {{concept}}.",
- "characters.heuristic.motivation": "A core desire connected to {{concept}} drives their choices.",
- "characters.heuristic.appearance": "Describe how they present themselves — let their look hint at {{concept}}.",
- "characters.heuristic.personalityTraits": "Resourceful, guarded, determined.",
- "characters.heuristic.flaws": "A weakness that complicates their goals.",
- "characters.heuristic.characterArc": "They begin guarded and, through the story, are changed by {{concept}}.",
- "characters.heuristic.relationships": "Note the key bonds and rivalries that define them.",
"apiKey.connectionFailed": "تست اتصال ناموفق بود.",
"apiKey.connectionSuccess": "اتصال موفق شد! API به درستی پاسخ می دهد.",
"apiKey.decryptFailed": "کلید API را نمی توان رمزگشایی کرد",
@@ -125,6 +125,11 @@
"apiKey.test": "تست اتصال",
"apiKey.testConnection": "اتصال API را آزمایش کنید",
"apiKey.testing": "تست…",
+ "assisted.badge.label": "Assisted",
+ "assisted.badge.srLabel": "Assisted mode — generated without AI",
+ "assisted.enhance": "Enhance with AI",
+ "assisted.toast.description": "Used built-in assistance. Enhance with AI when a model is available.",
+ "assisted.toast.title": "AI unavailable",
"charGraph.characters": "شخصیت ها",
"charGraph.noCharacters": "هنوز هیچ شخصیتی وجود ندارد",
"charGraph.noCharactersHint": "کاراکترها را در نمای کاراکترها اضافه کنید تا روابط آنها را در اینجا تجسم کنید.",
@@ -286,6 +291,8 @@
"error.db.unknown": "خطای ناشناخته هنگام دسترسی به پایگاه داده.",
"error.deepLink.title": "فایل پروژه باز نشد",
"error.deepLink.unknown": "خطای ناشناخته",
+ "error.fallback.generic": "AI is unavailable — used built-in assistance.",
+ "error.fallback.offline": "You're offline — used built-in assistance.",
"error.fileImportError": "خطای وارد کردن فایل",
"error.mic.denied": "دسترسی به میکروفون رد شد. لطفاً در تنظیمات مرورگر خود مجوز بدهید.",
"error.mic.generic": "خطای تشخیص گفتار: {{error}}",
@@ -382,6 +389,16 @@
"palette.voice.listeningLive": "ورودی صوتی فعال است",
"palette.voice.start": "جستجوی صوتی را شروع کنید",
"palette.voice.stop": "توقف جستجوی صوتی",
+ "plotBoard.heuristic.complicate.description": "Add an obstacle or reveal that forces a change of plan.",
+ "plotBoard.heuristic.complicate.rationale": "A fresh complication tests the characters and opens new threads.",
+ "plotBoard.heuristic.complicate.title": "Introduce a complication",
+ "plotBoard.heuristic.escalate.description": "Increase the pressure on your protagonist so the next choice costs more.",
+ "plotBoard.heuristic.escalate.rationale": "Escalation keeps momentum when the middle sags.",
+ "plotBoard.heuristic.escalate.title": "Raise the stakes",
+ "plotBoard.heuristic.position": "Right after the selected scene",
+ "plotBoard.heuristic.reverse.description": "Flip an expectation — an ally falters, a win turns sour, or a hidden truth surfaces.",
+ "plotBoard.heuristic.reverse.rationale": "Reversals refresh tension and deepen the arc.",
+ "plotBoard.heuristic.reverse.title": "Add a reversal",
"preview.controls.ariaLabel": "پیش نمایش کنترل ها",
"preview.controls.decreaseFontSize": "اندازه فونت را کاهش دهید",
"preview.controls.exitFullscreen": "خروج از تمام صفحه",
@@ -449,10 +466,6 @@
"proforge.progress.awaitingReviewHint": "⚠️ این مرحله منتظر بررسی شماست. برای بررسی موارد روی دکمه مرحله بالا کلیک کنید.",
"proforge.progress.completedStages": "مراحل تکمیل شده",
"proforge.progress.currentStatus": "وضعیت فعلی",
- "proforge.progress.overall": "Overall progress",
- "proforge.progress.preparing": "Preparing…",
- "proforge.progress.stageOfTotal": "Stage {{current}} of {{total}}",
- "proforge.progress.percentComplete": "{{percent}}% complete",
"proforge.progress.itemsCount": "{{count}} مورد",
"proforge.progress.metric.aiCalls": "هوش مصنوعی تماس می گیرد",
"proforge.progress.metric.duration": "مدت زمان",
@@ -463,7 +476,11 @@
"proforge.progress.metric.totalTime": "زمان کل",
"proforge.progress.metric.totalTokens": "کل توکن ها",
"proforge.progress.noneRunning": "هیچ خط لوله ای در حال اجرا نیست.",
+ "proforge.progress.overall": "Overall progress",
+ "proforge.progress.percentComplete": "{{percent}}% complete",
+ "proforge.progress.preparing": "Preparing…",
"proforge.progress.stageDetails": "جزئیات مرحله: {{stage}}",
+ "proforge.progress.stageOfTotal": "Stage {{current}} of {{total}}",
"proforge.progress.statusLabel": "وضعیت",
"proforge.progress.totals": "مجموع خطوط لوله",
"proforge.review.accept": "قبول کنید",
@@ -777,9 +794,9 @@
"vc.title": "تاریخچه نسخه",
"vc.words": "کلمات",
"voice.cancelSpeech": "لغو سخنرانی",
+ "voice.feedback.confidence": "اطمینان {{percent}}%",
"voice.modeChip.commands": "دستورات",
"voice.modeChip.dictation": "دیکته",
- "voice.feedback.confidence": "اطمینان {{percent}}%",
"voice.panelLabel": "کنترل صدا",
"voice.permissionDenied": "دسترسی به میکروفون رد شد. برای استفاده از ویژگیهای صوتی، لطفاً به میکروفون در تنظیمات مرورگر خود اجازه دهید.",
"voice.startDictation": "دیکته را شروع کنید",
@@ -793,23 +810,6 @@
"voice.stopListening": "گوش دادن را متوقف کنید",
"worlds.emptyState.description": "مکانها، قوانین و تاریخهایی را بسازید که داستانتان در آن زندگی میکند. با یک مکان شروع کنید.",
"worlds.emptyState.title": "دنیا منتظر است",
- "error.fallback.generic": "AI is unavailable — used built-in assistance.",
- "error.fallback.offline": "You're offline — used built-in assistance.",
- "assisted.badge.label": "Assisted",
- "assisted.badge.srLabel": "Assisted mode — generated without AI",
- "assisted.toast.title": "AI unavailable",
- "assisted.toast.description": "Used built-in assistance. Enhance with AI when a model is available.",
- "assisted.enhance": "Enhance with AI",
- "plotBoard.heuristic.position": "Right after the selected scene",
- "plotBoard.heuristic.escalate.title": "Raise the stakes",
- "plotBoard.heuristic.escalate.description": "Increase the pressure on your protagonist so the next choice costs more.",
- "plotBoard.heuristic.escalate.rationale": "Escalation keeps momentum when the middle sags.",
- "plotBoard.heuristic.complicate.title": "Introduce a complication",
- "plotBoard.heuristic.complicate.description": "Add an obstacle or reveal that forces a change of plan.",
- "plotBoard.heuristic.complicate.rationale": "A fresh complication tests the characters and opens new threads.",
- "plotBoard.heuristic.reverse.title": "Add a reversal",
- "plotBoard.heuristic.reverse.description": "Flip an expectation — an ally falters, a win turns sour, or a hidden truth surfaces.",
- "plotBoard.heuristic.reverse.rationale": "Reversals refresh tension and deepen the arc.",
"copilot.annotationCount": "{{count}} بینش برای این فصل",
"copilot.announceClosed": "AI Copilot بسته شد",
"copilot.announceOpened": "AI Copilot باز شد",
@@ -1090,10 +1090,10 @@
"export.pasteSection.importAsChapter": "وارد کردن به عنوان فصل",
"export.pasteSection.textPlaceholder": "متن را از Google Docs یا Notion در اینجا جایگذاری کنید (Ctrl+V)...",
"export.pasteSection.titlePlaceholder": "عنوان فصل (اختیاری)",
- "export.preview.noContent": "برای مشاهده پیش نمایش، محتوا را انتخاب کنید.",
"export.preview.modeLabel": "حالت پیشنمایش",
- "export.preview.modeText": "متن",
"export.preview.modeRendered": "رندرشده",
+ "export.preview.modeText": "متن",
+ "export.preview.noContent": "برای مشاهده پیش نمایش، محتوا را انتخاب کنید.",
"export.preview.title": "پیش نمایش زنده",
"export.title": "Export Publishing Suite",
"export.toggleSection": "تغییر وضعیت دید برای {{title}}",
@@ -1519,6 +1519,23 @@
"outline.deleteConfirm": "آیا مطمئن هستید که می خواهید این بخش طرح کلی را حذف کنید؟",
"outline.description": "ایده داستان خود را توصیف کنید و اجازه دهید هوش مصنوعی یک طرح کلی ساختار یافته و قابل ویرایش برای شما ایجاد کند.",
"outline.error.generationFailed": "تولید محتوا انجام نشد. لطفا دوباره امتحان کنید.",
+ "outline.heuristic.beat.climax.desc": "The central conflict comes to a head in the story's defining confrontation.",
+ "outline.heuristic.beat.climax.title": "Climax",
+ "outline.heuristic.beat.complications.desc": "Setbacks and conflicts deepen; the path forward narrows.",
+ "outline.heuristic.beat.complications.title": "Complications",
+ "outline.heuristic.beat.incitingIncident.desc": "The event that sets the story in motion: {{idea}}.",
+ "outline.heuristic.beat.incitingIncident.title": "Inciting Incident",
+ "outline.heuristic.beat.midpoint.desc": "A turning point shifts the direction of the story and raises the stakes.",
+ "outline.heuristic.beat.midpoint.title": "Midpoint",
+ "outline.heuristic.beat.resolution.desc": "Loose ends are tied up and a new status quo emerges.",
+ "outline.heuristic.beat.resolution.title": "Resolution",
+ "outline.heuristic.beat.risingAction.desc": "Complications escalate and the stakes grow as the characters pursue their goal.",
+ "outline.heuristic.beat.risingAction.title": "Rising Action",
+ "outline.heuristic.beat.setup.desc": "Introduce the world and the main characters, and establish the status quo before everything changes.",
+ "outline.heuristic.beat.setup.title": "Setup",
+ "outline.heuristic.beat.twist.desc": "An unexpected revelation upends what the characters believed to be true.",
+ "outline.heuristic.beat.twist.title": "Twist",
+ "outline.heuristic.fallbackIdea": "the central idea",
"outline.idea.generateButton": "طرح کلی را ایجاد کنید",
"outline.idea.genreLabel": "ژانر",
"outline.idea.genrePlaceholder": "به عنوان مثال، علمی تخیلی، فانتزی، رازآلود",
@@ -1541,23 +1558,6 @@
"outline.result.twistTooltip": "پیچ و تاب پلات تولید شده توسط هوش مصنوعی",
"outline.selectSection": "بخش \"{{title}}\" را انتخاب کنید",
"outline.title": "مولد طرح کلی داستان هوش مصنوعی",
- "outline.heuristic.fallbackIdea": "the central idea",
- "outline.heuristic.beat.setup.title": "Setup",
- "outline.heuristic.beat.setup.desc": "Introduce the world and the main characters, and establish the status quo before everything changes.",
- "outline.heuristic.beat.incitingIncident.title": "Inciting Incident",
- "outline.heuristic.beat.incitingIncident.desc": "The event that sets the story in motion: {{idea}}.",
- "outline.heuristic.beat.risingAction.title": "Rising Action",
- "outline.heuristic.beat.risingAction.desc": "Complications escalate and the stakes grow as the characters pursue their goal.",
- "outline.heuristic.beat.midpoint.title": "Midpoint",
- "outline.heuristic.beat.midpoint.desc": "A turning point shifts the direction of the story and raises the stakes.",
- "outline.heuristic.beat.complications.title": "Complications",
- "outline.heuristic.beat.complications.desc": "Setbacks and conflicts deepen; the path forward narrows.",
- "outline.heuristic.beat.twist.title": "Twist",
- "outline.heuristic.beat.twist.desc": "An unexpected revelation upends what the characters believed to be true.",
- "outline.heuristic.beat.climax.title": "Climax",
- "outline.heuristic.beat.climax.desc": "The central conflict comes to a head in the story's defining confrontation.",
- "outline.heuristic.beat.resolution.title": "Resolution",
- "outline.heuristic.beat.resolution.desc": "Loose ends are tied up and a new status quo emerges.",
"portal.back": "بازگشت",
"portal.demo.chapterContent": "مه صبحگاهی به اسکلهها چسبیده بود که لیرا نقشه کهنه شهر را گشود. دایرهای کمرنگ گوشه شمالغربی را نشان میداد — برجی که هیچکس از آن سخن نمیگفت.\n\nکاغذ را کنار گذاشت و کورهراه باریک را دنبال کرد تا آنکه شبکه آهنی پیش رویش برافراشته شد. قفل در آفتاب گرم بود؛ اما فلز هنوز سرد.",
"portal.demo.chapterTitle": "فصل ۱ — پیش از دروازه",
@@ -1752,6 +1752,7 @@
"settings.ai.gpu.troubleshootLowEnd": "دستگاه شما منابع محدودی دارد. هوش مصنوعی محلی از مدل های کوچکتر استفاده خواهد کرد. برای عملکرد بهتر، سایر تب های مرورگر را ببندید یا حالت Eco Mode را فعال کنید.",
"settings.ai.gpu.troubleshootQueue": "چندین کار هوش مصنوعی در صف قرار می گیرند. فقط یکی در یک زمان اجرا می شود تا از برخورد VRAM جلوگیری شود. منتظر بمانید تا کار فعلی تمام شود.",
"settings.ai.gpu.waitingConsumers": "در انتظار",
+ "settings.ai.grokKey": "Grok API Key",
"settings.ai.hybridFallbackHint": "اگر ارائهدهنده اصلی شکست بخورد، WorldScript موارد بازگشتی فهرست شده (مولد صحنه، ابزار کدکس) را امتحان میکند. پخش جریانی نویسنده فقط از ارائه دهنده اصلی شما استفاده می کند.",
"settings.ai.hybridFallbackTitle": "بازگشت ترکیبی (ابزارهای هوش مصنوعی پروژه)",
"settings.ai.hybridFallbackToggle": "فعال کردن زنجیره بازگشتی",
@@ -1832,6 +1833,11 @@
"settings.ai.preset.lmStudio": "LM Studio",
"settings.ai.preset.ollamaDefault": "اولاما (درگاه پیش فرض)",
"settings.ai.preset.vllm": "vLLM",
+ "settings.ai.provider.anthropic": "Anthropic Claude",
+ "settings.ai.provider.gemini": "Google Gemini",
+ "settings.ai.provider.grok": "xAI Grok",
+ "settings.ai.provider.ollama": "Ollama (local)",
+ "settings.ai.provider.openai": "OpenAI",
"settings.ai.providerDescription": "انتخاب کنید که WorldScript Studio از کدام ارائه دهنده هوش مصنوعی استفاده کند.",
"settings.ai.providerOnnx": "ONNX (WASM)",
"settings.ai.providerStatusConnected": "متصل شد",
@@ -2711,6 +2717,11 @@
"worlds.edit.notes": "یادداشت ها",
"worlds.editorTabsAriaLabel": "برگه های ویرایشگر جهان",
"worlds.error.imageFailed": "تولید تصویر محیطی ناموفق بود. لطفاً سعی کنید جزئیات بیشتری را به شرح جهان اضافه کنید یا اتصال خود را بررسی کنید.",
+ "worlds.heuristic.culture": "Describe the peoples, beliefs, and daily life shaped by {{concept}}.",
+ "worlds.heuristic.description": "A world defined by its central premise: {{concept}}.",
+ "worlds.heuristic.geography": "Outline the major regions, climates, and natural features of {{concept}}.",
+ "worlds.heuristic.magicSystem": "Define the rules, costs, and limits of power in {{concept}}.",
+ "worlds.heuristic.name": "New World",
"worlds.loading.profile": "ایجاد نمایه جهانی دقیق...",
"worlds.newWorldName": "دنیای جدید",
"worlds.noWorlds": "هنوز جهانی ساخته نشده است.",
@@ -2729,11 +2740,6 @@
"worlds.title": "اطلس جهانی",
"worlds.uploadImage": "آپلود تصویر",
"worlds.yourWorlds": "دنیاهای شما",
- "worlds.heuristic.name": "New World",
- "worlds.heuristic.description": "A world defined by its central premise: {{concept}}.",
- "worlds.heuristic.geography": "Outline the major regions, climates, and natural features of {{concept}}.",
- "worlds.heuristic.magicSystem": "Define the rules, costs, and limits of power in {{concept}}.",
- "worlds.heuristic.culture": "Describe the peoples, beliefs, and daily life shaped by {{concept}}.",
"writer.cancelledTag": "لغو شد",
"writer.chapter.label": "فصل: {{title}}",
"writer.coachmark.dismiss": "Got it",
@@ -2755,6 +2761,20 @@
"writer.focusMode.enterLabel": "حالت فوکوس",
"writer.focusMode.exit": "از حالت فوکوس خارج شوید",
"writer.focusMode.exitLabel": "خروج از تمرکز",
+ "writer.grammar.addToDictionary": "Add to dictionary",
+ "writer.grammar.apply": "Apply",
+ "writer.grammar.checkButton": "Check this scene",
+ "writer.grammar.checking": "Checking…",
+ "writer.grammar.disabled": "Enable LanguageTool in Settings → Connections to check this scene.",
+ "writer.grammar.error": "The LanguageTool server returned an error.",
+ "writer.grammar.ignore": "Ignore",
+ "writer.grammar.issuesFound": "{{count}} issues found",
+ "writer.grammar.noIssues": "No issues found.",
+ "writer.grammar.noSuggestions": "No suggestions",
+ "writer.grammar.offline": "Couldn't reach the LanguageTool server. Is it running?",
+ "writer.grammar.selectScene": "Select a scene to check.",
+ "writer.grammar.title": "Grammar & Spelling",
+ "writer.grammar.unsupported": "Grammar check isn't available for this language.",
"writer.imagePrompt.description": "یک دستور DALL·E 3 / Midjourney بهینه شده را از صحنه یا متن فعلی انتخاب می کند.",
"writer.imagePrompt.note": "اعلان ایجاد شده مستقیماً در DALL·E 3 و Midjourney کار می کند.",
"writer.imagePrompt.tip": "نکته: یک بخش متن خاص را برای اعلان صحنه متمرکز انتخاب کنید.",
@@ -2787,12 +2807,10 @@
"writer.studio.controls.tones.poetic": "شاعرانه تر",
"writer.studio.controls.tones.suspenseful": "معلق تر",
"writer.studio.description": "نویسنده همکار هوش مصنوعی شما. تولید، بهبود، و طوفان فکری با زمینه کامل پروژه.",
+ "writer.studio.rag.chunkScore": "ارتباط {{score}}",
"writer.studio.rag.chunksBadge": "{{count}} قسمت های داستان پیدا شد",
"writer.studio.rag.chunksHint": "گزیدههای مرتبط از دستنوشته شما - قسمتهای بیشتر به معنای زمینه غنیتر هوش مصنوعی است",
"writer.studio.rag.inspectorLabel": "زمینهٔ بازیابیشده",
- "writer.studio.rag.chunkScore": "ارتباط {{score}}",
- "writer.studio.tokens.badge": "~{{count}} توکن",
- "writer.studio.tokens.hint": "تعداد تقریبی توکنهای استفادهشده در آخرین درخواست هوش مصنوعی",
"writer.studio.rag.useContext": "از داستان من بیرون بکش",
"writer.studio.result.insert": "درج کنید",
"writer.studio.result.next": "بعدی",
@@ -2802,6 +2820,8 @@
"writer.studio.result.retry": "دوباره امتحان کنید",
"writer.studio.result.title": "AI Scratchpad",
"writer.studio.title": "استودیوی نوشتن هوش مصنوعی",
+ "writer.studio.tokens.badge": "~{{count}} توکن",
+ "writer.studio.tokens.hint": "تعداد تقریبی توکنهای استفادهشده در آخرین درخواست هوش مصنوعی",
"writer.studio.tools.brainstorm.contextLabel": "زمینه طوفان فکری (اختیاری)",
"writer.studio.tools.brainstorm.contextPlaceholder": "یک موقعیت مختصر ارائه دهید، در غیر این صورت هوش مصنوعی از بخش دستنوشته فعلی استفاده خواهد کرد.",
"writer.studio.tools.brainstorm.title": "ایده های طوفان فکری",
@@ -2833,19 +2853,5 @@
"writer.tts.start": "با صدای بلند بخوانید",
"writer.tts.stop": "خواندن را متوقف کنید",
"writer.versionControl.label": "نسخه ها",
- "writer.versionControl.tooltip": "کنترل نسخه (شاخه ها و عکس های فوری)",
- "writer.grammar.title": "Grammar & Spelling",
- "writer.grammar.checkButton": "Check this scene",
- "writer.grammar.checking": "Checking…",
- "writer.grammar.issuesFound": "{{count}} issues found",
- "writer.grammar.noIssues": "No issues found.",
- "writer.grammar.selectScene": "Select a scene to check.",
- "writer.grammar.unsupported": "Grammar check isn't available for this language.",
- "writer.grammar.disabled": "Enable LanguageTool in Settings → Connections to check this scene.",
- "writer.grammar.offline": "Couldn't reach the LanguageTool server. Is it running?",
- "writer.grammar.error": "The LanguageTool server returned an error.",
- "writer.grammar.apply": "Apply",
- "writer.grammar.ignore": "Ignore",
- "writer.grammar.addToDictionary": "Add to dictionary",
- "writer.grammar.noSuggestions": "No suggestions"
+ "writer.versionControl.tooltip": "کنترل نسخه (شاخه ها و عکس های فوری)"
}
diff --git a/public/locales/fi/bundle.json b/public/locales/fi/bundle.json
index 1468c5c3..f47e4025 100644
--- a/public/locales/fi/bundle.json
+++ b/public/locales/fi/bundle.json
@@ -90,6 +90,14 @@
"characters.edit.relationships": "Suhteet",
"characters.editorTabsAriaLabel": "Merkkieditorin välilehdet",
"characters.error.portraitFailed": "Muotokuvan luominen epäonnistui. Yritä lisätä ulkoasun kuvaukseen yksityiskohtia.",
+ "characters.heuristic.appearance": "Describe how they present themselves — let their look hint at {{concept}}.",
+ "characters.heuristic.backstory": "Shaped by formative experiences, this character carries a past tied to {{concept}}.",
+ "characters.heuristic.characterArc": "They begin guarded and, through the story, are changed by {{concept}}.",
+ "characters.heuristic.flaws": "A weakness that complicates their goals.",
+ "characters.heuristic.motivation": "A core desire connected to {{concept}} drives their choices.",
+ "characters.heuristic.name": "New Character",
+ "characters.heuristic.personalityTraits": "Resourceful, guarded, determined.",
+ "characters.heuristic.relationships": "Note the key bonds and rivalries that define them.",
"characters.loading.profile": "Luodaan yksityiskohtaista profiilia...",
"characters.newCharacterName": "Uusi hahmo",
"characters.noCharacters": "Ei ole vielä luotu hahmoja.",
@@ -107,14 +115,6 @@
"characters.title": "Hahmoasiakirjat",
"characters.uploadImage": "Lataa kuva",
"characters.yourCharacters": "Sinun hahmosi",
- "characters.heuristic.name": "New Character",
- "characters.heuristic.backstory": "Shaped by formative experiences, this character carries a past tied to {{concept}}.",
- "characters.heuristic.motivation": "A core desire connected to {{concept}} drives their choices.",
- "characters.heuristic.appearance": "Describe how they present themselves — let their look hint at {{concept}}.",
- "characters.heuristic.personalityTraits": "Resourceful, guarded, determined.",
- "characters.heuristic.flaws": "A weakness that complicates their goals.",
- "characters.heuristic.characterArc": "They begin guarded and, through the story, are changed by {{concept}}.",
- "characters.heuristic.relationships": "Note the key bonds and rivalries that define them.",
"apiKey.connectionFailed": "Yhteystesti epäonnistui.",
"apiKey.connectionSuccess": "Yhteys onnistui! API vastaa oikein.",
"apiKey.decryptFailed": "API-avaimen salausta ei voitu purkaa",
@@ -125,6 +125,11 @@
"apiKey.test": "Testaa yhteys",
"apiKey.testConnection": "Testaa API-yhteyttä",
"apiKey.testing": "Testaus…",
+ "assisted.badge.label": "Assisted",
+ "assisted.badge.srLabel": "Assisted mode — generated without AI",
+ "assisted.enhance": "Enhance with AI",
+ "assisted.toast.description": "Used built-in assistance. Enhance with AI when a model is available.",
+ "assisted.toast.title": "AI unavailable",
"charGraph.characters": "Hahmot",
"charGraph.noCharacters": "Ei vielä hahmoja",
"charGraph.noCharactersHint": "Lisää merkkejä Hahmot-näkymään nähdäksesi heidän suhteensa täällä.",
@@ -286,6 +291,8 @@
"error.db.unknown": "Tuntematon virhe käytettäessä tietokantaa.",
"error.deepLink.title": "Projektitiedoston avaaminen epäonnistui",
"error.deepLink.unknown": "Tuntematon virhe",
+ "error.fallback.generic": "AI is unavailable — used built-in assistance.",
+ "error.fallback.offline": "You're offline — used built-in assistance.",
"error.fileImportError": "Tiedoston tuontivirhe",
"error.mic.denied": "Mikrofonin käyttö estetty. Anna lupa selaimesi asetuksista.",
"error.mic.generic": "Puheentunnistusvirhe: {{error}}",
@@ -382,6 +389,16 @@
"palette.voice.listeningLive": "Äänisyöttö on aktiivinen",
"palette.voice.start": "Aloita puhehaku",
"palette.voice.stop": "Lopeta puhehaku",
+ "plotBoard.heuristic.complicate.description": "Add an obstacle or reveal that forces a change of plan.",
+ "plotBoard.heuristic.complicate.rationale": "A fresh complication tests the characters and opens new threads.",
+ "plotBoard.heuristic.complicate.title": "Introduce a complication",
+ "plotBoard.heuristic.escalate.description": "Increase the pressure on your protagonist so the next choice costs more.",
+ "plotBoard.heuristic.escalate.rationale": "Escalation keeps momentum when the middle sags.",
+ "plotBoard.heuristic.escalate.title": "Raise the stakes",
+ "plotBoard.heuristic.position": "Right after the selected scene",
+ "plotBoard.heuristic.reverse.description": "Flip an expectation — an ally falters, a win turns sour, or a hidden truth surfaces.",
+ "plotBoard.heuristic.reverse.rationale": "Reversals refresh tension and deepen the arc.",
+ "plotBoard.heuristic.reverse.title": "Add a reversal",
"preview.controls.ariaLabel": "Esikatseluohjaimet",
"preview.controls.decreaseFontSize": "Pienennä fonttikokoa",
"preview.controls.exitFullscreen": "Poistu koko näytöstä",
@@ -449,10 +466,6 @@
"proforge.progress.awaitingReviewHint": "⚠️ Tämä vaihe odottaa arvosteluasi. Napsauta yllä olevaa vaihepainiketta tarkastellaksesi kohteita.",
"proforge.progress.completedStages": "Valmistuneet vaiheet",
"proforge.progress.currentStatus": "Nykyinen tila",
- "proforge.progress.overall": "Overall progress",
- "proforge.progress.preparing": "Preparing…",
- "proforge.progress.stageOfTotal": "Stage {{current}} of {{total}}",
- "proforge.progress.percentComplete": "{{percent}}% complete",
"proforge.progress.itemsCount": "{{count}} kohdetta",
"proforge.progress.metric.aiCalls": "AI-puhelut",
"proforge.progress.metric.duration": "Kesto",
@@ -463,7 +476,11 @@
"proforge.progress.metric.totalTime": "Kokonaisaika",
"proforge.progress.metric.totalTokens": "Tokeneja yhteensä",
"proforge.progress.noneRunning": "Putki ei ole käynnissä.",
+ "proforge.progress.overall": "Overall progress",
+ "proforge.progress.percentComplete": "{{percent}}% complete",
+ "proforge.progress.preparing": "Preparing…",
"proforge.progress.stageDetails": "Lavan tiedot: {{stage}}",
+ "proforge.progress.stageOfTotal": "Stage {{current}} of {{total}}",
"proforge.progress.statusLabel": "Status",
"proforge.progress.totals": "Pipeline Totals",
"proforge.review.accept": "Hyväksyä",
@@ -777,9 +794,9 @@
"vc.title": "Versiohistoria",
"vc.words": "sanoja",
"voice.cancelSpeech": "Peruuta puhe",
+ "voice.feedback.confidence": "Varmuus {{percent}} %",
"voice.modeChip.commands": "Komennot",
"voice.modeChip.dictation": "Sanelu",
- "voice.feedback.confidence": "Varmuus {{percent}} %",
"voice.panelLabel": "Ääniohjaus",
"voice.permissionDenied": "Mikrofonin käyttö estetty. Salli mikrofonin käyttö selaimesi asetuksista, jotta voit käyttää ääniominaisuuksia.",
"voice.startDictation": "Aloita sanelu",
@@ -793,23 +810,6 @@
"voice.stopListening": "Lopeta kuunteleminen",
"worlds.emptyState.description": "Rakenna paikat, säännöt ja historiat, joissa tarinasi elää. Aloita sijainnista.",
"worlds.emptyState.title": "Maailma odottaa",
- "error.fallback.generic": "AI is unavailable — used built-in assistance.",
- "error.fallback.offline": "You're offline — used built-in assistance.",
- "assisted.badge.label": "Assisted",
- "assisted.badge.srLabel": "Assisted mode — generated without AI",
- "assisted.toast.title": "AI unavailable",
- "assisted.toast.description": "Used built-in assistance. Enhance with AI when a model is available.",
- "assisted.enhance": "Enhance with AI",
- "plotBoard.heuristic.position": "Right after the selected scene",
- "plotBoard.heuristic.escalate.title": "Raise the stakes",
- "plotBoard.heuristic.escalate.description": "Increase the pressure on your protagonist so the next choice costs more.",
- "plotBoard.heuristic.escalate.rationale": "Escalation keeps momentum when the middle sags.",
- "plotBoard.heuristic.complicate.title": "Introduce a complication",
- "plotBoard.heuristic.complicate.description": "Add an obstacle or reveal that forces a change of plan.",
- "plotBoard.heuristic.complicate.rationale": "A fresh complication tests the characters and opens new threads.",
- "plotBoard.heuristic.reverse.title": "Add a reversal",
- "plotBoard.heuristic.reverse.description": "Flip an expectation — an ally falters, a win turns sour, or a hidden truth surfaces.",
- "plotBoard.heuristic.reverse.rationale": "Reversals refresh tension and deepen the arc.",
"copilot.annotationCount": "{{count}} tietoa tästä luvusta",
"copilot.announceClosed": "AI Copilot suljettu",
"copilot.announceOpened": "AI Copilot avattiin",
@@ -1090,10 +1090,10 @@
"export.pasteSection.importAsChapter": "Tuo kappaleena",
"export.pasteSection.textPlaceholder": "Liitä teksti Google Docsista tai Notionista tähän (Ctrl+V)...",
"export.pasteSection.titlePlaceholder": "Luvun otsikko (valinnainen)",
- "export.preview.noContent": "Valitse sisältö nähdäksesi esikatselun.",
"export.preview.modeLabel": "Esikatselutila",
- "export.preview.modeText": "Teksti",
"export.preview.modeRendered": "Renderöity",
+ "export.preview.modeText": "Teksti",
+ "export.preview.noContent": "Valitse sisältö nähdäksesi esikatselun.",
"export.preview.title": "Live-esikatselu",
"export.title": "Vie Publishing Suite",
"export.toggleSection": "Vaihda näkyvyys {{title}}",
@@ -1519,6 +1519,23 @@
"outline.deleteConfirm": "Haluatko varmasti poistaa tämän ääriviivaosion?",
"outline.description": "Kuvaile tarina-ideaasi ja anna tekoäly luoda jäsennelty, muokattava ääriviiva sinulle.",
"outline.error.generationFailed": "Sisällön luominen epäonnistui. Yritä uudelleen.",
+ "outline.heuristic.beat.climax.desc": "The central conflict comes to a head in the story's defining confrontation.",
+ "outline.heuristic.beat.climax.title": "Climax",
+ "outline.heuristic.beat.complications.desc": "Setbacks and conflicts deepen; the path forward narrows.",
+ "outline.heuristic.beat.complications.title": "Complications",
+ "outline.heuristic.beat.incitingIncident.desc": "The event that sets the story in motion: {{idea}}.",
+ "outline.heuristic.beat.incitingIncident.title": "Inciting Incident",
+ "outline.heuristic.beat.midpoint.desc": "A turning point shifts the direction of the story and raises the stakes.",
+ "outline.heuristic.beat.midpoint.title": "Midpoint",
+ "outline.heuristic.beat.resolution.desc": "Loose ends are tied up and a new status quo emerges.",
+ "outline.heuristic.beat.resolution.title": "Resolution",
+ "outline.heuristic.beat.risingAction.desc": "Complications escalate and the stakes grow as the characters pursue their goal.",
+ "outline.heuristic.beat.risingAction.title": "Rising Action",
+ "outline.heuristic.beat.setup.desc": "Introduce the world and the main characters, and establish the status quo before everything changes.",
+ "outline.heuristic.beat.setup.title": "Setup",
+ "outline.heuristic.beat.twist.desc": "An unexpected revelation upends what the characters believed to be true.",
+ "outline.heuristic.beat.twist.title": "Twist",
+ "outline.heuristic.fallbackIdea": "the central idea",
"outline.idea.generateButton": "Luo ääriviivat",
"outline.idea.genreLabel": "Genre",
"outline.idea.genrePlaceholder": "esim. scifi, fantasia, mysteeri",
@@ -1541,23 +1558,6 @@
"outline.result.twistTooltip": "AI-Generated Plot Twist",
"outline.selectSection": "Valitse osio '{{title}}'",
"outline.title": "AI Story Outline Generator",
- "outline.heuristic.fallbackIdea": "the central idea",
- "outline.heuristic.beat.setup.title": "Setup",
- "outline.heuristic.beat.setup.desc": "Introduce the world and the main characters, and establish the status quo before everything changes.",
- "outline.heuristic.beat.incitingIncident.title": "Inciting Incident",
- "outline.heuristic.beat.incitingIncident.desc": "The event that sets the story in motion: {{idea}}.",
- "outline.heuristic.beat.risingAction.title": "Rising Action",
- "outline.heuristic.beat.risingAction.desc": "Complications escalate and the stakes grow as the characters pursue their goal.",
- "outline.heuristic.beat.midpoint.title": "Midpoint",
- "outline.heuristic.beat.midpoint.desc": "A turning point shifts the direction of the story and raises the stakes.",
- "outline.heuristic.beat.complications.title": "Complications",
- "outline.heuristic.beat.complications.desc": "Setbacks and conflicts deepen; the path forward narrows.",
- "outline.heuristic.beat.twist.title": "Twist",
- "outline.heuristic.beat.twist.desc": "An unexpected revelation upends what the characters believed to be true.",
- "outline.heuristic.beat.climax.title": "Climax",
- "outline.heuristic.beat.climax.desc": "The central conflict comes to a head in the story's defining confrontation.",
- "outline.heuristic.beat.resolution.title": "Resolution",
- "outline.heuristic.beat.resolution.desc": "Loose ends are tied up and a new status quo emerges.",
"portal.back": "Takaisin",
"portal.demo.chapterContent": "Aamusumu takertui laitureihin, kun Lyra avasi vanhan kaupunginkartan. Vaalea ympyrä merkitsi luoteiskulman — tornin, josta kukaan ei puhunut.\n\nHän pani paperin pois ja seurasi kapeaa polkua, kunnes rautaristikko kohosi hänen eteensä. Munalukko oli lämmin auringossa; metalli yhä kylmää.",
"portal.demo.chapterTitle": "Luku 1 — Portin edessä",
@@ -1752,6 +1752,7 @@
"settings.ai.gpu.troubleshootLowEnd": "Laitteesi resurssit ovat rajalliset. Paikallinen tekoäly käyttää pienempiä malleja. Suorituskyvyn parantamiseksi sulje muut selaimen välilehdet tai ota Eco Mode käyttöön.",
"settings.ai.gpu.troubleshootQueue": "Useita tekoälytehtäviä on jonossa. Vain yksi toimii kerrallaan VRAM-törmäysten välttämiseksi. Odota nykyisen tehtävän valmistumista.",
"settings.ai.gpu.waitingConsumers": "Odottaa",
+ "settings.ai.grokKey": "Grok API Key",
"settings.ai.hybridFallbackHint": "Jos ensisijainen toimittaja epäonnistuu, WorldScript yrittää lueteltuja varavaihtoehtoja (kohtausgeneraattorit, codex-työkalut). Writer-suoratoisto käyttää vain ensisijaista palveluntarjoajaasi.",
"settings.ai.hybridFallbackTitle": "Hybridivaraus (projektin tekoälytyökalut)",
"settings.ai.hybridFallbackToggle": "Ota varaketju käyttöön",
@@ -1832,6 +1833,11 @@
"settings.ai.preset.lmStudio": "LM Studio",
"settings.ai.preset.ollamaDefault": "Ollama (oletusportti)",
"settings.ai.preset.vllm": "vLLM",
+ "settings.ai.provider.anthropic": "Anthropic Claude",
+ "settings.ai.provider.gemini": "Google Gemini",
+ "settings.ai.provider.grok": "xAI Grok",
+ "settings.ai.provider.ollama": "Ollama (local)",
+ "settings.ai.provider.openai": "OpenAI",
"settings.ai.providerDescription": "Valitse, mitä tekoälyn tarjoajaa WorldScript Studion tulee käyttää.",
"settings.ai.providerOnnx": "ONNX (WASM)",
"settings.ai.providerStatusConnected": "Yhdistetty",
@@ -2711,6 +2717,11 @@
"worlds.edit.notes": "Huomautuksia",
"worlds.editorTabsAriaLabel": "Maailman muokkausvälilehdet",
"worlds.error.imageFailed": "Tunnelmakuvan luominen epäonnistui. Yritä lisätä yksityiskohtia maailmankuvaukseen tai tarkista yhteys.",
+ "worlds.heuristic.culture": "Describe the peoples, beliefs, and daily life shaped by {{concept}}.",
+ "worlds.heuristic.description": "A world defined by its central premise: {{concept}}.",
+ "worlds.heuristic.geography": "Outline the major regions, climates, and natural features of {{concept}}.",
+ "worlds.heuristic.magicSystem": "Define the rules, costs, and limits of power in {{concept}}.",
+ "worlds.heuristic.name": "New World",
"worlds.loading.profile": "Luodaan yksityiskohtaista maailmanprofiilia...",
"worlds.newWorldName": "Uusi maailma",
"worlds.noWorlds": "Maailmaa ei ole vielä luotu.",
@@ -2729,11 +2740,6 @@
"worlds.title": "Maailman atlas",
"worlds.uploadImage": "Lataa kuva",
"worlds.yourWorlds": "Sinun maailmasi",
- "worlds.heuristic.name": "New World",
- "worlds.heuristic.description": "A world defined by its central premise: {{concept}}.",
- "worlds.heuristic.geography": "Outline the major regions, climates, and natural features of {{concept}}.",
- "worlds.heuristic.magicSystem": "Define the rules, costs, and limits of power in {{concept}}.",
- "worlds.heuristic.culture": "Describe the peoples, beliefs, and daily life shaped by {{concept}}.",
"writer.cancelledTag": "Peruutettu",
"writer.chapter.label": "Luku: {{title}}",
"writer.coachmark.dismiss": "Got it",
@@ -2755,6 +2761,20 @@
"writer.focusMode.enterLabel": "Tarkennustila",
"writer.focusMode.exit": "Poistu tarkennustilasta",
"writer.focusMode.exitLabel": "Poistu tarkennuksesta",
+ "writer.grammar.addToDictionary": "Add to dictionary",
+ "writer.grammar.apply": "Apply",
+ "writer.grammar.checkButton": "Check this scene",
+ "writer.grammar.checking": "Checking…",
+ "writer.grammar.disabled": "Enable LanguageTool in Settings → Connections to check this scene.",
+ "writer.grammar.error": "The LanguageTool server returned an error.",
+ "writer.grammar.ignore": "Ignore",
+ "writer.grammar.issuesFound": "{{count}} issues found",
+ "writer.grammar.noIssues": "No issues found.",
+ "writer.grammar.noSuggestions": "No suggestions",
+ "writer.grammar.offline": "Couldn't reach the LanguageTool server. Is it running?",
+ "writer.grammar.selectScene": "Select a scene to check.",
+ "writer.grammar.title": "Grammar & Spelling",
+ "writer.grammar.unsupported": "Grammar check isn't available for this language.",
"writer.imagePrompt.description": "Luo optimoidun DALL·E 3 / Midjourney -kehotteen nykyisestä kohtauksesta tai tekstivalinnasta.",
"writer.imagePrompt.note": "Luotu kehote toimii suoraan DALL·E 3:ssa ja Midjourneyssa.",
"writer.imagePrompt.tip": "Vihje: Valitse tietty tekstiosio kohdistetulle kohtaukselle.",
@@ -2787,12 +2807,10 @@
"writer.studio.controls.tones.poetic": "Lisää runollista",
"writer.studio.controls.tones.suspenseful": "Jännittävämpää",
"writer.studio.description": "Tekoälytoverisi. Luo, paranna ja aivoriihi koko projektin kontekstissa.",
+ "writer.studio.rag.chunkScore": "osuvuus {{score}}",
"writer.studio.rag.chunksBadge": "{{count}} tarinan pätkiä löydetty",
"writer.studio.rag.chunksHint": "Asiaankuuluvia otteita käsikirjoituksestasi – enemmän kohtia tarkoittaa rikkaampaa tekoälykontekstia",
"writer.studio.rag.inspectorLabel": "Haettu konteksti",
- "writer.studio.rag.chunkScore": "osuvuus {{score}}",
- "writer.studio.tokens.badge": "~{{count}} tokenia",
- "writer.studio.tokens.hint": "Arvioitu tokenien määrä viimeisimmässä tekoälypyynnössä",
"writer.studio.rag.useContext": "Poimi tarinastani",
"writer.studio.result.insert": "Lisää",
"writer.studio.result.next": "Seuraava",
@@ -2802,6 +2820,8 @@
"writer.studio.result.retry": "Yritä uudelleen",
"writer.studio.result.title": "AI Scratchpad",
"writer.studio.title": "AI kirjoitusstudio",
+ "writer.studio.tokens.badge": "~{{count}} tokenia",
+ "writer.studio.tokens.hint": "Arvioitu tokenien määrä viimeisimmässä tekoälypyynnössä",
"writer.studio.tools.brainstorm.contextLabel": "Aivoriihen konteksti (valinnainen)",
"writer.studio.tools.brainstorm.contextPlaceholder": "Anna lyhyt tilanne, tai tekoäly käyttää nykyistä käsikirjoitusosaa.",
"writer.studio.tools.brainstorm.title": "Aivoriihi Ideat",
@@ -2833,19 +2853,5 @@
"writer.tts.start": "Lue ääneen",
"writer.tts.stop": "Lopeta lukeminen",
"writer.versionControl.label": "Versiot",
- "writer.versionControl.tooltip": "Versionhallinta (oksat ja tilannekuvat)",
- "writer.grammar.title": "Grammar & Spelling",
- "writer.grammar.checkButton": "Check this scene",
- "writer.grammar.checking": "Checking…",
- "writer.grammar.issuesFound": "{{count}} issues found",
- "writer.grammar.noIssues": "No issues found.",
- "writer.grammar.selectScene": "Select a scene to check.",
- "writer.grammar.unsupported": "Grammar check isn't available for this language.",
- "writer.grammar.disabled": "Enable LanguageTool in Settings → Connections to check this scene.",
- "writer.grammar.offline": "Couldn't reach the LanguageTool server. Is it running?",
- "writer.grammar.error": "The LanguageTool server returned an error.",
- "writer.grammar.apply": "Apply",
- "writer.grammar.ignore": "Ignore",
- "writer.grammar.addToDictionary": "Add to dictionary",
- "writer.grammar.noSuggestions": "No suggestions"
+ "writer.versionControl.tooltip": "Versionhallinta (oksat ja tilannekuvat)"
}
diff --git a/public/locales/fr/bundle.json b/public/locales/fr/bundle.json
index a7d24f71..5bc2d9cd 100644
--- a/public/locales/fr/bundle.json
+++ b/public/locales/fr/bundle.json
@@ -90,6 +90,14 @@
"characters.edit.relationships": "Relations",
"characters.editorTabsAriaLabel": "Onglets de l'éditeur de personnage",
"characters.error.portraitFailed": "Échec de la génération du portrait. Essayez d'ajouter plus de détails à la description de l'apparence.",
+ "characters.heuristic.appearance": "Décrivez comment il se présente — laissez son apparence évoquer {{concept}}.",
+ "characters.heuristic.backstory": "Façonné par des expériences déterminantes, ce personnage porte un passé lié à {{concept}}.",
+ "characters.heuristic.characterArc": "Il commence sur la réserve et, au fil de l'histoire, est transformé par {{concept}}.",
+ "characters.heuristic.flaws": "Une faiblesse qui complique ses objectifs.",
+ "characters.heuristic.motivation": "Un désir central lié à {{concept}} guide ses choix.",
+ "characters.heuristic.name": "Nouveau personnage",
+ "characters.heuristic.personalityTraits": "Ingénieux, réservé, déterminé.",
+ "characters.heuristic.relationships": "Notez les liens et rivalités clés qui le définissent.",
"characters.loading.profile": "Génération du profil détaillé...",
"characters.newCharacterName": "Nouveau personnage",
"characters.noCharacters": "Aucun personnage créé.",
@@ -107,14 +115,6 @@
"characters.title": "Dossiers de personnages",
"characters.uploadImage": "Télécharger une image",
"characters.yourCharacters": "Vos personnages",
- "characters.heuristic.name": "Nouveau personnage",
- "characters.heuristic.backstory": "Façonné par des expériences déterminantes, ce personnage porte un passé lié à {{concept}}.",
- "characters.heuristic.motivation": "Un désir central lié à {{concept}} guide ses choix.",
- "characters.heuristic.appearance": "Décrivez comment il se présente — laissez son apparence évoquer {{concept}}.",
- "characters.heuristic.personalityTraits": "Ingénieux, réservé, déterminé.",
- "characters.heuristic.flaws": "Une faiblesse qui complique ses objectifs.",
- "characters.heuristic.characterArc": "Il commence sur la réserve et, au fil de l'histoire, est transformé par {{concept}}.",
- "characters.heuristic.relationships": "Notez les liens et rivalités clés qui le définissent.",
"apiKey.connectionFailed": "Échec du test de connexion.",
"apiKey.connectionSuccess": "Connexion réussie ! L'API répond correctement.",
"apiKey.decryptFailed": "Impossible de déchiffrer la clé API",
@@ -125,6 +125,11 @@
"apiKey.test": "Tester la connexion",
"apiKey.testConnection": "Tester la connexion API",
"apiKey.testing": "Test en cours…",
+ "assisted.badge.label": "Assisté",
+ "assisted.badge.srLabel": "Mode assisté — généré sans IA",
+ "assisted.enhance": "Améliorer avec l'IA",
+ "assisted.toast.description": "Assistance intégrée utilisée. Améliorez avec l'IA quand un modèle est disponible.",
+ "assisted.toast.title": "IA indisponible",
"charGraph.characters": "Personnages",
"charGraph.noCharacters": "Aucun personnage encore",
"charGraph.noCharactersHint": "Ajoutez des personnages dans la vue Personnages pour visualiser leurs relations ici.",
@@ -185,8 +190,8 @@
"common.add": "Ajouter",
"common.appLoading": "L'application se charge",
"common.back": "Retour",
- "common.badge.experimental": "Expérimental",
"common.badge.beta": "Bêta",
+ "common.badge.experimental": "Expérimental",
"common.badge.new": "Nouveau",
"common.cancel": "Annuler",
"common.close": "Fermer",
@@ -217,16 +222,16 @@
"common.words": "mots",
"consistencyChecker.checkButton": "Vérifier la cohérence",
"consistencyChecker.description": "Vérifiez la cohérence de vos personnages avec le lore établi, les autres personnages et votre manuscrit.",
+ "consistencyChecker.noFindings": "Aucune incohérence trouvée — ce personnage semble cohérent.",
"consistencyChecker.noResults": "Aucun résultat",
"consistencyChecker.noResultsHint": "Sélectionnez un personnage dans la liste de gauche et cliquez sur Vérifier la cohérence pour analyser votre manuscrit.",
- "consistencyChecker.results": "Résultats",
- "consistencyChecker.severity.info": "Info",
- "consistencyChecker.severity.warn": "Avertissement",
- "consistencyChecker.severity.error": "Conflit",
"consistencyChecker.refLabel": "Lié à",
- "consistencyChecker.noFindings": "Aucune incohérence trouvée — ce personnage semble cohérent.",
+ "consistencyChecker.results": "Résultats",
"consistencyChecker.selectCharacter": "Sélectionner un personnage",
"consistencyChecker.selectPlaceholder": "Choisir un personnage à vérifier",
+ "consistencyChecker.severity.error": "Conflit",
+ "consistencyChecker.severity.info": "Info",
+ "consistencyChecker.severity.warn": "Avertissement",
"consistencyChecker.storyBible.edgesTitle": "Co-occurrences d'entités (top)",
"consistencyChecker.storyBible.empty": "Activez « Story Bible avancé » dans Paramètres → IA → Drapeaux de fonctionnalités, puis modifiez le manuscrit pour extraire les données du graphe Codex.",
"consistencyChecker.storyBible.hintsTitle": "Conseils de cohérence",
@@ -286,6 +291,8 @@
"error.db.unknown": "Erreur inconnue lors de l'accès à la base de données.",
"error.deepLink.title": "Échec de l'ouverture du fichier projet",
"error.deepLink.unknown": "Erreur inconnue",
+ "error.fallback.generic": "IA indisponible — assistance intégrée utilisée.",
+ "error.fallback.offline": "Vous êtes hors ligne — assistance intégrée utilisée.",
"error.fileImportError": "Erreur d'importation de fichier",
"error.mic.denied": "Accès au microphone refusé. Accordez l'autorisation dans les paramètres de votre navigateur.",
"error.mic.generic": "Erreur de reconnaissance vocale : {{error}}",
@@ -382,22 +389,32 @@
"palette.voice.listeningLive": "Saisie vocale active",
"palette.voice.start": "Démarrer la recherche vocale",
"palette.voice.stop": "Arrêter la recherche vocale",
+ "plotBoard.heuristic.complicate.description": "Ajoutez un obstacle ou une révélation qui force un changement de plan.",
+ "plotBoard.heuristic.complicate.rationale": "Une nouvelle complication éprouve les personnages et ouvre des pistes.",
+ "plotBoard.heuristic.complicate.title": "Introduire une complication",
+ "plotBoard.heuristic.escalate.description": "Accentuez la pression sur votre protagoniste pour que le prochain choix coûte davantage.",
+ "plotBoard.heuristic.escalate.rationale": "L'escalade maintient l'élan quand le milieu s'essouffle.",
+ "plotBoard.heuristic.escalate.title": "Augmenter les enjeux",
+ "plotBoard.heuristic.position": "Juste après la scène sélectionnée",
+ "plotBoard.heuristic.reverse.description": "Renversez une attente — un allié flanche, une victoire tourne mal ou une vérité cachée émerge.",
+ "plotBoard.heuristic.reverse.rationale": "Les retournements ravivent la tension et approfondissent l'arc.",
+ "plotBoard.heuristic.reverse.title": "Ajouter un retournement",
"preview.controls.ariaLabel": "Contrôles de l'aperçu",
"preview.controls.decreaseFontSize": "Réduire la taille de police",
"preview.controls.exitFullscreen": "Quitter le plein écran",
"preview.controls.export": "Exporter (EPUB)",
- "preview.controls.pagedMode": "Vue paginée",
- "preview.progress.ariaLabel": "Progression de lecture",
"preview.controls.fontFamily": "Police de caractères",
"preview.controls.fontMono": "Monospace",
"preview.controls.fontSerif": "Serif",
"preview.controls.fontSystemUi": "Système",
"preview.controls.fullscreen": "Plein écran",
"preview.controls.increaseFontSize": "Augmenter la taille de police",
+ "preview.controls.pagedMode": "Vue paginée",
"preview.controls.wordCount": "Nombre de mots",
"preview.emptyScene": "Aucun contenu pour l'instant.",
"preview.noScenes": "Le manuscrit est vide",
"preview.noScenesHint": "Rendez-vous dans la vue Manuscrit et ajoutez votre première scène pour voir un aperçu ici.",
+ "preview.progress.ariaLabel": "Progression de lecture",
"preview.title": "Aperçu du livre",
"preview.toc.ariaLabel": "Table des matières",
"preview.toc.close": "Fermer la table des matières",
@@ -449,10 +466,6 @@
"proforge.progress.awaitingReviewHint": "⚠️ Cette étape attend votre relecture. Cliquez sur le bouton de l'étape ci-dessus pour examiner les éléments.",
"proforge.progress.completedStages": "Étapes terminées",
"proforge.progress.currentStatus": "Statut actuel",
- "proforge.progress.overall": "Progression globale",
- "proforge.progress.preparing": "Préparation…",
- "proforge.progress.stageOfTotal": "Étape {{current}} sur {{total}}",
- "proforge.progress.percentComplete": "{{percent}} % terminé",
"proforge.progress.itemsCount": "{{count}} éléments",
"proforge.progress.metric.aiCalls": "Appels à l'IA",
"proforge.progress.metric.duration": "Durée",
@@ -463,7 +476,11 @@
"proforge.progress.metric.totalTime": "Temps total",
"proforge.progress.metric.totalTokens": "Total des jetons",
"proforge.progress.noneRunning": "Aucun pipeline en cours.",
+ "proforge.progress.overall": "Progression globale",
+ "proforge.progress.percentComplete": "{{percent}} % terminé",
+ "proforge.progress.preparing": "Préparation…",
"proforge.progress.stageDetails": "Détails de l'étape : {{stage}}",
+ "proforge.progress.stageOfTotal": "Étape {{current}} sur {{total}}",
"proforge.progress.statusLabel": "Statut",
"proforge.progress.totals": "Totaux du pipeline",
"proforge.review.accept": "Accepter",
@@ -631,9 +648,9 @@
"sceneboard.act3.label": "Acte 3 – Résolution",
"sceneboard.addScene": "Ajouter une scène",
"sceneboard.addSceneToAct": "Ajouter une scène à cet acte",
+ "sceneboard.ai.contextNote": "L'analyse utilise les titres de scène et les premières lignes, jusqu'à ~2 000 caractères.",
"sceneboard.ai.empty": "Aucune suggestion. Réessayez après du contenu.",
"sceneboard.ai.panelTitle": "Suggestions de plot IA",
- "sceneboard.ai.contextNote": "L'analyse utilise les titres de scène et les premières lignes, jusqu'à ~2 000 caractères.",
"sceneboard.ai.ragChunks": "{{count}} passages de l'histoire",
"sceneboard.ai.retry": "Resuggérer",
"sceneboard.ai.suggestBeat": "Beat IA",
@@ -777,9 +794,9 @@
"vc.title": "Historique des versions",
"vc.words": "mots",
"voice.cancelSpeech": "Annuler la parole",
+ "voice.feedback.confidence": "Confiance {{percent}} %",
"voice.modeChip.commands": "Commandes",
"voice.modeChip.dictation": "Dictée",
- "voice.feedback.confidence": "Confiance {{percent}} %",
"voice.panelLabel": "Contrôle vocal",
"voice.permissionDenied": "Accès au micro refusé. Veuillez autoriser l’accès au microphone dans les paramètres de votre navigateur.",
"voice.startDictation": "Commencer la dictée",
@@ -793,23 +810,6 @@
"voice.stopListening": "Arrêter l’écoute",
"worlds.emptyState.description": "Construisez les lieux, les règles et les histoires dans lesquels votre récit prend vie. Commencez par un lieu.",
"worlds.emptyState.title": "Le monde vous attend",
- "error.fallback.generic": "IA indisponible — assistance intégrée utilisée.",
- "error.fallback.offline": "Vous êtes hors ligne — assistance intégrée utilisée.",
- "assisted.badge.label": "Assisté",
- "assisted.badge.srLabel": "Mode assisté — généré sans IA",
- "assisted.toast.title": "IA indisponible",
- "assisted.toast.description": "Assistance intégrée utilisée. Améliorez avec l'IA quand un modèle est disponible.",
- "assisted.enhance": "Améliorer avec l'IA",
- "plotBoard.heuristic.position": "Juste après la scène sélectionnée",
- "plotBoard.heuristic.escalate.title": "Augmenter les enjeux",
- "plotBoard.heuristic.escalate.description": "Accentuez la pression sur votre protagoniste pour que le prochain choix coûte davantage.",
- "plotBoard.heuristic.escalate.rationale": "L'escalade maintient l'élan quand le milieu s'essouffle.",
- "plotBoard.heuristic.complicate.title": "Introduire une complication",
- "plotBoard.heuristic.complicate.description": "Ajoutez un obstacle ou une révélation qui force un changement de plan.",
- "plotBoard.heuristic.complicate.rationale": "Une nouvelle complication éprouve les personnages et ouvre des pistes.",
- "plotBoard.heuristic.reverse.title": "Ajouter un retournement",
- "plotBoard.heuristic.reverse.description": "Renversez une attente — un allié flanche, une victoire tourne mal ou une vérité cachée émerge.",
- "plotBoard.heuristic.reverse.rationale": "Les retournements ravivent la tension et approfondissent l'arc.",
"copilot.annotationCount": "{{count}} insight for this chapter",
"copilot.announceClosed": "Copilot IA fermé",
"copilot.announceOpened": "Copilot IA ouvert",
@@ -877,11 +877,9 @@
"copilot.you": "Vous",
"dashboard.authorInsights.readability": "Lisibilité (Kandel-Moles, heuristique FR)",
"dashboard.authorInsights.readabilityFootnote": "Des scores plus élevés lisent souvent plus facilement ; adaptez selon le genre.",
- "dashboard.authorInsights.readabilityTooltip": "Échelle de lisibilité Flesch 0–100 : plus c'est élevé, plus c'est facile à lire (60–70 = langage courant). Un indicateur approximatif, pas une note normative.",
- "dashboard.authorInsights.readabilityScaleSuffix": "/100",
- "dashboard.logline.updated": "Logline mise à jour",
- "dashboard.logline.updatedUndo": "Appuyez sur Ctrl+Z pour annuler.",
"dashboard.authorInsights.readabilityNeedMore": "Écrivez encore un peu — score stable vers 40+ mots.",
+ "dashboard.authorInsights.readabilityScaleSuffix": "/100",
+ "dashboard.authorInsights.readabilityTooltip": "Échelle de lisibilité Flesch 0–100 : plus c'est élevé, plus c'est facile à lire (60–70 = langage courant). Un indicateur approximatif, pas une note normative.",
"dashboard.authorInsights.timeline": "Contrôles chronologie des scènes",
"dashboard.authorInsights.timelineClear": "Aucun avertissement à partir des métadonnées.",
"dashboard.authorInsights.timelineWarnBadge": "{{count}} avertissements — vérifiez dates/durées sur le tableau des scènes.",
@@ -953,6 +951,8 @@
"dashboard.healthScore.title": "Santé du projet",
"dashboard.healthScore.world": "Création de l'univers",
"dashboard.healthScore.writing": "Progression d'écriture",
+ "dashboard.logline.updated": "Logline mise à jour",
+ "dashboard.logline.updatedUndo": "Appuyez sur Ctrl+Z pour annuler.",
"dashboard.loglineModal.loading": "Génération de loglines brillantes...",
"dashboard.loglineModal.title": "Suggestions de loglines IA",
"dashboard.momentum.activity": "14 derniers jours",
@@ -986,23 +986,23 @@
"initialProject.chapter1": "Chapitre 1",
"initialProject.logline": "Un voyage de mille lieues commence par un seul pas...",
"initialProject.title": "Mon histoire sans titre",
- "desktop.menu.file": "Fichier",
+ "desktop.menu.commandPalette": "Palette de commandes",
+ "desktop.menu.edit": "Édition",
"desktop.menu.export": "Exporter le projet…",
+ "desktop.menu.file": "Fichier",
+ "desktop.menu.help": "Aide",
+ "desktop.menu.helpCenter": "Centre d'aide",
"desktop.menu.settings": "Paramètres",
- "desktop.menu.edit": "Édition",
"desktop.menu.view": "Affichage",
- "desktop.menu.commandPalette": "Palette de commandes",
"desktop.menu.window": "Fenêtre",
- "desktop.menu.help": "Aide",
- "desktop.menu.helpCenter": "Centre d'aide",
- "desktop.tray.tooltip": "WorldScript Studio",
- "desktop.tray.show": "Afficher WorldScript Studio",
- "desktop.tray.settings": "Paramètres",
- "desktop.tray.commandPalette": "Palette de commandes",
- "desktop.tray.quit": "Quitter",
- "desktop.settings.sectionTitle": "Bureau",
"desktop.settings.minimizeToTray": "Réduire dans la zone de notification à la fermeture",
"desktop.settings.minimizeToTrayHint": "Garder WorldScript Studio actif dans la zone de notification au lieu de quitter lorsque vous fermez la fenêtre.",
+ "desktop.settings.sectionTitle": "Bureau",
+ "desktop.tray.commandPalette": "Palette de commandes",
+ "desktop.tray.quit": "Quitter",
+ "desktop.tray.settings": "Paramètres",
+ "desktop.tray.show": "Afficher WorldScript Studio",
+ "desktop.tray.tooltip": "WorldScript Studio",
"export.ai.generateButton": "Générer le synopsis",
"export.ai.generating": "Génération en cours...",
"export.ai.synopsis": "Générer un synopsis IA",
@@ -1090,10 +1090,10 @@
"export.pasteSection.importAsChapter": "Importer comme chapitre",
"export.pasteSection.textPlaceholder": "Collez du texte depuis Google Docs ou Notion ici (Ctrl+V)...",
"export.pasteSection.titlePlaceholder": "Titre du chapitre (facultatif)",
- "export.preview.noContent": "Sélectionnez du contenu pour voir un aperçu.",
"export.preview.modeLabel": "Mode d'aperçu",
- "export.preview.modeText": "Texte",
"export.preview.modeRendered": "Rendu",
+ "export.preview.modeText": "Texte",
+ "export.preview.noContent": "Sélectionnez du contenu pour voir un aperçu.",
"export.preview.title": "Aperçu en direct",
"export.title": "Suite de publication Export",
"export.toggleSection": "Basculer la visibilité pour {{title}}",
@@ -1519,6 +1519,23 @@
"outline.deleteConfirm": "Êtes-vous sûr de vouloir supprimer cette section du plan ?",
"outline.description": "Décrivez votre idée d'histoire et laissez l'IA créer un plan structuré et modifiable pour vous.",
"outline.error.generationFailed": "Échec de la génération du contenu. Veuillez réessayer.",
+ "outline.heuristic.beat.climax.desc": "Le conflit central atteint son paroxysme lors de la confrontation décisive de l'histoire.",
+ "outline.heuristic.beat.climax.title": "Apogée",
+ "outline.heuristic.beat.complications.desc": "Les revers et les conflits s'aggravent ; la voie à suivre se rétrécit.",
+ "outline.heuristic.beat.complications.title": "Complications",
+ "outline.heuristic.beat.incitingIncident.desc": "L'événement qui met l'histoire en mouvement : {{idea}}.",
+ "outline.heuristic.beat.incitingIncident.title": "Élément déclencheur",
+ "outline.heuristic.beat.midpoint.desc": "Un tournant change la direction de l'histoire et augmente les enjeux.",
+ "outline.heuristic.beat.midpoint.title": "Point médian",
+ "outline.heuristic.beat.resolution.desc": "Les fils dénoués se rejoignent et un nouveau statu quo émerge.",
+ "outline.heuristic.beat.resolution.title": "Dénouement",
+ "outline.heuristic.beat.risingAction.desc": "Les complications s'intensifient et les enjeux grandissent à mesure que les personnages poursuivent leur but.",
+ "outline.heuristic.beat.risingAction.title": "Action montante",
+ "outline.heuristic.beat.setup.desc": "Présentez le monde et les personnages principaux, et établissez le statu quo avant que tout ne change.",
+ "outline.heuristic.beat.setup.title": "Mise en place",
+ "outline.heuristic.beat.twist.desc": "Une révélation inattendue bouleverse ce que les personnages croyaient vrai.",
+ "outline.heuristic.beat.twist.title": "Rebondissement",
+ "outline.heuristic.fallbackIdea": "l'idée centrale",
"outline.idea.generateButton": "Générer le plan",
"outline.idea.genreLabel": "Genre",
"outline.idea.genrePlaceholder": "ex. SF, Fantasy, Mystère",
@@ -1541,23 +1558,6 @@
"outline.result.twistTooltip": "Rebondissement généré par IA",
"outline.selectSection": "Sélectionner la section « {{title}} »",
"outline.title": "Générateur de plan d'histoire IA",
- "outline.heuristic.fallbackIdea": "l'idée centrale",
- "outline.heuristic.beat.setup.title": "Mise en place",
- "outline.heuristic.beat.setup.desc": "Présentez le monde et les personnages principaux, et établissez le statu quo avant que tout ne change.",
- "outline.heuristic.beat.incitingIncident.title": "Élément déclencheur",
- "outline.heuristic.beat.incitingIncident.desc": "L'événement qui met l'histoire en mouvement : {{idea}}.",
- "outline.heuristic.beat.risingAction.title": "Action montante",
- "outline.heuristic.beat.risingAction.desc": "Les complications s'intensifient et les enjeux grandissent à mesure que les personnages poursuivent leur but.",
- "outline.heuristic.beat.midpoint.title": "Point médian",
- "outline.heuristic.beat.midpoint.desc": "Un tournant change la direction de l'histoire et augmente les enjeux.",
- "outline.heuristic.beat.complications.title": "Complications",
- "outline.heuristic.beat.complications.desc": "Les revers et les conflits s'aggravent ; la voie à suivre se rétrécit.",
- "outline.heuristic.beat.twist.title": "Rebondissement",
- "outline.heuristic.beat.twist.desc": "Une révélation inattendue bouleverse ce que les personnages croyaient vrai.",
- "outline.heuristic.beat.climax.title": "Apogée",
- "outline.heuristic.beat.climax.desc": "Le conflit central atteint son paroxysme lors de la confrontation décisive de l'histoire.",
- "outline.heuristic.beat.resolution.title": "Dénouement",
- "outline.heuristic.beat.resolution.desc": "Les fils dénoués se rejoignent et un nouveau statu quo émerge.",
"portal.back": "Retour",
"portal.demo.chapterContent": "Le brouillard du matin collait aux quais lorsque Lyra déroula la vieille carte. Un cercle à peine lisible marquait le nord-ouest — la tour dont personne ne parlait.\n\nElle rangea le papier et suivit le sentier jusqu’à ce que la grille de fer se dresse devant elle. Le cadenas était tiède au soleil ; le métal, encore froid.",
"portal.demo.chapterTitle": "Chapitre 1 — Devant la grille",
@@ -1752,6 +1752,7 @@
"settings.ai.gpu.troubleshootLowEnd": "Votre appareil dispose de ressources limitées. L'IA locale utilisera des modèles plus petits. Fermez d'autres onglets ou activez le mode éco.",
"settings.ai.gpu.troubleshootQueue": "Plusieurs tâches IA sont en file d'attente. Une seule s'exécute à la fois pour éviter les collisions VRAM. Attendez la fin de la tâche en cours.",
"settings.ai.gpu.waitingConsumers": "En attente",
+ "settings.ai.grokKey": "Clé API Grok",
"settings.ai.hybridFallbackHint": "Si le fournisseur principal échoue, WorldScript essaie les replis listés. La diffusion en continu de l'écrivain utilise uniquement votre fournisseur principal.",
"settings.ai.hybridFallbackTitle": "Repli hybride (outils IA du projet)",
"settings.ai.hybridFallbackToggle": "Activer la chaîne de repli",
@@ -1832,6 +1833,11 @@
"settings.ai.preset.lmStudio": "LM Studio",
"settings.ai.preset.ollamaDefault": "Ollama (port par défaut)",
"settings.ai.preset.vllm": "vLLM",
+ "settings.ai.provider.anthropic": "Anthropic Claude",
+ "settings.ai.provider.gemini": "Google Gemini",
+ "settings.ai.provider.grok": "xAI Grok",
+ "settings.ai.provider.ollama": "Ollama (local)",
+ "settings.ai.provider.openai": "OpenAI",
"settings.ai.providerDescription": "Choisissez quel fournisseur d'IA WorldScript Studio doit utiliser.",
"settings.ai.providerOnnx": "ONNX (WASM)",
"settings.ai.providerStatusConnected": "Connecté",
@@ -2711,6 +2717,11 @@
"worlds.edit.notes": "Notes",
"worlds.editorTabsAriaLabel": "Onglets de l'éditeur de monde",
"worlds.error.imageFailed": "Échec de la génération de l'image d'ambiance. Essayez d'ajouter plus de détails à la description du monde.",
+ "worlds.heuristic.culture": "Décrivez les peuples, croyances et la vie quotidienne façonnés par {{concept}}.",
+ "worlds.heuristic.description": "Un monde défini par sa prémisse centrale : {{concept}}.",
+ "worlds.heuristic.geography": "Esquissez les grandes régions, climats et caractéristiques naturelles de {{concept}}.",
+ "worlds.heuristic.magicSystem": "Définissez les règles, les coûts et les limites du pouvoir dans {{concept}}.",
+ "worlds.heuristic.name": "Nouveau monde",
"worlds.loading.profile": "Génération du profil de monde détaillé...",
"worlds.newWorldName": "Nouveau monde",
"worlds.noWorlds": "Aucun monde créé.",
@@ -2729,32 +2740,19 @@
"worlds.title": "Atlas des mondes",
"worlds.uploadImage": "Télécharger une image",
"worlds.yourWorlds": "Vos mondes",
- "worlds.heuristic.name": "Nouveau monde",
- "worlds.heuristic.description": "Un monde défini par sa prémisse centrale : {{concept}}.",
- "worlds.heuristic.geography": "Esquissez les grandes régions, climats et caractéristiques naturelles de {{concept}}.",
- "worlds.heuristic.magicSystem": "Définissez les règles, les coûts et les limites du pouvoir dans {{concept}}.",
- "worlds.heuristic.culture": "Décrivez les peuples, croyances et la vie quotidienne façonnés par {{concept}}.",
"writer.cancelledTag": "Annulé",
"writer.chapter.label": "Chapitre : {{title}}",
- "writer.context.hide": "Masquer le contexte",
- "writer.context.label": "Contexte",
- "writer.context.show": "Afficher le contexte",
- "writer.flowMode.enterLabel": "Mode flux",
- "writer.modeBadge.label": "Modes actifs :",
- "writer.modeBadge.flow": "Flux",
- "writer.modeBadge.focus": "Focus",
- "writer.modeBadge.proforge": "ProForge",
- "writer.modeBadge.contextHidden": "Contexte masqué",
- "writer.modeBadge.toolsHidden": "Outils masqués",
- "writer.modeBadge.reset": "Rétablir la disposition standard",
- "writer.modeBadge.resetTitle": "Réinitialiser la disposition standard à trois colonnes",
"writer.coachmark.dismiss": "Compris",
- "writer.coachmark.flow.title": "Mode flux",
"writer.coachmark.flow.body": "Seul le panneau d'écriture est affiché — tout le reste est masqué. Appuyez sur Échap ou « Rétablir la disposition standard » pour revenir.",
- "writer.coachmark.focus.title": "Mode focus",
+ "writer.coachmark.flow.title": "Mode flux",
"writer.coachmark.focus.body": "Affiche votre manuscrit et le contexte côte à côte, en masquant la colonne des outils. Désactivable à tout moment depuis l'en-tête.",
- "writer.coachmark.proforge.title": "Pipeline ProForge",
+ "writer.coachmark.focus.title": "Mode focus",
"writer.coachmark.proforge.body": "La colonne des outils exécute désormais le pipeline d'édition en plusieurs étapes. Votre manuscrit n'est jamais modifié sans votre validation.",
+ "writer.coachmark.proforge.title": "Pipeline ProForge",
+ "writer.context.hide": "Masquer le contexte",
+ "writer.context.label": "Contexte",
+ "writer.context.show": "Afficher le contexte",
+ "writer.flowMode.enterLabel": "Mode flux",
"writer.flowMode.exit": "Quitter le mode flux",
"writer.flowMode.exitLabel": "Quitter le flux",
"writer.flowMode.hint": "Écrivez sans interruption. Appuyez sur Échap pour revenir.",
@@ -2763,9 +2761,31 @@
"writer.focusMode.enterLabel": "Mode concentration",
"writer.focusMode.exit": "Quitter le mode concentration",
"writer.focusMode.exitLabel": "Quitter la concentration",
+ "writer.grammar.addToDictionary": "Ajouter au dictionnaire",
+ "writer.grammar.apply": "Appliquer",
+ "writer.grammar.checkButton": "Vérifier cette scène",
+ "writer.grammar.checking": "Vérification…",
+ "writer.grammar.disabled": "Activez LanguageTool dans Paramètres → Connexions pour vérifier cette scène.",
+ "writer.grammar.error": "Le serveur LanguageTool a renvoyé une erreur.",
+ "writer.grammar.ignore": "Ignorer",
+ "writer.grammar.issuesFound": "{{count}} problèmes détectés",
+ "writer.grammar.noIssues": "Aucun problème détecté.",
+ "writer.grammar.noSuggestions": "Aucune suggestion",
+ "writer.grammar.offline": "Impossible de joindre le serveur LanguageTool. Est-il démarré ?",
+ "writer.grammar.selectScene": "Sélectionnez une scène à vérifier.",
+ "writer.grammar.title": "Grammaire et orthographe",
+ "writer.grammar.unsupported": "La vérification grammaticale n'est pas disponible pour cette langue.",
"writer.imagePrompt.description": "Génère un prompt optimisé DALL·E 3 / Midjourney à partir de la scène actuelle ou de la sélection de texte.",
"writer.imagePrompt.note": "Le prompt généré fonctionne directement dans DALL·E 3 et Midjourney.",
"writer.imagePrompt.tip": "Astuce : Sélectionnez une section de texte spécifique pour un prompt de scène ciblé.",
+ "writer.modeBadge.contextHidden": "Contexte masqué",
+ "writer.modeBadge.flow": "Flux",
+ "writer.modeBadge.focus": "Focus",
+ "writer.modeBadge.label": "Modes actifs :",
+ "writer.modeBadge.proforge": "ProForge",
+ "writer.modeBadge.reset": "Rétablir la disposition standard",
+ "writer.modeBadge.resetTitle": "Réinitialiser la disposition standard à trois colonnes",
+ "writer.modeBadge.toolsHidden": "Outils masqués",
"writer.stopGenerating": "Arrêter la génération",
"writer.studio.context.contentPlaceholder": "Sélectionnez ou créez une section du manuscrit pour commencer.",
"writer.studio.context.sectionLabel": "Section de travail",
@@ -2787,12 +2807,10 @@
"writer.studio.controls.tones.poetic": "Plus poétique",
"writer.studio.controls.tones.suspenseful": "Plus suspensif",
"writer.studio.description": "Votre co-auteur IA. Générez, améliorez et brainstormez avec le contexte complet du projet.",
+ "writer.studio.rag.chunkScore": "pertinence {{score}}",
"writer.studio.rag.chunksBadge": "{{count}} passages trouvés",
"writer.studio.rag.chunksHint": "Extraits pertinents de votre manuscrit — plus de passages signifie un contexte IA plus riche",
"writer.studio.rag.inspectorLabel": "Contexte récupéré",
- "writer.studio.rag.chunkScore": "pertinence {{score}}",
- "writer.studio.tokens.badge": "~{{count}} jetons",
- "writer.studio.tokens.hint": "Jetons approximatifs utilisés par votre dernière requête IA",
"writer.studio.rag.useContext": "Puiser dans mon histoire",
"writer.studio.result.insert": "Insérer",
"writer.studio.result.next": "Suivant",
@@ -2802,6 +2820,8 @@
"writer.studio.result.retry": "Réessayer",
"writer.studio.result.title": "Zone de travail IA",
"writer.studio.title": "Studio d'écriture IA",
+ "writer.studio.tokens.badge": "~{{count}} jetons",
+ "writer.studio.tokens.hint": "Jetons approximatifs utilisés par votre dernière requête IA",
"writer.studio.tools.brainstorm.contextLabel": "Contexte de brainstorming (facultatif)",
"writer.studio.tools.brainstorm.contextPlaceholder": "Fournissez une brève situation, ou l'IA utilisera la section du manuscrit actuelle.",
"writer.studio.tools.brainstorm.title": "Brainstormer des idées",
@@ -2833,19 +2853,5 @@
"writer.tts.start": "Lire à haute voix",
"writer.tts.stop": "Arrêter la lecture",
"writer.versionControl.label": "Versions",
- "writer.versionControl.tooltip": "Contrôle de version (branches et instantanés)",
- "writer.grammar.title": "Grammaire et orthographe",
- "writer.grammar.checkButton": "Vérifier cette scène",
- "writer.grammar.checking": "Vérification…",
- "writer.grammar.issuesFound": "{{count}} problèmes détectés",
- "writer.grammar.noIssues": "Aucun problème détecté.",
- "writer.grammar.selectScene": "Sélectionnez une scène à vérifier.",
- "writer.grammar.unsupported": "La vérification grammaticale n'est pas disponible pour cette langue.",
- "writer.grammar.disabled": "Activez LanguageTool dans Paramètres → Connexions pour vérifier cette scène.",
- "writer.grammar.offline": "Impossible de joindre le serveur LanguageTool. Est-il démarré ?",
- "writer.grammar.error": "Le serveur LanguageTool a renvoyé une erreur.",
- "writer.grammar.apply": "Appliquer",
- "writer.grammar.ignore": "Ignorer",
- "writer.grammar.addToDictionary": "Ajouter au dictionnaire",
- "writer.grammar.noSuggestions": "Aucune suggestion"
+ "writer.versionControl.tooltip": "Contrôle de version (branches et instantanés)"
}
diff --git a/public/locales/he/bundle.json b/public/locales/he/bundle.json
index 77035a29..c9e8f28f 100644
--- a/public/locales/he/bundle.json
+++ b/public/locales/he/bundle.json
@@ -90,6 +90,14 @@
"characters.edit.relationships": "יחסים",
"characters.editorTabsAriaLabel": "לשוניות עורך הדמות",
"characters.error.portraitFailed": "יצירת הדיוקן נכשלה. נסו להוסיף פרטים נוספים לתיאור המראה.",
+ "characters.heuristic.appearance": "Describe how they present themselves — let their look hint at {{concept}}.",
+ "characters.heuristic.backstory": "Shaped by formative experiences, this character carries a past tied to {{concept}}.",
+ "characters.heuristic.characterArc": "They begin guarded and, through the story, are changed by {{concept}}.",
+ "characters.heuristic.flaws": "A weakness that complicates their goals.",
+ "characters.heuristic.motivation": "A core desire connected to {{concept}} drives their choices.",
+ "characters.heuristic.name": "New Character",
+ "characters.heuristic.personalityTraits": "Resourceful, guarded, determined.",
+ "characters.heuristic.relationships": "Note the key bonds and rivalries that define them.",
"characters.loading.profile": "יוצר פרופיל מפורט...",
"characters.newCharacterName": "דמות חדשה",
"characters.noCharacters": "עדיין לא נוצרו דמויות.",
@@ -107,14 +115,6 @@
"characters.title": "תיקי דמויות",
"characters.uploadImage": "העלאת תמונה",
"characters.yourCharacters": "הדמויות שלכם",
- "characters.heuristic.name": "New Character",
- "characters.heuristic.backstory": "Shaped by formative experiences, this character carries a past tied to {{concept}}.",
- "characters.heuristic.motivation": "A core desire connected to {{concept}} drives their choices.",
- "characters.heuristic.appearance": "Describe how they present themselves — let their look hint at {{concept}}.",
- "characters.heuristic.personalityTraits": "Resourceful, guarded, determined.",
- "characters.heuristic.flaws": "A weakness that complicates their goals.",
- "characters.heuristic.characterArc": "They begin guarded and, through the story, are changed by {{concept}}.",
- "characters.heuristic.relationships": "Note the key bonds and rivalries that define them.",
"apiKey.connectionFailed": "בדיקת החיבור נכשלה.",
"apiKey.connectionSuccess": "החיבור הצליח! ה‑API מגיב כראוי.",
"apiKey.decryptFailed": "לא ניתן לפענח את מפתח ה‑API",
@@ -125,6 +125,11 @@
"apiKey.test": "בדיקת חיבור",
"apiKey.testConnection": "בדיקת חיבור API",
"apiKey.testing": "בודק…",
+ "assisted.badge.label": "Assisted",
+ "assisted.badge.srLabel": "Assisted mode — generated without AI",
+ "assisted.enhance": "Enhance with AI",
+ "assisted.toast.description": "Used built-in assistance. Enhance with AI when a model is available.",
+ "assisted.toast.title": "AI unavailable",
"charGraph.characters": "דמויות",
"charGraph.noCharacters": "אין עדיין דמויות",
"charGraph.noCharactersHint": "הוסיפו דמויות בתצוגת הדמויות כדי להמחיש את היחסים ביניהן כאן.",
@@ -286,6 +291,8 @@
"error.db.unknown": "שגיאה לא ידועה בעת גישה למסד הנתונים.",
"error.deepLink.title": "Failed to open project file",
"error.deepLink.unknown": "Unknown error",
+ "error.fallback.generic": "AI is unavailable — used built-in assistance.",
+ "error.fallback.offline": "You're offline — used built-in assistance.",
"error.fileImportError": "שגיאת ייבוא קובץ",
"error.mic.denied": "הגישה למיקרופון נדחתה. אנא העניקו הרשאה בהגדרות הדפדפן שלכם.",
"error.mic.generic": "שגיאת זיהוי דיבור: {{error}}",
@@ -382,6 +389,16 @@
"palette.voice.listeningLive": "קלט קולי פעיל",
"palette.voice.start": "התחלת חיפוש קולי",
"palette.voice.stop": "עצירת חיפוש קולי",
+ "plotBoard.heuristic.complicate.description": "Add an obstacle or reveal that forces a change of plan.",
+ "plotBoard.heuristic.complicate.rationale": "A fresh complication tests the characters and opens new threads.",
+ "plotBoard.heuristic.complicate.title": "Introduce a complication",
+ "plotBoard.heuristic.escalate.description": "Increase the pressure on your protagonist so the next choice costs more.",
+ "plotBoard.heuristic.escalate.rationale": "Escalation keeps momentum when the middle sags.",
+ "plotBoard.heuristic.escalate.title": "Raise the stakes",
+ "plotBoard.heuristic.position": "Right after the selected scene",
+ "plotBoard.heuristic.reverse.description": "Flip an expectation — an ally falters, a win turns sour, or a hidden truth surfaces.",
+ "plotBoard.heuristic.reverse.rationale": "Reversals refresh tension and deepen the arc.",
+ "plotBoard.heuristic.reverse.title": "Add a reversal",
"preview.controls.ariaLabel": "בקרות תצוגה מקדימה",
"preview.controls.decreaseFontSize": "הקטנת גודל הגופן",
"preview.controls.exitFullscreen": "יציאה ממסך מלא",
@@ -449,10 +466,6 @@
"proforge.progress.awaitingReviewHint": "⚠️ This stage is awaiting your review. Click the stage button above to review items.",
"proforge.progress.completedStages": "Completed Stages",
"proforge.progress.currentStatus": "Current Status",
- "proforge.progress.overall": "Overall progress",
- "proforge.progress.preparing": "Preparing…",
- "proforge.progress.stageOfTotal": "Stage {{current}} of {{total}}",
- "proforge.progress.percentComplete": "{{percent}}% complete",
"proforge.progress.itemsCount": "{{count}} items",
"proforge.progress.metric.aiCalls": "AI Calls",
"proforge.progress.metric.duration": "Duration",
@@ -463,7 +476,11 @@
"proforge.progress.metric.totalTime": "Total Time",
"proforge.progress.metric.totalTokens": "Total Tokens",
"proforge.progress.noneRunning": "No pipeline running.",
+ "proforge.progress.overall": "Overall progress",
+ "proforge.progress.percentComplete": "{{percent}}% complete",
+ "proforge.progress.preparing": "Preparing…",
"proforge.progress.stageDetails": "Stage Details: {{stage}}",
+ "proforge.progress.stageOfTotal": "Stage {{current}} of {{total}}",
"proforge.progress.statusLabel": "Status",
"proforge.progress.totals": "Pipeline Totals",
"proforge.review.accept": "Accept",
@@ -777,9 +794,9 @@
"vc.title": "היסטוריית גרסאות",
"vc.words": "מילים",
"voice.cancelSpeech": "ביטול דיבור",
+ "voice.feedback.confidence": "ביטחון {{percent}}%",
"voice.modeChip.commands": "פקודות",
"voice.modeChip.dictation": "הכתבה",
- "voice.feedback.confidence": "ביטחון {{percent}}%",
"voice.panelLabel": "בקרה קולית",
"voice.permissionDenied": "הגישה למיקרופון נדחתה. אנא אפשרו גישה למיקרופון בהגדרות הדפדפן כדי להשתמש בתכונות הקוליות.",
"voice.startDictation": "התחלת הכתבה",
@@ -793,23 +810,6 @@
"voice.stopListening": "עצירת האזנה",
"worlds.emptyState.description": "בנו את המקומות, החוקים וההיסטוריות שבהם הסיפור שלכם חי. התחילו במיקום.",
"worlds.emptyState.title": "העולם ממתין",
- "error.fallback.generic": "AI is unavailable — used built-in assistance.",
- "error.fallback.offline": "You're offline — used built-in assistance.",
- "assisted.badge.label": "Assisted",
- "assisted.badge.srLabel": "Assisted mode — generated without AI",
- "assisted.toast.title": "AI unavailable",
- "assisted.toast.description": "Used built-in assistance. Enhance with AI when a model is available.",
- "assisted.enhance": "Enhance with AI",
- "plotBoard.heuristic.position": "Right after the selected scene",
- "plotBoard.heuristic.escalate.title": "Raise the stakes",
- "plotBoard.heuristic.escalate.description": "Increase the pressure on your protagonist so the next choice costs more.",
- "plotBoard.heuristic.escalate.rationale": "Escalation keeps momentum when the middle sags.",
- "plotBoard.heuristic.complicate.title": "Introduce a complication",
- "plotBoard.heuristic.complicate.description": "Add an obstacle or reveal that forces a change of plan.",
- "plotBoard.heuristic.complicate.rationale": "A fresh complication tests the characters and opens new threads.",
- "plotBoard.heuristic.reverse.title": "Add a reversal",
- "plotBoard.heuristic.reverse.description": "Flip an expectation — an ally falters, a win turns sour, or a hidden truth surfaces.",
- "plotBoard.heuristic.reverse.rationale": "Reversals refresh tension and deepen the arc.",
"copilot.annotationCount": "{{count}} insight for this chapter",
"copilot.announceClosed": "AI Copilot closed",
"copilot.announceOpened": "AI Copilot opened",
@@ -1090,10 +1090,10 @@
"export.pasteSection.importAsChapter": "ייבוא כפרק",
"export.pasteSection.textPlaceholder": "הדביקו כאן טקסט מ‑Google Docs או מ‑Notion (Ctrl+V)...",
"export.pasteSection.titlePlaceholder": "כותרת הפרק (אופציונלי)",
- "export.preview.noContent": "בחרו תוכן כדי לראות תצוגה מקדימה.",
"export.preview.modeLabel": "מצב תצוגה מקדימה",
- "export.preview.modeText": "טקסט",
"export.preview.modeRendered": "מעובד",
+ "export.preview.modeText": "טקסט",
+ "export.preview.noContent": "בחרו תוכן כדי לראות תצוגה מקדימה.",
"export.preview.title": "תצוגה מקדימה חיה",
"export.title": "חבילת הוצאה לאור וייצוא",
"export.toggleSection": "החלפת נראות עבור {{title}}",
@@ -1519,6 +1519,23 @@
"outline.deleteConfirm": "האם אתם בטוחים שברצונכם למחוק את סעיף המתווה הזה?",
"outline.description": "תארו את רעיון הסיפור שלכם ותנו ל‑AI ליצור עבורכם מתווה מובנה הניתן לעריכה.",
"outline.error.generationFailed": "יצירת התוכן נכשלה. אנא נסו שוב.",
+ "outline.heuristic.beat.climax.desc": "The central conflict comes to a head in the story's defining confrontation.",
+ "outline.heuristic.beat.climax.title": "Climax",
+ "outline.heuristic.beat.complications.desc": "Setbacks and conflicts deepen; the path forward narrows.",
+ "outline.heuristic.beat.complications.title": "Complications",
+ "outline.heuristic.beat.incitingIncident.desc": "The event that sets the story in motion: {{idea}}.",
+ "outline.heuristic.beat.incitingIncident.title": "Inciting Incident",
+ "outline.heuristic.beat.midpoint.desc": "A turning point shifts the direction of the story and raises the stakes.",
+ "outline.heuristic.beat.midpoint.title": "Midpoint",
+ "outline.heuristic.beat.resolution.desc": "Loose ends are tied up and a new status quo emerges.",
+ "outline.heuristic.beat.resolution.title": "Resolution",
+ "outline.heuristic.beat.risingAction.desc": "Complications escalate and the stakes grow as the characters pursue their goal.",
+ "outline.heuristic.beat.risingAction.title": "Rising Action",
+ "outline.heuristic.beat.setup.desc": "Introduce the world and the main characters, and establish the status quo before everything changes.",
+ "outline.heuristic.beat.setup.title": "Setup",
+ "outline.heuristic.beat.twist.desc": "An unexpected revelation upends what the characters believed to be true.",
+ "outline.heuristic.beat.twist.title": "Twist",
+ "outline.heuristic.fallbackIdea": "the central idea",
"outline.idea.generateButton": "יצירת מתווה",
"outline.idea.genreLabel": "ז׳אנר",
"outline.idea.genrePlaceholder": "לדוגמה: מדע בדיוני, פנטזיה, מסתורין",
@@ -1541,23 +1558,6 @@
"outline.result.twistTooltip": "תפנית עלילתית שנוצרה ב‑AI",
"outline.selectSection": "Select section '{{title}}'",
"outline.title": "מחולל מתווה סיפור ב‑AI",
- "outline.heuristic.fallbackIdea": "the central idea",
- "outline.heuristic.beat.setup.title": "Setup",
- "outline.heuristic.beat.setup.desc": "Introduce the world and the main characters, and establish the status quo before everything changes.",
- "outline.heuristic.beat.incitingIncident.title": "Inciting Incident",
- "outline.heuristic.beat.incitingIncident.desc": "The event that sets the story in motion: {{idea}}.",
- "outline.heuristic.beat.risingAction.title": "Rising Action",
- "outline.heuristic.beat.risingAction.desc": "Complications escalate and the stakes grow as the characters pursue their goal.",
- "outline.heuristic.beat.midpoint.title": "Midpoint",
- "outline.heuristic.beat.midpoint.desc": "A turning point shifts the direction of the story and raises the stakes.",
- "outline.heuristic.beat.complications.title": "Complications",
- "outline.heuristic.beat.complications.desc": "Setbacks and conflicts deepen; the path forward narrows.",
- "outline.heuristic.beat.twist.title": "Twist",
- "outline.heuristic.beat.twist.desc": "An unexpected revelation upends what the characters believed to be true.",
- "outline.heuristic.beat.climax.title": "Climax",
- "outline.heuristic.beat.climax.desc": "The central conflict comes to a head in the story's defining confrontation.",
- "outline.heuristic.beat.resolution.title": "Resolution",
- "outline.heuristic.beat.resolution.desc": "Loose ends are tied up and a new status quo emerges.",
"portal.back": "חזרה",
"portal.demo.chapterContent": "ערפל הבוקר נצמד לרציפים בעוד לירה פורשת את מפת העיר הישנה. עיגול דהוי סימן את הפינה הצפון‑מערבית — המגדל שאיש אינו מזכיר.\n\nהיא קיפלה את הנייר ופנתה אל השביל הצר, עד שסבך הברזל התרומם מולה. המנעול היה חמים בשמש; המתכת עוד קרה.",
"portal.demo.chapterTitle": "פרק 1 — לפני השער",
@@ -1752,6 +1752,7 @@
"settings.ai.gpu.troubleshootLowEnd": "למכשיר שלכם משאבים מוגבלים. ה‑AI המקומי ישתמש במודלים קטנים יותר. לביצועים טובים יותר, סגרו לשוניות דפדפן אחרות או הפעילו מצב חיסכון.",
"settings.ai.gpu.troubleshootQueue": "מספר משימות AI בתור. רק אחת רצה בכל פעם כדי להימנע מהתנגשויות VRAM. המתינו לסיום המשימה הנוכחית.",
"settings.ai.gpu.waitingConsumers": "ממתין",
+ "settings.ai.grokKey": "Grok API Key",
"settings.ai.hybridFallbackHint": "אם הספק הראשי נכשל, WorldScript מנסה את החלופות הרשומות (מחוללי סצנות, כלי קודקס). הזרמת הכותב משתמשת בספק הראשי שלכם בלבד.",
"settings.ai.hybridFallbackTitle": "חלופה היברידית (כלי AI של הפרויקט)",
"settings.ai.hybridFallbackToggle": "הפעלת שרשרת חלופות",
@@ -1832,6 +1833,11 @@
"settings.ai.preset.lmStudio": "LM Studio",
"settings.ai.preset.ollamaDefault": "Ollama (פורט ברירת מחדל)",
"settings.ai.preset.vllm": "vLLM",
+ "settings.ai.provider.anthropic": "Anthropic Claude",
+ "settings.ai.provider.gemini": "Google Gemini",
+ "settings.ai.provider.grok": "xAI Grok",
+ "settings.ai.provider.ollama": "Ollama (local)",
+ "settings.ai.provider.openai": "OpenAI",
"settings.ai.providerDescription": "בחרו באיזה ספק AI WorldScript Studio ישתמש.",
"settings.ai.providerOnnx": "ONNX (WASM)",
"settings.ai.providerStatusConnected": "מחובר",
@@ -2711,6 +2717,11 @@
"worlds.edit.notes": "הערות",
"worlds.editorTabsAriaLabel": "לשוניות עורך העולם",
"worlds.error.imageFailed": "יצירת תמונת האווירה נכשלה. נסו להוסיף פרטים נוספים לתיאור העולם או בדקו את החיבור שלכם.",
+ "worlds.heuristic.culture": "Describe the peoples, beliefs, and daily life shaped by {{concept}}.",
+ "worlds.heuristic.description": "A world defined by its central premise: {{concept}}.",
+ "worlds.heuristic.geography": "Outline the major regions, climates, and natural features of {{concept}}.",
+ "worlds.heuristic.magicSystem": "Define the rules, costs, and limits of power in {{concept}}.",
+ "worlds.heuristic.name": "New World",
"worlds.loading.profile": "יוצר פרופיל עולם מפורט...",
"worlds.newWorldName": "עולם חדש",
"worlds.noWorlds": "עדיין לא נוצרו עולמות.",
@@ -2729,11 +2740,6 @@
"worlds.title": "אטלס עולם",
"worlds.uploadImage": "העלאת תמונה",
"worlds.yourWorlds": "העולמות שלכם",
- "worlds.heuristic.name": "New World",
- "worlds.heuristic.description": "A world defined by its central premise: {{concept}}.",
- "worlds.heuristic.geography": "Outline the major regions, climates, and natural features of {{concept}}.",
- "worlds.heuristic.magicSystem": "Define the rules, costs, and limits of power in {{concept}}.",
- "worlds.heuristic.culture": "Describe the peoples, beliefs, and daily life shaped by {{concept}}.",
"writer.cancelledTag": "Cancelled",
"writer.chapter.label": "פרק: {{title}}",
"writer.coachmark.dismiss": "Got it",
@@ -2755,6 +2761,20 @@
"writer.focusMode.enterLabel": "מצב מיקוד",
"writer.focusMode.exit": "יציאה ממצב מיקוד",
"writer.focusMode.exitLabel": "יציאה ממיקוד",
+ "writer.grammar.addToDictionary": "Add to dictionary",
+ "writer.grammar.apply": "Apply",
+ "writer.grammar.checkButton": "Check this scene",
+ "writer.grammar.checking": "Checking…",
+ "writer.grammar.disabled": "Enable LanguageTool in Settings → Connections to check this scene.",
+ "writer.grammar.error": "The LanguageTool server returned an error.",
+ "writer.grammar.ignore": "Ignore",
+ "writer.grammar.issuesFound": "{{count}} issues found",
+ "writer.grammar.noIssues": "No issues found.",
+ "writer.grammar.noSuggestions": "No suggestions",
+ "writer.grammar.offline": "Couldn't reach the LanguageTool server. Is it running?",
+ "writer.grammar.selectScene": "Select a scene to check.",
+ "writer.grammar.title": "Grammar & Spelling",
+ "writer.grammar.unsupported": "Grammar check isn't available for this language.",
"writer.imagePrompt.description": "יוצר הנחיית DALL·E 3 / Midjourney מותאמת מהסצנה הנוכחית או מבחירת הטקסט.",
"writer.imagePrompt.note": "ההנחיה שנוצרה עובדת ישירות ב‑DALL·E 3 וב‑Midjourney.",
"writer.imagePrompt.tip": "טיפ: בחרו קטע טקסט ספציפי לקבלת הנחיית סצנה ממוקדת.",
@@ -2787,12 +2807,10 @@
"writer.studio.controls.tones.poetic": "יותר פיוטי",
"writer.studio.controls.tones.suspenseful": "יותר מותח",
"writer.studio.description": "שותף הכתיבה ה‑AI שלכם. צרו, שפרו וסיעור מוחות עם הקשר פרויקט מלא.",
+ "writer.studio.rag.chunkScore": "רלוונטיות {{score}}",
"writer.studio.rag.chunksBadge": "נמצאו {{count}} קטעי סיפור",
"writer.studio.rag.chunksHint": "קטעים רלוונטיים מכתב היד שלכם — יותר קטעים משמעם הקשר AI עשיר יותר",
"writer.studio.rag.inspectorLabel": "הקשר שנשלף",
- "writer.studio.rag.chunkScore": "רלוונטיות {{score}}",
- "writer.studio.tokens.badge": "~{{count}} אסימונים",
- "writer.studio.tokens.hint": "מספר האסימונים המשוער ששימש בבקשת ה-AI האחרונה",
"writer.studio.rag.useContext": "שאבו מהסיפור שלי",
"writer.studio.result.insert": "הוספה",
"writer.studio.result.next": "הבא",
@@ -2802,6 +2820,8 @@
"writer.studio.result.retry": "ניסיון חוזר",
"writer.studio.result.title": "טיוטת AI",
"writer.studio.title": "סטודיו כתיבה ב‑AI",
+ "writer.studio.tokens.badge": "~{{count}} אסימונים",
+ "writer.studio.tokens.hint": "מספר האסימונים המשוער ששימש בבקשת ה-AI האחרונה",
"writer.studio.tools.brainstorm.contextLabel": "הקשר סיעור מוחות (אופציונלי)",
"writer.studio.tools.brainstorm.contextPlaceholder": "ספקו מצב קצר, או שה‑AI ישתמש בסעיף כתב היד הנוכחי.",
"writer.studio.tools.brainstorm.title": "סיעור רעיונות",
@@ -2833,19 +2853,5 @@
"writer.tts.start": "הקראה בקול",
"writer.tts.stop": "עצירת הקראה",
"writer.versionControl.label": "גרסאות",
- "writer.versionControl.tooltip": "בקרת גרסאות (ענפים ותמונות מצב)",
- "writer.grammar.title": "Grammar & Spelling",
- "writer.grammar.checkButton": "Check this scene",
- "writer.grammar.checking": "Checking…",
- "writer.grammar.issuesFound": "{{count}} issues found",
- "writer.grammar.noIssues": "No issues found.",
- "writer.grammar.selectScene": "Select a scene to check.",
- "writer.grammar.unsupported": "Grammar check isn't available for this language.",
- "writer.grammar.disabled": "Enable LanguageTool in Settings → Connections to check this scene.",
- "writer.grammar.offline": "Couldn't reach the LanguageTool server. Is it running?",
- "writer.grammar.error": "The LanguageTool server returned an error.",
- "writer.grammar.apply": "Apply",
- "writer.grammar.ignore": "Ignore",
- "writer.grammar.addToDictionary": "Add to dictionary",
- "writer.grammar.noSuggestions": "No suggestions"
+ "writer.versionControl.tooltip": "בקרת גרסאות (ענפים ותמונות מצב)"
}
diff --git a/public/locales/hu/bundle.json b/public/locales/hu/bundle.json
index 109146ac..434c749a 100644
--- a/public/locales/hu/bundle.json
+++ b/public/locales/hu/bundle.json
@@ -90,6 +90,14 @@
"characters.edit.relationships": "Kapcsolatok",
"characters.editorTabsAriaLabel": "Karakterszerkesztő lapok",
"characters.error.portraitFailed": "A portrégenerálás nem sikerült. Próbáljon több részletet hozzáadni a megjelenés leírásához.",
+ "characters.heuristic.appearance": "Describe how they present themselves — let their look hint at {{concept}}.",
+ "characters.heuristic.backstory": "Shaped by formative experiences, this character carries a past tied to {{concept}}.",
+ "characters.heuristic.characterArc": "They begin guarded and, through the story, are changed by {{concept}}.",
+ "characters.heuristic.flaws": "A weakness that complicates their goals.",
+ "characters.heuristic.motivation": "A core desire connected to {{concept}} drives their choices.",
+ "characters.heuristic.name": "New Character",
+ "characters.heuristic.personalityTraits": "Resourceful, guarded, determined.",
+ "characters.heuristic.relationships": "Note the key bonds and rivalries that define them.",
"characters.loading.profile": "Részletes profil létrehozása...",
"characters.newCharacterName": "Új karakter",
"characters.noCharacters": "Még nincsenek karakterek létrehozva.",
@@ -107,14 +115,6 @@
"characters.title": "Karakter dossziék",
"characters.uploadImage": "Kép feltöltése",
"characters.yourCharacters": "A karaktereid",
- "characters.heuristic.name": "New Character",
- "characters.heuristic.backstory": "Shaped by formative experiences, this character carries a past tied to {{concept}}.",
- "characters.heuristic.motivation": "A core desire connected to {{concept}} drives their choices.",
- "characters.heuristic.appearance": "Describe how they present themselves — let their look hint at {{concept}}.",
- "characters.heuristic.personalityTraits": "Resourceful, guarded, determined.",
- "characters.heuristic.flaws": "A weakness that complicates their goals.",
- "characters.heuristic.characterArc": "They begin guarded and, through the story, are changed by {{concept}}.",
- "characters.heuristic.relationships": "Note the key bonds and rivalries that define them.",
"apiKey.connectionFailed": "A csatlakozási teszt sikertelen.",
"apiKey.connectionSuccess": "Sikeres csatlakozás! Az API helyesen válaszol.",
"apiKey.decryptFailed": "Az API-kulcsot nem sikerült visszafejteni",
@@ -125,6 +125,11 @@
"apiKey.test": "Kapcsolat tesztelése",
"apiKey.testConnection": "Teszt API-kapcsolat",
"apiKey.testing": "Tesztelés…",
+ "assisted.badge.label": "Assisted",
+ "assisted.badge.srLabel": "Assisted mode — generated without AI",
+ "assisted.enhance": "Enhance with AI",
+ "assisted.toast.description": "Used built-in assistance. Enhance with AI when a model is available.",
+ "assisted.toast.title": "AI unavailable",
"charGraph.characters": "Karakterek",
"charGraph.noCharacters": "Még nincsenek karakterek",
"charGraph.noCharactersHint": "Adjon hozzá karaktereket a Karakterek nézetben, hogy megjelenítse kapcsolataikat.",
@@ -286,6 +291,8 @@
"error.db.unknown": "Ismeretlen hiba az adatbázis elérésekor.",
"error.deepLink.title": "Nem sikerült megnyitni a projektfájlt",
"error.deepLink.unknown": "Ismeretlen hiba",
+ "error.fallback.generic": "AI is unavailable — used built-in assistance.",
+ "error.fallback.offline": "You're offline — used built-in assistance.",
"error.fileImportError": "Fájlimportálási hiba",
"error.mic.denied": "Mikrofon hozzáférés megtagadva. Kérjük, adjon engedélyt a böngésző beállításaiban.",
"error.mic.generic": "Beszédfelismerési hiba: {{error}}",
@@ -382,6 +389,16 @@
"palette.voice.listeningLive": "A hangbemenet aktív",
"palette.voice.start": "Indítsa el a hangalapú keresést",
"palette.voice.stop": "Hangalapú keresés leállítása",
+ "plotBoard.heuristic.complicate.description": "Add an obstacle or reveal that forces a change of plan.",
+ "plotBoard.heuristic.complicate.rationale": "A fresh complication tests the characters and opens new threads.",
+ "plotBoard.heuristic.complicate.title": "Introduce a complication",
+ "plotBoard.heuristic.escalate.description": "Increase the pressure on your protagonist so the next choice costs more.",
+ "plotBoard.heuristic.escalate.rationale": "Escalation keeps momentum when the middle sags.",
+ "plotBoard.heuristic.escalate.title": "Raise the stakes",
+ "plotBoard.heuristic.position": "Right after the selected scene",
+ "plotBoard.heuristic.reverse.description": "Flip an expectation — an ally falters, a win turns sour, or a hidden truth surfaces.",
+ "plotBoard.heuristic.reverse.rationale": "Reversals refresh tension and deepen the arc.",
+ "plotBoard.heuristic.reverse.title": "Add a reversal",
"preview.controls.ariaLabel": "Előnézeti vezérlők",
"preview.controls.decreaseFontSize": "Csökkentse a betűméretet",
"preview.controls.exitFullscreen": "Lépjen ki a teljes képernyőről",
@@ -449,10 +466,6 @@
"proforge.progress.awaitingReviewHint": "⚠️ Ez a szakasz az értékelésedre vár. Kattintson a fenti szakasz gombra az elemek áttekintéséhez.",
"proforge.progress.completedStages": "Befejezett szakaszok",
"proforge.progress.currentStatus": "Jelenlegi állapot",
- "proforge.progress.overall": "Overall progress",
- "proforge.progress.preparing": "Preparing…",
- "proforge.progress.stageOfTotal": "Stage {{current}} of {{total}}",
- "proforge.progress.percentComplete": "{{percent}}% complete",
"proforge.progress.itemsCount": "{{count}} elem",
"proforge.progress.metric.aiCalls": "AI hívások",
"proforge.progress.metric.duration": "Időtartam",
@@ -463,7 +476,11 @@
"proforge.progress.metric.totalTime": "Teljes idő",
"proforge.progress.metric.totalTokens": "Összes token",
"proforge.progress.noneRunning": "Nem fut csővezeték.",
+ "proforge.progress.overall": "Overall progress",
+ "proforge.progress.percentComplete": "{{percent}}% complete",
+ "proforge.progress.preparing": "Preparing…",
"proforge.progress.stageDetails": "A színpad részletei: {{stage}}",
+ "proforge.progress.stageOfTotal": "Stage {{current}} of {{total}}",
"proforge.progress.statusLabel": "Állapot",
"proforge.progress.totals": "Pipeline Totals",
"proforge.review.accept": "Elfogadás",
@@ -777,9 +794,9 @@
"vc.title": "Verziótörténet",
"vc.words": "szavak",
"voice.cancelSpeech": "Beszéd megszakítása",
+ "voice.feedback.confidence": "Megbízhatóság {{percent}}%",
"voice.modeChip.commands": "Parancsok",
"voice.modeChip.dictation": "Diktálás",
- "voice.feedback.confidence": "Megbízhatóság {{percent}}%",
"voice.panelLabel": "Hangvezérlés",
"voice.permissionDenied": "Mikrofon hozzáférés megtagadva. A hangfunkciók használatához engedélyezze a mikrofonhoz való hozzáférést a böngésző beállításaiban.",
"voice.startDictation": "Indítsa el a diktálást",
@@ -793,23 +810,6 @@
"voice.stopListening": "Ne hallgasson",
"worlds.emptyState.description": "Építsd fel azokat a helyeket, szabályokat és történeteket, amelyekben a történeted él. Kezdd egy hellyel.",
"worlds.emptyState.title": "A világ vár",
- "error.fallback.generic": "AI is unavailable — used built-in assistance.",
- "error.fallback.offline": "You're offline — used built-in assistance.",
- "assisted.badge.label": "Assisted",
- "assisted.badge.srLabel": "Assisted mode — generated without AI",
- "assisted.toast.title": "AI unavailable",
- "assisted.toast.description": "Used built-in assistance. Enhance with AI when a model is available.",
- "assisted.enhance": "Enhance with AI",
- "plotBoard.heuristic.position": "Right after the selected scene",
- "plotBoard.heuristic.escalate.title": "Raise the stakes",
- "plotBoard.heuristic.escalate.description": "Increase the pressure on your protagonist so the next choice costs more.",
- "plotBoard.heuristic.escalate.rationale": "Escalation keeps momentum when the middle sags.",
- "plotBoard.heuristic.complicate.title": "Introduce a complication",
- "plotBoard.heuristic.complicate.description": "Add an obstacle or reveal that forces a change of plan.",
- "plotBoard.heuristic.complicate.rationale": "A fresh complication tests the characters and opens new threads.",
- "plotBoard.heuristic.reverse.title": "Add a reversal",
- "plotBoard.heuristic.reverse.description": "Flip an expectation — an ally falters, a win turns sour, or a hidden truth surfaces.",
- "plotBoard.heuristic.reverse.rationale": "Reversals refresh tension and deepen the arc.",
"copilot.annotationCount": "{{count}} betekintést nyújt ehhez a fejezethez",
"copilot.announceClosed": "Az AI másodpilóta zárva",
"copilot.announceOpened": "Az AI másodpilóta megnyílt",
@@ -1090,10 +1090,10 @@
"export.pasteSection.importAsChapter": "Importálás fejezetként",
"export.pasteSection.textPlaceholder": "Illesszen be szöveget a Google Docsból vagy a Notionból (Ctrl+V)...",
"export.pasteSection.titlePlaceholder": "Fejezet címe (nem kötelező)",
- "export.preview.noContent": "Az előnézet megtekintéséhez válassza ki a tartalmat.",
"export.preview.modeLabel": "Előnézeti mód",
- "export.preview.modeText": "Szöveg",
"export.preview.modeRendered": "Megjelenített",
+ "export.preview.modeText": "Szöveg",
+ "export.preview.noContent": "Az előnézet megtekintéséhez válassza ki a tartalmat.",
"export.preview.title": "Élő előnézet",
"export.title": "Export Publishing Suite",
"export.toggleSection": "{{title}} láthatóságának váltása",
@@ -1519,6 +1519,23 @@
"outline.deleteConfirm": "Biztosan törli ezt a vázlatos részt?",
"outline.description": "Írja le történetötletét, és hagyja, hogy a mesterséges intelligencia strukturált, szerkeszthető vázlatot készítsen Önnek.",
"outline.error.generationFailed": "Nem sikerült tartalmat generálni. Kérjük, próbálja újra.",
+ "outline.heuristic.beat.climax.desc": "The central conflict comes to a head in the story's defining confrontation.",
+ "outline.heuristic.beat.climax.title": "Climax",
+ "outline.heuristic.beat.complications.desc": "Setbacks and conflicts deepen; the path forward narrows.",
+ "outline.heuristic.beat.complications.title": "Complications",
+ "outline.heuristic.beat.incitingIncident.desc": "The event that sets the story in motion: {{idea}}.",
+ "outline.heuristic.beat.incitingIncident.title": "Inciting Incident",
+ "outline.heuristic.beat.midpoint.desc": "A turning point shifts the direction of the story and raises the stakes.",
+ "outline.heuristic.beat.midpoint.title": "Midpoint",
+ "outline.heuristic.beat.resolution.desc": "Loose ends are tied up and a new status quo emerges.",
+ "outline.heuristic.beat.resolution.title": "Resolution",
+ "outline.heuristic.beat.risingAction.desc": "Complications escalate and the stakes grow as the characters pursue their goal.",
+ "outline.heuristic.beat.risingAction.title": "Rising Action",
+ "outline.heuristic.beat.setup.desc": "Introduce the world and the main characters, and establish the status quo before everything changes.",
+ "outline.heuristic.beat.setup.title": "Setup",
+ "outline.heuristic.beat.twist.desc": "An unexpected revelation upends what the characters believed to be true.",
+ "outline.heuristic.beat.twist.title": "Twist",
+ "outline.heuristic.fallbackIdea": "the central idea",
"outline.idea.generateButton": "Körvonal létrehozása",
"outline.idea.genreLabel": "Műfaj",
"outline.idea.genrePlaceholder": "például sci-fi, fantasy, rejtély",
@@ -1541,23 +1558,6 @@
"outline.result.twistTooltip": "AI által generált cselekménycsavar",
"outline.selectSection": "Válassza ki a '{{title}}' részt",
"outline.title": "AI Story Outline Generator",
- "outline.heuristic.fallbackIdea": "the central idea",
- "outline.heuristic.beat.setup.title": "Setup",
- "outline.heuristic.beat.setup.desc": "Introduce the world and the main characters, and establish the status quo before everything changes.",
- "outline.heuristic.beat.incitingIncident.title": "Inciting Incident",
- "outline.heuristic.beat.incitingIncident.desc": "The event that sets the story in motion: {{idea}}.",
- "outline.heuristic.beat.risingAction.title": "Rising Action",
- "outline.heuristic.beat.risingAction.desc": "Complications escalate and the stakes grow as the characters pursue their goal.",
- "outline.heuristic.beat.midpoint.title": "Midpoint",
- "outline.heuristic.beat.midpoint.desc": "A turning point shifts the direction of the story and raises the stakes.",
- "outline.heuristic.beat.complications.title": "Complications",
- "outline.heuristic.beat.complications.desc": "Setbacks and conflicts deepen; the path forward narrows.",
- "outline.heuristic.beat.twist.title": "Twist",
- "outline.heuristic.beat.twist.desc": "An unexpected revelation upends what the characters believed to be true.",
- "outline.heuristic.beat.climax.title": "Climax",
- "outline.heuristic.beat.climax.desc": "The central conflict comes to a head in the story's defining confrontation.",
- "outline.heuristic.beat.resolution.title": "Resolution",
- "outline.heuristic.beat.resolution.desc": "Loose ends are tied up and a new status quo emerges.",
"portal.back": "Vissza",
"portal.demo.chapterContent": "A reggeli köd a rakpartokra tapadt, ahogy Lyra kigöngyölte a régi várostérképet. Halvány kör jelölte az északnyugati sarkot — a tornyot, amelyet senki sem említett.\n\nEltette a papírt, és követte a keskeny ösvényt, míg a vasrács fel nem emelkedett előtte. A lakat meleg volt a napon; a fém még mindig hideg.",
"portal.demo.chapterTitle": "1. fejezet — A kapu előtt",
@@ -1752,6 +1752,7 @@
"settings.ai.gpu.troubleshootLowEnd": "Az eszköz korlátozott erőforrásokkal rendelkezik. A helyi AI kisebb modelleket fog használni. A jobb teljesítmény érdekében zárja be a böngésző többi lapját, vagy engedélyezze az Eco módot.",
"settings.ai.gpu.troubleshootQueue": "Több mesterségesintelligencia-feladat van sorban. Egyszerre csak egy fut a VRAM ütközések elkerülése érdekében. Várja meg, amíg az aktuális feladat befejeződik.",
"settings.ai.gpu.waitingConsumers": "Várakozás",
+ "settings.ai.grokKey": "Grok API Key",
"settings.ai.hybridFallbackHint": "Ha az elsődleges szolgáltató meghibásodik, a WorldScript megpróbálja a felsorolt tartalékokat (jelenetgenerátorok, kódexeszközök). A Writer streaming csak az elsődleges szolgáltatót használja.",
"settings.ai.hybridFallbackTitle": "Hibrid tartalék (projekt AI-eszközök)",
"settings.ai.hybridFallbackToggle": "Tartaléklánc engedélyezése",
@@ -1832,6 +1833,11 @@
"settings.ai.preset.lmStudio": "LM Stúdió",
"settings.ai.preset.ollamaDefault": "Ollama (alapértelmezett port)",
"settings.ai.preset.vllm": "vLLM",
+ "settings.ai.provider.anthropic": "Anthropic Claude",
+ "settings.ai.provider.gemini": "Google Gemini",
+ "settings.ai.provider.grok": "xAI Grok",
+ "settings.ai.provider.ollama": "Ollama (local)",
+ "settings.ai.provider.openai": "OpenAI",
"settings.ai.providerDescription": "Válassza ki, hogy a WorldScript Studio melyik AI-szolgáltatót használja.",
"settings.ai.providerOnnx": "ONNX (WASM)",
"settings.ai.providerStatusConnected": "Csatlakozva",
@@ -2711,6 +2717,11 @@
"worlds.edit.notes": "Megjegyzések",
"worlds.editorTabsAriaLabel": "Világszerkesztő lapok",
"worlds.error.imageFailed": "A hangulatkép létrehozása nem sikerült. Kérjük, próbáljon több részletet hozzáadni a világ leírásához, vagy ellenőrizze a kapcsolatot.",
+ "worlds.heuristic.culture": "Describe the peoples, beliefs, and daily life shaped by {{concept}}.",
+ "worlds.heuristic.description": "A world defined by its central premise: {{concept}}.",
+ "worlds.heuristic.geography": "Outline the major regions, climates, and natural features of {{concept}}.",
+ "worlds.heuristic.magicSystem": "Define the rules, costs, and limits of power in {{concept}}.",
+ "worlds.heuristic.name": "New World",
"worlds.loading.profile": "Részletes világprofil létrehozása...",
"worlds.newWorldName": "Új Világ",
"worlds.noWorlds": "Még nem jött létre világ.",
@@ -2729,11 +2740,6 @@
"worlds.title": "Világatlasz",
"worlds.uploadImage": "Kép feltöltése",
"worlds.yourWorlds": "A ti világotok",
- "worlds.heuristic.name": "New World",
- "worlds.heuristic.description": "A world defined by its central premise: {{concept}}.",
- "worlds.heuristic.geography": "Outline the major regions, climates, and natural features of {{concept}}.",
- "worlds.heuristic.magicSystem": "Define the rules, costs, and limits of power in {{concept}}.",
- "worlds.heuristic.culture": "Describe the peoples, beliefs, and daily life shaped by {{concept}}.",
"writer.cancelledTag": "Törölve",
"writer.chapter.label": "fejezet: {{title}}",
"writer.coachmark.dismiss": "Got it",
@@ -2755,6 +2761,20 @@
"writer.focusMode.enterLabel": "Fókusz mód",
"writer.focusMode.exit": "Lépjen ki a fókusz módból",
"writer.focusMode.exitLabel": "Kilépés a fókuszból",
+ "writer.grammar.addToDictionary": "Add to dictionary",
+ "writer.grammar.apply": "Apply",
+ "writer.grammar.checkButton": "Check this scene",
+ "writer.grammar.checking": "Checking…",
+ "writer.grammar.disabled": "Enable LanguageTool in Settings → Connections to check this scene.",
+ "writer.grammar.error": "The LanguageTool server returned an error.",
+ "writer.grammar.ignore": "Ignore",
+ "writer.grammar.issuesFound": "{{count}} issues found",
+ "writer.grammar.noIssues": "No issues found.",
+ "writer.grammar.noSuggestions": "No suggestions",
+ "writer.grammar.offline": "Couldn't reach the LanguageTool server. Is it running?",
+ "writer.grammar.selectScene": "Select a scene to check.",
+ "writer.grammar.title": "Grammar & Spelling",
+ "writer.grammar.unsupported": "Grammar check isn't available for this language.",
"writer.imagePrompt.description": "Optimalizált DALL·E 3 / Midjourney promptot generál az aktuális jelenetből vagy szövegkijelölésből.",
"writer.imagePrompt.note": "A generált prompt közvetlenül működik a DALL·E 3-ban és a Midjourney-ben.",
"writer.imagePrompt.tip": "Tipp: Válasszon ki egy adott szövegrészt a fókuszált jelenet prompthoz.",
@@ -2787,12 +2807,10 @@
"writer.studio.controls.tones.poetic": "Költőibb",
"writer.studio.controls.tones.suspenseful": "Izgalmasabb",
"writer.studio.description": "Az AI társszerzője. Generáljon, javítson és ötleteljen a teljes projektkörnyezetben.",
+ "writer.studio.rag.chunkScore": "relevancia {{score}}",
"writer.studio.rag.chunksBadge": "{{count}} történetrészletek találhatók",
"writer.studio.rag.chunksHint": "Releváns kivonatok a kéziratból – több szövegrész gazdagabb AI-kontextust jelent",
"writer.studio.rag.inspectorLabel": "Lekért kontextus",
- "writer.studio.rag.chunkScore": "relevancia {{score}}",
- "writer.studio.tokens.badge": "~{{count}} token",
- "writer.studio.tokens.hint": "A legutóbbi MI-kérés hozzávetőleges tokenszáma",
"writer.studio.rag.useContext": "Húzza ki a történetemből",
"writer.studio.result.insert": "Beszúrás",
"writer.studio.result.next": "Következő",
@@ -2802,6 +2820,8 @@
"writer.studio.result.retry": "Próbálja újra",
"writer.studio.result.title": "AI Scratchpad",
"writer.studio.title": "AI Íróstúdió",
+ "writer.studio.tokens.badge": "~{{count}} token",
+ "writer.studio.tokens.hint": "A legutóbbi MI-kérés hozzávetőleges tokenszáma",
"writer.studio.tools.brainstorm.contextLabel": "Ötletbörze kontextus (opcionális)",
"writer.studio.tools.brainstorm.contextPlaceholder": "Adjon meg egy rövid helyzetet, különben a mesterséges intelligencia az aktuális kézirat-részt fogja használni.",
"writer.studio.tools.brainstorm.title": "Ötletek ötletbörze",
@@ -2833,19 +2853,5 @@
"writer.tts.start": "Olvass fel hangosan",
"writer.tts.stop": "Hagyd abba az olvasást",
"writer.versionControl.label": "Verziók",
- "writer.versionControl.tooltip": "Verzióvezérlés (elágazások és pillanatképek)",
- "writer.grammar.title": "Grammar & Spelling",
- "writer.grammar.checkButton": "Check this scene",
- "writer.grammar.checking": "Checking…",
- "writer.grammar.issuesFound": "{{count}} issues found",
- "writer.grammar.noIssues": "No issues found.",
- "writer.grammar.selectScene": "Select a scene to check.",
- "writer.grammar.unsupported": "Grammar check isn't available for this language.",
- "writer.grammar.disabled": "Enable LanguageTool in Settings → Connections to check this scene.",
- "writer.grammar.offline": "Couldn't reach the LanguageTool server. Is it running?",
- "writer.grammar.error": "The LanguageTool server returned an error.",
- "writer.grammar.apply": "Apply",
- "writer.grammar.ignore": "Ignore",
- "writer.grammar.addToDictionary": "Add to dictionary",
- "writer.grammar.noSuggestions": "No suggestions"
+ "writer.versionControl.tooltip": "Verzióvezérlés (elágazások és pillanatképek)"
}
diff --git a/public/locales/is/bundle.json b/public/locales/is/bundle.json
index 0c6888a8..44dec7b0 100644
--- a/public/locales/is/bundle.json
+++ b/public/locales/is/bundle.json
@@ -90,6 +90,14 @@
"characters.edit.relationships": "Sambönd",
"characters.editorTabsAriaLabel": "Flipar ritstjóra",
"characters.error.portraitFailed": "Andlitsmyndagerð mistókst. Prófaðu að bæta nánari upplýsingum við útlitslýsinguna.",
+ "characters.heuristic.appearance": "Describe how they present themselves — let their look hint at {{concept}}.",
+ "characters.heuristic.backstory": "Shaped by formative experiences, this character carries a past tied to {{concept}}.",
+ "characters.heuristic.characterArc": "They begin guarded and, through the story, are changed by {{concept}}.",
+ "characters.heuristic.flaws": "A weakness that complicates their goals.",
+ "characters.heuristic.motivation": "A core desire connected to {{concept}} drives their choices.",
+ "characters.heuristic.name": "New Character",
+ "characters.heuristic.personalityTraits": "Resourceful, guarded, determined.",
+ "characters.heuristic.relationships": "Note the key bonds and rivalries that define them.",
"characters.loading.profile": "Býr til nákvæma prófíl...",
"characters.newCharacterName": "Ný persóna",
"characters.noCharacters": "Engar persónur búnar til ennþá.",
@@ -107,14 +115,6 @@
"characters.title": "Persónuskjöl",
"characters.uploadImage": "Hladdu upp mynd",
"characters.yourCharacters": "Persónurnar þínar",
- "characters.heuristic.name": "New Character",
- "characters.heuristic.backstory": "Shaped by formative experiences, this character carries a past tied to {{concept}}.",
- "characters.heuristic.motivation": "A core desire connected to {{concept}} drives their choices.",
- "characters.heuristic.appearance": "Describe how they present themselves — let their look hint at {{concept}}.",
- "characters.heuristic.personalityTraits": "Resourceful, guarded, determined.",
- "characters.heuristic.flaws": "A weakness that complicates their goals.",
- "characters.heuristic.characterArc": "They begin guarded and, through the story, are changed by {{concept}}.",
- "characters.heuristic.relationships": "Note the key bonds and rivalries that define them.",
"apiKey.connectionFailed": "Tengingarpróf mistókst.",
"apiKey.connectionSuccess": "Tenging tókst! API svarar rétt.",
"apiKey.decryptFailed": "Ekki var hægt að afkóða API lykil",
@@ -125,6 +125,11 @@
"apiKey.test": "Prófaðu tengingu",
"apiKey.testConnection": "Prófaðu API tengingu",
"apiKey.testing": "Er að prófa…",
+ "assisted.badge.label": "Assisted",
+ "assisted.badge.srLabel": "Assisted mode — generated without AI",
+ "assisted.enhance": "Enhance with AI",
+ "assisted.toast.description": "Used built-in assistance. Enhance with AI when a model is available.",
+ "assisted.toast.title": "AI unavailable",
"charGraph.characters": "Persónur",
"charGraph.noCharacters": "Engar persónur ennþá",
"charGraph.noCharactersHint": "Bættu við persónum í persónuskjánum til að sjá tengsl þeirra hér.",
@@ -286,6 +291,8 @@
"error.db.unknown": "Óþekkt villa við aðgang að gagnagrunninum.",
"error.deepLink.title": "Mistókst að opna verkefnaskrá",
"error.deepLink.unknown": "Óþekkt villa",
+ "error.fallback.generic": "AI is unavailable — used built-in assistance.",
+ "error.fallback.offline": "You're offline — used built-in assistance.",
"error.fileImportError": "Villa við skráainnflutning",
"error.mic.denied": "Aðgangi hljóðnema hafnað. Vinsamlegast veittu leyfi í stillingum vafrans.",
"error.mic.generic": "Talgreiningarvilla: {{error}}",
@@ -382,6 +389,16 @@
"palette.voice.listeningLive": "Raddinntak er virkt",
"palette.voice.start": "Byrjaðu raddleit",
"palette.voice.stop": "Stöðva raddleit",
+ "plotBoard.heuristic.complicate.description": "Add an obstacle or reveal that forces a change of plan.",
+ "plotBoard.heuristic.complicate.rationale": "A fresh complication tests the characters and opens new threads.",
+ "plotBoard.heuristic.complicate.title": "Introduce a complication",
+ "plotBoard.heuristic.escalate.description": "Increase the pressure on your protagonist so the next choice costs more.",
+ "plotBoard.heuristic.escalate.rationale": "Escalation keeps momentum when the middle sags.",
+ "plotBoard.heuristic.escalate.title": "Raise the stakes",
+ "plotBoard.heuristic.position": "Right after the selected scene",
+ "plotBoard.heuristic.reverse.description": "Flip an expectation — an ally falters, a win turns sour, or a hidden truth surfaces.",
+ "plotBoard.heuristic.reverse.rationale": "Reversals refresh tension and deepen the arc.",
+ "plotBoard.heuristic.reverse.title": "Add a reversal",
"preview.controls.ariaLabel": "Forskoðunarstýringar",
"preview.controls.decreaseFontSize": "Minnka leturstærð",
"preview.controls.exitFullscreen": "Hætta á öllum skjánum",
@@ -449,10 +466,6 @@
"proforge.progress.awaitingReviewHint": "⚠️ Þetta stig bíður skoðunar þinnar. Smelltu á sviðshnappinn hér að ofan til að skoða atriði.",
"proforge.progress.completedStages": "Lokið stig",
"proforge.progress.currentStatus": "Núverandi staða",
- "proforge.progress.overall": "Overall progress",
- "proforge.progress.preparing": "Preparing…",
- "proforge.progress.stageOfTotal": "Stage {{current}} of {{total}}",
- "proforge.progress.percentComplete": "{{percent}}% complete",
"proforge.progress.itemsCount": "{{count}} hlutir",
"proforge.progress.metric.aiCalls": "AI kallar",
"proforge.progress.metric.duration": "Lengd",
@@ -463,7 +476,11 @@
"proforge.progress.metric.totalTime": "Heildartími",
"proforge.progress.metric.totalTokens": "Samtals tákn",
"proforge.progress.noneRunning": "Engin leiðsla í gangi.",
+ "proforge.progress.overall": "Overall progress",
+ "proforge.progress.percentComplete": "{{percent}}% complete",
+ "proforge.progress.preparing": "Preparing…",
"proforge.progress.stageDetails": "Sviðsupplýsingar: {{stage}}",
+ "proforge.progress.stageOfTotal": "Stage {{current}} of {{total}}",
"proforge.progress.statusLabel": "Staða",
"proforge.progress.totals": "Heildarfjöldi leiðslu",
"proforge.review.accept": "Samþykkja",
@@ -777,9 +794,9 @@
"vc.title": "Útgáfusaga",
"vc.words": "orð",
"voice.cancelSpeech": "Hætta við ræðu",
+ "voice.feedback.confidence": "Vissa {{percent}}%",
"voice.modeChip.commands": "Skipanir",
"voice.modeChip.dictation": "Upplestur",
- "voice.feedback.confidence": "Vissa {{percent}}%",
"voice.panelLabel": "Raddstýring",
"voice.permissionDenied": "Aðgangi hljóðnema hafnað. Vinsamlegast leyfðu aðgang að hljóðnema í stillingum vafrans til að nota raddaðgerðir.",
"voice.startDictation": "Byrjaðu á einræði",
@@ -793,23 +810,6 @@
"voice.stopListening": "Hættu að hlusta",
"worlds.emptyState.description": "Búðu til staðina, reglurnar og söguna sem sagan þín býr í. Byrjaðu á staðsetningu.",
"worlds.emptyState.title": "Heimurinn bíður",
- "error.fallback.generic": "AI is unavailable — used built-in assistance.",
- "error.fallback.offline": "You're offline — used built-in assistance.",
- "assisted.badge.label": "Assisted",
- "assisted.badge.srLabel": "Assisted mode — generated without AI",
- "assisted.toast.title": "AI unavailable",
- "assisted.toast.description": "Used built-in assistance. Enhance with AI when a model is available.",
- "assisted.enhance": "Enhance with AI",
- "plotBoard.heuristic.position": "Right after the selected scene",
- "plotBoard.heuristic.escalate.title": "Raise the stakes",
- "plotBoard.heuristic.escalate.description": "Increase the pressure on your protagonist so the next choice costs more.",
- "plotBoard.heuristic.escalate.rationale": "Escalation keeps momentum when the middle sags.",
- "plotBoard.heuristic.complicate.title": "Introduce a complication",
- "plotBoard.heuristic.complicate.description": "Add an obstacle or reveal that forces a change of plan.",
- "plotBoard.heuristic.complicate.rationale": "A fresh complication tests the characters and opens new threads.",
- "plotBoard.heuristic.reverse.title": "Add a reversal",
- "plotBoard.heuristic.reverse.description": "Flip an expectation — an ally falters, a win turns sour, or a hidden truth surfaces.",
- "plotBoard.heuristic.reverse.rationale": "Reversals refresh tension and deepen the arc.",
"copilot.annotationCount": "{{count}} innsýn fyrir þennan kafla",
"copilot.announceClosed": "AI Copilot lokað",
"copilot.announceOpened": "AI Copilot opnaður",
@@ -1090,10 +1090,10 @@
"export.pasteSection.importAsChapter": "Flytja inn sem kafli",
"export.pasteSection.textPlaceholder": "Límdu texta úr Google skjölum eða hugmynd hér (Ctrl+V)...",
"export.pasteSection.titlePlaceholder": "Kaflaheiti (valfrjálst)",
- "export.preview.noContent": "Veldu efni til að sjá forskoðun.",
"export.preview.modeLabel": "Forskoðunarhamur",
- "export.preview.modeText": "Texti",
"export.preview.modeRendered": "Myndað",
+ "export.preview.modeText": "Texti",
+ "export.preview.noContent": "Veldu efni til að sjá forskoðun.",
"export.preview.title": "Forskoðun í beinni",
"export.title": "Flytja út útgáfusvítu",
"export.toggleSection": "Skipta á sýnileika fyrir {{title}}",
@@ -1519,6 +1519,23 @@
"outline.deleteConfirm": "Ertu viss um að þú viljir eyða þessum yfirlitshluta?",
"outline.description": "Lýstu söguhugmynd þinni og láttu gervigreind búa til skipulagða, breytanlega útlínur fyrir þig.",
"outline.error.generationFailed": "Mistókst að búa til efni. Vinsamlegast reyndu aftur.",
+ "outline.heuristic.beat.climax.desc": "The central conflict comes to a head in the story's defining confrontation.",
+ "outline.heuristic.beat.climax.title": "Climax",
+ "outline.heuristic.beat.complications.desc": "Setbacks and conflicts deepen; the path forward narrows.",
+ "outline.heuristic.beat.complications.title": "Complications",
+ "outline.heuristic.beat.incitingIncident.desc": "The event that sets the story in motion: {{idea}}.",
+ "outline.heuristic.beat.incitingIncident.title": "Inciting Incident",
+ "outline.heuristic.beat.midpoint.desc": "A turning point shifts the direction of the story and raises the stakes.",
+ "outline.heuristic.beat.midpoint.title": "Midpoint",
+ "outline.heuristic.beat.resolution.desc": "Loose ends are tied up and a new status quo emerges.",
+ "outline.heuristic.beat.resolution.title": "Resolution",
+ "outline.heuristic.beat.risingAction.desc": "Complications escalate and the stakes grow as the characters pursue their goal.",
+ "outline.heuristic.beat.risingAction.title": "Rising Action",
+ "outline.heuristic.beat.setup.desc": "Introduce the world and the main characters, and establish the status quo before everything changes.",
+ "outline.heuristic.beat.setup.title": "Setup",
+ "outline.heuristic.beat.twist.desc": "An unexpected revelation upends what the characters believed to be true.",
+ "outline.heuristic.beat.twist.title": "Twist",
+ "outline.heuristic.fallbackIdea": "the central idea",
"outline.idea.generateButton": "Búðu til yfirlit",
"outline.idea.genreLabel": "Tegund",
"outline.idea.genrePlaceholder": "t.d. Sci-Fi, Fantasy, Mystery",
@@ -1541,23 +1558,6 @@
"outline.result.twistTooltip": "AI-myndaður söguþráður",
"outline.selectSection": "Veldu hluta '{{title}}'",
"outline.title": "AI Story Outline Generator",
- "outline.heuristic.fallbackIdea": "the central idea",
- "outline.heuristic.beat.setup.title": "Setup",
- "outline.heuristic.beat.setup.desc": "Introduce the world and the main characters, and establish the status quo before everything changes.",
- "outline.heuristic.beat.incitingIncident.title": "Inciting Incident",
- "outline.heuristic.beat.incitingIncident.desc": "The event that sets the story in motion: {{idea}}.",
- "outline.heuristic.beat.risingAction.title": "Rising Action",
- "outline.heuristic.beat.risingAction.desc": "Complications escalate and the stakes grow as the characters pursue their goal.",
- "outline.heuristic.beat.midpoint.title": "Midpoint",
- "outline.heuristic.beat.midpoint.desc": "A turning point shifts the direction of the story and raises the stakes.",
- "outline.heuristic.beat.complications.title": "Complications",
- "outline.heuristic.beat.complications.desc": "Setbacks and conflicts deepen; the path forward narrows.",
- "outline.heuristic.beat.twist.title": "Twist",
- "outline.heuristic.beat.twist.desc": "An unexpected revelation upends what the characters believed to be true.",
- "outline.heuristic.beat.climax.title": "Climax",
- "outline.heuristic.beat.climax.desc": "The central conflict comes to a head in the story's defining confrontation.",
- "outline.heuristic.beat.resolution.title": "Resolution",
- "outline.heuristic.beat.resolution.desc": "Loose ends are tied up and a new status quo emerges.",
"portal.back": "Til baka",
"portal.demo.chapterContent": "Morgunþokan loddi við bryggjurnar þegar Lyra rúllaði upp gamla borgarkortinu. Daufur hringur merkti norðvesturhornið — turninn sem enginn minntist á.\n\nHún stakk blaðinu undan og fylgdi mjóa stígnum þar til járngrindin reis fyrir framan hana. Hengilásinn var heitur í sólinni; málmurinn enn kaldur.",
"portal.demo.chapterTitle": "1. kafli — Fyrir framan hliðið",
@@ -1752,6 +1752,7 @@
"settings.ai.gpu.troubleshootLowEnd": "Tækið þitt hefur takmarkað fjármagn. Staðbundin gervigreind mun nota smærri gerðir. Til að fá betri frammistöðu skaltu loka öðrum vafraflipa eða virkja umhverfisstillingu.",
"settings.ai.gpu.troubleshootQueue": "Mörg gervigreind verkefni eru í biðröð. Aðeins einn keyrir í einu til að forðast VRAM árekstra. Bíddu þar til núverandi verkefni lýkur.",
"settings.ai.gpu.waitingConsumers": "Bíður",
+ "settings.ai.grokKey": "Grok API Key",
"settings.ai.hybridFallbackHint": "Ef aðalveitan mistakast, reynir WorldScript upptaldar fallbacks (senuframleiðendur, kóðaxverkfæri). Writer streymi notar eingöngu aðalveituna þína.",
"settings.ai.hybridFallbackTitle": "Hybrid fallback (verkfæri gervigreindarverkefnis)",
"settings.ai.hybridFallbackToggle": "Virkja afturkeðju",
@@ -1832,6 +1833,11 @@
"settings.ai.preset.lmStudio": "LM stúdíó",
"settings.ai.preset.ollamaDefault": "Ollama (sjálfgefin höfn)",
"settings.ai.preset.vllm": "vLLM",
+ "settings.ai.provider.anthropic": "Anthropic Claude",
+ "settings.ai.provider.gemini": "Google Gemini",
+ "settings.ai.provider.grok": "xAI Grok",
+ "settings.ai.provider.ollama": "Ollama (local)",
+ "settings.ai.provider.openai": "OpenAI",
"settings.ai.providerDescription": "Veldu hvaða gervigreindarfyrirtæki WorldScript Studio ætti að nota.",
"settings.ai.providerOnnx": "ONNX (WASM)",
"settings.ai.providerStatusConnected": "Tengdur",
@@ -2711,6 +2717,11 @@
"worlds.edit.notes": "Skýringar",
"worlds.editorTabsAriaLabel": "Heimur ritstjóri flipar",
"worlds.error.imageFailed": "Ekki tókst að búa til stemningsmyndir. Vinsamlegast reyndu að bæta við meiri smáatriðum við heimslýsinguna eða athugaðu tenginguna þína.",
+ "worlds.heuristic.culture": "Describe the peoples, beliefs, and daily life shaped by {{concept}}.",
+ "worlds.heuristic.description": "A world defined by its central premise: {{concept}}.",
+ "worlds.heuristic.geography": "Outline the major regions, climates, and natural features of {{concept}}.",
+ "worlds.heuristic.magicSystem": "Define the rules, costs, and limits of power in {{concept}}.",
+ "worlds.heuristic.name": "New World",
"worlds.loading.profile": "Býr til nákvæma heimsprófíl...",
"worlds.newWorldName": "Nýr heimur",
"worlds.noWorlds": "Engir heimar skapaðir ennþá.",
@@ -2729,11 +2740,6 @@
"worlds.title": "Heimsatlas",
"worlds.uploadImage": "Hladdu upp mynd",
"worlds.yourWorlds": "Heimir þínir",
- "worlds.heuristic.name": "New World",
- "worlds.heuristic.description": "A world defined by its central premise: {{concept}}.",
- "worlds.heuristic.geography": "Outline the major regions, climates, and natural features of {{concept}}.",
- "worlds.heuristic.magicSystem": "Define the rules, costs, and limits of power in {{concept}}.",
- "worlds.heuristic.culture": "Describe the peoples, beliefs, and daily life shaped by {{concept}}.",
"writer.cancelledTag": "Hætt við",
"writer.chapter.label": "Kafli: {{title}}",
"writer.coachmark.dismiss": "Got it",
@@ -2755,6 +2761,20 @@
"writer.focusMode.enterLabel": "Fókusstilling",
"writer.focusMode.exit": "Hætta í fókusstillingu",
"writer.focusMode.exitLabel": "Hætta fókus",
+ "writer.grammar.addToDictionary": "Add to dictionary",
+ "writer.grammar.apply": "Apply",
+ "writer.grammar.checkButton": "Check this scene",
+ "writer.grammar.checking": "Checking…",
+ "writer.grammar.disabled": "Enable LanguageTool in Settings → Connections to check this scene.",
+ "writer.grammar.error": "The LanguageTool server returned an error.",
+ "writer.grammar.ignore": "Ignore",
+ "writer.grammar.issuesFound": "{{count}} issues found",
+ "writer.grammar.noIssues": "No issues found.",
+ "writer.grammar.noSuggestions": "No suggestions",
+ "writer.grammar.offline": "Couldn't reach the LanguageTool server. Is it running?",
+ "writer.grammar.selectScene": "Select a scene to check.",
+ "writer.grammar.title": "Grammar & Spelling",
+ "writer.grammar.unsupported": "Grammar check isn't available for this language.",
"writer.imagePrompt.description": "Býr til bjartsýni DALL·E 3 / Midjourney hvetja úr núverandi atriði eða textavali.",
"writer.imagePrompt.note": "Myndað hvetja virkar beint í DALL·E 3 og Midjourney.",
"writer.imagePrompt.tip": "Ábending: Veldu tiltekinn textahluta fyrir markvissa senukvaðningu.",
@@ -2787,12 +2807,10 @@
"writer.studio.controls.tones.poetic": "Meira ljóðrænt",
"writer.studio.controls.tones.suspenseful": "Meira spennuþrungið",
"writer.studio.description": "Meðhöfundur þinn gervigreind. Búðu til, bættu og hugsaðu um með fullu verkefnasamhengi.",
+ "writer.studio.rag.chunkScore": "vægi {{score}}",
"writer.studio.rag.chunksBadge": "{{count}} söguþættir fundust",
"writer.studio.rag.chunksHint": "Viðeigandi brot úr handritinu þínu - fleiri kaflar þýða ríkara gervigreind samhengi",
"writer.studio.rag.inspectorLabel": "Sótt samhengi",
- "writer.studio.rag.chunkScore": "vægi {{score}}",
- "writer.studio.tokens.badge": "~{{count}} tóken",
- "writer.studio.tokens.hint": "Áætlaður fjöldi tókena í síðustu gervigreindarfyrirspurn",
"writer.studio.rag.useContext": "Dragðu úr sögunni minni",
"writer.studio.result.insert": "Settu inn",
"writer.studio.result.next": "Næsta",
@@ -2802,6 +2820,8 @@
"writer.studio.result.retry": "Reyndu aftur",
"writer.studio.result.title": "AI skrafi",
"writer.studio.title": "AI ritstúdíó",
+ "writer.studio.tokens.badge": "~{{count}} tóken",
+ "writer.studio.tokens.hint": "Áætlaður fjöldi tókena í síðustu gervigreindarfyrirspurn",
"writer.studio.tools.brainstorm.contextLabel": "Hugaflugssamhengi (valfrjálst)",
"writer.studio.tools.brainstorm.contextPlaceholder": "Gefðu stutta stöðu, annars mun gervigreindin nota núverandi handritahluta.",
"writer.studio.tools.brainstorm.title": "Hugmyndir",
@@ -2833,19 +2853,5 @@
"writer.tts.start": "Lestu upphátt",
"writer.tts.stop": "Hættu að lesa",
"writer.versionControl.label": "Útgáfur",
- "writer.versionControl.tooltip": "Útgáfustýring (útibú og skyndimyndir)",
- "writer.grammar.title": "Grammar & Spelling",
- "writer.grammar.checkButton": "Check this scene",
- "writer.grammar.checking": "Checking…",
- "writer.grammar.issuesFound": "{{count}} issues found",
- "writer.grammar.noIssues": "No issues found.",
- "writer.grammar.selectScene": "Select a scene to check.",
- "writer.grammar.unsupported": "Grammar check isn't available for this language.",
- "writer.grammar.disabled": "Enable LanguageTool in Settings → Connections to check this scene.",
- "writer.grammar.offline": "Couldn't reach the LanguageTool server. Is it running?",
- "writer.grammar.error": "The LanguageTool server returned an error.",
- "writer.grammar.apply": "Apply",
- "writer.grammar.ignore": "Ignore",
- "writer.grammar.addToDictionary": "Add to dictionary",
- "writer.grammar.noSuggestions": "No suggestions"
+ "writer.versionControl.tooltip": "Útgáfustýring (útibú og skyndimyndir)"
}
diff --git a/public/locales/it/bundle.json b/public/locales/it/bundle.json
index f6216ada..1736eaba 100644
--- a/public/locales/it/bundle.json
+++ b/public/locales/it/bundle.json
@@ -90,6 +90,14 @@
"characters.edit.relationships": "Relazioni",
"characters.editorTabsAriaLabel": "Schede editor personaggio",
"characters.error.portraitFailed": "Generazione ritratto fallita. Prova ad aggiungere più dettagli alla descrizione dell'aspetto.",
+ "characters.heuristic.appearance": "Descrivi come si presenta — lascia che il suo aspetto suggerisca {{concept}}.",
+ "characters.heuristic.backstory": "Plasmato da esperienze formative, questo personaggio porta un passato legato a {{concept}}.",
+ "characters.heuristic.characterArc": "Inizia guardingo e, nel corso della storia, viene cambiato da {{concept}}.",
+ "characters.heuristic.flaws": "Una debolezza che complica i suoi obiettivi.",
+ "characters.heuristic.motivation": "Un desiderio centrale connesso a {{concept}} guida le sue scelte.",
+ "characters.heuristic.name": "Nuovo personaggio",
+ "characters.heuristic.personalityTraits": "Pieno di risorse, guardingo, determinato.",
+ "characters.heuristic.relationships": "Annota i legami e le rivalità chiave che lo definiscono.",
"characters.loading.profile": "Generazione profilo dettagliato...",
"characters.newCharacterName": "Nuovo personaggio",
"characters.noCharacters": "Nessun personaggio creato.",
@@ -107,14 +115,6 @@
"characters.title": "Dossier personaggi",
"characters.uploadImage": "Carica immagine",
"characters.yourCharacters": "I tuoi personaggi",
- "characters.heuristic.name": "Nuovo personaggio",
- "characters.heuristic.backstory": "Plasmato da esperienze formative, questo personaggio porta un passato legato a {{concept}}.",
- "characters.heuristic.motivation": "Un desiderio centrale connesso a {{concept}} guida le sue scelte.",
- "characters.heuristic.appearance": "Descrivi come si presenta — lascia che il suo aspetto suggerisca {{concept}}.",
- "characters.heuristic.personalityTraits": "Pieno di risorse, guardingo, determinato.",
- "characters.heuristic.flaws": "Una debolezza che complica i suoi obiettivi.",
- "characters.heuristic.characterArc": "Inizia guardingo e, nel corso della storia, viene cambiato da {{concept}}.",
- "characters.heuristic.relationships": "Annota i legami e le rivalità chiave che lo definiscono.",
"apiKey.connectionFailed": "Test di connessione fallito.",
"apiKey.connectionSuccess": "Connessione riuscita! L'API risponde correttamente.",
"apiKey.decryptFailed": "Impossibile decrittare la chiave API",
@@ -125,6 +125,11 @@
"apiKey.test": "Testa connessione",
"apiKey.testConnection": "Testa connessione API",
"apiKey.testing": "Test in corso…",
+ "assisted.badge.label": "Assistito",
+ "assisted.badge.srLabel": "Modalità assistita: generato senza IA",
+ "assisted.enhance": "Migliora con l'IA",
+ "assisted.toast.description": "Usata l'assistenza integrata. Migliora con l'IA quando un modello è disponibile.",
+ "assisted.toast.title": "IA non disponibile",
"charGraph.characters": "Personaggi",
"charGraph.noCharacters": "Nessun personaggio ancora",
"charGraph.noCharactersHint": "Aggiungi personaggi nella vista Personaggi per visualizzare le loro relazioni qui.",
@@ -185,8 +190,8 @@
"common.add": "Aggiungi",
"common.appLoading": "L'applicazione è in caricamento",
"common.back": "Indietro",
- "common.badge.experimental": "Sperimentale",
"common.badge.beta": "Beta",
+ "common.badge.experimental": "Sperimentale",
"common.badge.new": "Nuovo",
"common.cancel": "Annulla",
"common.close": "Chiudi",
@@ -217,16 +222,16 @@
"common.words": "parole",
"consistencyChecker.checkButton": "Verifica coerenza",
"consistencyChecker.description": "Verifica la coerenza dei tuoi personaggi con il lore stabilito, altri personaggi e il tuo manoscritto.",
+ "consistencyChecker.noFindings": "Nessuna incoerenza trovata — questo personaggio sembra coerente.",
"consistencyChecker.noResults": "Nessun risultato",
"consistencyChecker.noResultsHint": "Seleziona un personaggio dall'elenco a sinistra e fai clic su Verifica coerenza per analizzare il manoscritto.",
- "consistencyChecker.results": "Risultati",
- "consistencyChecker.severity.info": "Info",
- "consistencyChecker.severity.warn": "Avviso",
- "consistencyChecker.severity.error": "Conflitto",
"consistencyChecker.refLabel": "Correlato",
- "consistencyChecker.noFindings": "Nessuna incoerenza trovata — questo personaggio sembra coerente.",
+ "consistencyChecker.results": "Risultati",
"consistencyChecker.selectCharacter": "Seleziona personaggio",
"consistencyChecker.selectPlaceholder": "Scegli un personaggio da verificare",
+ "consistencyChecker.severity.error": "Conflitto",
+ "consistencyChecker.severity.info": "Info",
+ "consistencyChecker.severity.warn": "Avviso",
"consistencyChecker.storyBible.edgesTitle": "Co-occorrenza entità (top)",
"consistencyChecker.storyBible.empty": "Attiva «Story Bible avanzato» in Impostazioni → IA → Flag funzionalità, poi modifica il manoscritto per estrarre dati dal grafo Codex.",
"consistencyChecker.storyBible.hintsTitle": "Suggerimenti di coerenza",
@@ -286,6 +291,8 @@
"error.db.unknown": "Errore sconosciuto durante l'accesso al database.",
"error.deepLink.title": "Impossibile aprire il file del progetto",
"error.deepLink.unknown": "Errore sconosciuto",
+ "error.fallback.generic": "IA non disponibile: usata l'assistenza integrata.",
+ "error.fallback.offline": "Sei offline: usata l'assistenza integrata.",
"error.fileImportError": "Errore importazione file",
"error.mic.denied": "Accesso al microfono negato. Concedi il permesso nelle impostazioni del browser.",
"error.mic.generic": "Errore di riconoscimento vocale: {{error}}",
@@ -382,22 +389,32 @@
"palette.voice.listeningLive": "Ingresso vocale attivo",
"palette.voice.start": "Avvia ricerca vocale",
"palette.voice.stop": "Ferma ricerca vocale",
+ "plotBoard.heuristic.complicate.description": "Aggiungi un ostacolo o una rivelazione che imponga un cambio di piano.",
+ "plotBoard.heuristic.complicate.rationale": "Una nuova complicazione mette alla prova i personaggi e apre nuovi fili.",
+ "plotBoard.heuristic.complicate.title": "Introdurre una complicazione",
+ "plotBoard.heuristic.escalate.description": "Aumenta la pressione sul protagonista così che la prossima scelta costi di più.",
+ "plotBoard.heuristic.escalate.rationale": "L'escalation mantiene lo slancio quando la parte centrale cala.",
+ "plotBoard.heuristic.escalate.title": "Alzare la posta",
+ "plotBoard.heuristic.position": "Subito dopo la scena selezionata",
+ "plotBoard.heuristic.reverse.description": "Ribalta un'aspettativa: un alleato vacilla, una vittoria si guasta o una verità nascosta emerge.",
+ "plotBoard.heuristic.reverse.rationale": "I ribaltamenti rinnovano la tensione e approfondiscono l'arco.",
+ "plotBoard.heuristic.reverse.title": "Aggiungere un colpo di scena",
"preview.controls.ariaLabel": "Controlli anteprima",
"preview.controls.decreaseFontSize": "Riduci dimensione font",
"preview.controls.exitFullscreen": "Esci dallo schermo intero",
"preview.controls.export": "Esporta (EPUB)",
- "preview.controls.pagedMode": "Vista pagina",
- "preview.progress.ariaLabel": "Avanzamento lettura",
"preview.controls.fontFamily": "Tipo di carattere",
"preview.controls.fontMono": "Monospace",
"preview.controls.fontSerif": "Serif",
"preview.controls.fontSystemUi": "Sistema",
"preview.controls.fullscreen": "Schermo intero",
"preview.controls.increaseFontSize": "Aumenta dimensione font",
+ "preview.controls.pagedMode": "Vista pagina",
"preview.controls.wordCount": "Conteggio parole",
"preview.emptyScene": "Nessun contenuto ancora.",
"preview.noScenes": "Il manoscritto è vuoto",
"preview.noScenesHint": "Vai alla vista Manoscritto e aggiungi la tua prima scena per vedere un'anteprima qui.",
+ "preview.progress.ariaLabel": "Avanzamento lettura",
"preview.title": "Anteprima libro",
"preview.toc.ariaLabel": "Indice dei contenuti",
"preview.toc.close": "Chiudi indice",
@@ -449,10 +466,6 @@
"proforge.progress.awaitingReviewHint": "⚠️ Questa fase è in attesa della tua revisione. Fai clic sul pulsante della fase qui sopra per esaminare gli elementi.",
"proforge.progress.completedStages": "Fasi completate",
"proforge.progress.currentStatus": "Stato attuale",
- "proforge.progress.overall": "Avanzamento complessivo",
- "proforge.progress.preparing": "Preparazione…",
- "proforge.progress.stageOfTotal": "Fase {{current}} di {{total}}",
- "proforge.progress.percentComplete": "{{percent}} % completato",
"proforge.progress.itemsCount": "{{count}} elementi",
"proforge.progress.metric.aiCalls": "Chiamate all'IA",
"proforge.progress.metric.duration": "Durata",
@@ -463,7 +476,11 @@
"proforge.progress.metric.totalTime": "Tempo totale",
"proforge.progress.metric.totalTokens": "Totale token",
"proforge.progress.noneRunning": "Nessuna pipeline in esecuzione.",
+ "proforge.progress.overall": "Avanzamento complessivo",
+ "proforge.progress.percentComplete": "{{percent}} % completato",
+ "proforge.progress.preparing": "Preparazione…",
"proforge.progress.stageDetails": "Dettagli della fase: {{stage}}",
+ "proforge.progress.stageOfTotal": "Fase {{current}} di {{total}}",
"proforge.progress.statusLabel": "Stato",
"proforge.progress.totals": "Totali della pipeline",
"proforge.review.accept": "Accetta",
@@ -631,9 +648,9 @@
"sceneboard.act3.label": "Atto 3 – Risoluzione",
"sceneboard.addScene": "Aggiungi scena",
"sceneboard.addSceneToAct": "Aggiungi scena a questo atto",
+ "sceneboard.ai.contextNote": "L'analisi usa i titoli delle scene e le righe iniziali, fino a ~2.000 caratteri.",
"sceneboard.ai.empty": "Nessun suggerimento. Riprova con contenuto.",
"sceneboard.ai.panelTitle": "Suggerimenti trama IA",
- "sceneboard.ai.contextNote": "L'analisi usa i titoli delle scene e le righe iniziali, fino a ~2.000 caratteri.",
"sceneboard.ai.ragChunks": "{{count}} passaggi della storia",
"sceneboard.ai.retry": "Suggerisci ancora",
"sceneboard.ai.suggestBeat": "Suggerisci beat IA",
@@ -777,9 +794,9 @@
"vc.title": "Cronologia versioni",
"vc.words": "parole",
"voice.cancelSpeech": "Annulla voce",
+ "voice.feedback.confidence": "Affidabilità {{percent}}%",
"voice.modeChip.commands": "Comandi",
"voice.modeChip.dictation": "Dettatura",
- "voice.feedback.confidence": "Affidabilità {{percent}}%",
"voice.panelLabel": "Controllo vocale",
"voice.permissionDenied": "Accesso al microfono negato. Consenti l’accesso al microfono nelle impostazioni del browser.",
"voice.startDictation": "Inizia dettatura",
@@ -793,23 +810,6 @@
"voice.stopListening": "Ferma ascolto",
"worlds.emptyState.description": "Costruisci i luoghi, le regole e le storie in cui vive la tua narrazione. Inizia con una location.",
"worlds.emptyState.title": "Il mondo ti aspetta",
- "error.fallback.generic": "IA non disponibile: usata l'assistenza integrata.",
- "error.fallback.offline": "Sei offline: usata l'assistenza integrata.",
- "assisted.badge.label": "Assistito",
- "assisted.badge.srLabel": "Modalità assistita: generato senza IA",
- "assisted.toast.title": "IA non disponibile",
- "assisted.toast.description": "Usata l'assistenza integrata. Migliora con l'IA quando un modello è disponibile.",
- "assisted.enhance": "Migliora con l'IA",
- "plotBoard.heuristic.position": "Subito dopo la scena selezionata",
- "plotBoard.heuristic.escalate.title": "Alzare la posta",
- "plotBoard.heuristic.escalate.description": "Aumenta la pressione sul protagonista così che la prossima scelta costi di più.",
- "plotBoard.heuristic.escalate.rationale": "L'escalation mantiene lo slancio quando la parte centrale cala.",
- "plotBoard.heuristic.complicate.title": "Introdurre una complicazione",
- "plotBoard.heuristic.complicate.description": "Aggiungi un ostacolo o una rivelazione che imponga un cambio di piano.",
- "plotBoard.heuristic.complicate.rationale": "Una nuova complicazione mette alla prova i personaggi e apre nuovi fili.",
- "plotBoard.heuristic.reverse.title": "Aggiungere un colpo di scena",
- "plotBoard.heuristic.reverse.description": "Ribalta un'aspettativa: un alleato vacilla, una vittoria si guasta o una verità nascosta emerge.",
- "plotBoard.heuristic.reverse.rationale": "I ribaltamenti rinnovano la tensione e approfondiscono l'arco.",
"copilot.annotationCount": "{{count}} insight for this chapter",
"copilot.announceClosed": "Copilota IA chiuso",
"copilot.announceOpened": "Copilota IA aperto",
@@ -877,11 +877,9 @@
"copilot.you": "Tu",
"dashboard.authorInsights.readability": "Leggibilità (Gulpease, euristica IT)",
"dashboard.authorInsights.readabilityFootnote": "Punteggi più alti sono spesso più facili da leggere; calibra sul genere.",
- "dashboard.authorInsights.readabilityTooltip": "Indice di leggibilità Gulpease 0–100: più alto = più facile da leggere (soglia ~60 per la scuola media, ~80 per la scuola elementare). È un indicatore approssimativo, non un voto normativo.",
- "dashboard.authorInsights.readabilityScaleSuffix": "/100",
- "dashboard.logline.updated": "Logline aggiornata",
- "dashboard.logline.updatedUndo": "Premi Ctrl+Z per annullare.",
"dashboard.authorInsights.readabilityNeedMore": "Scrivi ancora — servono ~40+ parole per un punteggio stabile.",
+ "dashboard.authorInsights.readabilityScaleSuffix": "/100",
+ "dashboard.authorInsights.readabilityTooltip": "Indice di leggibilità Gulpease 0–100: più alto = più facile da leggere (soglia ~60 per la scuola media, ~80 per la scuola elementare). È un indicatore approssimativo, non un voto normativo.",
"dashboard.authorInsights.timeline": "Controlli cronologia scene",
"dashboard.authorInsights.timelineClear": "Nessun avviso dai metadati.",
"dashboard.authorInsights.timelineWarnBadge": "{{count}} avvisi — controlla date/durate sul board.",
@@ -953,6 +951,8 @@
"dashboard.healthScore.title": "Salute del progetto",
"dashboard.healthScore.world": "Costruzione del mondo",
"dashboard.healthScore.writing": "Progresso di scrittura",
+ "dashboard.logline.updated": "Logline aggiornata",
+ "dashboard.logline.updatedUndo": "Premi Ctrl+Z per annullare.",
"dashboard.loglineModal.loading": "Generazione di logline brillanti...",
"dashboard.loglineModal.title": "Suggerimenti logline IA",
"dashboard.momentum.activity": "Ultimi 14 giorni",
@@ -986,23 +986,23 @@
"initialProject.chapter1": "Capitolo 1",
"initialProject.logline": "Un viaggio di mille miglia inizia con un solo passo...",
"initialProject.title": "La mia storia senza titolo",
- "desktop.menu.file": "File",
+ "desktop.menu.commandPalette": "Palette comandi",
+ "desktop.menu.edit": "Modifica",
"desktop.menu.export": "Esporta progetto…",
+ "desktop.menu.file": "File",
+ "desktop.menu.help": "Aiuto",
+ "desktop.menu.helpCenter": "Centro assistenza",
"desktop.menu.settings": "Impostazioni",
- "desktop.menu.edit": "Modifica",
"desktop.menu.view": "Visualizza",
- "desktop.menu.commandPalette": "Palette comandi",
"desktop.menu.window": "Finestra",
- "desktop.menu.help": "Aiuto",
- "desktop.menu.helpCenter": "Centro assistenza",
- "desktop.tray.tooltip": "WorldScript Studio",
- "desktop.tray.show": "Mostra WorldScript Studio",
- "desktop.tray.settings": "Impostazioni",
- "desktop.tray.commandPalette": "Palette comandi",
- "desktop.tray.quit": "Esci",
- "desktop.settings.sectionTitle": "Desktop",
"desktop.settings.minimizeToTray": "Riduci nella barra delle applicazioni alla chiusura",
"desktop.settings.minimizeToTrayHint": "Mantieni WorldScript Studio attivo nell'area di notifica invece di uscire quando chiudi la finestra.",
+ "desktop.settings.sectionTitle": "Desktop",
+ "desktop.tray.commandPalette": "Palette comandi",
+ "desktop.tray.quit": "Esci",
+ "desktop.tray.settings": "Impostazioni",
+ "desktop.tray.show": "Mostra WorldScript Studio",
+ "desktop.tray.tooltip": "WorldScript Studio",
"export.ai.generateButton": "Genera sinossi",
"export.ai.generating": "Generazione...",
"export.ai.synopsis": "Genera sinossi IA",
@@ -1090,10 +1090,10 @@
"export.pasteSection.importAsChapter": "Importa come capitolo",
"export.pasteSection.textPlaceholder": "Incolla testo da Google Docs o Notion qui (Ctrl+V)...",
"export.pasteSection.titlePlaceholder": "Titolo capitolo (opzionale)",
- "export.preview.noContent": "Seleziona contenuto per vedere un'anteprima.",
"export.preview.modeLabel": "Modalità anteprima",
- "export.preview.modeText": "Testo",
"export.preview.modeRendered": "Renderizzato",
+ "export.preview.modeText": "Testo",
+ "export.preview.noContent": "Seleziona contenuto per vedere un'anteprima.",
"export.preview.title": "Anteprima in diretta",
"export.title": "Suite di pubblicazione Export",
"export.toggleSection": "Attiva/disattiva visibilità per {{title}}",
@@ -1519,6 +1519,23 @@
"outline.deleteConfirm": "Sei sicuro di voler eliminare questa sezione dello schema?",
"outline.description": "Descrivi la tua idea di storia e lascia che l'IA crei uno schema strutturato e modificabile per te.",
"outline.error.generationFailed": "Generazione del contenuto fallita. Per favore riprova.",
+ "outline.heuristic.beat.climax.desc": "Il conflitto centrale raggiunge il culmine nello scontro decisivo della storia.",
+ "outline.heuristic.beat.climax.title": "Climax",
+ "outline.heuristic.beat.complications.desc": "Battute d'arresto e conflitti si intensificano; la via da seguire si restringe.",
+ "outline.heuristic.beat.complications.title": "Complicazioni",
+ "outline.heuristic.beat.incitingIncident.desc": "L'evento che mette in moto la storia: {{idea}}.",
+ "outline.heuristic.beat.incitingIncident.title": "Incidente scatenante",
+ "outline.heuristic.beat.midpoint.desc": "Una svolta cambia la direzione della storia e alza la posta in gioco.",
+ "outline.heuristic.beat.midpoint.title": "Punto centrale",
+ "outline.heuristic.beat.resolution.desc": "I nodi vengono sciolti ed emerge un nuovo status quo.",
+ "outline.heuristic.beat.resolution.title": "Risoluzione",
+ "outline.heuristic.beat.risingAction.desc": "Le complicazioni aumentano e la posta in gioco cresce mentre i personaggi perseguono il loro obiettivo.",
+ "outline.heuristic.beat.risingAction.title": "Azione crescente",
+ "outline.heuristic.beat.setup.desc": "Presenta il mondo e i personaggi principali e stabilisci lo status quo prima che tutto cambi.",
+ "outline.heuristic.beat.setup.title": "Impostazione",
+ "outline.heuristic.beat.twist.desc": "Una rivelazione inaspettata sconvolge ciò che i personaggi credevano vero.",
+ "outline.heuristic.beat.twist.title": "Colpo di scena",
+ "outline.heuristic.fallbackIdea": "l'idea centrale",
"outline.idea.generateButton": "Genera schema",
"outline.idea.genreLabel": "Genere",
"outline.idea.genrePlaceholder": "es. Fantascienza, Fantasy, Mistero",
@@ -1541,23 +1558,6 @@
"outline.result.twistTooltip": "Colpo di scena generato dall'IA",
"outline.selectSection": "Seleziona la sezione «{{title}}»",
"outline.title": "Generatore di schema storia IA",
- "outline.heuristic.fallbackIdea": "l'idea centrale",
- "outline.heuristic.beat.setup.title": "Impostazione",
- "outline.heuristic.beat.setup.desc": "Presenta il mondo e i personaggi principali e stabilisci lo status quo prima che tutto cambi.",
- "outline.heuristic.beat.incitingIncident.title": "Incidente scatenante",
- "outline.heuristic.beat.incitingIncident.desc": "L'evento che mette in moto la storia: {{idea}}.",
- "outline.heuristic.beat.risingAction.title": "Azione crescente",
- "outline.heuristic.beat.risingAction.desc": "Le complicazioni aumentano e la posta in gioco cresce mentre i personaggi perseguono il loro obiettivo.",
- "outline.heuristic.beat.midpoint.title": "Punto centrale",
- "outline.heuristic.beat.midpoint.desc": "Una svolta cambia la direzione della storia e alza la posta in gioco.",
- "outline.heuristic.beat.complications.title": "Complicazioni",
- "outline.heuristic.beat.complications.desc": "Battute d'arresto e conflitti si intensificano; la via da seguire si restringe.",
- "outline.heuristic.beat.twist.title": "Colpo di scena",
- "outline.heuristic.beat.twist.desc": "Una rivelazione inaspettata sconvolge ciò che i personaggi credevano vero.",
- "outline.heuristic.beat.climax.title": "Climax",
- "outline.heuristic.beat.climax.desc": "Il conflitto centrale raggiunge il culmine nello scontro decisivo della storia.",
- "outline.heuristic.beat.resolution.title": "Risoluzione",
- "outline.heuristic.beat.resolution.desc": "I nodi vengono sciolti ed emerge un nuovo status quo.",
"portal.back": "Indietro",
"portal.demo.chapterContent": "La nebbia del mattino avvolgeva i moli mentre Lyra srotolava la vecchia pianta della città. Un cerchio appena leggibile segnava il nord-ovest — la torre di cui nessuno parlava.\n\nRipiegò il foglio e seguì il sentiero finché la grata di ferro non le si parò davanti. Il lucchetto era tiepido al sole; il metallo ancora freddo.",
"portal.demo.chapterTitle": "Capitolo 1 — Davanti al cancello",
@@ -1752,6 +1752,7 @@
"settings.ai.gpu.troubleshootLowEnd": "Il tuo dispositivo ha risorse limitate. L'IA locale utilizzerà modelli più piccoli. Chiudi altre schede o attiva la modalità eco.",
"settings.ai.gpu.troubleshootQueue": "Più attività IA sono in coda. Solo una viene eseguita alla volta per evitare collisioni VRAM. Attendi il completamento dell'attività corrente.",
"settings.ai.gpu.waitingConsumers": "In attesa",
+ "settings.ai.grokKey": "Chiave API Grok",
"settings.ai.hybridFallbackHint": "Se il provider principale fallisce, WorldScript prova i fallback elencati. Lo streaming dello scrittore usa solo il tuo provider principale.",
"settings.ai.hybridFallbackTitle": "Fallback ibrido (strumenti IA del progetto)",
"settings.ai.hybridFallbackToggle": "Abilita catena di fallback",
@@ -1832,6 +1833,11 @@
"settings.ai.preset.lmStudio": "LM Studio",
"settings.ai.preset.ollamaDefault": "Ollama (porta predefinita)",
"settings.ai.preset.vllm": "vLLM",
+ "settings.ai.provider.anthropic": "Anthropic Claude",
+ "settings.ai.provider.gemini": "Google Gemini",
+ "settings.ai.provider.grok": "xAI Grok",
+ "settings.ai.provider.ollama": "Ollama (locale)",
+ "settings.ai.provider.openai": "OpenAI",
"settings.ai.providerDescription": "Scegli quale provider IA WorldScript Studio deve utilizzare.",
"settings.ai.providerOnnx": "ONNX (WASM)",
"settings.ai.providerStatusConnected": "Connesso",
@@ -2711,6 +2717,11 @@
"worlds.edit.notes": "Note",
"worlds.editorTabsAriaLabel": "Schede editor mondo",
"worlds.error.imageFailed": "Generazione immagine ambientale fallita. Prova ad aggiungere più dettagli alla descrizione del mondo.",
+ "worlds.heuristic.culture": "Descrivi i popoli, le credenze e la vita quotidiana plasmati da {{concept}}.",
+ "worlds.heuristic.description": "Un mondo definito dalla sua premessa centrale: {{concept}}.",
+ "worlds.heuristic.geography": "Delinea le principali regioni, i climi e gli elementi naturali di {{concept}}.",
+ "worlds.heuristic.magicSystem": "Definisci le regole, i costi e i limiti del potere in {{concept}}.",
+ "worlds.heuristic.name": "Nuovo mondo",
"worlds.loading.profile": "Generazione profilo mondo dettagliato...",
"worlds.newWorldName": "Nuovo mondo",
"worlds.noWorlds": "Nessun mondo creato.",
@@ -2729,32 +2740,19 @@
"worlds.title": "Atlante dei mondi",
"worlds.uploadImage": "Carica immagine",
"worlds.yourWorlds": "I tuoi mondi",
- "worlds.heuristic.name": "Nuovo mondo",
- "worlds.heuristic.description": "Un mondo definito dalla sua premessa centrale: {{concept}}.",
- "worlds.heuristic.geography": "Delinea le principali regioni, i climi e gli elementi naturali di {{concept}}.",
- "worlds.heuristic.magicSystem": "Definisci le regole, i costi e i limiti del potere in {{concept}}.",
- "worlds.heuristic.culture": "Descrivi i popoli, le credenze e la vita quotidiana plasmati da {{concept}}.",
"writer.cancelledTag": "Annullato",
"writer.chapter.label": "Capitolo: {{title}}",
- "writer.context.hide": "Nascondi contesto",
- "writer.context.label": "Contesto",
- "writer.context.show": "Mostra contesto",
- "writer.flowMode.enterLabel": "Modalità flusso",
- "writer.modeBadge.label": "Modalità attive:",
- "writer.modeBadge.flow": "Flusso",
- "writer.modeBadge.focus": "Focus",
- "writer.modeBadge.proforge": "ProForge",
- "writer.modeBadge.contextHidden": "Contesto nascosto",
- "writer.modeBadge.toolsHidden": "Strumenti nascosti",
- "writer.modeBadge.reset": "Ripristina layout standard",
- "writer.modeBadge.resetTitle": "Ripristina il layout standard a tre colonne",
"writer.coachmark.dismiss": "Ho capito",
- "writer.coachmark.flow.title": "Modalità flusso",
"writer.coachmark.flow.body": "Viene mostrato solo il pannello di scrittura — tutto il resto è nascosto. Premi Esc o \"Ripristina layout standard\" per tornare.",
- "writer.coachmark.focus.title": "Modalità focus",
+ "writer.coachmark.flow.title": "Modalità flusso",
"writer.coachmark.focus.body": "Mostra il manoscritto e il contesto affiancati, nascondendo la colonna degli strumenti. Disattivabile in qualsiasi momento dall'intestazione.",
- "writer.coachmark.proforge.title": "Pipeline ProForge",
+ "writer.coachmark.focus.title": "Modalità focus",
"writer.coachmark.proforge.body": "La colonna degli strumenti ora esegue la pipeline di editing multifase. Il manoscritto non viene mai modificato senza la tua revisione.",
+ "writer.coachmark.proforge.title": "Pipeline ProForge",
+ "writer.context.hide": "Nascondi contesto",
+ "writer.context.label": "Contesto",
+ "writer.context.show": "Mostra contesto",
+ "writer.flowMode.enterLabel": "Modalità flusso",
"writer.flowMode.exit": "Esci dalla modalità flusso",
"writer.flowMode.exitLabel": "Esci dal flusso",
"writer.flowMode.hint": "Scrivi senza interruzioni. Premi Esc per tornare.",
@@ -2763,9 +2761,31 @@
"writer.focusMode.enterLabel": "Modalità focus",
"writer.focusMode.exit": "Esci dalla modalità focus",
"writer.focusMode.exitLabel": "Esci dal focus",
+ "writer.grammar.addToDictionary": "Aggiungi al dizionario",
+ "writer.grammar.apply": "Applica",
+ "writer.grammar.checkButton": "Controlla questa scena",
+ "writer.grammar.checking": "Controllo…",
+ "writer.grammar.disabled": "Attiva LanguageTool in Impostazioni → Connessioni per controllare questa scena.",
+ "writer.grammar.error": "Il server LanguageTool ha restituito un errore.",
+ "writer.grammar.ignore": "Ignora",
+ "writer.grammar.issuesFound": "{{count}} problemi rilevati",
+ "writer.grammar.noIssues": "Nessun problema rilevato.",
+ "writer.grammar.noSuggestions": "Nessun suggerimento",
+ "writer.grammar.offline": "Impossibile raggiungere il server LanguageTool. È in esecuzione?",
+ "writer.grammar.selectScene": "Seleziona una scena da controllare.",
+ "writer.grammar.title": "Grammatica e ortografia",
+ "writer.grammar.unsupported": "Il controllo grammaticale non è disponibile per questa lingua.",
"writer.imagePrompt.description": "Genera un prompt ottimizzato per DALL·E 3 / Midjourney dalla scena attuale o dalla selezione del testo.",
"writer.imagePrompt.note": "Il prompt generato funziona direttamente in DALL·E 3 e Midjourney.",
"writer.imagePrompt.tip": "Suggerimento: Seleziona una sezione di testo specifica per un prompt di scena mirato.",
+ "writer.modeBadge.contextHidden": "Contesto nascosto",
+ "writer.modeBadge.flow": "Flusso",
+ "writer.modeBadge.focus": "Focus",
+ "writer.modeBadge.label": "Modalità attive:",
+ "writer.modeBadge.proforge": "ProForge",
+ "writer.modeBadge.reset": "Ripristina layout standard",
+ "writer.modeBadge.resetTitle": "Ripristina il layout standard a tre colonne",
+ "writer.modeBadge.toolsHidden": "Strumenti nascosti",
"writer.stopGenerating": "Interrompi generazione",
"writer.studio.context.contentPlaceholder": "Seleziona o crea una sezione del manoscritto per iniziare.",
"writer.studio.context.sectionLabel": "Sezione di lavoro",
@@ -2787,12 +2807,10 @@
"writer.studio.controls.tones.poetic": "Più poetico",
"writer.studio.controls.tones.suspenseful": "Più suspensivo",
"writer.studio.description": "Il tuo co-autore IA. Genera, migliora e fai brainstorming con il contesto completo del progetto.",
+ "writer.studio.rag.chunkScore": "pertinenza {{score}}",
"writer.studio.rag.chunksBadge": "{{count}} passaggi trovati",
"writer.studio.rag.chunksHint": "Estratti pertinenti del tuo manoscritto — più passaggi significa un contesto IA più ricco",
"writer.studio.rag.inspectorLabel": "Contesto recuperato",
- "writer.studio.rag.chunkScore": "pertinenza {{score}}",
- "writer.studio.tokens.badge": "~{{count}} token",
- "writer.studio.tokens.hint": "Token approssimativi usati dall'ultima richiesta IA",
"writer.studio.rag.useContext": "Attingi dalla mia storia",
"writer.studio.result.insert": "Inserisci",
"writer.studio.result.next": "Successivo",
@@ -2802,6 +2820,8 @@
"writer.studio.result.retry": "Riprova",
"writer.studio.result.title": "Area di lavoro IA",
"writer.studio.title": "Studio di scrittura IA",
+ "writer.studio.tokens.badge": "~{{count}} token",
+ "writer.studio.tokens.hint": "Token approssimativi usati dall'ultima richiesta IA",
"writer.studio.tools.brainstorm.contextLabel": "Contesto brainstorming (opzionale)",
"writer.studio.tools.brainstorm.contextPlaceholder": "Fornisci una breve situazione, o l'IA userà la sezione del manoscritto corrente.",
"writer.studio.tools.brainstorm.title": "Brainstorming idee",
@@ -2833,19 +2853,5 @@
"writer.tts.start": "Leggi ad alta voce",
"writer.tts.stop": "Interrompi lettura",
"writer.versionControl.label": "Versioni",
- "writer.versionControl.tooltip": "Controllo versione (rami e istantanee)",
- "writer.grammar.title": "Grammatica e ortografia",
- "writer.grammar.checkButton": "Controlla questa scena",
- "writer.grammar.checking": "Controllo…",
- "writer.grammar.issuesFound": "{{count}} problemi rilevati",
- "writer.grammar.noIssues": "Nessun problema rilevato.",
- "writer.grammar.selectScene": "Seleziona una scena da controllare.",
- "writer.grammar.unsupported": "Il controllo grammaticale non è disponibile per questa lingua.",
- "writer.grammar.disabled": "Attiva LanguageTool in Impostazioni → Connessioni per controllare questa scena.",
- "writer.grammar.offline": "Impossibile raggiungere il server LanguageTool. È in esecuzione?",
- "writer.grammar.error": "Il server LanguageTool ha restituito un errore.",
- "writer.grammar.apply": "Applica",
- "writer.grammar.ignore": "Ignora",
- "writer.grammar.addToDictionary": "Aggiungi al dizionario",
- "writer.grammar.noSuggestions": "Nessun suggerimento"
+ "writer.versionControl.tooltip": "Controllo versione (rami e istantanee)"
}
diff --git a/public/locales/ja/bundle.json b/public/locales/ja/bundle.json
index 1e13e4ee..e96ef378 100644
--- a/public/locales/ja/bundle.json
+++ b/public/locales/ja/bundle.json
@@ -90,6 +90,14 @@
"characters.edit.relationships": "人間関係",
"characters.editorTabsAriaLabel": "キャラクター editor tabs",
"characters.error.portraitFailed": "ポートレートの生成に失敗しました。外観の説明にさらに詳細を追加してみてください。",
+ "characters.heuristic.appearance": "Describe how they present themselves — let their look hint at {{concept}}.",
+ "characters.heuristic.backstory": "Shaped by formative experiences, this character carries a past tied to {{concept}}.",
+ "characters.heuristic.characterArc": "They begin guarded and, through the story, are changed by {{concept}}.",
+ "characters.heuristic.flaws": "A weakness that complicates their goals.",
+ "characters.heuristic.motivation": "A core desire connected to {{concept}} drives their choices.",
+ "characters.heuristic.name": "New Character",
+ "characters.heuristic.personalityTraits": "Resourceful, guarded, determined.",
+ "characters.heuristic.relationships": "Note the key bonds and rivalries that define them.",
"characters.loading.profile": "詳細なプロファイルを生成しています...",
"characters.newCharacterName": "New キャラクター",
"characters.noCharacters": "まだキャラクターは作成されていません。",
@@ -107,14 +115,6 @@
"characters.title": "キャラクター Dossiers",
"characters.uploadImage": "画像をアップロードする",
"characters.yourCharacters": "あなたのキャラクター",
- "characters.heuristic.name": "New Character",
- "characters.heuristic.backstory": "Shaped by formative experiences, this character carries a past tied to {{concept}}.",
- "characters.heuristic.motivation": "A core desire connected to {{concept}} drives their choices.",
- "characters.heuristic.appearance": "Describe how they present themselves — let their look hint at {{concept}}.",
- "characters.heuristic.personalityTraits": "Resourceful, guarded, determined.",
- "characters.heuristic.flaws": "A weakness that complicates their goals.",
- "characters.heuristic.characterArc": "They begin guarded and, through the story, are changed by {{concept}}.",
- "characters.heuristic.relationships": "Note the key bonds and rivalries that define them.",
"apiKey.connectionFailed": "接続テストに失敗しました。",
"apiKey.connectionSuccess": "接続成功! APIは正しく応答します。",
"apiKey.decryptFailed": "APIキーを復号化できませんでした",
@@ -125,6 +125,11 @@
"apiKey.test": "テスト接続",
"apiKey.testConnection": "API接続のテスト",
"apiKey.testing": "テスト中…",
+ "assisted.badge.label": "Assisted",
+ "assisted.badge.srLabel": "Assisted mode — generated without AI",
+ "assisted.enhance": "Enhance with AI",
+ "assisted.toast.description": "Used built-in assistance. Enhance with AI when a model is available.",
+ "assisted.toast.title": "AI unavailable",
"charGraph.characters": "キャラクター",
"charGraph.noCharacters": "まだ文字がありません",
"charGraph.noCharactersHint": "追加 characters in the Characters view to visualize their relationships here.",
@@ -286,6 +291,8 @@
"error.db.unknown": "データベースへのアクセス中に不明なエラーが発生しました。",
"error.deepLink.title": "プロジェクトファイルを開けませんでした",
"error.deepLink.unknown": "不明なエラー",
+ "error.fallback.generic": "AI is unavailable — used built-in assistance.",
+ "error.fallback.offline": "You're offline — used built-in assistance.",
"error.fileImportError": "ファイルインポートエラー",
"error.mic.denied": "マイクへのアクセスが拒否されました。ブラウザの設定で許可を与えてください。",
"error.mic.generic": "音声認識エラー: {{error}}",
@@ -382,6 +389,16 @@
"palette.voice.listeningLive": "音声入力が有効になっています",
"palette.voice.start": "音声検索を開始する",
"palette.voice.stop": "音声検索を停止する",
+ "plotBoard.heuristic.complicate.description": "Add an obstacle or reveal that forces a change of plan.",
+ "plotBoard.heuristic.complicate.rationale": "A fresh complication tests the characters and opens new threads.",
+ "plotBoard.heuristic.complicate.title": "Introduce a complication",
+ "plotBoard.heuristic.escalate.description": "Increase the pressure on your protagonist so the next choice costs more.",
+ "plotBoard.heuristic.escalate.rationale": "Escalation keeps momentum when the middle sags.",
+ "plotBoard.heuristic.escalate.title": "Raise the stakes",
+ "plotBoard.heuristic.position": "Right after the selected scene",
+ "plotBoard.heuristic.reverse.description": "Flip an expectation — an ally falters, a win turns sour, or a hidden truth surfaces.",
+ "plotBoard.heuristic.reverse.rationale": "Reversals refresh tension and deepen the arc.",
+ "plotBoard.heuristic.reverse.title": "Add a reversal",
"preview.controls.ariaLabel": "プレビューコントロール",
"preview.controls.decreaseFontSize": "フォントサイズを小さくする",
"preview.controls.exitFullscreen": "全画面表示を終了する",
@@ -449,10 +466,6 @@
"proforge.progress.awaitingReviewHint": "⚠️ このステージはあなたのレビューを待っています。項目を確認するには、上のステージ ボタンをクリックしてください。",
"proforge.progress.completedStages": "完了したステージ",
"proforge.progress.currentStatus": "現在の状況",
- "proforge.progress.overall": "Overall progress",
- "proforge.progress.preparing": "Preparing…",
- "proforge.progress.stageOfTotal": "Stage {{current}} of {{total}}",
- "proforge.progress.percentComplete": "{{percent}}% complete",
"proforge.progress.itemsCount": "{{count}} アイテム",
"proforge.progress.metric.aiCalls": "AI通話",
"proforge.progress.metric.duration": "間隔",
@@ -463,7 +476,11 @@
"proforge.progress.metric.totalTime": "合計時間",
"proforge.progress.metric.totalTokens": "総トークン数",
"proforge.progress.noneRunning": "パイプラインが実行されていません。",
+ "proforge.progress.overall": "Overall progress",
+ "proforge.progress.percentComplete": "{{percent}}% complete",
+ "proforge.progress.preparing": "Preparing…",
"proforge.progress.stageDetails": "ステージ詳細: {{stage}}",
+ "proforge.progress.stageOfTotal": "Stage {{current}} of {{total}}",
"proforge.progress.statusLabel": "状態",
"proforge.progress.totals": "パイプラインの合計",
"proforge.review.accept": "受け入れる",
@@ -777,9 +794,9 @@
"vc.title": "バージョン履歴",
"vc.words": "言葉",
"voice.cancelSpeech": "キャンセル speech",
+ "voice.feedback.confidence": "信頼度 {{percent}}%",
"voice.modeChip.commands": "コマンド",
"voice.modeChip.dictation": "ディクテーション",
- "voice.feedback.confidence": "信頼度 {{percent}}%",
"voice.panelLabel": "音声制御",
"voice.permissionDenied": "マイクへのアクセスが拒否されました。音声機能を使用するには、ブラウザの設定でマイクへのアクセスを許可してください。",
"voice.startDictation": "ディクテーションを開始する",
@@ -793,23 +810,6 @@
"voice.stopListening": "聞くのをやめる",
"worlds.emptyState.description": "あなたの物語が生きる場所、ルール、歴史を構築します。場所から始めます。",
"worlds.emptyState.title": "世界が待っています",
- "error.fallback.generic": "AI is unavailable — used built-in assistance.",
- "error.fallback.offline": "You're offline — used built-in assistance.",
- "assisted.badge.label": "Assisted",
- "assisted.badge.srLabel": "Assisted mode — generated without AI",
- "assisted.toast.title": "AI unavailable",
- "assisted.toast.description": "Used built-in assistance. Enhance with AI when a model is available.",
- "assisted.enhance": "Enhance with AI",
- "plotBoard.heuristic.position": "Right after the selected scene",
- "plotBoard.heuristic.escalate.title": "Raise the stakes",
- "plotBoard.heuristic.escalate.description": "Increase the pressure on your protagonist so the next choice costs more.",
- "plotBoard.heuristic.escalate.rationale": "Escalation keeps momentum when the middle sags.",
- "plotBoard.heuristic.complicate.title": "Introduce a complication",
- "plotBoard.heuristic.complicate.description": "Add an obstacle or reveal that forces a change of plan.",
- "plotBoard.heuristic.complicate.rationale": "A fresh complication tests the characters and opens new threads.",
- "plotBoard.heuristic.reverse.title": "Add a reversal",
- "plotBoard.heuristic.reverse.description": "Flip an expectation — an ally falters, a win turns sour, or a hidden truth surfaces.",
- "plotBoard.heuristic.reverse.rationale": "Reversals refresh tension and deepen the arc.",
"copilot.annotationCount": "{{count}} この章の洞察",
"copilot.announceClosed": "AI コパイロットは終了しました",
"copilot.announceOpened": "AI Copilot がオープンしました",
@@ -1090,10 +1090,10 @@
"export.pasteSection.importAsChapter": "章としてインポート",
"export.pasteSection.textPlaceholder": "Google ドキュメントまたは Notion からここにテキストを貼り付けます (Ctrl+V)...",
"export.pasteSection.titlePlaceholder": "章のタイトル (オプション)",
- "export.preview.noContent": "コンテンツを選択してプレビューを表示します。",
"export.preview.modeLabel": "プレビューモード",
- "export.preview.modeText": "テキスト",
"export.preview.modeRendered": "レンダリング",
+ "export.preview.modeText": "テキスト",
+ "export.preview.noContent": "コンテンツを選択してプレビューを表示します。",
"export.preview.title": "ライブプレビュー",
"export.title": "エクスポート Publishing Suite",
"export.toggleSection": "{{title}} の公開設定を切り替えます",
@@ -1519,6 +1519,23 @@
"outline.deleteConfirm": "このアウトラインセクションを削除してもよろしいですか?",
"outline.description": "ストーリーのアイデアを説明すると、AI が構造化された編集可能なアウトラインを作成します。",
"outline.error.generationFailed": "コンテンツの生成に失敗しました。もう一度試してください。",
+ "outline.heuristic.beat.climax.desc": "The central conflict comes to a head in the story's defining confrontation.",
+ "outline.heuristic.beat.climax.title": "Climax",
+ "outline.heuristic.beat.complications.desc": "Setbacks and conflicts deepen; the path forward narrows.",
+ "outline.heuristic.beat.complications.title": "Complications",
+ "outline.heuristic.beat.incitingIncident.desc": "The event that sets the story in motion: {{idea}}.",
+ "outline.heuristic.beat.incitingIncident.title": "Inciting Incident",
+ "outline.heuristic.beat.midpoint.desc": "A turning point shifts the direction of the story and raises the stakes.",
+ "outline.heuristic.beat.midpoint.title": "Midpoint",
+ "outline.heuristic.beat.resolution.desc": "Loose ends are tied up and a new status quo emerges.",
+ "outline.heuristic.beat.resolution.title": "Resolution",
+ "outline.heuristic.beat.risingAction.desc": "Complications escalate and the stakes grow as the characters pursue their goal.",
+ "outline.heuristic.beat.risingAction.title": "Rising Action",
+ "outline.heuristic.beat.setup.desc": "Introduce the world and the main characters, and establish the status quo before everything changes.",
+ "outline.heuristic.beat.setup.title": "Setup",
+ "outline.heuristic.beat.twist.desc": "An unexpected revelation upends what the characters believed to be true.",
+ "outline.heuristic.beat.twist.title": "Twist",
+ "outline.heuristic.fallbackIdea": "the central idea",
"outline.idea.generateButton": "生成 アウトライン",
"outline.idea.genreLabel": "ジャンル",
"outline.idea.genrePlaceholder": "例: SF、ファンタジー、ミステリー",
@@ -1541,23 +1558,6 @@
"outline.result.twistTooltip": "AI が生成したどんでん返し",
"outline.selectSection": "セクション「{{title}}」を選択してください",
"outline.title": "AI Story アウトライン Generator",
- "outline.heuristic.fallbackIdea": "the central idea",
- "outline.heuristic.beat.setup.title": "Setup",
- "outline.heuristic.beat.setup.desc": "Introduce the world and the main characters, and establish the status quo before everything changes.",
- "outline.heuristic.beat.incitingIncident.title": "Inciting Incident",
- "outline.heuristic.beat.incitingIncident.desc": "The event that sets the story in motion: {{idea}}.",
- "outline.heuristic.beat.risingAction.title": "Rising Action",
- "outline.heuristic.beat.risingAction.desc": "Complications escalate and the stakes grow as the characters pursue their goal.",
- "outline.heuristic.beat.midpoint.title": "Midpoint",
- "outline.heuristic.beat.midpoint.desc": "A turning point shifts the direction of the story and raises the stakes.",
- "outline.heuristic.beat.complications.title": "Complications",
- "outline.heuristic.beat.complications.desc": "Setbacks and conflicts deepen; the path forward narrows.",
- "outline.heuristic.beat.twist.title": "Twist",
- "outline.heuristic.beat.twist.desc": "An unexpected revelation upends what the characters believed to be true.",
- "outline.heuristic.beat.climax.title": "Climax",
- "outline.heuristic.beat.climax.desc": "The central conflict comes to a head in the story's defining confrontation.",
- "outline.heuristic.beat.resolution.title": "Resolution",
- "outline.heuristic.beat.resolution.desc": "Loose ends are tied up and a new status quo emerges.",
"portal.back": "戻る",
"portal.demo.chapterContent": "ライラが古い都市の地図を広げている間、朝霧が岸壁に張り付いていました。かすかな円が北西の角を示していました - 誰も言及しなかった塔です。\n\n彼女は紙をしまい込み、鉄の格子が目の前に現れるまで細い道を進みました。南京錠は太陽の下で暖かかった。金属はまだ冷たい。",
"portal.demo.chapterTitle": "第 1 章 — 門の前",
@@ -1752,6 +1752,7 @@
"settings.ai.gpu.troubleshootLowEnd": "デバイスのリソースは限られています。ローカル AI はより小さなモデルを使用します。パフォーマンスを向上させるには、他のブラウザ タブを閉じるか、エコ モードを有効にしてください。",
"settings.ai.gpu.troubleshootQueue": "複数の AI タスクがキューに入れられます。 VRAM の衝突を避けるために、一度に 1 つだけが実行されます。現在のタスクが完了するまで待ちます。",
"settings.ai.gpu.waitingConsumers": "待っている",
+ "settings.ai.grokKey": "Grok API Key",
"settings.ai.hybridFallbackHint": "プライマリ プロバイダーが失敗した場合、WorldScript はリストされているフォールバック (シーン ジェネレーター、コーデックス ツール) を試行します。ライター ストリーミングでは、プライマリ プロバイダーのみが使用されます。",
"settings.ai.hybridFallbackTitle": "ハイブリッド フォールバック (プロジェクト AI ツール)",
"settings.ai.hybridFallbackToggle": "フォールバック チェーンを有効にする",
@@ -1832,6 +1833,11 @@
"settings.ai.preset.lmStudio": "LMスタジオ",
"settings.ai.preset.ollamaDefault": "オラマ (デフォルトのポート)",
"settings.ai.preset.vllm": "vLLM",
+ "settings.ai.provider.anthropic": "Anthropic Claude",
+ "settings.ai.provider.gemini": "Google Gemini",
+ "settings.ai.provider.grok": "xAI Grok",
+ "settings.ai.provider.ollama": "Ollama (local)",
+ "settings.ai.provider.openai": "OpenAI",
"settings.ai.providerDescription": "WorldScript Studio が使用する AI プロバイダーを選択します。",
"settings.ai.providerOnnx": "ONNX (WASM)",
"settings.ai.providerStatusConnected": "接続済み",
@@ -2711,6 +2717,11 @@
"worlds.edit.notes": "注意事項",
"worlds.editorTabsAriaLabel": "世界 editor tabs",
"worlds.error.imageFailed": "アンビエンス画像の生成に失敗しました。世界の説明にさらに詳細を追加するか、接続を確認してください。",
+ "worlds.heuristic.culture": "Describe the peoples, beliefs, and daily life shaped by {{concept}}.",
+ "worlds.heuristic.description": "A world defined by its central premise: {{concept}}.",
+ "worlds.heuristic.geography": "Outline the major regions, climates, and natural features of {{concept}}.",
+ "worlds.heuristic.magicSystem": "Define the rules, costs, and limits of power in {{concept}}.",
+ "worlds.heuristic.name": "New World",
"worlds.loading.profile": "詳細な世界プロファイルを生成しています...",
"worlds.newWorldName": "New 世界",
"worlds.noWorlds": "まだワールドが作成されていません。",
@@ -2729,11 +2740,6 @@
"worlds.title": "世界 Atlas",
"worlds.uploadImage": "画像をアップロードする",
"worlds.yourWorlds": "あなたの世界",
- "worlds.heuristic.name": "New World",
- "worlds.heuristic.description": "A world defined by its central premise: {{concept}}.",
- "worlds.heuristic.geography": "Outline the major regions, climates, and natural features of {{concept}}.",
- "worlds.heuristic.magicSystem": "Define the rules, costs, and limits of power in {{concept}}.",
- "worlds.heuristic.culture": "Describe the peoples, beliefs, and daily life shaped by {{concept}}.",
"writer.cancelledTag": "キャンセル",
"writer.chapter.label": "章: {{title}}",
"writer.coachmark.dismiss": "Got it",
@@ -2755,6 +2761,20 @@
"writer.focusMode.enterLabel": "フォーカスモード",
"writer.focusMode.exit": "フォーカスモードを終了する",
"writer.focusMode.exitLabel": "フォーカスを終了",
+ "writer.grammar.addToDictionary": "Add to dictionary",
+ "writer.grammar.apply": "Apply",
+ "writer.grammar.checkButton": "Check this scene",
+ "writer.grammar.checking": "Checking…",
+ "writer.grammar.disabled": "Enable LanguageTool in Settings → Connections to check this scene.",
+ "writer.grammar.error": "The LanguageTool server returned an error.",
+ "writer.grammar.ignore": "Ignore",
+ "writer.grammar.issuesFound": "{{count}} issues found",
+ "writer.grammar.noIssues": "No issues found.",
+ "writer.grammar.noSuggestions": "No suggestions",
+ "writer.grammar.offline": "Couldn't reach the LanguageTool server. Is it running?",
+ "writer.grammar.selectScene": "Select a scene to check.",
+ "writer.grammar.title": "Grammar & Spelling",
+ "writer.grammar.unsupported": "Grammar check isn't available for this language.",
"writer.imagePrompt.description": "現在のシーンまたはテキスト選択から最適化された DALL・E 3 / Midjourney プロンプトを生成します。",
"writer.imagePrompt.note": "生成されたプロンプトは、DALL・E 3 および Midjourney で直接動作します。",
"writer.imagePrompt.tip": "ヒント: フォーカスされたシーン プロンプトの特定のテキスト セクションを選択します。",
@@ -2787,12 +2807,10 @@
"writer.studio.controls.tones.poetic": "より詩的",
"writer.studio.controls.tones.suspenseful": "よりサスペンスフルな",
"writer.studio.description": "Your AI co-author. 生成, improve, and brainstorm with full project context.",
+ "writer.studio.rag.chunkScore": "関連度 {{score}}",
"writer.studio.rag.chunksBadge": "{{count}} 件のストーリーの一節が見つかりました",
"writer.studio.rag.chunksHint": "原稿からの関連する抜粋 — 文章が多いほど、AI コンテキストが豊富になります",
"writer.studio.rag.inspectorLabel": "取得したコンテキスト",
- "writer.studio.rag.chunkScore": "関連度 {{score}}",
- "writer.studio.tokens.badge": "~{{count}} トークン",
- "writer.studio.tokens.hint": "直近のAIリクエストで使用したおおよそのトークン数",
"writer.studio.rag.useContext": "私の話から抜粋",
"writer.studio.result.insert": "入れる",
"writer.studio.result.next": "次へ",
@@ -2802,6 +2820,8 @@
"writer.studio.result.retry": "リトライ",
"writer.studio.result.title": "AI スクラッチパッド",
"writer.studio.title": "AIライティングスタジオ",
+ "writer.studio.tokens.badge": "~{{count}} トークン",
+ "writer.studio.tokens.hint": "直近のAIリクエストで使用したおおよそのトークン数",
"writer.studio.tools.brainstorm.contextLabel": "ブレーンストーミングのコンテキスト (オプション)",
"writer.studio.tools.brainstorm.contextPlaceholder": "簡単な状況を提供しない場合、AI は現在の原稿セクションを使用します。",
"writer.studio.tools.brainstorm.title": "アイデアのブレインストーミング",
@@ -2833,19 +2853,5 @@
"writer.tts.start": "声に出して読む",
"writer.tts.stop": "読むのをやめる",
"writer.versionControl.label": "バージョン",
- "writer.versionControl.tooltip": "バージョン管理 (ブランチとスナップショット)",
- "writer.grammar.title": "Grammar & Spelling",
- "writer.grammar.checkButton": "Check this scene",
- "writer.grammar.checking": "Checking…",
- "writer.grammar.issuesFound": "{{count}} issues found",
- "writer.grammar.noIssues": "No issues found.",
- "writer.grammar.selectScene": "Select a scene to check.",
- "writer.grammar.unsupported": "Grammar check isn't available for this language.",
- "writer.grammar.disabled": "Enable LanguageTool in Settings → Connections to check this scene.",
- "writer.grammar.offline": "Couldn't reach the LanguageTool server. Is it running?",
- "writer.grammar.error": "The LanguageTool server returned an error.",
- "writer.grammar.apply": "Apply",
- "writer.grammar.ignore": "Ignore",
- "writer.grammar.addToDictionary": "Add to dictionary",
- "writer.grammar.noSuggestions": "No suggestions"
+ "writer.versionControl.tooltip": "バージョン管理 (ブランチとスナップショット)"
}
diff --git a/public/locales/ko/bundle.json b/public/locales/ko/bundle.json
index 3bd4499f..885a4730 100644
--- a/public/locales/ko/bundle.json
+++ b/public/locales/ko/bundle.json
@@ -90,6 +90,14 @@
"characters.edit.relationships": "관계",
"characters.editorTabsAriaLabel": "문자 편집기 탭",
"characters.error.portraitFailed": "인물 사진 생성에 실패했습니다. 모양 설명에 더 자세한 내용을 추가해 보세요.",
+ "characters.heuristic.appearance": "Describe how they present themselves — let their look hint at {{concept}}.",
+ "characters.heuristic.backstory": "Shaped by formative experiences, this character carries a past tied to {{concept}}.",
+ "characters.heuristic.characterArc": "They begin guarded and, through the story, are changed by {{concept}}.",
+ "characters.heuristic.flaws": "A weakness that complicates their goals.",
+ "characters.heuristic.motivation": "A core desire connected to {{concept}} drives their choices.",
+ "characters.heuristic.name": "New Character",
+ "characters.heuristic.personalityTraits": "Resourceful, guarded, determined.",
+ "characters.heuristic.relationships": "Note the key bonds and rivalries that define them.",
"characters.loading.profile": "상세 프로필 생성 중...",
"characters.newCharacterName": "새로운 캐릭터",
"characters.noCharacters": "아직 생성된 캐릭터가 없습니다.",
@@ -107,14 +115,6 @@
"characters.title": "캐릭터 서류",
"characters.uploadImage": "이미지 업로드",
"characters.yourCharacters": "당신의 캐릭터",
- "characters.heuristic.name": "New Character",
- "characters.heuristic.backstory": "Shaped by formative experiences, this character carries a past tied to {{concept}}.",
- "characters.heuristic.motivation": "A core desire connected to {{concept}} drives their choices.",
- "characters.heuristic.appearance": "Describe how they present themselves — let their look hint at {{concept}}.",
- "characters.heuristic.personalityTraits": "Resourceful, guarded, determined.",
- "characters.heuristic.flaws": "A weakness that complicates their goals.",
- "characters.heuristic.characterArc": "They begin guarded and, through the story, are changed by {{concept}}.",
- "characters.heuristic.relationships": "Note the key bonds and rivalries that define them.",
"apiKey.connectionFailed": "연결 테스트에 실패했습니다.",
"apiKey.connectionSuccess": "연결 성공! API가 올바르게 응답합니다.",
"apiKey.decryptFailed": "API 키를 복호화할 수 없습니다.",
@@ -125,6 +125,11 @@
"apiKey.test": "연결 테스트",
"apiKey.testConnection": "API 연결 테스트",
"apiKey.testing": "테스트 중…",
+ "assisted.badge.label": "Assisted",
+ "assisted.badge.srLabel": "Assisted mode — generated without AI",
+ "assisted.enhance": "Enhance with AI",
+ "assisted.toast.description": "Used built-in assistance. Enhance with AI when a model is available.",
+ "assisted.toast.title": "AI unavailable",
"charGraph.characters": "캐릭터",
"charGraph.noCharacters": "아직 문자가 없습니다.",
"charGraph.noCharactersHint": "여기서 캐릭터의 관계를 시각화하려면 캐릭터 보기에 캐릭터를 추가하세요.",
@@ -286,6 +291,8 @@
"error.db.unknown": "데이터베이스에 액세스하는 동안 알 수 없는 오류가 발생했습니다.",
"error.deepLink.title": "프로젝트 파일을 열지 못했습니다.",
"error.deepLink.unknown": "알 수 없는 오류",
+ "error.fallback.generic": "AI is unavailable — used built-in assistance.",
+ "error.fallback.offline": "You're offline — used built-in assistance.",
"error.fileImportError": "파일 가져오기 오류",
"error.mic.denied": "마이크 액세스가 거부되었습니다. 브라우저 설정에서 권한을 부여해주세요.",
"error.mic.generic": "음성 인식 오류: {{error}}",
@@ -382,6 +389,16 @@
"palette.voice.listeningLive": "음성 입력이 활성화되었습니다.",
"palette.voice.start": "음성 검색 시작",
"palette.voice.stop": "음성 검색 중지",
+ "plotBoard.heuristic.complicate.description": "Add an obstacle or reveal that forces a change of plan.",
+ "plotBoard.heuristic.complicate.rationale": "A fresh complication tests the characters and opens new threads.",
+ "plotBoard.heuristic.complicate.title": "Introduce a complication",
+ "plotBoard.heuristic.escalate.description": "Increase the pressure on your protagonist so the next choice costs more.",
+ "plotBoard.heuristic.escalate.rationale": "Escalation keeps momentum when the middle sags.",
+ "plotBoard.heuristic.escalate.title": "Raise the stakes",
+ "plotBoard.heuristic.position": "Right after the selected scene",
+ "plotBoard.heuristic.reverse.description": "Flip an expectation — an ally falters, a win turns sour, or a hidden truth surfaces.",
+ "plotBoard.heuristic.reverse.rationale": "Reversals refresh tension and deepen the arc.",
+ "plotBoard.heuristic.reverse.title": "Add a reversal",
"preview.controls.ariaLabel": "미리보기 컨트롤",
"preview.controls.decreaseFontSize": "글꼴 크기 줄이기",
"preview.controls.exitFullscreen": "전체 화면 종료",
@@ -449,10 +466,6 @@
"proforge.progress.awaitingReviewHint": "⚠️ 이 단계는 귀하의 검토를 기다리고 있습니다. 항목을 검토하려면 위의 단계 버튼을 클릭하세요.",
"proforge.progress.completedStages": "완료된 단계",
"proforge.progress.currentStatus": "현황",
- "proforge.progress.overall": "Overall progress",
- "proforge.progress.preparing": "Preparing…",
- "proforge.progress.stageOfTotal": "Stage {{current}} of {{total}}",
- "proforge.progress.percentComplete": "{{percent}}% complete",
"proforge.progress.itemsCount": "{{count}} 항목",
"proforge.progress.metric.aiCalls": "AI 호출",
"proforge.progress.metric.duration": "지속",
@@ -463,7 +476,11 @@
"proforge.progress.metric.totalTime": "총 시간",
"proforge.progress.metric.totalTokens": "총 토큰",
"proforge.progress.noneRunning": "실행 중인 파이프라인이 없습니다.",
+ "proforge.progress.overall": "Overall progress",
+ "proforge.progress.percentComplete": "{{percent}}% complete",
+ "proforge.progress.preparing": "Preparing…",
"proforge.progress.stageDetails": "스테이지 세부정보: {{stage}}",
+ "proforge.progress.stageOfTotal": "Stage {{current}} of {{total}}",
"proforge.progress.statusLabel": "상태",
"proforge.progress.totals": "파이프라인 합계",
"proforge.review.accept": "수용하다",
@@ -777,9 +794,9 @@
"vc.title": "버전 기록",
"vc.words": "단어",
"voice.cancelSpeech": "음성 취소",
+ "voice.feedback.confidence": "신뢰도 {{percent}}%",
"voice.modeChip.commands": "명령",
"voice.modeChip.dictation": "받아쓰기",
- "voice.feedback.confidence": "신뢰도 {{percent}}%",
"voice.panelLabel": "음성 제어",
"voice.permissionDenied": "마이크 액세스가 거부되었습니다. 음성 기능을 사용하려면 브라우저 설정에서 마이크 접근을 허용해주세요.",
"voice.startDictation": "받아쓰기 시작",
@@ -793,23 +810,6 @@
"voice.stopListening": "듣기 중지",
"worlds.emptyState.description": "당신의 이야기가 담긴 장소, 규칙, 역사를 만들어 보세요. 위치부터 시작하세요.",
"worlds.emptyState.title": "세계가 기다리고 있다",
- "error.fallback.generic": "AI is unavailable — used built-in assistance.",
- "error.fallback.offline": "You're offline — used built-in assistance.",
- "assisted.badge.label": "Assisted",
- "assisted.badge.srLabel": "Assisted mode — generated without AI",
- "assisted.toast.title": "AI unavailable",
- "assisted.toast.description": "Used built-in assistance. Enhance with AI when a model is available.",
- "assisted.enhance": "Enhance with AI",
- "plotBoard.heuristic.position": "Right after the selected scene",
- "plotBoard.heuristic.escalate.title": "Raise the stakes",
- "plotBoard.heuristic.escalate.description": "Increase the pressure on your protagonist so the next choice costs more.",
- "plotBoard.heuristic.escalate.rationale": "Escalation keeps momentum when the middle sags.",
- "plotBoard.heuristic.complicate.title": "Introduce a complication",
- "plotBoard.heuristic.complicate.description": "Add an obstacle or reveal that forces a change of plan.",
- "plotBoard.heuristic.complicate.rationale": "A fresh complication tests the characters and opens new threads.",
- "plotBoard.heuristic.reverse.title": "Add a reversal",
- "plotBoard.heuristic.reverse.description": "Flip an expectation — an ally falters, a win turns sour, or a hidden truth surfaces.",
- "plotBoard.heuristic.reverse.rationale": "Reversals refresh tension and deepen the arc.",
"copilot.annotationCount": "{{count}} 이 장에 대한 통찰력",
"copilot.announceClosed": "AI 부조종사 폐쇄",
"copilot.announceOpened": "AI 코파일럿 오픈",
@@ -1090,10 +1090,10 @@
"export.pasteSection.importAsChapter": "장으로 가져오기",
"export.pasteSection.textPlaceholder": "Google Docs 또는 Notion의 텍스트를 여기에 붙여넣습니다(Ctrl+V)...",
"export.pasteSection.titlePlaceholder": "장 제목(선택사항)",
- "export.preview.noContent": "미리보기를 보려면 콘텐츠를 선택하세요.",
"export.preview.modeLabel": "미리 보기 모드",
- "export.preview.modeText": "텍스트",
"export.preview.modeRendered": "렌더링됨",
+ "export.preview.modeText": "텍스트",
+ "export.preview.noContent": "미리보기를 보려면 콘텐츠를 선택하세요.",
"export.preview.title": "실시간 미리보기",
"export.title": "출판 제품군 내보내기",
"export.toggleSection": "{{title}}에 대한 공개 여부를 전환합니다.",
@@ -1519,6 +1519,23 @@
"outline.deleteConfirm": "이 개요 섹션을 삭제하시겠습니까?",
"outline.description": "스토리 아이디어를 설명하고 AI가 구조화되고 편집 가능한 개요를 생성하도록 하세요.",
"outline.error.generationFailed": "콘텐츠를 생성하지 못했습니다. 다시 시도해 주세요.",
+ "outline.heuristic.beat.climax.desc": "The central conflict comes to a head in the story's defining confrontation.",
+ "outline.heuristic.beat.climax.title": "Climax",
+ "outline.heuristic.beat.complications.desc": "Setbacks and conflicts deepen; the path forward narrows.",
+ "outline.heuristic.beat.complications.title": "Complications",
+ "outline.heuristic.beat.incitingIncident.desc": "The event that sets the story in motion: {{idea}}.",
+ "outline.heuristic.beat.incitingIncident.title": "Inciting Incident",
+ "outline.heuristic.beat.midpoint.desc": "A turning point shifts the direction of the story and raises the stakes.",
+ "outline.heuristic.beat.midpoint.title": "Midpoint",
+ "outline.heuristic.beat.resolution.desc": "Loose ends are tied up and a new status quo emerges.",
+ "outline.heuristic.beat.resolution.title": "Resolution",
+ "outline.heuristic.beat.risingAction.desc": "Complications escalate and the stakes grow as the characters pursue their goal.",
+ "outline.heuristic.beat.risingAction.title": "Rising Action",
+ "outline.heuristic.beat.setup.desc": "Introduce the world and the main characters, and establish the status quo before everything changes.",
+ "outline.heuristic.beat.setup.title": "Setup",
+ "outline.heuristic.beat.twist.desc": "An unexpected revelation upends what the characters believed to be true.",
+ "outline.heuristic.beat.twist.title": "Twist",
+ "outline.heuristic.fallbackIdea": "the central idea",
"outline.idea.generateButton": "개요 생성",
"outline.idea.genreLabel": "장르",
"outline.idea.genrePlaceholder": "예: 공상과학, 판타지, 미스터리",
@@ -1541,23 +1558,6 @@
"outline.result.twistTooltip": "AI가 생성한 플롯 트위스트",
"outline.selectSection": "섹션 '{{title}}' 선택",
"outline.title": "AI 스토리 개요 생성기",
- "outline.heuristic.fallbackIdea": "the central idea",
- "outline.heuristic.beat.setup.title": "Setup",
- "outline.heuristic.beat.setup.desc": "Introduce the world and the main characters, and establish the status quo before everything changes.",
- "outline.heuristic.beat.incitingIncident.title": "Inciting Incident",
- "outline.heuristic.beat.incitingIncident.desc": "The event that sets the story in motion: {{idea}}.",
- "outline.heuristic.beat.risingAction.title": "Rising Action",
- "outline.heuristic.beat.risingAction.desc": "Complications escalate and the stakes grow as the characters pursue their goal.",
- "outline.heuristic.beat.midpoint.title": "Midpoint",
- "outline.heuristic.beat.midpoint.desc": "A turning point shifts the direction of the story and raises the stakes.",
- "outline.heuristic.beat.complications.title": "Complications",
- "outline.heuristic.beat.complications.desc": "Setbacks and conflicts deepen; the path forward narrows.",
- "outline.heuristic.beat.twist.title": "Twist",
- "outline.heuristic.beat.twist.desc": "An unexpected revelation upends what the characters believed to be true.",
- "outline.heuristic.beat.climax.title": "Climax",
- "outline.heuristic.beat.climax.desc": "The central conflict comes to a head in the story's defining confrontation.",
- "outline.heuristic.beat.resolution.title": "Resolution",
- "outline.heuristic.beat.resolution.desc": "Loose ends are tied up and a new status quo emerges.",
"portal.back": "뒤로",
"portal.demo.chapterContent": "Lyra가 오래된 도시 지도를 펼치는 동안 아침 안개가 부두에 달라붙었습니다. 북서쪽 모퉁이에는 희미한 원이 표시되어 있었는데, 아무도 언급하지 않은 탑이었습니다.\n\n그녀는 종이를 집어넣고 철 격자가 그녀 앞에 올라올 때까지 좁은 길을 따라갔습니다. 자물쇠는 햇볕에 따뜻했습니다. 금속은 아직 차갑다.",
"portal.demo.chapterTitle": "1장 - 문 앞",
@@ -1752,6 +1752,7 @@
"settings.ai.gpu.troubleshootLowEnd": "귀하의 장치에는 리소스가 제한되어 있습니다. 로컬 AI는 더 작은 모델을 사용합니다. 성능을 향상하려면 다른 브라우저 탭을 닫거나 에코 모드를 활성화하세요.",
"settings.ai.gpu.troubleshootQueue": "여러 AI 작업이 대기열에 추가됩니다. VRAM 충돌을 피하기 위해 한 번에 하나만 실행됩니다. 현재 작업이 완료될 때까지 기다립니다.",
"settings.ai.gpu.waitingConsumers": "대기 중",
+ "settings.ai.grokKey": "Grok API Key",
"settings.ai.hybridFallbackHint": "기본 공급자가 실패하면 WorldScript는 나열된 폴백(장면 생성기, 코덱스 도구)을 시도합니다. 작성자 스트리밍은 기본 공급자만 사용합니다.",
"settings.ai.hybridFallbackTitle": "하이브리드 폴백(프로젝트 AI 도구)",
"settings.ai.hybridFallbackToggle": "대체 체인 활성화",
@@ -1832,6 +1833,11 @@
"settings.ai.preset.lmStudio": "LM 스튜디오",
"settings.ai.preset.ollamaDefault": "올라마(기본 포트)",
"settings.ai.preset.vllm": "vLLM",
+ "settings.ai.provider.anthropic": "Anthropic Claude",
+ "settings.ai.provider.gemini": "Google Gemini",
+ "settings.ai.provider.grok": "xAI Grok",
+ "settings.ai.provider.ollama": "Ollama (local)",
+ "settings.ai.provider.openai": "OpenAI",
"settings.ai.providerDescription": "WorldScript Studio가 사용해야 할 AI 제공자를 선택하세요.",
"settings.ai.providerOnnx": "ONNX(WASM)",
"settings.ai.providerStatusConnected": "연결됨",
@@ -2711,6 +2717,11 @@
"worlds.edit.notes": "메모",
"worlds.editorTabsAriaLabel": "월드 에디터 탭",
"worlds.error.imageFailed": "분위기 이미지 생성에 실패했습니다. 세계 설명에 더 자세한 내용을 추가하거나 연결을 확인해보세요.",
+ "worlds.heuristic.culture": "Describe the peoples, beliefs, and daily life shaped by {{concept}}.",
+ "worlds.heuristic.description": "A world defined by its central premise: {{concept}}.",
+ "worlds.heuristic.geography": "Outline the major regions, climates, and natural features of {{concept}}.",
+ "worlds.heuristic.magicSystem": "Define the rules, costs, and limits of power in {{concept}}.",
+ "worlds.heuristic.name": "New World",
"worlds.loading.profile": "자세한 세계 프로필을 생성하는 중...",
"worlds.newWorldName": "새로운 세계",
"worlds.noWorlds": "아직 생성된 세계가 없습니다.",
@@ -2729,11 +2740,6 @@
"worlds.title": "월드 아틀라스",
"worlds.uploadImage": "이미지 업로드",
"worlds.yourWorlds": "당신의 세계",
- "worlds.heuristic.name": "New World",
- "worlds.heuristic.description": "A world defined by its central premise: {{concept}}.",
- "worlds.heuristic.geography": "Outline the major regions, climates, and natural features of {{concept}}.",
- "worlds.heuristic.magicSystem": "Define the rules, costs, and limits of power in {{concept}}.",
- "worlds.heuristic.culture": "Describe the peoples, beliefs, and daily life shaped by {{concept}}.",
"writer.cancelledTag": "취소",
"writer.chapter.label": "장: {{title}}",
"writer.coachmark.dismiss": "알았어요",
@@ -2755,6 +2761,20 @@
"writer.focusMode.enterLabel": "초점 모드",
"writer.focusMode.exit": "집중 모드 종료",
"writer.focusMode.exitLabel": "포커스 종료",
+ "writer.grammar.addToDictionary": "Add to dictionary",
+ "writer.grammar.apply": "Apply",
+ "writer.grammar.checkButton": "Check this scene",
+ "writer.grammar.checking": "Checking…",
+ "writer.grammar.disabled": "Enable LanguageTool in Settings → Connections to check this scene.",
+ "writer.grammar.error": "The LanguageTool server returned an error.",
+ "writer.grammar.ignore": "Ignore",
+ "writer.grammar.issuesFound": "{{count}} issues found",
+ "writer.grammar.noIssues": "No issues found.",
+ "writer.grammar.noSuggestions": "No suggestions",
+ "writer.grammar.offline": "Couldn't reach the LanguageTool server. Is it running?",
+ "writer.grammar.selectScene": "Select a scene to check.",
+ "writer.grammar.title": "Grammar & Spelling",
+ "writer.grammar.unsupported": "Grammar check isn't available for this language.",
"writer.imagePrompt.description": "현재 장면이나 텍스트 선택에서 최적화된 DALL·E 3 / Midjourney 프롬프트를 생성합니다.",
"writer.imagePrompt.note": "생성된 프롬프트는 DALL·E 3 및 Midjourney에서 직접 작동합니다.",
"writer.imagePrompt.tip": "팁: 초점이 맞춰진 장면 프롬프트에 대한 특정 텍스트 섹션을 선택하세요.",
@@ -2787,12 +2807,10 @@
"writer.studio.controls.tones.poetic": "더 시적인",
"writer.studio.controls.tones.suspenseful": "더욱 긴장감 넘치는",
"writer.studio.description": "당신의 AI 공동저자. 전체 프로젝트 컨텍스트를 바탕으로 생성, 개선 및 브레인스토밍하세요.",
+ "writer.studio.rag.chunkScore": "관련도 {{score}}",
"writer.studio.rag.chunksBadge": "{{count}} 스토리 구절 발견됨",
"writer.studio.rag.chunksHint": "원고에서 관련 발췌 - 구절이 많을수록 AI 컨텍스트가 풍부해집니다.",
"writer.studio.rag.inspectorLabel": "검색된 컨텍스트",
- "writer.studio.rag.chunkScore": "관련도 {{score}}",
- "writer.studio.tokens.badge": "~{{count}} 토큰",
- "writer.studio.tokens.hint": "마지막 AI 요청에 사용된 대략적인 토큰 수",
"writer.studio.rag.useContext": "내 이야기에서 끌어와",
"writer.studio.result.insert": "끼워 넣다",
"writer.studio.result.next": "다음",
@@ -2802,6 +2820,8 @@
"writer.studio.result.retry": "다시 해 보다",
"writer.studio.result.title": "AI 스크래치패드",
"writer.studio.title": "AI 글쓰기 스튜디오",
+ "writer.studio.tokens.badge": "~{{count}} 토큰",
+ "writer.studio.tokens.hint": "마지막 AI 요청에 사용된 대략적인 토큰 수",
"writer.studio.tools.brainstorm.contextLabel": "브레인스토밍 컨텍스트(선택 사항)",
"writer.studio.tools.brainstorm.contextPlaceholder": "간단한 상황을 제공하지 않으면 AI가 현재 원고 섹션을 사용합니다.",
"writer.studio.tools.brainstorm.title": "아이디어 브레인스토밍",
@@ -2833,19 +2853,5 @@
"writer.tts.start": "소리내어 읽기",
"writer.tts.stop": "읽기 중지",
"writer.versionControl.label": "버전",
- "writer.versionControl.tooltip": "버전 관리(브랜치 및 스냅샷)",
- "writer.grammar.title": "Grammar & Spelling",
- "writer.grammar.checkButton": "Check this scene",
- "writer.grammar.checking": "Checking…",
- "writer.grammar.issuesFound": "{{count}} issues found",
- "writer.grammar.noIssues": "No issues found.",
- "writer.grammar.selectScene": "Select a scene to check.",
- "writer.grammar.unsupported": "Grammar check isn't available for this language.",
- "writer.grammar.disabled": "Enable LanguageTool in Settings → Connections to check this scene.",
- "writer.grammar.offline": "Couldn't reach the LanguageTool server. Is it running?",
- "writer.grammar.error": "The LanguageTool server returned an error.",
- "writer.grammar.apply": "Apply",
- "writer.grammar.ignore": "Ignore",
- "writer.grammar.addToDictionary": "Add to dictionary",
- "writer.grammar.noSuggestions": "No suggestions"
+ "writer.versionControl.tooltip": "버전 관리(브랜치 및 스냅샷)"
}
diff --git a/public/locales/pt/bundle.json b/public/locales/pt/bundle.json
index 215efa72..7741249f 100644
--- a/public/locales/pt/bundle.json
+++ b/public/locales/pt/bundle.json
@@ -90,6 +90,14 @@
"characters.edit.relationships": "Relacionamentos",
"characters.editorTabsAriaLabel": "Personagem editor tabs",
"characters.error.portraitFailed": "Falha na geração do retrato. Tente adicionar mais detalhes à descrição da aparência.",
+ "characters.heuristic.appearance": "Describe how they present themselves — let their look hint at {{concept}}.",
+ "characters.heuristic.backstory": "Shaped by formative experiences, this character carries a past tied to {{concept}}.",
+ "characters.heuristic.characterArc": "They begin guarded and, through the story, are changed by {{concept}}.",
+ "characters.heuristic.flaws": "A weakness that complicates their goals.",
+ "characters.heuristic.motivation": "A core desire connected to {{concept}} drives their choices.",
+ "characters.heuristic.name": "New Character",
+ "characters.heuristic.personalityTraits": "Resourceful, guarded, determined.",
+ "characters.heuristic.relationships": "Note the key bonds and rivalries that define them.",
"characters.loading.profile": "Gerando perfil detalhado...",
"characters.newCharacterName": "New Personagem",
"characters.noCharacters": "Nenhum personagem criado ainda.",
@@ -107,14 +115,6 @@
"characters.title": "Personagem Dossiers",
"characters.uploadImage": "Carregar imagem",
"characters.yourCharacters": "Seus personagens",
- "characters.heuristic.name": "New Character",
- "characters.heuristic.backstory": "Shaped by formative experiences, this character carries a past tied to {{concept}}.",
- "characters.heuristic.motivation": "A core desire connected to {{concept}} drives their choices.",
- "characters.heuristic.appearance": "Describe how they present themselves — let their look hint at {{concept}}.",
- "characters.heuristic.personalityTraits": "Resourceful, guarded, determined.",
- "characters.heuristic.flaws": "A weakness that complicates their goals.",
- "characters.heuristic.characterArc": "They begin guarded and, through the story, are changed by {{concept}}.",
- "characters.heuristic.relationships": "Note the key bonds and rivalries that define them.",
"apiKey.connectionFailed": "O teste de conexão falhou.",
"apiKey.connectionSuccess": "Conexão bem-sucedida! API responde corretamente.",
"apiKey.decryptFailed": "A chave de API não pôde ser descriptografada",
@@ -125,6 +125,11 @@
"apiKey.test": "Conexão de teste",
"apiKey.testConnection": "Testar conexão API",
"apiKey.testing": "Testando…",
+ "assisted.badge.label": "Assisted",
+ "assisted.badge.srLabel": "Assisted mode — generated without AI",
+ "assisted.enhance": "Enhance with AI",
+ "assisted.toast.description": "Used built-in assistance. Enhance with AI when a model is available.",
+ "assisted.toast.title": "AI unavailable",
"charGraph.characters": "Personagens",
"charGraph.noCharacters": "Nenhum personagem ainda",
"charGraph.noCharactersHint": "Adicionar characters in the Characters view to visualize their relationships here.",
@@ -286,6 +291,8 @@
"error.db.unknown": "Erro desconhecido ao acessar o banco de dados.",
"error.deepLink.title": "Falha ao abrir o arquivo do projeto",
"error.deepLink.unknown": "Erro desconhecido",
+ "error.fallback.generic": "AI is unavailable — used built-in assistance.",
+ "error.fallback.offline": "You're offline — used built-in assistance.",
"error.fileImportError": "Erro de importação de arquivo",
"error.mic.denied": "Acesso ao microfone negado. Por favor, conceda permissão nas configurações do seu navegador.",
"error.mic.generic": "Erro de reconhecimento de fala: {{error}}",
@@ -382,6 +389,16 @@
"palette.voice.listeningLive": "A entrada de voz está ativa",
"palette.voice.start": "Iniciar pesquisa por voz",
"palette.voice.stop": "Interromper a pesquisa por voz",
+ "plotBoard.heuristic.complicate.description": "Add an obstacle or reveal that forces a change of plan.",
+ "plotBoard.heuristic.complicate.rationale": "A fresh complication tests the characters and opens new threads.",
+ "plotBoard.heuristic.complicate.title": "Introduce a complication",
+ "plotBoard.heuristic.escalate.description": "Increase the pressure on your protagonist so the next choice costs more.",
+ "plotBoard.heuristic.escalate.rationale": "Escalation keeps momentum when the middle sags.",
+ "plotBoard.heuristic.escalate.title": "Raise the stakes",
+ "plotBoard.heuristic.position": "Right after the selected scene",
+ "plotBoard.heuristic.reverse.description": "Flip an expectation — an ally falters, a win turns sour, or a hidden truth surfaces.",
+ "plotBoard.heuristic.reverse.rationale": "Reversals refresh tension and deepen the arc.",
+ "plotBoard.heuristic.reverse.title": "Add a reversal",
"preview.controls.ariaLabel": "Controles de visualização",
"preview.controls.decreaseFontSize": "Diminuir o tamanho da fonte",
"preview.controls.exitFullscreen": "Sair da tela cheia",
@@ -449,10 +466,6 @@
"proforge.progress.awaitingReviewHint": "⚠️ Esta etapa aguarda sua análise. Clique no botão de estágio acima para revisar os itens.",
"proforge.progress.completedStages": "Etapas concluídas",
"proforge.progress.currentStatus": "Status atual",
- "proforge.progress.overall": "Overall progress",
- "proforge.progress.preparing": "Preparing…",
- "proforge.progress.stageOfTotal": "Stage {{current}} of {{total}}",
- "proforge.progress.percentComplete": "{{percent}}% complete",
"proforge.progress.itemsCount": "{{count}} itens",
"proforge.progress.metric.aiCalls": "Chamadas de IA",
"proforge.progress.metric.duration": "Duração",
@@ -463,7 +476,11 @@
"proforge.progress.metric.totalTime": "Tempo total",
"proforge.progress.metric.totalTokens": "Total de fichas",
"proforge.progress.noneRunning": "Nenhum pipeline em execução.",
+ "proforge.progress.overall": "Overall progress",
+ "proforge.progress.percentComplete": "{{percent}}% complete",
+ "proforge.progress.preparing": "Preparing…",
"proforge.progress.stageDetails": "Detalhes do estágio: {{stage}}",
+ "proforge.progress.stageOfTotal": "Stage {{current}} of {{total}}",
"proforge.progress.statusLabel": "Status",
"proforge.progress.totals": "Totais do pipeline",
"proforge.review.accept": "Aceitar",
@@ -777,9 +794,9 @@
"vc.title": "Histórico de versões",
"vc.words": "palavras",
"voice.cancelSpeech": "Cancelar speech",
+ "voice.feedback.confidence": "Confiança {{percent}}%",
"voice.modeChip.commands": "Comandos",
"voice.modeChip.dictation": "Ditado",
- "voice.feedback.confidence": "Confiança {{percent}}%",
"voice.panelLabel": "Controle de voz",
"voice.permissionDenied": "Acesso ao microfone negado. Permita o acesso ao microfone nas configurações do seu navegador para usar os recursos de voz.",
"voice.startDictation": "Iniciar ditado",
@@ -793,23 +810,6 @@
"voice.stopListening": "Pare de ouvir",
"worlds.emptyState.description": "Construa os lugares, regras e histórias em que sua história vive. Comece com um local.",
"worlds.emptyState.title": "O mundo espera",
- "error.fallback.generic": "AI is unavailable — used built-in assistance.",
- "error.fallback.offline": "You're offline — used built-in assistance.",
- "assisted.badge.label": "Assisted",
- "assisted.badge.srLabel": "Assisted mode — generated without AI",
- "assisted.toast.title": "AI unavailable",
- "assisted.toast.description": "Used built-in assistance. Enhance with AI when a model is available.",
- "assisted.enhance": "Enhance with AI",
- "plotBoard.heuristic.position": "Right after the selected scene",
- "plotBoard.heuristic.escalate.title": "Raise the stakes",
- "plotBoard.heuristic.escalate.description": "Increase the pressure on your protagonist so the next choice costs more.",
- "plotBoard.heuristic.escalate.rationale": "Escalation keeps momentum when the middle sags.",
- "plotBoard.heuristic.complicate.title": "Introduce a complication",
- "plotBoard.heuristic.complicate.description": "Add an obstacle or reveal that forces a change of plan.",
- "plotBoard.heuristic.complicate.rationale": "A fresh complication tests the characters and opens new threads.",
- "plotBoard.heuristic.reverse.title": "Add a reversal",
- "plotBoard.heuristic.reverse.description": "Flip an expectation — an ally falters, a win turns sour, or a hidden truth surfaces.",
- "plotBoard.heuristic.reverse.rationale": "Reversals refresh tension and deepen the arc.",
"copilot.annotationCount": "{{count}} visão para este capítulo",
"copilot.announceClosed": "Copiloto AI fechado",
"copilot.announceOpened": "Copiloto AI aberto",
@@ -1090,10 +1090,10 @@
"export.pasteSection.importAsChapter": "Importar como capítulo",
"export.pasteSection.textPlaceholder": "Cole o texto do Google Docs ou Notion aqui (Ctrl+V)...",
"export.pasteSection.titlePlaceholder": "Título do capítulo (opcional)",
- "export.preview.noContent": "Selecione o conteúdo para ver uma prévia.",
"export.preview.modeLabel": "Modo de pré-visualização",
- "export.preview.modeText": "Texto",
"export.preview.modeRendered": "Renderizado",
+ "export.preview.modeText": "Texto",
+ "export.preview.noContent": "Selecione o conteúdo para ver uma prévia.",
"export.preview.title": "Visualização ao vivo",
"export.title": "Exportar Publishing Suite",
"export.toggleSection": "Alternar visibilidade para {{title}}",
@@ -1519,6 +1519,23 @@
"outline.deleteConfirm": "Tem certeza de que deseja excluir esta seção do esboço?",
"outline.description": "Describe your story idea and let IA create a structured, editable outline for you.",
"outline.error.generationFailed": "Falha ao gerar conteúdo. Por favor, tente novamente.",
+ "outline.heuristic.beat.climax.desc": "The central conflict comes to a head in the story's defining confrontation.",
+ "outline.heuristic.beat.climax.title": "Climax",
+ "outline.heuristic.beat.complications.desc": "Setbacks and conflicts deepen; the path forward narrows.",
+ "outline.heuristic.beat.complications.title": "Complications",
+ "outline.heuristic.beat.incitingIncident.desc": "The event that sets the story in motion: {{idea}}.",
+ "outline.heuristic.beat.incitingIncident.title": "Inciting Incident",
+ "outline.heuristic.beat.midpoint.desc": "A turning point shifts the direction of the story and raises the stakes.",
+ "outline.heuristic.beat.midpoint.title": "Midpoint",
+ "outline.heuristic.beat.resolution.desc": "Loose ends are tied up and a new status quo emerges.",
+ "outline.heuristic.beat.resolution.title": "Resolution",
+ "outline.heuristic.beat.risingAction.desc": "Complications escalate and the stakes grow as the characters pursue their goal.",
+ "outline.heuristic.beat.risingAction.title": "Rising Action",
+ "outline.heuristic.beat.setup.desc": "Introduce the world and the main characters, and establish the status quo before everything changes.",
+ "outline.heuristic.beat.setup.title": "Setup",
+ "outline.heuristic.beat.twist.desc": "An unexpected revelation upends what the characters believed to be true.",
+ "outline.heuristic.beat.twist.title": "Twist",
+ "outline.heuristic.fallbackIdea": "the central idea",
"outline.idea.generateButton": "Gerar Esboço",
"outline.idea.genreLabel": "Gênero",
"outline.idea.genrePlaceholder": "por exemplo, ficção científica, fantasia, mistério",
@@ -1541,23 +1558,6 @@
"outline.result.twistTooltip": "IA-Generated Plot Twist",
"outline.selectSection": "Selecione a seção '{{title}}'",
"outline.title": "IA Story Esboço Generator",
- "outline.heuristic.fallbackIdea": "the central idea",
- "outline.heuristic.beat.setup.title": "Setup",
- "outline.heuristic.beat.setup.desc": "Introduce the world and the main characters, and establish the status quo before everything changes.",
- "outline.heuristic.beat.incitingIncident.title": "Inciting Incident",
- "outline.heuristic.beat.incitingIncident.desc": "The event that sets the story in motion: {{idea}}.",
- "outline.heuristic.beat.risingAction.title": "Rising Action",
- "outline.heuristic.beat.risingAction.desc": "Complications escalate and the stakes grow as the characters pursue their goal.",
- "outline.heuristic.beat.midpoint.title": "Midpoint",
- "outline.heuristic.beat.midpoint.desc": "A turning point shifts the direction of the story and raises the stakes.",
- "outline.heuristic.beat.complications.title": "Complications",
- "outline.heuristic.beat.complications.desc": "Setbacks and conflicts deepen; the path forward narrows.",
- "outline.heuristic.beat.twist.title": "Twist",
- "outline.heuristic.beat.twist.desc": "An unexpected revelation upends what the characters believed to be true.",
- "outline.heuristic.beat.climax.title": "Climax",
- "outline.heuristic.beat.climax.desc": "The central conflict comes to a head in the story's defining confrontation.",
- "outline.heuristic.beat.resolution.title": "Resolution",
- "outline.heuristic.beat.resolution.desc": "Loose ends are tied up and a new status quo emerges.",
"portal.back": "Voltar",
"portal.demo.chapterContent": "A névoa matinal cobria o cais enquanto Lyra desenrolava o antigo mapa da cidade. Um círculo tênue marcava o canto noroeste – a torre que ninguém mencionou.\n\nEla guardou o papel e seguiu pelo caminho estreito até que a grade de ferro se ergueu diante dela. O cadeado estava quente ao sol; o metal ainda frio.",
"portal.demo.chapterTitle": "Capítulo 1 - Antes do Portão",
@@ -1752,6 +1752,7 @@
"settings.ai.gpu.troubleshootLowEnd": "Your device has limited resources. Local IA will use smaller models. For better performance, close other browser tabs or enable Eco Mode.",
"settings.ai.gpu.troubleshootQueue": "Multiple IA tasks are queued. Only one runs at a time to avoid VRAM collisions. Wait for the current task to finish.",
"settings.ai.gpu.waitingConsumers": "Esperando",
+ "settings.ai.grokKey": "Grok API Key",
"settings.ai.hybridFallbackHint": "Se o provedor primário falhar, o WorldScript tenta os substitutos listados (geradores de cena, ferramentas de códice). O streaming do gravador usa apenas seu provedor principal.",
"settings.ai.hybridFallbackTitle": "Hybrid fallback (project IA tools)",
"settings.ai.hybridFallbackToggle": "Ativar cadeia de fallback",
@@ -1832,6 +1833,11 @@
"settings.ai.preset.lmStudio": "Estúdio LM",
"settings.ai.preset.ollamaDefault": "Ollama (porta padrão)",
"settings.ai.preset.vllm": "vLLM",
+ "settings.ai.provider.anthropic": "Anthropic Claude",
+ "settings.ai.provider.gemini": "Google Gemini",
+ "settings.ai.provider.grok": "xAI Grok",
+ "settings.ai.provider.ollama": "Ollama (local)",
+ "settings.ai.provider.openai": "OpenAI",
"settings.ai.providerDescription": "Choose which IA provider WorldScript Studio should use.",
"settings.ai.providerOnnx": "ONNX (WASM)",
"settings.ai.providerStatusConnected": "Conectado",
@@ -2711,6 +2717,11 @@
"worlds.edit.notes": "Notas",
"worlds.editorTabsAriaLabel": "Mundo editor tabs",
"worlds.error.imageFailed": "Falha na geração da imagem do ambiente. Por favor, tente adicionar mais detalhes à descrição do mundo ou verifique sua conexão.",
+ "worlds.heuristic.culture": "Describe the peoples, beliefs, and daily life shaped by {{concept}}.",
+ "worlds.heuristic.description": "A world defined by its central premise: {{concept}}.",
+ "worlds.heuristic.geography": "Outline the major regions, climates, and natural features of {{concept}}.",
+ "worlds.heuristic.magicSystem": "Define the rules, costs, and limits of power in {{concept}}.",
+ "worlds.heuristic.name": "New World",
"worlds.loading.profile": "Gerando perfil mundial detalhado...",
"worlds.newWorldName": "New Mundo",
"worlds.noWorlds": "Nenhum mundo criado ainda.",
@@ -2729,11 +2740,6 @@
"worlds.title": "Mundo Atlas",
"worlds.uploadImage": "Carregar imagem",
"worlds.yourWorlds": "Seus mundos",
- "worlds.heuristic.name": "New World",
- "worlds.heuristic.description": "A world defined by its central premise: {{concept}}.",
- "worlds.heuristic.geography": "Outline the major regions, climates, and natural features of {{concept}}.",
- "worlds.heuristic.magicSystem": "Define the rules, costs, and limits of power in {{concept}}.",
- "worlds.heuristic.culture": "Describe the peoples, beliefs, and daily life shaped by {{concept}}.",
"writer.cancelledTag": "Cancelado",
"writer.chapter.label": "Capítulo: {{title}}",
"writer.coachmark.dismiss": "Got it",
@@ -2755,6 +2761,20 @@
"writer.focusMode.enterLabel": "Modo de foco",
"writer.focusMode.exit": "Sair do modo de foco",
"writer.focusMode.exitLabel": "Sair do foco",
+ "writer.grammar.addToDictionary": "Add to dictionary",
+ "writer.grammar.apply": "Apply",
+ "writer.grammar.checkButton": "Check this scene",
+ "writer.grammar.checking": "Checking…",
+ "writer.grammar.disabled": "Enable LanguageTool in Settings → Connections to check this scene.",
+ "writer.grammar.error": "The LanguageTool server returned an error.",
+ "writer.grammar.ignore": "Ignore",
+ "writer.grammar.issuesFound": "{{count}} issues found",
+ "writer.grammar.noIssues": "No issues found.",
+ "writer.grammar.noSuggestions": "No suggestions",
+ "writer.grammar.offline": "Couldn't reach the LanguageTool server. Is it running?",
+ "writer.grammar.selectScene": "Select a scene to check.",
+ "writer.grammar.title": "Grammar & Spelling",
+ "writer.grammar.unsupported": "Grammar check isn't available for this language.",
"writer.imagePrompt.description": "Gera um prompt DALL·E 3 / Midjourney otimizado a partir da cena atual ou seleção de texto.",
"writer.imagePrompt.note": "O prompt gerado funciona diretamente no DALL·E 3 e Midjourney.",
"writer.imagePrompt.tip": "Dica: Selecione uma seção de texto específica para um prompt de cena em foco.",
@@ -2787,12 +2807,10 @@
"writer.studio.controls.tones.poetic": "Mais Poético",
"writer.studio.controls.tones.suspenseful": "Mais suspense",
"writer.studio.description": "Your IA co-author. Gerar, improve, and brainstorm with full project context.",
+ "writer.studio.rag.chunkScore": "relevância {{score}}",
"writer.studio.rag.chunksBadge": "{{count}} passagens da história encontradas",
"writer.studio.rag.chunksHint": "Relevant excerpts from your manuscript — more passages means richer IA context",
"writer.studio.rag.inspectorLabel": "Contexto recuperado",
- "writer.studio.rag.chunkScore": "relevância {{score}}",
- "writer.studio.tokens.badge": "~{{count}} tokens",
- "writer.studio.tokens.hint": "Tokens aproximados usados na sua última solicitação de IA",
"writer.studio.rag.useContext": "Retire da minha história",
"writer.studio.result.insert": "Inserir",
"writer.studio.result.next": "Próximo",
@@ -2802,6 +2820,8 @@
"writer.studio.result.retry": "Tentar novamente",
"writer.studio.result.title": "IA Scratchpad",
"writer.studio.title": "IA Writing Studio",
+ "writer.studio.tokens.badge": "~{{count}} tokens",
+ "writer.studio.tokens.hint": "Tokens aproximados usados na sua última solicitação de IA",
"writer.studio.tools.brainstorm.contextLabel": "Contexto de brainstorming (opcional)",
"writer.studio.tools.brainstorm.contextPlaceholder": "Provide a brief situation, or the IA will use the current manuscript section.",
"writer.studio.tools.brainstorm.title": "Brainstorming de ideias",
@@ -2833,19 +2853,5 @@
"writer.tts.start": "Ler em voz alta",
"writer.tts.stop": "Pare de ler",
"writer.versionControl.label": "Versões",
- "writer.versionControl.tooltip": "Controle de versão (ramos e instantâneos)",
- "writer.grammar.title": "Grammar & Spelling",
- "writer.grammar.checkButton": "Check this scene",
- "writer.grammar.checking": "Checking…",
- "writer.grammar.issuesFound": "{{count}} issues found",
- "writer.grammar.noIssues": "No issues found.",
- "writer.grammar.selectScene": "Select a scene to check.",
- "writer.grammar.unsupported": "Grammar check isn't available for this language.",
- "writer.grammar.disabled": "Enable LanguageTool in Settings → Connections to check this scene.",
- "writer.grammar.offline": "Couldn't reach the LanguageTool server. Is it running?",
- "writer.grammar.error": "The LanguageTool server returned an error.",
- "writer.grammar.apply": "Apply",
- "writer.grammar.ignore": "Ignore",
- "writer.grammar.addToDictionary": "Add to dictionary",
- "writer.grammar.noSuggestions": "No suggestions"
+ "writer.versionControl.tooltip": "Controle de versão (ramos e instantâneos)"
}
diff --git a/public/locales/ru/bundle.json b/public/locales/ru/bundle.json
index 3a1a32ff..1ff99808 100644
--- a/public/locales/ru/bundle.json
+++ b/public/locales/ru/bundle.json
@@ -90,6 +90,14 @@
"characters.edit.relationships": "Отношения",
"characters.editorTabsAriaLabel": "Вкладки редактора персонажей",
"characters.error.portraitFailed": "Не удалось создать портрет. Попробуйте добавить больше деталей в описание внешности.",
+ "characters.heuristic.appearance": "Describe how they present themselves — let their look hint at {{concept}}.",
+ "characters.heuristic.backstory": "Shaped by formative experiences, this character carries a past tied to {{concept}}.",
+ "characters.heuristic.characterArc": "They begin guarded and, through the story, are changed by {{concept}}.",
+ "characters.heuristic.flaws": "A weakness that complicates their goals.",
+ "characters.heuristic.motivation": "A core desire connected to {{concept}} drives their choices.",
+ "characters.heuristic.name": "New Character",
+ "characters.heuristic.personalityTraits": "Resourceful, guarded, determined.",
+ "characters.heuristic.relationships": "Note the key bonds and rivalries that define them.",
"characters.loading.profile": "Создание подробного профиля...",
"characters.newCharacterName": "Новый персонаж",
"characters.noCharacters": "Персонажи еще не созданы.",
@@ -107,14 +115,6 @@
"characters.title": "Досье персонажей",
"characters.uploadImage": "Загрузить изображение",
"characters.yourCharacters": "Ваши персонажи",
- "characters.heuristic.name": "New Character",
- "characters.heuristic.backstory": "Shaped by formative experiences, this character carries a past tied to {{concept}}.",
- "characters.heuristic.motivation": "A core desire connected to {{concept}} drives their choices.",
- "characters.heuristic.appearance": "Describe how they present themselves — let their look hint at {{concept}}.",
- "characters.heuristic.personalityTraits": "Resourceful, guarded, determined.",
- "characters.heuristic.flaws": "A weakness that complicates their goals.",
- "characters.heuristic.characterArc": "They begin guarded and, through the story, are changed by {{concept}}.",
- "characters.heuristic.relationships": "Note the key bonds and rivalries that define them.",
"apiKey.connectionFailed": "Проверка соединения не удалась.",
"apiKey.connectionSuccess": "Подключение успешно! API отвечает правильно.",
"apiKey.decryptFailed": "Ключ API не удалось расшифровать",
@@ -125,6 +125,11 @@
"apiKey.test": "Тестовое соединение",
"apiKey.testConnection": "Проверить соединение API",
"apiKey.testing": "Тестирование…",
+ "assisted.badge.label": "Assisted",
+ "assisted.badge.srLabel": "Assisted mode — generated without AI",
+ "assisted.enhance": "Enhance with AI",
+ "assisted.toast.description": "Used built-in assistance. Enhance with AI when a model is available.",
+ "assisted.toast.title": "AI unavailable",
"charGraph.characters": "Персонажи",
"charGraph.noCharacters": "Персонажей пока нет",
"charGraph.noCharactersHint": "Добавьте персонажей в представление «Персонажи», чтобы визуализировать здесь их взаимоотношения.",
@@ -286,6 +291,8 @@
"error.db.unknown": "Неизвестная ошибка при доступе к базе данных.",
"error.deepLink.title": "Не удалось открыть файл проекта",
"error.deepLink.unknown": "Неизвестная ошибка",
+ "error.fallback.generic": "AI is unavailable — used built-in assistance.",
+ "error.fallback.offline": "You're offline — used built-in assistance.",
"error.fileImportError": "Ошибка импорта файла",
"error.mic.denied": "Доступ к микрофону запрещен. Пожалуйста, дайте разрешение в настройках вашего браузера.",
"error.mic.generic": "Ошибка распознавания речи: {{error}}",
@@ -382,6 +389,16 @@
"palette.voice.listeningLive": "Голосовой ввод активен",
"palette.voice.start": "Запустить голосовой поиск",
"palette.voice.stop": "Остановить голосовой поиск",
+ "plotBoard.heuristic.complicate.description": "Add an obstacle or reveal that forces a change of plan.",
+ "plotBoard.heuristic.complicate.rationale": "A fresh complication tests the characters and opens new threads.",
+ "plotBoard.heuristic.complicate.title": "Introduce a complication",
+ "plotBoard.heuristic.escalate.description": "Increase the pressure on your protagonist so the next choice costs more.",
+ "plotBoard.heuristic.escalate.rationale": "Escalation keeps momentum when the middle sags.",
+ "plotBoard.heuristic.escalate.title": "Raise the stakes",
+ "plotBoard.heuristic.position": "Right after the selected scene",
+ "plotBoard.heuristic.reverse.description": "Flip an expectation — an ally falters, a win turns sour, or a hidden truth surfaces.",
+ "plotBoard.heuristic.reverse.rationale": "Reversals refresh tension and deepen the arc.",
+ "plotBoard.heuristic.reverse.title": "Add a reversal",
"preview.controls.ariaLabel": "Предварительный просмотр элементов управления",
"preview.controls.decreaseFontSize": "Уменьшить размер шрифта",
"preview.controls.exitFullscreen": "Выйти из полноэкранного режима",
@@ -449,10 +466,6 @@
"proforge.progress.awaitingReviewHint": "⚠️Этот этап ожидает вашего рассмотрения. Нажмите кнопку этапа выше, чтобы просмотреть элементы.",
"proforge.progress.completedStages": "Завершенные этапы",
"proforge.progress.currentStatus": "Текущий статус",
- "proforge.progress.overall": "Overall progress",
- "proforge.progress.preparing": "Preparing…",
- "proforge.progress.stageOfTotal": "Stage {{current}} of {{total}}",
- "proforge.progress.percentComplete": "{{percent}}% complete",
"proforge.progress.itemsCount": "{{count}} предметов",
"proforge.progress.metric.aiCalls": "AI-вызовы",
"proforge.progress.metric.duration": "Продолжительность",
@@ -463,7 +476,11 @@
"proforge.progress.metric.totalTime": "Общее время",
"proforge.progress.metric.totalTokens": "Всего токенов",
"proforge.progress.noneRunning": "Ни один трубопровод не работает.",
+ "proforge.progress.overall": "Overall progress",
+ "proforge.progress.percentComplete": "{{percent}}% complete",
+ "proforge.progress.preparing": "Preparing…",
"proforge.progress.stageDetails": "Детали этапа: {{stage}}",
+ "proforge.progress.stageOfTotal": "Stage {{current}} of {{total}}",
"proforge.progress.statusLabel": "Статус",
"proforge.progress.totals": "Итоги трубопровода",
"proforge.review.accept": "Принимать",
@@ -777,9 +794,9 @@
"vc.title": "История версий",
"vc.words": "слова",
"voice.cancelSpeech": "Отменить речь",
+ "voice.feedback.confidence": "Уверенность {{percent}}%",
"voice.modeChip.commands": "Команды",
"voice.modeChip.dictation": "Диктант",
- "voice.feedback.confidence": "Уверенность {{percent}}%",
"voice.panelLabel": "Голосовое управление",
"voice.permissionDenied": "Доступ к микрофону запрещен. Разрешите доступ к микрофону в настройках браузера, чтобы использовать голосовые функции.",
"voice.startDictation": "Начать диктовку",
@@ -793,23 +810,6 @@
"voice.stopListening": "Хватит слушать",
"worlds.emptyState.description": "Создайте места, правила и историю, в которых живет ваша история. Начните с локации.",
"worlds.emptyState.title": "Мир ждет",
- "error.fallback.generic": "AI is unavailable — used built-in assistance.",
- "error.fallback.offline": "You're offline — used built-in assistance.",
- "assisted.badge.label": "Assisted",
- "assisted.badge.srLabel": "Assisted mode — generated without AI",
- "assisted.toast.title": "AI unavailable",
- "assisted.toast.description": "Used built-in assistance. Enhance with AI when a model is available.",
- "assisted.enhance": "Enhance with AI",
- "plotBoard.heuristic.position": "Right after the selected scene",
- "plotBoard.heuristic.escalate.title": "Raise the stakes",
- "plotBoard.heuristic.escalate.description": "Increase the pressure on your protagonist so the next choice costs more.",
- "plotBoard.heuristic.escalate.rationale": "Escalation keeps momentum when the middle sags.",
- "plotBoard.heuristic.complicate.title": "Introduce a complication",
- "plotBoard.heuristic.complicate.description": "Add an obstacle or reveal that forces a change of plan.",
- "plotBoard.heuristic.complicate.rationale": "A fresh complication tests the characters and opens new threads.",
- "plotBoard.heuristic.reverse.title": "Add a reversal",
- "plotBoard.heuristic.reverse.description": "Flip an expectation — an ally falters, a win turns sour, or a hidden truth surfaces.",
- "plotBoard.heuristic.reverse.rationale": "Reversals refresh tension and deepen the arc.",
"copilot.annotationCount": "{{count}} информация по этой главе",
"copilot.announceClosed": "AI второй пилот закрыт",
"copilot.announceOpened": "AI второй пилот открыт",
@@ -1090,10 +1090,10 @@
"export.pasteSection.importAsChapter": "Импортировать как главу",
"export.pasteSection.textPlaceholder": "Вставьте сюда текст из Google Docs или Notion (Ctrl+V)...",
"export.pasteSection.titlePlaceholder": "Название главы (необязательно)",
- "export.preview.noContent": "Выберите контент, чтобы просмотреть его.",
"export.preview.modeLabel": "Режим предпросмотра",
- "export.preview.modeText": "Текст",
"export.preview.modeRendered": "С разметкой",
+ "export.preview.modeText": "Текст",
+ "export.preview.noContent": "Выберите контент, чтобы просмотреть его.",
"export.preview.title": "Живой просмотр",
"export.title": "Экспортный издательский пакет",
"export.toggleSection": "Переключить видимость для {{title}}",
@@ -1519,6 +1519,23 @@
"outline.deleteConfirm": "Вы уверены, что хотите удалить этот раздел структуры?",
"outline.description": "Опишите идею своей истории, и пусть ИИ создаст для вас структурированный, редактируемый план.",
"outline.error.generationFailed": "Не удалось создать контент. Пожалуйста, попробуйте еще раз.",
+ "outline.heuristic.beat.climax.desc": "The central conflict comes to a head in the story's defining confrontation.",
+ "outline.heuristic.beat.climax.title": "Climax",
+ "outline.heuristic.beat.complications.desc": "Setbacks and conflicts deepen; the path forward narrows.",
+ "outline.heuristic.beat.complications.title": "Complications",
+ "outline.heuristic.beat.incitingIncident.desc": "The event that sets the story in motion: {{idea}}.",
+ "outline.heuristic.beat.incitingIncident.title": "Inciting Incident",
+ "outline.heuristic.beat.midpoint.desc": "A turning point shifts the direction of the story and raises the stakes.",
+ "outline.heuristic.beat.midpoint.title": "Midpoint",
+ "outline.heuristic.beat.resolution.desc": "Loose ends are tied up and a new status quo emerges.",
+ "outline.heuristic.beat.resolution.title": "Resolution",
+ "outline.heuristic.beat.risingAction.desc": "Complications escalate and the stakes grow as the characters pursue their goal.",
+ "outline.heuristic.beat.risingAction.title": "Rising Action",
+ "outline.heuristic.beat.setup.desc": "Introduce the world and the main characters, and establish the status quo before everything changes.",
+ "outline.heuristic.beat.setup.title": "Setup",
+ "outline.heuristic.beat.twist.desc": "An unexpected revelation upends what the characters believed to be true.",
+ "outline.heuristic.beat.twist.title": "Twist",
+ "outline.heuristic.fallbackIdea": "the central idea",
"outline.idea.generateButton": "Создать схему",
"outline.idea.genreLabel": "Жанр",
"outline.idea.genrePlaceholder": "например, научная фантастика, фэнтези, мистика",
@@ -1541,23 +1558,6 @@
"outline.result.twistTooltip": "Поворот сюжета, созданный искусственным интеллектом",
"outline.selectSection": "Выберите раздел '{{title}}'",
"outline.title": "Генератор контуров историй с использованием искусственного интеллекта",
- "outline.heuristic.fallbackIdea": "the central idea",
- "outline.heuristic.beat.setup.title": "Setup",
- "outline.heuristic.beat.setup.desc": "Introduce the world and the main characters, and establish the status quo before everything changes.",
- "outline.heuristic.beat.incitingIncident.title": "Inciting Incident",
- "outline.heuristic.beat.incitingIncident.desc": "The event that sets the story in motion: {{idea}}.",
- "outline.heuristic.beat.risingAction.title": "Rising Action",
- "outline.heuristic.beat.risingAction.desc": "Complications escalate and the stakes grow as the characters pursue their goal.",
- "outline.heuristic.beat.midpoint.title": "Midpoint",
- "outline.heuristic.beat.midpoint.desc": "A turning point shifts the direction of the story and raises the stakes.",
- "outline.heuristic.beat.complications.title": "Complications",
- "outline.heuristic.beat.complications.desc": "Setbacks and conflicts deepen; the path forward narrows.",
- "outline.heuristic.beat.twist.title": "Twist",
- "outline.heuristic.beat.twist.desc": "An unexpected revelation upends what the characters believed to be true.",
- "outline.heuristic.beat.climax.title": "Climax",
- "outline.heuristic.beat.climax.desc": "The central conflict comes to a head in the story's defining confrontation.",
- "outline.heuristic.beat.resolution.title": "Resolution",
- "outline.heuristic.beat.resolution.desc": "Loose ends are tied up and a new status quo emerges.",
"portal.back": "Назад",
"portal.demo.chapterContent": "Утренний туман окутал набережную, пока Лира разворачивала старую карту города. Слабый круг отмечал северо-западный угол — башню, о которой никто не упоминал.\n\nОна спрятала газету и пошла по узкой дорожке, пока перед ней не выросла железная решетка. Замок нагрелся на солнце; металл еще холодный.",
"portal.demo.chapterTitle": "Глава 1 — Перед воротами",
@@ -1752,6 +1752,7 @@
"settings.ai.gpu.troubleshootLowEnd": "Ваше устройство имеет ограниченные ресурсы. Местный ИИ будет использовать модели меньшего размера. Для повышения производительности закройте другие вкладки браузера или включите экономичный режим.",
"settings.ai.gpu.troubleshootQueue": "Несколько задач ИИ ставятся в очередь. Одновременно запускается только один, чтобы избежать коллизий VRAM. Дождитесь завершения текущей задачи.",
"settings.ai.gpu.waitingConsumers": "Ожидающий",
+ "settings.ai.grokKey": "Grok API Key",
"settings.ai.hybridFallbackHint": "Если основной поставщик дает сбой, WorldScript пробует использовать перечисленные резервные варианты (генераторы сцен, инструменты кодекса). Потоковая передача Writer использует только вашего основного провайдера.",
"settings.ai.hybridFallbackTitle": "Гибридный запасной вариант (инструменты искусственного интеллекта проекта)",
"settings.ai.hybridFallbackToggle": "Включить резервную цепочку",
@@ -1832,6 +1833,11 @@
"settings.ai.preset.lmStudio": "ЛМ Студия",
"settings.ai.preset.ollamaDefault": "Оллама (порт по умолчанию)",
"settings.ai.preset.vllm": "vLLM",
+ "settings.ai.provider.anthropic": "Anthropic Claude",
+ "settings.ai.provider.gemini": "Google Gemini",
+ "settings.ai.provider.grok": "xAI Grok",
+ "settings.ai.provider.ollama": "Ollama (local)",
+ "settings.ai.provider.openai": "OpenAI",
"settings.ai.providerDescription": "Выберите, какой поставщик искусственного интеллекта будет использовать WorldScript Studio.",
"settings.ai.providerOnnx": "ОННКС (ВАСМ)",
"settings.ai.providerStatusConnected": "Подключено",
@@ -2711,6 +2717,11 @@
"worlds.edit.notes": "Примечания",
"worlds.editorTabsAriaLabel": "Вкладки редактора мира",
"worlds.error.imageFailed": "Не удалось создать изображение атмосферы. Попробуйте добавить больше деталей в описание мира или проверьте подключение.",
+ "worlds.heuristic.culture": "Describe the peoples, beliefs, and daily life shaped by {{concept}}.",
+ "worlds.heuristic.description": "A world defined by its central premise: {{concept}}.",
+ "worlds.heuristic.geography": "Outline the major regions, climates, and natural features of {{concept}}.",
+ "worlds.heuristic.magicSystem": "Define the rules, costs, and limits of power in {{concept}}.",
+ "worlds.heuristic.name": "New World",
"worlds.loading.profile": "Создание подробного профиля мира...",
"worlds.newWorldName": "Новый Свет",
"worlds.noWorlds": "Миры еще не созданы.",
@@ -2729,11 +2740,6 @@
"worlds.title": "Мировой Атлас",
"worlds.uploadImage": "Загрузить изображение",
"worlds.yourWorlds": "Ваши миры",
- "worlds.heuristic.name": "New World",
- "worlds.heuristic.description": "A world defined by its central premise: {{concept}}.",
- "worlds.heuristic.geography": "Outline the major regions, climates, and natural features of {{concept}}.",
- "worlds.heuristic.magicSystem": "Define the rules, costs, and limits of power in {{concept}}.",
- "worlds.heuristic.culture": "Describe the peoples, beliefs, and daily life shaped by {{concept}}.",
"writer.cancelledTag": "Отменено",
"writer.chapter.label": "Глава: {{title}}",
"writer.coachmark.dismiss": "Понятно",
@@ -2755,6 +2761,20 @@
"writer.focusMode.enterLabel": "Режим фокусировки",
"writer.focusMode.exit": "Выйти из режима фокусировки",
"writer.focusMode.exitLabel": "Выйти из фокуса",
+ "writer.grammar.addToDictionary": "Add to dictionary",
+ "writer.grammar.apply": "Apply",
+ "writer.grammar.checkButton": "Check this scene",
+ "writer.grammar.checking": "Checking…",
+ "writer.grammar.disabled": "Enable LanguageTool in Settings → Connections to check this scene.",
+ "writer.grammar.error": "The LanguageTool server returned an error.",
+ "writer.grammar.ignore": "Ignore",
+ "writer.grammar.issuesFound": "{{count}} issues found",
+ "writer.grammar.noIssues": "No issues found.",
+ "writer.grammar.noSuggestions": "No suggestions",
+ "writer.grammar.offline": "Couldn't reach the LanguageTool server. Is it running?",
+ "writer.grammar.selectScene": "Select a scene to check.",
+ "writer.grammar.title": "Grammar & Spelling",
+ "writer.grammar.unsupported": "Grammar check isn't available for this language.",
"writer.imagePrompt.description": "Создает оптимизированное приглашение DALL·E 3 / Midjourney на основе текущей сцены или выделенного текста.",
"writer.imagePrompt.note": "Созданная подсказка работает непосредственно в DALL·E 3 и Midjourney.",
"writer.imagePrompt.tip": "Совет: выберите конкретный текстовый раздел для подсказки конкретной сцены.",
@@ -2787,12 +2807,10 @@
"writer.studio.controls.tones.poetic": "Более поэтично",
"writer.studio.controls.tones.suspenseful": "Более напряженный",
"writer.studio.description": "Ваш соавтор ИИ. Создавайте, улучшайте и проводите мозговые штурмы с полным контекстом проекта.",
+ "writer.studio.rag.chunkScore": "релевантность {{score}}",
"writer.studio.rag.chunksBadge": "{{count}} найдено отрывков из истории",
"writer.studio.rag.chunksHint": "Соответствующие выдержки из вашей рукописи — больше отрывков означает более богатый контекст ИИ.",
"writer.studio.rag.inspectorLabel": "Извлечённый контекст",
- "writer.studio.rag.chunkScore": "релевантность {{score}}",
- "writer.studio.tokens.badge": "~{{count}} токенов",
- "writer.studio.tokens.hint": "Приблизительное число токенов в последнем запросе ИИ",
"writer.studio.rag.useContext": "Возьмите из моей истории",
"writer.studio.result.insert": "Вставлять",
"writer.studio.result.next": "Далее",
@@ -2802,6 +2820,8 @@
"writer.studio.result.retry": "Повторить попытку",
"writer.studio.result.title": "Блокнот с искусственным интеллектом",
"writer.studio.title": "Студия письма AI",
+ "writer.studio.tokens.badge": "~{{count}} токенов",
+ "writer.studio.tokens.hint": "Приблизительное число токенов в последнем запросе ИИ",
"writer.studio.tools.brainstorm.contextLabel": "Контекст мозгового штурма (необязательно)",
"writer.studio.tools.brainstorm.contextPlaceholder": "Кратко опишите ситуацию, иначе ИИ будет использовать текущий раздел рукописи.",
"writer.studio.tools.brainstorm.title": "Идеи мозгового штурма",
@@ -2833,19 +2853,5 @@
"writer.tts.start": "Читать вслух",
"writer.tts.stop": "Хватит читать",
"writer.versionControl.label": "Версии",
- "writer.versionControl.tooltip": "Контроль версий (ветви и снимки)",
- "writer.grammar.title": "Grammar & Spelling",
- "writer.grammar.checkButton": "Check this scene",
- "writer.grammar.checking": "Checking…",
- "writer.grammar.issuesFound": "{{count}} issues found",
- "writer.grammar.noIssues": "No issues found.",
- "writer.grammar.selectScene": "Select a scene to check.",
- "writer.grammar.unsupported": "Grammar check isn't available for this language.",
- "writer.grammar.disabled": "Enable LanguageTool in Settings → Connections to check this scene.",
- "writer.grammar.offline": "Couldn't reach the LanguageTool server. Is it running?",
- "writer.grammar.error": "The LanguageTool server returned an error.",
- "writer.grammar.apply": "Apply",
- "writer.grammar.ignore": "Ignore",
- "writer.grammar.addToDictionary": "Add to dictionary",
- "writer.grammar.noSuggestions": "No suggestions"
+ "writer.versionControl.tooltip": "Контроль версий (ветви и снимки)"
}
diff --git a/public/locales/sv/bundle.json b/public/locales/sv/bundle.json
index 6c542cb6..2a310013 100644
--- a/public/locales/sv/bundle.json
+++ b/public/locales/sv/bundle.json
@@ -90,6 +90,14 @@
"characters.edit.relationships": "Relationer",
"characters.editorTabsAriaLabel": "Teckenredigeringsflikar",
"characters.error.portraitFailed": "Det gick inte att skapa porträtt. Försök att lägga till mer detaljer i utseendebeskrivningen.",
+ "characters.heuristic.appearance": "Describe how they present themselves — let their look hint at {{concept}}.",
+ "characters.heuristic.backstory": "Shaped by formative experiences, this character carries a past tied to {{concept}}.",
+ "characters.heuristic.characterArc": "They begin guarded and, through the story, are changed by {{concept}}.",
+ "characters.heuristic.flaws": "A weakness that complicates their goals.",
+ "characters.heuristic.motivation": "A core desire connected to {{concept}} drives their choices.",
+ "characters.heuristic.name": "New Character",
+ "characters.heuristic.personalityTraits": "Resourceful, guarded, determined.",
+ "characters.heuristic.relationships": "Note the key bonds and rivalries that define them.",
"characters.loading.profile": "Genererar detaljerad profil...",
"characters.newCharacterName": "Ny karaktär",
"characters.noCharacters": "Inga karaktärer har skapats ännu.",
@@ -107,14 +115,6 @@
"characters.title": "Karaktärsdokument",
"characters.uploadImage": "Ladda upp bild",
"characters.yourCharacters": "Dina karaktärer",
- "characters.heuristic.name": "New Character",
- "characters.heuristic.backstory": "Shaped by formative experiences, this character carries a past tied to {{concept}}.",
- "characters.heuristic.motivation": "A core desire connected to {{concept}} drives their choices.",
- "characters.heuristic.appearance": "Describe how they present themselves — let their look hint at {{concept}}.",
- "characters.heuristic.personalityTraits": "Resourceful, guarded, determined.",
- "characters.heuristic.flaws": "A weakness that complicates their goals.",
- "characters.heuristic.characterArc": "They begin guarded and, through the story, are changed by {{concept}}.",
- "characters.heuristic.relationships": "Note the key bonds and rivalries that define them.",
"apiKey.connectionFailed": "Anslutningstest misslyckades.",
"apiKey.connectionSuccess": "Anslutningen lyckades! API svarar korrekt.",
"apiKey.decryptFailed": "API-nyckeln kunde inte dekrypteras",
@@ -125,6 +125,11 @@
"apiKey.test": "Testa anslutningen",
"apiKey.testConnection": "Testa API-anslutning",
"apiKey.testing": "Testning…",
+ "assisted.badge.label": "Assisted",
+ "assisted.badge.srLabel": "Assisted mode — generated without AI",
+ "assisted.enhance": "Enhance with AI",
+ "assisted.toast.description": "Used built-in assistance. Enhance with AI when a model is available.",
+ "assisted.toast.title": "AI unavailable",
"charGraph.characters": "Karaktärer",
"charGraph.noCharacters": "Inga tecken ännu",
"charGraph.noCharactersHint": "Lägg till karaktärer i teckenvyn för att visualisera deras relationer här.",
@@ -286,6 +291,8 @@
"error.db.unknown": "Okänt fel vid åtkomst till databasen.",
"error.deepLink.title": "Det gick inte att öppna projektfilen",
"error.deepLink.unknown": "Okänt fel",
+ "error.fallback.generic": "AI is unavailable — used built-in assistance.",
+ "error.fallback.offline": "You're offline — used built-in assistance.",
"error.fileImportError": "Filimportfel",
"error.mic.denied": "Mikrofonåtkomst nekad. Vänligen ge tillstånd i din webbläsarinställningar.",
"error.mic.generic": "Taligenkänningsfel: {{error}}",
@@ -382,6 +389,16 @@
"palette.voice.listeningLive": "Röstinmatning är aktiv",
"palette.voice.start": "Starta röstsökning",
"palette.voice.stop": "Stoppa röstsökning",
+ "plotBoard.heuristic.complicate.description": "Add an obstacle or reveal that forces a change of plan.",
+ "plotBoard.heuristic.complicate.rationale": "A fresh complication tests the characters and opens new threads.",
+ "plotBoard.heuristic.complicate.title": "Introduce a complication",
+ "plotBoard.heuristic.escalate.description": "Increase the pressure on your protagonist so the next choice costs more.",
+ "plotBoard.heuristic.escalate.rationale": "Escalation keeps momentum when the middle sags.",
+ "plotBoard.heuristic.escalate.title": "Raise the stakes",
+ "plotBoard.heuristic.position": "Right after the selected scene",
+ "plotBoard.heuristic.reverse.description": "Flip an expectation — an ally falters, a win turns sour, or a hidden truth surfaces.",
+ "plotBoard.heuristic.reverse.rationale": "Reversals refresh tension and deepen the arc.",
+ "plotBoard.heuristic.reverse.title": "Add a reversal",
"preview.controls.ariaLabel": "Förhandsgranska kontroller",
"preview.controls.decreaseFontSize": "Minska teckenstorleken",
"preview.controls.exitFullscreen": "Avsluta helskärm",
@@ -449,10 +466,6 @@
"proforge.progress.awaitingReviewHint": "⚠️ Det här steget väntar på din recension. Klicka på scenknappen ovan för att granska objekt.",
"proforge.progress.completedStages": "Genomförda etapper",
"proforge.progress.currentStatus": "Aktuell status",
- "proforge.progress.overall": "Overall progress",
- "proforge.progress.preparing": "Preparing…",
- "proforge.progress.stageOfTotal": "Stage {{current}} of {{total}}",
- "proforge.progress.percentComplete": "{{percent}}% complete",
"proforge.progress.itemsCount": "{{count}} föremål",
"proforge.progress.metric.aiCalls": "AI-anrop",
"proforge.progress.metric.duration": "Varaktighet",
@@ -463,7 +476,11 @@
"proforge.progress.metric.totalTime": "Total tid",
"proforge.progress.metric.totalTokens": "Totala tokens",
"proforge.progress.noneRunning": "Ingen pipeline igång.",
+ "proforge.progress.overall": "Overall progress",
+ "proforge.progress.percentComplete": "{{percent}}% complete",
+ "proforge.progress.preparing": "Preparing…",
"proforge.progress.stageDetails": "Stegdetaljer: {{stage}}",
+ "proforge.progress.stageOfTotal": "Stage {{current}} of {{total}}",
"proforge.progress.statusLabel": "Status",
"proforge.progress.totals": "Rörledningssummor",
"proforge.review.accept": "Acceptera",
@@ -777,9 +794,9 @@
"vc.title": "Versionshistorik",
"vc.words": "ord",
"voice.cancelSpeech": "Avbryt tal",
+ "voice.feedback.confidence": "Säkerhet {{percent}} %",
"voice.modeChip.commands": "Kommandon",
"voice.modeChip.dictation": "Diktering",
- "voice.feedback.confidence": "Säkerhet {{percent}} %",
"voice.panelLabel": "Röststyrning",
"voice.permissionDenied": "Mikrofonåtkomst nekad. Tillåt mikrofonåtkomst i webbläsarinställningarna för att använda röstfunktioner.",
"voice.startDictation": "Börja diktering",
@@ -793,23 +810,6 @@
"voice.stopListening": "Sluta lyssna",
"worlds.emptyState.description": "Bygg upp platserna, reglerna och historien som din berättelse lever i. Börja med en plats.",
"worlds.emptyState.title": "Världen väntar",
- "error.fallback.generic": "AI is unavailable — used built-in assistance.",
- "error.fallback.offline": "You're offline — used built-in assistance.",
- "assisted.badge.label": "Assisted",
- "assisted.badge.srLabel": "Assisted mode — generated without AI",
- "assisted.toast.title": "AI unavailable",
- "assisted.toast.description": "Used built-in assistance. Enhance with AI when a model is available.",
- "assisted.enhance": "Enhance with AI",
- "plotBoard.heuristic.position": "Right after the selected scene",
- "plotBoard.heuristic.escalate.title": "Raise the stakes",
- "plotBoard.heuristic.escalate.description": "Increase the pressure on your protagonist so the next choice costs more.",
- "plotBoard.heuristic.escalate.rationale": "Escalation keeps momentum when the middle sags.",
- "plotBoard.heuristic.complicate.title": "Introduce a complication",
- "plotBoard.heuristic.complicate.description": "Add an obstacle or reveal that forces a change of plan.",
- "plotBoard.heuristic.complicate.rationale": "A fresh complication tests the characters and opens new threads.",
- "plotBoard.heuristic.reverse.title": "Add a reversal",
- "plotBoard.heuristic.reverse.description": "Flip an expectation — an ally falters, a win turns sour, or a hidden truth surfaces.",
- "plotBoard.heuristic.reverse.rationale": "Reversals refresh tension and deepen the arc.",
"copilot.annotationCount": "{{count}} insikt för detta kapitel",
"copilot.announceClosed": "AI Copilot stängd",
"copilot.announceOpened": "AI Copilot öppnade",
@@ -1090,10 +1090,10 @@
"export.pasteSection.importAsChapter": "Importera som kapitel",
"export.pasteSection.textPlaceholder": "Klistra in text från Google Dokument eller Notion här (Ctrl+V)...",
"export.pasteSection.titlePlaceholder": "Kapiteltitel (valfritt)",
- "export.preview.noContent": "Välj innehåll för att se en förhandsvisning.",
"export.preview.modeLabel": "Förhandsgranskningsläge",
- "export.preview.modeText": "Text",
"export.preview.modeRendered": "Renderad",
+ "export.preview.modeText": "Text",
+ "export.preview.noContent": "Välj innehåll för att se en förhandsvisning.",
"export.preview.title": "Live Preview",
"export.title": "Exportera Publishing Suite",
"export.toggleSection": "Växla synlighet för {{title}}",
@@ -1519,6 +1519,23 @@
"outline.deleteConfirm": "Är du säker på att du vill ta bort detta dispositionsavsnitt?",
"outline.description": "Beskriv din berättelseidé och låt AI skapa en strukturerad, redigerbar disposition åt dig.",
"outline.error.generationFailed": "Det gick inte att generera innehåll. Försök igen.",
+ "outline.heuristic.beat.climax.desc": "The central conflict comes to a head in the story's defining confrontation.",
+ "outline.heuristic.beat.climax.title": "Climax",
+ "outline.heuristic.beat.complications.desc": "Setbacks and conflicts deepen; the path forward narrows.",
+ "outline.heuristic.beat.complications.title": "Complications",
+ "outline.heuristic.beat.incitingIncident.desc": "The event that sets the story in motion: {{idea}}.",
+ "outline.heuristic.beat.incitingIncident.title": "Inciting Incident",
+ "outline.heuristic.beat.midpoint.desc": "A turning point shifts the direction of the story and raises the stakes.",
+ "outline.heuristic.beat.midpoint.title": "Midpoint",
+ "outline.heuristic.beat.resolution.desc": "Loose ends are tied up and a new status quo emerges.",
+ "outline.heuristic.beat.resolution.title": "Resolution",
+ "outline.heuristic.beat.risingAction.desc": "Complications escalate and the stakes grow as the characters pursue their goal.",
+ "outline.heuristic.beat.risingAction.title": "Rising Action",
+ "outline.heuristic.beat.setup.desc": "Introduce the world and the main characters, and establish the status quo before everything changes.",
+ "outline.heuristic.beat.setup.title": "Setup",
+ "outline.heuristic.beat.twist.desc": "An unexpected revelation upends what the characters believed to be true.",
+ "outline.heuristic.beat.twist.title": "Twist",
+ "outline.heuristic.fallbackIdea": "the central idea",
"outline.idea.generateButton": "Skapa disposition",
"outline.idea.genreLabel": "Genre",
"outline.idea.genrePlaceholder": "t.ex. Sci-Fi, Fantasy, Mystery",
@@ -1541,23 +1558,6 @@
"outline.result.twistTooltip": "AI-genererad plottwist",
"outline.selectSection": "Välj avsnitt '{{title}}'",
"outline.title": "AI Story Outline Generator",
- "outline.heuristic.fallbackIdea": "the central idea",
- "outline.heuristic.beat.setup.title": "Setup",
- "outline.heuristic.beat.setup.desc": "Introduce the world and the main characters, and establish the status quo before everything changes.",
- "outline.heuristic.beat.incitingIncident.title": "Inciting Incident",
- "outline.heuristic.beat.incitingIncident.desc": "The event that sets the story in motion: {{idea}}.",
- "outline.heuristic.beat.risingAction.title": "Rising Action",
- "outline.heuristic.beat.risingAction.desc": "Complications escalate and the stakes grow as the characters pursue their goal.",
- "outline.heuristic.beat.midpoint.title": "Midpoint",
- "outline.heuristic.beat.midpoint.desc": "A turning point shifts the direction of the story and raises the stakes.",
- "outline.heuristic.beat.complications.title": "Complications",
- "outline.heuristic.beat.complications.desc": "Setbacks and conflicts deepen; the path forward narrows.",
- "outline.heuristic.beat.twist.title": "Twist",
- "outline.heuristic.beat.twist.desc": "An unexpected revelation upends what the characters believed to be true.",
- "outline.heuristic.beat.climax.title": "Climax",
- "outline.heuristic.beat.climax.desc": "The central conflict comes to a head in the story's defining confrontation.",
- "outline.heuristic.beat.resolution.title": "Resolution",
- "outline.heuristic.beat.resolution.desc": "Loose ends are tied up and a new status quo emerges.",
"portal.back": "Tillbaka",
"portal.demo.chapterContent": "Morgondimman låg tät över kajerna när Lyra rullade ut den gamla stadskartan. En svag cirkel markerade det nordvästra hörnet — tornet som ingen nämnde.\n\nHon stoppade undan pappret och följde den smala stigen tills järngallret reste sig framför henne. Hänglåset var varmt i solen; metallen fortfarande kall.",
"portal.demo.chapterTitle": "Kapitel 1 — Framför porten",
@@ -1752,6 +1752,7 @@
"settings.ai.gpu.troubleshootLowEnd": "Din enhet har begränsade resurser. Lokal AI kommer att använda mindre modeller. För bättre prestanda, stäng andra webbläsarflikar eller aktivera Eco Mode.",
"settings.ai.gpu.troubleshootQueue": "Flera AI-uppgifter står i kö. Endast en kör åt gången för att undvika VRAM-kollisioner. Vänta tills den aktuella uppgiften är klar.",
"settings.ai.gpu.waitingConsumers": "Väntan",
+ "settings.ai.grokKey": "Grok API Key",
"settings.ai.hybridFallbackHint": "Om den primära leverantören misslyckas, försöker WorldScript de listade fallbacks (scengeneratorer, codexverktyg). Writer-strömning använder endast din primära leverantör.",
"settings.ai.hybridFallbackTitle": "Hybrid fallback (projekt AI-verktyg)",
"settings.ai.hybridFallbackToggle": "Aktivera reservkedja",
@@ -1832,6 +1833,11 @@
"settings.ai.preset.lmStudio": "LM Studio",
"settings.ai.preset.ollamaDefault": "Ollama (standardport)",
"settings.ai.preset.vllm": "vLLM",
+ "settings.ai.provider.anthropic": "Anthropic Claude",
+ "settings.ai.provider.gemini": "Google Gemini",
+ "settings.ai.provider.grok": "xAI Grok",
+ "settings.ai.provider.ollama": "Ollama (local)",
+ "settings.ai.provider.openai": "OpenAI",
"settings.ai.providerDescription": "Välj vilken AI-leverantör WorldScript Studio ska använda.",
"settings.ai.providerOnnx": "ONNX (WASM)",
"settings.ai.providerStatusConnected": "Ansluten",
@@ -2711,6 +2717,11 @@
"worlds.edit.notes": "Anteckningar",
"worlds.editorTabsAriaLabel": "World editor flikar",
"worlds.error.imageFailed": "Det gick inte att skapa stämningsbilder. Försök att lägga till mer detaljer i världsbeskrivningen eller kontrollera din anslutning.",
+ "worlds.heuristic.culture": "Describe the peoples, beliefs, and daily life shaped by {{concept}}.",
+ "worlds.heuristic.description": "A world defined by its central premise: {{concept}}.",
+ "worlds.heuristic.geography": "Outline the major regions, climates, and natural features of {{concept}}.",
+ "worlds.heuristic.magicSystem": "Define the rules, costs, and limits of power in {{concept}}.",
+ "worlds.heuristic.name": "New World",
"worlds.loading.profile": "Genererar detaljerad världsprofil...",
"worlds.newWorldName": "Ny värld",
"worlds.noWorlds": "Inga världar skapade ännu.",
@@ -2729,11 +2740,6 @@
"worlds.title": "Världsatlas",
"worlds.uploadImage": "Ladda upp bild",
"worlds.yourWorlds": "Dina världar",
- "worlds.heuristic.name": "New World",
- "worlds.heuristic.description": "A world defined by its central premise: {{concept}}.",
- "worlds.heuristic.geography": "Outline the major regions, climates, and natural features of {{concept}}.",
- "worlds.heuristic.magicSystem": "Define the rules, costs, and limits of power in {{concept}}.",
- "worlds.heuristic.culture": "Describe the peoples, beliefs, and daily life shaped by {{concept}}.",
"writer.cancelledTag": "Avbruten",
"writer.chapter.label": "Kapitel: {{title}}",
"writer.coachmark.dismiss": "Got it",
@@ -2755,6 +2761,20 @@
"writer.focusMode.enterLabel": "Fokusläge",
"writer.focusMode.exit": "Avsluta fokusläget",
"writer.focusMode.exitLabel": "Avsluta fokus",
+ "writer.grammar.addToDictionary": "Add to dictionary",
+ "writer.grammar.apply": "Apply",
+ "writer.grammar.checkButton": "Check this scene",
+ "writer.grammar.checking": "Checking…",
+ "writer.grammar.disabled": "Enable LanguageTool in Settings → Connections to check this scene.",
+ "writer.grammar.error": "The LanguageTool server returned an error.",
+ "writer.grammar.ignore": "Ignore",
+ "writer.grammar.issuesFound": "{{count}} issues found",
+ "writer.grammar.noIssues": "No issues found.",
+ "writer.grammar.noSuggestions": "No suggestions",
+ "writer.grammar.offline": "Couldn't reach the LanguageTool server. Is it running?",
+ "writer.grammar.selectScene": "Select a scene to check.",
+ "writer.grammar.title": "Grammar & Spelling",
+ "writer.grammar.unsupported": "Grammar check isn't available for this language.",
"writer.imagePrompt.description": "Genererar en optimerad DALL·E 3 / Midjourney-prompt från den aktuella scenen eller textvalet.",
"writer.imagePrompt.note": "Den genererade prompten fungerar direkt i DALL·E 3 och Midjourney.",
"writer.imagePrompt.tip": "Tips: Välj ett specifikt textavsnitt för en fokuserad scenuppmaning.",
@@ -2787,12 +2807,10 @@
"writer.studio.controls.tones.poetic": "Mer poetiskt",
"writer.studio.controls.tones.suspenseful": "Mer spännande",
"writer.studio.description": "Din AI-medförfattare. Generera, förbättra och brainstorma med hela projektkontexten.",
+ "writer.studio.rag.chunkScore": "relevans {{score}}",
"writer.studio.rag.chunksBadge": "{{count}} berättelsepassager hittades",
"writer.studio.rag.chunksHint": "Relevanta utdrag ur ditt manuskript – fler passager betyder rikare AI-kontext",
"writer.studio.rag.inspectorLabel": "Hämtad kontext",
- "writer.studio.rag.chunkScore": "relevans {{score}}",
- "writer.studio.tokens.badge": "~{{count}} tokens",
- "writer.studio.tokens.hint": "Ungefärligt antal tokens i din senaste AI-förfrågan",
"writer.studio.rag.useContext": "Dra ur min berättelse",
"writer.studio.result.insert": "Infoga",
"writer.studio.result.next": "Nästa",
@@ -2802,6 +2820,8 @@
"writer.studio.result.retry": "Försöka igen",
"writer.studio.result.title": "AI Scratchpad",
"writer.studio.title": "AI Writing Studio",
+ "writer.studio.tokens.badge": "~{{count}} tokens",
+ "writer.studio.tokens.hint": "Ungefärligt antal tokens i din senaste AI-förfrågan",
"writer.studio.tools.brainstorm.contextLabel": "Brainstormingskontext (valfritt)",
"writer.studio.tools.brainstorm.contextPlaceholder": "Ge en kort situation, annars använder AI den aktuella manuskriptsektionen.",
"writer.studio.tools.brainstorm.title": "Brainstorma idéer",
@@ -2833,19 +2853,5 @@
"writer.tts.start": "Läs högt",
"writer.tts.stop": "Sluta läsa",
"writer.versionControl.label": "Versioner",
- "writer.versionControl.tooltip": "Versionskontroll (grenar och ögonblicksbilder)",
- "writer.grammar.title": "Grammar & Spelling",
- "writer.grammar.checkButton": "Check this scene",
- "writer.grammar.checking": "Checking…",
- "writer.grammar.issuesFound": "{{count}} issues found",
- "writer.grammar.noIssues": "No issues found.",
- "writer.grammar.selectScene": "Select a scene to check.",
- "writer.grammar.unsupported": "Grammar check isn't available for this language.",
- "writer.grammar.disabled": "Enable LanguageTool in Settings → Connections to check this scene.",
- "writer.grammar.offline": "Couldn't reach the LanguageTool server. Is it running?",
- "writer.grammar.error": "The LanguageTool server returned an error.",
- "writer.grammar.apply": "Apply",
- "writer.grammar.ignore": "Ignore",
- "writer.grammar.addToDictionary": "Add to dictionary",
- "writer.grammar.noSuggestions": "No suggestions"
+ "writer.versionControl.tooltip": "Versionskontroll (grenar och ögonblicksbilder)"
}
diff --git a/public/locales/zh/bundle.json b/public/locales/zh/bundle.json
index aa09be0f..94d50873 100644
--- a/public/locales/zh/bundle.json
+++ b/public/locales/zh/bundle.json
@@ -90,6 +90,14 @@
"characters.edit.relationships": "人际关系",
"characters.editorTabsAriaLabel": "角色 editor tabs",
"characters.error.portraitFailed": "肖像生成失败。尝试在外观描述中添加更多细节。",
+ "characters.heuristic.appearance": "Describe how they present themselves — let their look hint at {{concept}}.",
+ "characters.heuristic.backstory": "Shaped by formative experiences, this character carries a past tied to {{concept}}.",
+ "characters.heuristic.characterArc": "They begin guarded and, through the story, are changed by {{concept}}.",
+ "characters.heuristic.flaws": "A weakness that complicates their goals.",
+ "characters.heuristic.motivation": "A core desire connected to {{concept}} drives their choices.",
+ "characters.heuristic.name": "New Character",
+ "characters.heuristic.personalityTraits": "Resourceful, guarded, determined.",
+ "characters.heuristic.relationships": "Note the key bonds and rivalries that define them.",
"characters.loading.profile": "正在生成详细的个人资料...",
"characters.newCharacterName": "New 角色",
"characters.noCharacters": "尚未创建任何角色。",
@@ -107,14 +115,6 @@
"characters.title": "角色 Dossiers",
"characters.uploadImage": "上传图片",
"characters.yourCharacters": "你的角色",
- "characters.heuristic.name": "New Character",
- "characters.heuristic.backstory": "Shaped by formative experiences, this character carries a past tied to {{concept}}.",
- "characters.heuristic.motivation": "A core desire connected to {{concept}} drives their choices.",
- "characters.heuristic.appearance": "Describe how they present themselves — let their look hint at {{concept}}.",
- "characters.heuristic.personalityTraits": "Resourceful, guarded, determined.",
- "characters.heuristic.flaws": "A weakness that complicates their goals.",
- "characters.heuristic.characterArc": "They begin guarded and, through the story, are changed by {{concept}}.",
- "characters.heuristic.relationships": "Note the key bonds and rivalries that define them.",
"apiKey.connectionFailed": "连接测试失败。",
"apiKey.connectionSuccess": "连接成功! API 响应正确。",
"apiKey.decryptFailed": "API密钥无法解密",
@@ -125,6 +125,11 @@
"apiKey.test": "测试连接",
"apiKey.testConnection": "测试API连接",
"apiKey.testing": "测试...",
+ "assisted.badge.label": "Assisted",
+ "assisted.badge.srLabel": "Assisted mode — generated without AI",
+ "assisted.enhance": "Enhance with AI",
+ "assisted.toast.description": "Used built-in assistance. Enhance with AI when a model is available.",
+ "assisted.toast.title": "AI unavailable",
"charGraph.characters": "人物",
"charGraph.noCharacters": "还没有角色",
"charGraph.noCharactersHint": "添加 characters in the Characters view to visualize their relationships here.",
@@ -286,6 +291,8 @@
"error.db.unknown": "访问数据库时出现未知错误。",
"error.deepLink.title": "无法打开项目文件",
"error.deepLink.unknown": "未知错误",
+ "error.fallback.generic": "AI is unavailable — used built-in assistance.",
+ "error.fallback.offline": "You're offline — used built-in assistance.",
"error.fileImportError": "文件导入错误",
"error.mic.denied": "麦克风访问被拒绝。请在您的浏览器设置中授予权限。",
"error.mic.generic": "语音识别错误:{{error}}",
@@ -382,6 +389,16 @@
"palette.voice.listeningLive": "语音输入已激活",
"palette.voice.start": "开始语音搜索",
"palette.voice.stop": "停止语音搜索",
+ "plotBoard.heuristic.complicate.description": "Add an obstacle or reveal that forces a change of plan.",
+ "plotBoard.heuristic.complicate.rationale": "A fresh complication tests the characters and opens new threads.",
+ "plotBoard.heuristic.complicate.title": "Introduce a complication",
+ "plotBoard.heuristic.escalate.description": "Increase the pressure on your protagonist so the next choice costs more.",
+ "plotBoard.heuristic.escalate.rationale": "Escalation keeps momentum when the middle sags.",
+ "plotBoard.heuristic.escalate.title": "Raise the stakes",
+ "plotBoard.heuristic.position": "Right after the selected scene",
+ "plotBoard.heuristic.reverse.description": "Flip an expectation — an ally falters, a win turns sour, or a hidden truth surfaces.",
+ "plotBoard.heuristic.reverse.rationale": "Reversals refresh tension and deepen the arc.",
+ "plotBoard.heuristic.reverse.title": "Add a reversal",
"preview.controls.ariaLabel": "预览控件",
"preview.controls.decreaseFontSize": "减小字体大小",
"preview.controls.exitFullscreen": "退出全屏",
@@ -449,10 +466,6 @@
"proforge.progress.awaitingReviewHint": "⚠️此阶段正在等待您的审核。单击上面的阶段按钮以查看项目。",
"proforge.progress.completedStages": "已完成的阶段",
"proforge.progress.currentStatus": "目前状况",
- "proforge.progress.overall": "Overall progress",
- "proforge.progress.preparing": "Preparing…",
- "proforge.progress.stageOfTotal": "Stage {{current}} of {{total}}",
- "proforge.progress.percentComplete": "{{percent}}% complete",
"proforge.progress.itemsCount": "{{count}} 项目",
"proforge.progress.metric.aiCalls": "人工智能通话",
"proforge.progress.metric.duration": "期间",
@@ -463,7 +476,11 @@
"proforge.progress.metric.totalTime": "总时间",
"proforge.progress.metric.totalTokens": "代币总数",
"proforge.progress.noneRunning": "没有管道运行。",
+ "proforge.progress.overall": "Overall progress",
+ "proforge.progress.percentComplete": "{{percent}}% complete",
+ "proforge.progress.preparing": "Preparing…",
"proforge.progress.stageDetails": "舞台详情:{{stage}}",
+ "proforge.progress.stageOfTotal": "Stage {{current}} of {{total}}",
"proforge.progress.statusLabel": "地位",
"proforge.progress.totals": "管道总计",
"proforge.review.accept": "接受",
@@ -777,9 +794,9 @@
"vc.title": "版本历史",
"vc.words": "字",
"voice.cancelSpeech": "取消 speech",
+ "voice.feedback.confidence": "置信度 {{percent}}%",
"voice.modeChip.commands": "命令",
"voice.modeChip.dictation": "听写",
- "voice.feedback.confidence": "置信度 {{percent}}%",
"voice.panelLabel": "语音控制",
"voice.permissionDenied": "麦克风访问被拒绝。请在浏览器设置中允许麦克风访问才能使用语音功能。",
"voice.startDictation": "开始听写",
@@ -793,23 +810,6 @@
"voice.stopListening": "停止聆听",
"worlds.emptyState.description": "构建你的故事所存在的地点、规则和历史。从一个地点开始。",
"worlds.emptyState.title": "世界等待着",
- "error.fallback.generic": "AI is unavailable — used built-in assistance.",
- "error.fallback.offline": "You're offline — used built-in assistance.",
- "assisted.badge.label": "Assisted",
- "assisted.badge.srLabel": "Assisted mode — generated without AI",
- "assisted.toast.title": "AI unavailable",
- "assisted.toast.description": "Used built-in assistance. Enhance with AI when a model is available.",
- "assisted.enhance": "Enhance with AI",
- "plotBoard.heuristic.position": "Right after the selected scene",
- "plotBoard.heuristic.escalate.title": "Raise the stakes",
- "plotBoard.heuristic.escalate.description": "Increase the pressure on your protagonist so the next choice costs more.",
- "plotBoard.heuristic.escalate.rationale": "Escalation keeps momentum when the middle sags.",
- "plotBoard.heuristic.complicate.title": "Introduce a complication",
- "plotBoard.heuristic.complicate.description": "Add an obstacle or reveal that forces a change of plan.",
- "plotBoard.heuristic.complicate.rationale": "A fresh complication tests the characters and opens new threads.",
- "plotBoard.heuristic.reverse.title": "Add a reversal",
- "plotBoard.heuristic.reverse.description": "Flip an expectation — an ally falters, a win turns sour, or a hidden truth surfaces.",
- "plotBoard.heuristic.reverse.rationale": "Reversals refresh tension and deepen the arc.",
"copilot.annotationCount": "{{count}} 本章见解",
"copilot.announceClosed": "AI副驾驶关闭",
"copilot.announceOpened": "AI副驾驶开启",
@@ -1090,10 +1090,10 @@
"export.pasteSection.importAsChapter": "作为章节导入",
"export.pasteSection.textPlaceholder": "将 Google Docs 或 Notion 中的文本粘贴到此处 (Ctrl+V)...",
"export.pasteSection.titlePlaceholder": "章节标题(可选)",
- "export.preview.noContent": "选择内容以查看预览。",
"export.preview.modeLabel": "预览模式",
- "export.preview.modeText": "文本",
"export.preview.modeRendered": "渲染",
+ "export.preview.modeText": "文本",
+ "export.preview.noContent": "选择内容以查看预览。",
"export.preview.title": "实时预览",
"export.title": "导出 Publishing Suite",
"export.toggleSection": "切换 {{title}} 的可见性",
@@ -1519,6 +1519,23 @@
"outline.deleteConfirm": "您确定要删除此大纲部分吗?",
"outline.description": "描述您的故事想法,让人工智能为您创建结构化、可编辑的大纲。",
"outline.error.generationFailed": "无法生成内容。请再试一次。",
+ "outline.heuristic.beat.climax.desc": "The central conflict comes to a head in the story's defining confrontation.",
+ "outline.heuristic.beat.climax.title": "Climax",
+ "outline.heuristic.beat.complications.desc": "Setbacks and conflicts deepen; the path forward narrows.",
+ "outline.heuristic.beat.complications.title": "Complications",
+ "outline.heuristic.beat.incitingIncident.desc": "The event that sets the story in motion: {{idea}}.",
+ "outline.heuristic.beat.incitingIncident.title": "Inciting Incident",
+ "outline.heuristic.beat.midpoint.desc": "A turning point shifts the direction of the story and raises the stakes.",
+ "outline.heuristic.beat.midpoint.title": "Midpoint",
+ "outline.heuristic.beat.resolution.desc": "Loose ends are tied up and a new status quo emerges.",
+ "outline.heuristic.beat.resolution.title": "Resolution",
+ "outline.heuristic.beat.risingAction.desc": "Complications escalate and the stakes grow as the characters pursue their goal.",
+ "outline.heuristic.beat.risingAction.title": "Rising Action",
+ "outline.heuristic.beat.setup.desc": "Introduce the world and the main characters, and establish the status quo before everything changes.",
+ "outline.heuristic.beat.setup.title": "Setup",
+ "outline.heuristic.beat.twist.desc": "An unexpected revelation upends what the characters believed to be true.",
+ "outline.heuristic.beat.twist.title": "Twist",
+ "outline.heuristic.fallbackIdea": "the central idea",
"outline.idea.generateButton": "生成 大纲",
"outline.idea.genreLabel": "类型",
"outline.idea.genrePlaceholder": "例如,科幻、奇幻、悬疑",
@@ -1541,23 +1558,6 @@
"outline.result.twistTooltip": "人工智能生成的情节扭曲",
"outline.selectSection": "选择“{{title}}”部分",
"outline.title": "AI Story 大纲 Generator",
- "outline.heuristic.fallbackIdea": "the central idea",
- "outline.heuristic.beat.setup.title": "Setup",
- "outline.heuristic.beat.setup.desc": "Introduce the world and the main characters, and establish the status quo before everything changes.",
- "outline.heuristic.beat.incitingIncident.title": "Inciting Incident",
- "outline.heuristic.beat.incitingIncident.desc": "The event that sets the story in motion: {{idea}}.",
- "outline.heuristic.beat.risingAction.title": "Rising Action",
- "outline.heuristic.beat.risingAction.desc": "Complications escalate and the stakes grow as the characters pursue their goal.",
- "outline.heuristic.beat.midpoint.title": "Midpoint",
- "outline.heuristic.beat.midpoint.desc": "A turning point shifts the direction of the story and raises the stakes.",
- "outline.heuristic.beat.complications.title": "Complications",
- "outline.heuristic.beat.complications.desc": "Setbacks and conflicts deepen; the path forward narrows.",
- "outline.heuristic.beat.twist.title": "Twist",
- "outline.heuristic.beat.twist.desc": "An unexpected revelation upends what the characters believed to be true.",
- "outline.heuristic.beat.climax.title": "Climax",
- "outline.heuristic.beat.climax.desc": "The central conflict comes to a head in the story's defining confrontation.",
- "outline.heuristic.beat.resolution.title": "Resolution",
- "outline.heuristic.beat.resolution.desc": "Loose ends are tied up and a new status quo emerges.",
"portal.back": "后退",
"portal.demo.chapterContent": "当莱拉展开旧城地图时,晨雾笼罩在码头上。西北角有一个淡淡的圆圈标记——那座塔无人提及。\n\n她把纸收起来,沿着狭窄的小路走,直到铁格子在她面前升起。挂锁在阳光下显得温暖;金属仍然冰冷。",
"portal.demo.chapterTitle": "第一章 门前",
@@ -1752,6 +1752,7 @@
"settings.ai.gpu.troubleshootLowEnd": "您的设备资源有限。本地人工智能将使用更小的模型。为了获得更好的性能,请关闭其他浏览器选项卡或启用 Eco 模式。",
"settings.ai.gpu.troubleshootQueue": "多个 AI 任务排队。一次仅运行一个以避免 VRAM 冲突。等待当前任务完成。",
"settings.ai.gpu.waitingConsumers": "等待",
+ "settings.ai.grokKey": "Grok API Key",
"settings.ai.hybridFallbackHint": "如果主要提供程序失败,WorldScript 会尝试列出的后备方案(场景生成器、法典工具)。作家流媒体仅使用您的主要提供商。",
"settings.ai.hybridFallbackTitle": "混合后备(项目 AI 工具)",
"settings.ai.hybridFallbackToggle": "启用后备链",
@@ -1832,6 +1833,11 @@
"settings.ai.preset.lmStudio": "LM工作室",
"settings.ai.preset.ollamaDefault": "奥拉马(默认端口)",
"settings.ai.preset.vllm": "法学硕士",
+ "settings.ai.provider.anthropic": "Anthropic Claude",
+ "settings.ai.provider.gemini": "Google Gemini",
+ "settings.ai.provider.grok": "xAI Grok",
+ "settings.ai.provider.ollama": "Ollama (local)",
+ "settings.ai.provider.openai": "OpenAI",
"settings.ai.providerDescription": "选择 WorldScript Studio 应使用的 AI 提供商。",
"settings.ai.providerOnnx": "ONNX (WASM)",
"settings.ai.providerStatusConnected": "已连接",
@@ -2711,6 +2717,11 @@
"worlds.edit.notes": "笔记",
"worlds.editorTabsAriaLabel": "世界 editor tabs",
"worlds.error.imageFailed": "氛围图像生成失败。请尝试在世界描述中添加更多详细信息或检查您的连接。",
+ "worlds.heuristic.culture": "Describe the peoples, beliefs, and daily life shaped by {{concept}}.",
+ "worlds.heuristic.description": "A world defined by its central premise: {{concept}}.",
+ "worlds.heuristic.geography": "Outline the major regions, climates, and natural features of {{concept}}.",
+ "worlds.heuristic.magicSystem": "Define the rules, costs, and limits of power in {{concept}}.",
+ "worlds.heuristic.name": "New World",
"worlds.loading.profile": "正在生成详细的世界概况...",
"worlds.newWorldName": "New 世界",
"worlds.noWorlds": "尚未创建任何世界。",
@@ -2729,11 +2740,6 @@
"worlds.title": "世界 Atlas",
"worlds.uploadImage": "上传图片",
"worlds.yourWorlds": "你的世界",
- "worlds.heuristic.name": "New World",
- "worlds.heuristic.description": "A world defined by its central premise: {{concept}}.",
- "worlds.heuristic.geography": "Outline the major regions, climates, and natural features of {{concept}}.",
- "worlds.heuristic.magicSystem": "Define the rules, costs, and limits of power in {{concept}}.",
- "worlds.heuristic.culture": "Describe the peoples, beliefs, and daily life shaped by {{concept}}.",
"writer.cancelledTag": "取消",
"writer.chapter.label": "章节:{{title}}",
"writer.coachmark.dismiss": "Got it",
@@ -2755,6 +2761,20 @@
"writer.focusMode.enterLabel": "对焦模式",
"writer.focusMode.exit": "退出对焦模式",
"writer.focusMode.exitLabel": "退出焦点",
+ "writer.grammar.addToDictionary": "Add to dictionary",
+ "writer.grammar.apply": "Apply",
+ "writer.grammar.checkButton": "Check this scene",
+ "writer.grammar.checking": "Checking…",
+ "writer.grammar.disabled": "Enable LanguageTool in Settings → Connections to check this scene.",
+ "writer.grammar.error": "The LanguageTool server returned an error.",
+ "writer.grammar.ignore": "Ignore",
+ "writer.grammar.issuesFound": "{{count}} issues found",
+ "writer.grammar.noIssues": "No issues found.",
+ "writer.grammar.noSuggestions": "No suggestions",
+ "writer.grammar.offline": "Couldn't reach the LanguageTool server. Is it running?",
+ "writer.grammar.selectScene": "Select a scene to check.",
+ "writer.grammar.title": "Grammar & Spelling",
+ "writer.grammar.unsupported": "Grammar check isn't available for this language.",
"writer.imagePrompt.description": "从当前场景或文本选择生成优化的 DALL·E 3 / 中途提示。",
"writer.imagePrompt.note": "生成的提示可直接在 DALL·E 3 和 Midjourney 中运行。",
"writer.imagePrompt.tip": "提示:为聚焦场景提示选择特定文本部分。",
@@ -2787,12 +2807,10 @@
"writer.studio.controls.tones.poetic": "更有诗意",
"writer.studio.controls.tones.suspenseful": "更悬疑",
"writer.studio.description": "Your AI co-author. 生成, improve, and brainstorm with full project context.",
+ "writer.studio.rag.chunkScore": "相关度 {{score}}",
"writer.studio.rag.chunksBadge": "找到 {{count}} 个故事段落",
"writer.studio.rag.chunksHint": "手稿的相关摘录——更多段落意味着更丰富的人工智能背景",
"writer.studio.rag.inspectorLabel": "检索到的上下文",
- "writer.studio.rag.chunkScore": "相关度 {{score}}",
- "writer.studio.tokens.badge": "~{{count}} 个令牌",
- "writer.studio.tokens.hint": "上次 AI 请求使用的大致令牌数",
"writer.studio.rag.useContext": "从我的故事中拉出来",
"writer.studio.result.insert": "插入",
"writer.studio.result.next": "下一步",
@@ -2802,6 +2820,8 @@
"writer.studio.result.retry": "重试",
"writer.studio.result.title": "人工智能便签本",
"writer.studio.title": "人工智能写作工作室",
+ "writer.studio.tokens.badge": "~{{count}} 个令牌",
+ "writer.studio.tokens.hint": "上次 AI 请求使用的大致令牌数",
"writer.studio.tools.brainstorm.contextLabel": "头脑风暴背景(可选)",
"writer.studio.tools.brainstorm.contextPlaceholder": "提供一个简短的情况,否则AI将使用当前的手稿部分。",
"writer.studio.tools.brainstorm.title": "集思广益",
@@ -2833,19 +2853,5 @@
"writer.tts.start": "大声朗读",
"writer.tts.stop": "停止阅读",
"writer.versionControl.label": "版本",
- "writer.versionControl.tooltip": "版本控制(分支和快照)",
- "writer.grammar.title": "Grammar & Spelling",
- "writer.grammar.checkButton": "Check this scene",
- "writer.grammar.checking": "Checking…",
- "writer.grammar.issuesFound": "{{count}} issues found",
- "writer.grammar.noIssues": "No issues found.",
- "writer.grammar.selectScene": "Select a scene to check.",
- "writer.grammar.unsupported": "Grammar check isn't available for this language.",
- "writer.grammar.disabled": "Enable LanguageTool in Settings → Connections to check this scene.",
- "writer.grammar.offline": "Couldn't reach the LanguageTool server. Is it running?",
- "writer.grammar.error": "The LanguageTool server returned an error.",
- "writer.grammar.apply": "Apply",
- "writer.grammar.ignore": "Ignore",
- "writer.grammar.addToDictionary": "Add to dictionary",
- "writer.grammar.noSuggestions": "No suggestions"
+ "writer.versionControl.tooltip": "版本控制(分支和快照)"
}
diff --git a/services/ai/providerFactory.ts b/services/ai/providerFactory.ts
index b9960f64..beb5b60c 100644
--- a/services/ai/providerFactory.ts
+++ b/services/ai/providerFactory.ts
@@ -76,14 +76,18 @@ export function createLanguageModelForWorldScript(
/** Mappt Redux-`AIProvider` auf Fabrik-Union (ohne Keys — Auflösung in `worldScriptCompletionFetch`). */
export function providerToKind(
provider: AIProvider,
-): 'gemini' | 'openai' | 'openaiCompatible' | 'unsupported' {
- // QNBS-v3: webllm/onnx/transformers route through localAiFacade, not this factory.
- // anthropic/grok are reserved in the type union but not yet implemented here.
+): 'gemini' | 'openai' | 'grok' | 'openaiCompatible' | 'unsupported' {
+ // QNBS-v3: webllm/onnx/transformers route through localAiFacade, not this factory. `grok` gets
+ // its own kind (not folded into 'openaiCompatible') because it needs a fixed baseURL + a real
+ // stored key, unlike the Ollama default this same 'openaiCompatible' path also serves.
+ // anthropic is reserved in the type union but not yet implemented here (see ADR-0016).
switch (provider) {
case 'gemini':
return 'gemini';
case 'openai':
return 'openai';
+ case 'grok':
+ return 'grok';
case 'ollama':
return 'openaiCompatible';
default:
diff --git a/services/ai/worldScriptCompletionFetch.ts b/services/ai/worldScriptCompletionFetch.ts
index 774d4eec..55734a4d 100644
--- a/services/ai/worldScriptCompletionFetch.ts
+++ b/services/ai/worldScriptCompletionFetch.ts
@@ -81,6 +81,20 @@ async function resolveModelConfig(
status: 422,
};
}
+ // QNBS-v3: xAI's API is OpenAI-Chat-Completions-compatible, so Grok reuses the
+ // 'openaiCompatible' shape with a fixed baseURL instead of needing its own branch type.
+ if (kind === 'grok') {
+ const apiKey = await storageService.getApiKey('grok');
+ if (!apiKey) {
+ return { error: 'No Grok API key configured.', status: 401 };
+ }
+ return {
+ provider: 'openaiCompatible',
+ baseURL: 'https://api.x.ai/v1',
+ apiKey,
+ modelId: model.startsWith('grok-') ? model : 'grok-3',
+ };
+ }
if (kind === 'gemini') {
const apiKey = await storageService.getGeminiApiKey();
if (!apiKey) {
diff --git a/tests/unit/ai/worldScriptCompletionFetch.test.ts b/tests/unit/ai/worldScriptCompletionFetch.test.ts
index 913959a8..832e0658 100644
--- a/tests/unit/ai/worldScriptCompletionFetch.test.ts
+++ b/tests/unit/ai/worldScriptCompletionFetch.test.ts
@@ -162,6 +162,16 @@ describe('worldScriptCompletionFetch — missing API key', () => {
);
expect(res.status).toBe(401);
});
+
+ it('returns 401 when Grok API key is missing', async () => {
+ mockProviderToKind.mockReturnValue('grok');
+ mockGetApiKey.mockResolvedValue(null);
+ const res = await worldScriptCompletionFetch(
+ 'worldscript-internal://completion',
+ makeInit(makeBody({ provider: 'grok', model: 'grok-3' })),
+ );
+ expect(res.status).toBe(401);
+ });
});
describe('worldScriptCompletionFetch — abort handling', () => {
@@ -235,6 +245,38 @@ describe('worldScriptCompletionFetch — success (ollama)', () => {
});
});
+describe('worldScriptCompletionFetch — success (grok)', () => {
+ it('resolves grok to openaiCompatible with the fixed xAI baseURL and the stored key', async () => {
+ mockProviderToKind.mockReturnValue('grok');
+ mockGetApiKey.mockResolvedValue('grok-key');
+ const res = await worldScriptCompletionFetch(
+ 'worldscript-internal://completion',
+ makeInit(makeBody({ provider: 'grok', model: 'grok-3-mini' })),
+ );
+ expect(res.status).toBe(200);
+ expect(mockCreateLanguageModelForWorldScript).toHaveBeenCalledWith(
+ expect.objectContaining({
+ provider: 'openaiCompatible',
+ baseURL: 'https://api.x.ai/v1',
+ apiKey: 'grok-key',
+ modelId: 'grok-3-mini',
+ }),
+ );
+ });
+
+ it('defaults modelId to grok-3 when the stored model is not a grok- id', async () => {
+ mockProviderToKind.mockReturnValue('grok');
+ mockGetApiKey.mockResolvedValue('grok-key');
+ await worldScriptCompletionFetch(
+ 'worldscript-internal://completion',
+ makeInit(makeBody({ provider: 'grok', model: 'some-other-id' })),
+ );
+ expect(mockCreateLanguageModelForWorldScript).toHaveBeenCalledWith(
+ expect.objectContaining({ modelId: 'grok-3' }),
+ );
+ });
+});
+
describe('worldScriptCompletionFetch — unexpected error', () => {
it('returns 500 for unexpected errors', async () => {
mockAssertCloudAiAllowed.mockRejectedValue(new Error('Network error'));
diff --git a/tests/unit/listenerMiddleware.test.ts b/tests/unit/listenerMiddleware.test.ts
index 57d6cf86..edf3e7d5 100644
--- a/tests/unit/listenerMiddleware.test.ts
+++ b/tests/unit/listenerMiddleware.test.ts
@@ -2,10 +2,13 @@ import { configureStore, type Reducer } from '@reduxjs/toolkit';
import undoable from 'redux-undo';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { listenerMiddleware } from '../../app/listenerMiddleware';
+import type { RootState } from '../../app/store';
import { useTransientUiStore } from '../../app/transientUiStore';
+// QNBS-v3: featureFlagsActions dispatches setEnableLocalFirstSync to exercise the local-first listener below
import featureFlagsReducer, {
featureFlagsActions,
} from '../../features/featureFlags/featureFlagsSlice';
+import { selectProjectData } from '../../features/project/projectSelectors';
import projectReducer, { projectActions } from '../../features/project/projectSlice';
import settingsReducer, { settingsActions } from '../../features/settings/settingsSlice';
import statusReducer, { statusActions } from '../../features/status/statusSlice';
@@ -56,6 +59,34 @@ vi.mock('../../services/storageBackend', () => ({
saveEnvelopeFromProjectData: (data: unknown) => mockSaveEnvelope(data),
}));
+// QNBS-v3: stub the real Yjs doc/binding/persistence chain so the test asserts selectProjectData's exact payload, not real Yjs behavior.
+const mockSyncFromProject = vi.fn();
+const mockVerify = vi.fn().mockReturnValue({ ok: true, mismatches: [] });
+const mockReproject = vi.fn();
+let lastBindingCtorArg: unknown;
+vi.mock('../../services/localFirst/projectDoc', () => ({
+ createBlankProjectDoc: vi.fn(() => ({})),
+}));
+// QNBS-v3: a class, not a function expression — the real code calls `new ProjectDocBinding(...)`, and Biome's useArrowFunction rule would otherwise rewrite a function expression into a non-constructible arrow function.
+class MockProjectDocBinding {
+ syncFromProject = mockSyncFromProject;
+ verify = mockVerify;
+ reproject = mockReproject;
+ constructor(initial: unknown) {
+ lastBindingCtorArg = initial;
+ }
+}
+vi.mock('../../services/localFirst/docBinding', () => ({
+ ProjectDocBinding: MockProjectDocBinding,
+}));
+vi.mock('../../services/localFirst/docPersistence', () => ({
+ NOOP_PERSISTENCE: { active: false, whenSynced: Promise.resolve() },
+ persistProjectDoc: vi.fn(() => ({ active: true, whenSynced: Promise.resolve() })),
+}));
+vi.mock('../../services/storage/storageEncryptionService', () => ({
+ isIdbEncryptionReady: vi.fn(() => true),
+}));
+
// QNBS-v3: Phase 0 audit — duckdbListenerLoader is lazily imported in listenerMiddleware.
// Mock all loader fns so listener effects complete cleanly in stress tests.
vi.mock('../../services/duckdb/duckdbListenerLoader', () => ({
@@ -454,18 +485,22 @@ describe('analytics privacy opt-out gating', () => {
});
});
+// QNBS-v3: covers canonical selector use during local-first sync — prevents project-data selection regressions
describe('local-first shadow sync (B1.1)', () => {
- it('reads project data via the canonical selector when the flag flips on', async () => {
+ it('passes the canonical selector output straight through to the binding', async () => {
const store = makeFullStore();
+ store.dispatch(projectActions.updateTitle('Local-First Title'));
store.dispatch(featureFlagsActions.setEnableLocalFirstSync(true));
await vi.advanceTimersByTimeAsync(100);
- // getLocalFirstHandle's dynamic imports (Yjs doc/binding/persistence) aren't mocked in this
- // suite; whatever happens next is caught internally and logged as non-critical (see
- // listenerMiddleware.ts's runLocalFirstShadowSync catch block) — this test only needs to prove
- // the selector line runs and the listener doesn't throw out to the store.
- // Real dynamic-imported Yjs doc/binding modules run for real here (not mocked) — a freshly
- // created shadow doc synced from the same present data has nothing to drift against, so a
- // clean run logs neither a warning (self-heal) nor an error.
+
+ // Asserts the actual selector→sync boundary directly (per review feedback) instead of
+ // inferring success from an absence of logger calls: the exact object selectProjectData(state)
+ // returns must be what reaches ProjectDocBinding's constructor and syncFromProject/verify.
+ const presentData = selectProjectData(store.getState() as unknown as RootState);
+ expect(lastBindingCtorArg).toBe(presentData);
+ expect(mockSyncFromProject).toHaveBeenCalledWith(presentData);
+ expect(mockVerify).toHaveBeenCalledWith(presentData);
+ expect(mockReproject).not.toHaveBeenCalled();
expect(mockLoggerWarn).not.toHaveBeenCalled();
expect(mockLoggerError).not.toHaveBeenCalled();
});
diff --git a/tests/unit/providerFactory.test.ts b/tests/unit/providerFactory.test.ts
index 240413c6..e54c08c2 100644
--- a/tests/unit/providerFactory.test.ts
+++ b/tests/unit/providerFactory.test.ts
@@ -63,8 +63,9 @@ describe('providerToKind', () => {
expect(providerToKind('anthropic')).toBe('unsupported');
});
- it('maps grok to unsupported', () => {
- expect(providerToKind('grok')).toBe('unsupported');
+ it('maps grok to its own grok kind (not folded into openaiCompatible)', () => {
+ // QNBS-v3: distinct from Ollama's 'openaiCompatible' default — grok needs a fixed baseURL + a real key.
+ expect(providerToKind('grok')).toBe('grok');
});
});
diff --git a/tests/unit/settings/AiProviderCard.test.tsx b/tests/unit/settings/AiProviderCard.test.tsx
index 9385158a..8a79f5d0 100644
--- a/tests/unit/settings/AiProviderCard.test.tsx
+++ b/tests/unit/settings/AiProviderCard.test.tsx
@@ -7,6 +7,7 @@ import {
scanLocalOpenAiCompatibleEndpoints,
testAIConnection,
} from '../../../services/aiProviderService';
+import { storageService } from '../../../services/storageService';
// ---------------------------------------------------------------------------
// Mocks
@@ -63,6 +64,8 @@ const mockOnAdvancedAiPatch = vi.fn();
const mockOnProviderChange = vi.fn();
const ollamaAdvancedAi = { ...mockAdvancedAi, provider: 'ollama' as const };
+// QNBS-v3: fixture for the grok-provider describe block below.
+const grokAdvancedAi = { ...mockAdvancedAi, provider: 'grok' as const, model: 'grok-3' as const };
function setDesktopRuntime(enabled: boolean): void {
const w = window as Window & { __TAURI_INTERNALS__?: unknown };
@@ -114,9 +117,12 @@ describe('AiProviderCard', () => {
onProviderChange={mockOnProviderChange}
/>,
);
- expect(screen.getByText('Google Gemini')).toBeTruthy();
- expect(screen.getByText('OpenAI')).toBeTruthy();
- expect(screen.getByText('Ollama (lokal)')).toBeTruthy();
+ // QNBS-v3: labels are translation keys now (t mock echoes the key) — was hardcoded literals
+ expect(screen.getByText('settings.ai.provider.gemini')).toBeTruthy();
+ expect(screen.getByText('settings.ai.provider.openai')).toBeTruthy();
+ expect(screen.getByText('settings.ai.provider.ollama')).toBeTruthy();
+ expect(screen.getByText('settings.ai.provider.anthropic')).toBeTruthy();
+ expect(screen.getByText('settings.ai.provider.grok')).toBeTruthy();
});
it('shows description text', () => {
@@ -337,3 +343,43 @@ describe('AiProviderCard — ollama provider (#266)', () => {
expect(screen.queryByText(/something internal broke/)).toBeNull();
});
});
+
+// QNBS-v3: covers the new grok key-input/model-selector UI added in Phase 1 (ADR-0016).
+describe('AiProviderCard — grok provider', () => {
+ afterEach(() => {
+ vi.clearAllMocks();
+ });
+
+ it('renders the API-key input and model selector for grok', async () => {
+ render(
+ ,
+ );
+ expect(screen.getByLabelText('settings.ai.grokKey')).toBeTruthy();
+ // QNBS-v3: the Select renders only the currently-selected option's label when closed, so "Grok 3 Mini" isn't asserted here.
+ await waitFor(() => {
+ expect(screen.getByText('Grok 3')).toBeTruthy();
+ });
+ });
+
+ it('saves the entered key via storageService.saveApiKey("grok", ...)', async () => {
+ const user = userEvent.setup();
+ render(
+ ,
+ );
+ const input = screen.getByLabelText('settings.ai.grokKey');
+ await user.type(input, 'xai-test-key');
+ const saveButton = screen.getByText('settings.ai.save');
+ await user.click(saveButton);
+ await waitFor(() => {
+ expect(storageService.saveApiKey).toHaveBeenCalledWith('grok', 'xai-test-key');
+ });
+ });
+});