From b03980e7f22f802324d4495146e84307449dec28 Mon Sep 17 00:00:00 2001 From: "Soumana.Amadou" Date: Tue, 17 Mar 2026 21:17:45 -0400 Subject: [PATCH] add_ translation --- AGENTS.md | 163 +++++ Docs/kb_1.md | 137 ++++ wren-ui/i18n-extract-report.md | 327 ++++++++++ wren-ui/messages/en.json | 591 ++++++++++++++++++ wren-ui/messages/fr.json | 134 ++++ wren-ui/next.config.js | 5 + wren-ui/package.json | 2 + wren-ui/scripts/extract-i18n.ts | 156 +++++ .../apollo/server/adaptors/wrenAIAdaptor.ts | 24 +- wren-ui/src/apollo/server/config.ts | 6 +- wren-ui/src/components/HeaderBar.tsx | 21 +- wren-ui/src/components/LogoBar.tsx | 20 +- .../src/components/learning/guide/stories.tsx | 6 +- .../src/components/modals/AdjustSQLModal.tsx | 20 +- .../modals/CalculatedFieldModal.tsx | 20 +- .../components/modals/InstructionModal.tsx | 35 +- .../modals/QuestionSQLPairModal.tsx | 39 +- .../src/components/modals/SaveAsViewModal.tsx | 15 +- .../pages/home/promptThread/AnswerResult.tsx | 2 +- .../pages/home/promptThread/ChartAnswer.tsx | 16 +- .../settings/DataSourceSettings.tsx | 20 +- .../components/settings/ProjectSettings.tsx | 23 +- wren-ui/src/components/settings/index.tsx | 2 +- wren-ui/src/components/sidebar/Home.tsx | 4 +- wren-ui/src/components/sidebar/Knowledge.tsx | 6 +- .../components/sidebar/modeling/ModelTree.tsx | 10 +- wren-ui/src/i18n/config.ts | 7 + wren-ui/src/i18n/loadMessages.ts | 23 + wren-ui/src/i18n/navigation.ts | 5 + wren-ui/src/pages/_app.tsx | 65 +- wren-ui/src/pages/_document.tsx | 4 +- .../api/v1/knowledge/instructions/[id].ts | 4 +- .../api/v1/knowledge/instructions/index.ts | 4 +- wren-ui/src/pages/home/[id].tsx | 10 +- wren-ui/src/pages/home/dashboard.tsx | 10 +- wren-ui/src/pages/home/index.tsx | 15 +- wren-ui/src/pages/knowledge/instructions.tsx | 30 +- .../pages/knowledge/question-sql-pairs.tsx | 24 +- wren-ui/src/pages/modeling.tsx | 26 +- wren-ui/src/types/next-intl.d.ts | 8 + wren-ui/yarn.lock | 108 +++- 41 files changed, 1965 insertions(+), 182 deletions(-) create mode 100644 AGENTS.md create mode 100644 Docs/kb_1.md create mode 100644 wren-ui/i18n-extract-report.md create mode 100644 wren-ui/messages/en.json create mode 100644 wren-ui/messages/fr.json create mode 100644 wren-ui/scripts/extract-i18n.ts create mode 100644 wren-ui/src/i18n/config.ts create mode 100644 wren-ui/src/i18n/loadMessages.ts create mode 100644 wren-ui/src/i18n/navigation.ts create mode 100644 wren-ui/src/types/next-intl.d.ts diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000000..6848f1a50d --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,163 @@ +# AGENTS.md + +## Purpose +This file provides operational guidance for agentic coding agents working in this repository. +It captures project architecture, build/lint/test commands, single-test workflows, and style conventions. +Follow these defaults unless the user explicitly asks for a different approach. + +## Repository architecture +- Monorepo root: `/Users/Soumana.Amadou/Desktop/Projects/WrenAI`. +- `wren-ui/`: Next.js + TypeScript service (frontend plus GraphQL/server utilities). +- `wren-ai-service/`: Python service (FastAPI ecosystem, LLM pipelines, eval tooling). +- `wren-launcher/`: Go CLI for launching and dbt-related workflows. +- `wren-mdl/`: model schema artifacts (JSON schema and related metadata). +- `wren-engine/`: engine component (separate service module included in repo). +- `docker/`: docker-compose and config templates for local orchestration. +- `deployment/`: deployment docs/resources. + +## Rule files (Cursor/Copilot) +- Cursor rules directory `.cursor/rules/`: not found. +- Cursor root rules file `.cursorrules`: not found. +- Copilot instructions `.github/copilot-instructions.md`: not found. +- If any of these files are later added, read and obey them before making changes. + +## Global workflow expectations +- Prefer minimal, targeted edits over broad refactors. +- Keep changes scoped to one subproject unless cross-service work is required. +- Use existing scripts/Make targets/Just recipes rather than ad-hoc commands. +- Run lint/tests for touched components before finalizing when feasible. +- Never hardcode secrets or tokens. + +## Build, lint, test commands + +### wren-ui (Next.js + TypeScript) +Working dir: `wren-ui/` +- Install dependencies: `yarn` +- Start dev server: `yarn dev` +- Production build: `yarn build` +- Start built app: `yarn start` +- Lint + typecheck: `yarn lint` +- Typecheck only: `yarn check-types` +- Unit/integration tests: `yarn test` +- E2E tests: `yarn test:e2e` +- DB migrate: `yarn migrate` +- DB rollback: `yarn rollback` +- GraphQL codegen: `yarn generate-gql` + +Run a single Jest test: +- Single test file: `yarn test path/to/file.test.ts` +- By test name: `yarn test path/to/file.test.ts -t "name fragment"` +- By pattern: `yarn test --testPathPattern=someFeature` + +### wren-launcher (Go) +Working dir: `wren-launcher/` +- Build all binaries: `make build` +- Clean artifacts: `make clean` +- Rebuild: `make rebuild` +- Format: `make fmt` +- Import formatting: `make imports` +- Static checks: `make vet` +- Lint: `make lint` +- Lint with fixes: `make lint-fix` +- Combined checks: `make check` +- Run all tests: `make test` + +Run a single Go test: +- Single package: `go test ./commands/dbt` +- Single test func regex: `go test -run TestDataSource ./commands/dbt` +- Verbose single package: `go test -v ./path/to/package` + +### wren-ai-service (Python) +Working dir: `wren-ai-service/` +- Install deps: `poetry install` +- Initialize local files: `just init` +- Start service: `just start` +- Start dev stack: `just up` +- Stop dev stack: `just down` +- Run tests via Justfile: `just test` +- Run pytest directly: `poetry run pytest` +- Run usecase tests: `just test-usecases usecases='all' lang='en'` + +Run a single pytest test: +- Single file: `poetry run pytest tests/path/test_file.py -q` +- Single test node: `poetry run pytest tests/path/test_file.py::test_name -q` +- Keyword match: `poetry run pytest -k "name_fragment" -q` + +## Formatting and linting standards + +### Shared basics +- Follow `.editorconfig` defaults: UTF-8, spaces, final newline, trim trailing whitespace. +- Markdown files may keep trailing whitespace disabled and no max line length. +- Makefiles require tab indentation. + +### TypeScript/JavaScript style (wren-ui) +- Formatter: Prettier (`.prettierrc` sets `singleQuote: true`). +- Linter: ESLint (`next/core-web-vitals`, `@typescript-eslint/recommended`, `prettier`). +- Unused vars: underscore-prefixed names are allowed for intentional non-use. +- `any` is permitted by lint config, but prefer specific types where practical. +- Non-null assertions are allowed but should be rare and justified. +- TypeScript `strict` is currently `false`; still write defensively typed code. + +Import conventions: +- Keep imports grouped logically: external packages, aliases/internal modules, relative imports. +- Remove unused imports. +- Prefer stable alias paths (`@/`, `@server`) over deep relative traversal when available. + +Naming conventions: +- Variables/functions: `camelCase`. +- React components/types/interfaces/enums: `PascalCase`. +- Constants: `UPPER_SNAKE_CASE` for true constants. +- Test files: align with existing patterns (`*.test.ts`, `*.test.tsx`). + +### Go style (wren-launcher) +- Formatting is mandatory through `go fmt`. +- Import order managed by `goimports`. +- Lint policy enforced via `.golangci.yml` with linters including: + `errcheck`, `govet`, `ineffassign`, `staticcheck`, `unused`, `misspell`, + `unconvert`, `gosec`, `dupl`, `goconst`, `gocyclo`, `bodyclose`, `whitespace`. +- Keep functions focused; extract helpers when cyclomatic complexity grows. + +Naming conventions: +- Exported identifiers: `PascalCase`. +- Unexported identifiers: `camelCase`. +- Package names: short, lowercase, no underscores. + +### Python style (wren-ai-service) +- Ruff config in `ruff.toml` controls lint + formatting behavior. +- Line length: 88, spaces for indentation, double quotes preferred by formatter. +- Import sorting rule `I001` is enabled; keep imports sorted and grouped. +- Target version in Ruff is `py38`, while project runtime in Poetry is Python 3.12. + Keep syntax compatible with the project runtime and existing codebase patterns. + +Naming conventions: +- Functions/variables/modules: `snake_case`. +- Classes: `PascalCase`. +- Constants: `UPPER_SNAKE_CASE`. + +## Error handling guidelines +- Do not swallow errors silently. +- Add context to errors before returning/raising. +- Prefer explicit, typed/domain exceptions over generic catch-all blocks. +- In Go, check returned `error` immediately and wrap with context. +- In TypeScript/Python, fail fast on invalid external input and surface actionable messages. +- Log useful diagnostic details without leaking secrets. + +## Testing guidance +- Add or update tests for behavior changes and bug fixes. +- Keep tests deterministic and isolated; avoid time/network dependence unless intentional. +- Prefer focused single-test runs during iteration, then run broader suites before handoff. +- For wren-ui, include UI behavior assertions rather than implementation details. +- For wren-launcher and Python, verify error-path tests when touching error handling. + +## Security and config guidance +- Never commit API keys, passwords, or tokens. +- Use env vars and existing config templates (`docker/.env.example`, `docker/config.example.yaml`). +- Validate and sanitize untrusted input, especially around SQL, shell, and file paths. +- Prefer least-privilege defaults for service integrations. + +## Agent delivery checklist +- Confirm changed files belong to the intended subproject(s). +- Run formatter/linter for touched language(s). +- Run at least targeted tests (single test or package) related to the change. +- Summarize what was run and any skipped checks in the final handoff. +- If commands fail due to environment limits, report exact failure and suggested next command. diff --git a/Docs/kb_1.md b/Docs/kb_1.md new file mode 100644 index 0000000000..912e480c59 --- /dev/null +++ b/Docs/kb_1.md @@ -0,0 +1,137 @@ +Great request. I audited your current wren-ui and here’s the most practical i18n rollout plan for 2026 App Router standards using next-intl with strong type safety and RSC-first patterns. +Audit Findings +- You are currently on the Pages Router (wren-ui/src/pages/...), not App Router. +- Existing dynamic route needing localization support: wren-ui/src/pages/home/[id].tsx. +- Metadata/localization gaps: + - Global title hardcoded in wren-ui/src/pages/_app.tsx:19 (Wren AI). + - No locale-aware in wren-ui/src/pages/_document.tsx:34. +- High-impact hardcoded UI strings in shared components: + - wren-ui/src/components/HeaderBar.tsx:56 (Home, Modeling, Knowledge, API) + - wren-ui/src/components/sidebar/Home.tsx:81 (Dashboard) + - wren-ui/src/components/sidebar/Knowledge.tsx:35 (Question-SQL pairs, Instructions) + - wren-ui/src/pages/home/index.tsx:31 (Know more about your data) +- High volume of localized notifications needed: + - wren-ui/src/pages/modeling.tsx:99+ + - wren-ui/src/pages/knowledge/question-sql-pairs.tsx:52+ + - wren-ui/src/pages/home/[id].tsx:91+ +- Routing currently depends on static enum paths in wren-ui/src/utils/enum/path.ts:1, which must become locale-aware. +--- +Target Architecture (Recommended) +Use App Router + locale segment + route groups: +wren-ui/src/ + app/ + [locale]/ + (marketing)/ + page.tsx + (dashboard)/ + home/ + page.tsx + [id]/ + page.tsx + dashboard/ + page.tsx + modeling/ + page.tsx + knowledge/ + question-sql-pairs/ + page.tsx + instructions/ + page.tsx + api-management/ + history/ + page.tsx + layout.tsx + not-found.tsx + i18n/ + routing.ts + navigation.ts + request.ts + messages/ + en.json + fr.json +Why this works well: +- [locale] enables locale-prefixed URLs and per-locale metadata. +- Route groups let you keep shared app shell (HeaderBar, sidebar layout) without duplicating layout logic. +- Keeps pages/api as-is during migration (safe hybrid migration path). +--- +Phase 1 — Core i18n Foundation +1. Install next-intl and configure plugin in next.config.js. +2. Add wren-ui/src/i18n/routing.ts with: + - locales, defaultLocale, optional localePrefix. + - pathnames mapping for localized slugs (SEO-safe). +3. Add wren-ui/src/i18n/request.ts for server-side message loading. +4. Add middleware (wren-ui/src/middleware.ts) for locale detection: + - Detect from path → cookie → Accept-Language. + - Exclude _next, api, static assets in matcher. +5. Add wren-ui/src/app/[locale]/layout.tsx: + - + - NextIntlClientProvider with server-fetched messages. +6. Type-safe keys (strict): + - Create global.d.ts module augmentation for next-intl with Messages from messages/en.json. + - This gives compile-time key checking for t('...'). +--- +Phase 2 — Localized Navigation + SEO +1. Replace next/link and next/router usage with next-intl/navigation wrappers. +2. Create wren-ui/src/i18n/navigation.ts via createNavigation(routing) and export: + - Link, useRouter, usePathname, redirect, getPathname. +3. Replace path enum usage gradually: + - Keep internal route IDs/constants. + - Resolve localized pathname via typed getPathname. +4. SEO requirements: + - In each route’s generateMetadata, output: + - localized title/description + - alternates.languages for all supported locales + - Keep canonical per locale. +5. Keep dynamic IDs untranslated (/en/home/123, /fr/accueil/123 if localized segment mapping enabled). +--- +Phase 3 — Component Conversion Examples (RSC-first) +Server Component example (preferred for bundle size): +// src/app/[locale]/(dashboard)/home/page.tsx +import {getTranslations} from 'next-intl/server'; +export default async function HomePage() { + const t = await getTranslations('Home'); + return

{t('title')}

; +} +Client Component example: +'use client'; +import {useTranslations} from 'next-intl'; +export function HeaderNav() { + const t = useTranslations('Nav'); + return ( + <> + + + + + ); +} +Migration rule: +- Prefer getTranslations in RSC pages/layouts. +- Only use useTranslations in interactive client components. +- For notifications (message.success), pass translated strings from parent/server when possible, or use client hook if truly client-only. +--- +Phase 4 — Automation for Existing Strings +Use a two-step codemod pipeline: +1. Extract strings (AST script with ts-morph or Babel): + - Scan .tsx/.ts. + - Capture JSX text nodes, string literals in UI props (title, label, placeholder) and toast messages. + - Ignore technical strings (URLs, class names, GraphQL names, route constants). + - Output to messages/en.json with namespaced keys (e.g., Header.nav.home). +2. Optional transform pass: + - Replace extracted literals with t('...'). + - Insert useTranslations('Namespace') or getTranslations('Namespace') depending on component type. + - Mark low-confidence replacements for manual review. +Recommended script outputs: +- messages/en.json +- i18n-extract-report.md (file, line, key, confidence) +- i18n-todo.csv for unresolved strings +--- +Important Notes for Your Current Codebase +- Because you’re on Pages Router, do a staged migration: + 1) Introduce App Router + i18n scaffold, + 2) Move shared shell (HeaderBar, sidebar layout), + 3) Migrate high-traffic pages (home, modeling, knowledge), + 4) Remove old Pages routes when parity is done. +- Keep pages/api/* unchanged until you intentionally migrate API handlers. +--- +If you want, I can next produce a concrete file-by-file migration checklist for your exact routes (/home, /home/[id], /modeling, /knowledge/*, /api-management/history) with estimated effort and risk per file \ No newline at end of file diff --git a/wren-ui/i18n-extract-report.md b/wren-ui/i18n-extract-report.md new file mode 100644 index 0000000000..897bdbca12 --- /dev/null +++ b/wren-ui/i18n-extract-report.md @@ -0,0 +1,327 @@ +# i18n extraction report + +Found 286 entries + +| key | value | location | +| --- | --- | --- | +| `toast.ibisadaptorts.model_not_found` | Model not found | `src/apollo/server/adaptors/ibisAdaptor.ts:606` | +| `toast.ibisadaptorts.sqlparserparsingexception` | sql.parser.ParsingException | `src/apollo/server/adaptors/ibisAdaptor.ts:609` | +| `toast.ibisadaptorts.` | : | `src/apollo/server/adaptors/ibisAdaptor.ts:613` | +| `auto.ellipsiswrappertsx.` | ... | `src/components/EllipsisWrapper.tsx:87` | +| `auto.ellipsiswrappertsx.more` | more | `src/components/EllipsisWrapper.tsx:87` | +| `auto.pageloadingtsx.loading` | Loading... | `src/components/PageLoading.tsx:51` | +| `auto.indextsx.no_available_data` | No available data | `src/components/chart/index.tsx:128` | +| `auto.indextsx.there_are_too_many_categories_to_display` | There are too many categories to display effectively. Click + 'Show top 25' to view the top results, or ask a follow-up + question to focus on a specific group or filter results. | `src/components/chart/index.tsx:155` | +| `auto.indextsx.show_top_25` | Show top 25 | `src/components/chart/index.tsx:164` | +| `auto.deploytsx.deploying` | Deploying... | `src/components/deploy/Deploy.tsx:20` | +| `auto.deploytsx.synced` | Synced | `src/components/deploy/Deploy.tsx:26` | +| `auto.deploytsx.undeployed_changes` | Undeployed changes | `src/components/deploy/Deploy.tsx:32` | +| `toast.deploytsx.failed_to_deploy_please_check_the_log_fo` | Failed to deploy. Please check the log for more details. | `src/components/deploy/Deploy.tsx:50` | +| `auto.deploytsx.deploy` | Deploy | `src/components/deploy/Deploy.tsx:92` | +| `auto.customdropdowntsx.update_columns` | Update Columns | `src/components/diagram/CustomDropdown.tsx:69` | +| `auto.customdropdowntsx.edit` | Edit | `src/components/diagram/CustomDropdown.tsx:118` | +| `auto.customdropdowntsx.cache_settings` | Cache settings | `src/components/diagram/CustomDropdown.tsx:144` | +| `auto.customdropdowntsx.show_categories` | Show categories | `src/components/diagram/CustomDropdown.tsx:171` | +| `auto.customdropdowntsx.hide_categories` | Hide categories | `src/components/diagram/CustomDropdown.tsx:176` | +| `auto.customdropdowntsx.view` | View | `src/components/diagram/CustomDropdown.tsx:218` | +| `auto.columntsx.and` | and | `src/components/diagram/customNode/Column.tsx:96` | +| `auto.columntsx.more` | more | `src/components/diagram/customNode/Column.tsx:96` | +| `auto.modelnodetsx.columns` | Columns | `src/components/diagram/customNode/ModelNode.tsx:90` | +| `auto.modelnodetsx.calculated_fields` | Calculated Fields | `src/components/diagram/customNode/ModelNode.tsx:102` | +| `auto.modelnodetsx.relationships` | Relationships | `src/components/diagram/customNode/ModelNode.tsx:115` | +| `auto.utilstsx.cached` | Cached | `src/components/diagram/customNode/utils.tsx:101` | +| `auto.markdowneditortsx.` | ( | `src/components/editor/MarkdownEditor.tsx:86` | +| `auto.markdowneditortsx.characters` | characters | `src/components/editor/MarkdownEditor.tsx:215` | +| `auto.storiestsx.data_modeling_guide` | Data modeling guide | `src/components/learning/guide/stories.tsx:95` | +| `auto.storiestsx.data_modeling_adds_a_logical_layer_over_` | Data modeling adds a logical layer over your original data schema, + organizing relationships, semantics, and calculations. This helps AI + align with business logic, retrieve precise data, and generate + meaningful insights. | `src/components/learning/guide/stories.tsx:100` | +| `auto.storiestsx.more_details` | More details | `src/components/learning/guide/stories.tsx:109` | +| `auto.storiestsx.we_use` | We use | `src/components/learning/guide/stories.tsx:115` | +| `auto.storiestsx.dataset_to_present_the_guide_to_know_mor` | Dataset to present the guide. + To know more, please visit | `src/components/learning/guide/stories.tsx:115` | +| `auto.storiestsx.about_the` | about the | `src/components/learning/guide/stories.tsx:122` | +| `auto.storiestsx.dataset` | Dataset. | `src/components/learning/guide/stories.tsx:122` | +| `auto.storiestsx.create_a_model` | Create a model | `src/components/learning/guide/stories.tsx:146` | +| `auto.storiestsx.click_the_add_icon_to_start_create_your_` | Click the add icon to start create your first model. | `src/components/learning/guide/stories.tsx:150` | +| `auto.storiestsx.edit_a_model` | Edit a model | `src/components/learning/guide/stories.tsx:166` | +| `auto.storiestsx.click_the_more_icon_to_update_the_column` | Click the more icon to update the columns of model or delete it. | `src/components/learning/guide/stories.tsx:170` | +| `auto.storiestsx.edit_metadata` | Edit metadata | `src/components/learning/guide/stories.tsx:186` | +| `auto.storiestsx.you_could_edit_alias_alternative_name_an` | You could edit alias (alternative name) and descriptions of models + and columns. | `src/components/learning/guide/stories.tsx:191` | +| `auto.storiestsx.deploy_modeling` | Deploy modeling | `src/components/learning/guide/stories.tsx:212` | +| `auto.storiestsx.after_editing_the_models_remember_to_dep` | After editing the models, remember to deploy the changes. | `src/components/learning/guide/stories.tsx:216` | +| `auto.storiestsx.ask_questions` | Ask questions | `src/components/learning/guide/stories.tsx:231` | +| `auto.storiestsx.when_you_finish_editing_your_models_you_` | When you finish editing your models, you can visit “Home” and start + asking questions. | `src/components/learning/guide/stories.tsx:236` | +| `auto.storiestsx.project_language` | Project language | `src/components/learning/guide/stories.tsx:268` | +| `auto.storiestsx.switch_the_language` | Switch the language | `src/components/learning/guide/stories.tsx:303` | +| `auto.storiestsx.choose_your_preferred_language_once_set_` | Choose your preferred language. Once set up, AI will respond in your + chosen language. | `src/components/learning/guide/stories.tsx:308` | +| `auto.storiestsx.you_can_go_to_project_settings_to_change` | You can go to project settings to change it if you change your mind. | `src/components/learning/guide/stories.tsx:313` | +| `auto.storiestsx.build_knowledge_base_questionsql_pairs` | Build knowledge base: Question-SQL pairs | `src/components/learning/guide/stories.tsx:395` | +| `auto.storiestsx.create_and_manage` | Create and manage | `src/components/learning/guide/stories.tsx:400` | +| `auto.storiestsx.questionsql_pairs` | Question-SQL pairs | `src/components/learning/guide/stories.tsx:400` | +| `auto.storiestsx.to_refine_wren_ais_sql_generation_you_ca` | to refine Wren AI’s SQL + generation. You can manually add pairs here or go to Home, ask a + question, and save the correct answer to Knowledge. The more you + save, the smarter Wren AI becomes! | `src/components/learning/guide/stories.tsx:400` | +| `auto.storiestsx.build_knowledge_base_instructions` | Build knowledge base: Instructions | `src/components/learning/guide/stories.tsx:423` | +| `auto.storiestsx.in_addition_to_questionsql_pairs_you_can` | In addition to Question-SQL pairs, you can create instructions to + define | `src/components/learning/guide/stories.tsx:428` | +| `auto.storiestsx.business_rules` | business rules | `src/components/learning/guide/stories.tsx:429` | +| `auto.storiestsx.and` | and | `src/components/learning/guide/stories.tsx:429` | +| `auto.storiestsx.query_logic` | query logic | `src/components/learning/guide/stories.tsx:429` | +| `auto.storiestsx.these_rules_guide_wren_ai_in_applying_co` | . These rules + guide Wren AI in applying consistent filters, constraints, and best + practices to SQL queries. | `src/components/learning/guide/stories.tsx:429` | +| `auto.storiestsx.save_to_knowledge` | Save to knowledge | `src/components/learning/guide/stories.tsx:480` | +| `auto.storiestsx.if_the_aigenerated_answer_is_correct_sav` | If the AI-generated answer is correct, save it as a | `src/components/learning/guide/stories.tsx:485` | +| `auto.storiestsx.questionsql_pair` | Question-SQL pair | `src/components/learning/guide/stories.tsx:486` | +| `auto.storiestsx.to_improve_ai_learning_if_its_incorrect_` | to improve AI learning. If it's incorrect, + refine it with follow-ups before saving to ensure accuracy. | `src/components/learning/guide/stories.tsx:486` | +| `auto.indextsx.learning` | Learning | `src/components/learning/index.tsx:340` | +| `auto.indextsx.finished` | Finished | `src/components/learning/index.tsx:352` | +| `auto.adjustreasoningstepsmodaltsx.select_the_tables_needed_to_answer_your_` | Select the tables needed to answer your question. | `src/components/modals/AdjustReasoningStepsModal.tsx:141` | +| `auto.adjustreasoningstepsmodaltsx.tables_not_selected_wont_be_used_in_sql_` | Tables not selected won't be used in SQL generation. | `src/components/modals/AdjustReasoningStepsModal.tsx:143` | +| `auto.adjustreasoningstepsmodaltsx.protip_use_to_choose_model_in_the_textar` | Protip: Use @ to choose model in the textarea. | `src/components/modals/AdjustReasoningStepsModal.tsx:161` | +| `auto.adjustreasoningstepsmodaltsx.edit_the_reasoning_logic_below_each_step` | Edit the reasoning logic below. Each step should build toward + answering the question accurately. | `src/components/modals/AdjustReasoningStepsModal.tsx:166` | +| `auto.adjustsqlmodaltsx.the_sql_statement_used_here_follows` | The SQL statement used here follows | `src/components/modals/AdjustSQLModal.tsx:147` | +| `auto.adjustsqlmodaltsx.wren_sql` | Wren SQL | `src/components/modals/AdjustSQLModal.tsx:147` | +| `auto.adjustsqlmodaltsx.which_is` | , which is | `src/components/modals/AdjustSQLModal.tsx:147` | +| `auto.deletemodaltsx.delete` | Delete | `src/components/modals/DeleteModal.tsx:54` | +| `auto.fixsqlmodaltsx.the_following_sql_statement_needs_to_be_` | The following SQL statement needs to be fixed: | `src/components/modals/FixSQLModal.tsx:89` | +| `auto.fixsqlmodaltsx.data_preview_50_rows` | Data preview (50 rows) | `src/components/modals/FixSQLModal.tsx:108` | +| `auto.fixsqlmodaltsx.preview_data` | Preview data | `src/components/modals/FixSQLModal.tsx:115` | +| `auto.instructionmodaltsx.choose_whether_this_instruction_applies_` | Choose whether this instruction applies to | `src/components/modals/InstructionModal.tsx:103` | +| `auto.instructionmodaltsx.` | . | `src/components/modals/InstructionModal.tsx:109` | +| `auto.questionsqlpairmodaltsx.` | , | `src/components/modals/QuestionSQLPairModal.tsx:224` | +| `auto.schemachangemodaltsx.calculated_field` | Calculated Field | `src/components/modals/SchemaChangeModal.tsx:79` | +| `auto.schemachangemodaltsx.relationship` | Relationship | `src/components/modals/SchemaChangeModal.tsx:83` | +| `auto.schemachangemodaltsx.tables_affected` | table(s) affected | `src/components/modals/SchemaChangeModal.tsx:114` | +| `auto.schemachangemodaltsx.resolve` | Resolve | `src/components/modals/SchemaChangeModal.tsx:133` | +| `auto.schemachangemodaltsx.schema_changes` | Schema Changes | `src/components/modals/SchemaChangeModal.tsx:275` | +| `auto.schemachangemodaltsx.we_have_detected_schema_changes_from_you` | We have detected schema changes from your connected data source. Please + review the impacts of these changes. | `src/components/modals/SchemaChangeModal.tsx:285` | +| `auto.detailsdrawertsx.api_type` | API type | `src/components/pages/apiManagement/DetailsDrawer.tsx:53` | +| `auto.detailsdrawertsx.thread_id` | Thread ID | `src/components/pages/apiManagement/DetailsDrawer.tsx:61` | +| `auto.detailsdrawertsx.created_at` | Created at | `src/components/pages/apiManagement/DetailsDrawer.tsx:69` | +| `auto.detailsdrawertsx.duration` | Duration | `src/components/pages/apiManagement/DetailsDrawer.tsx:75` | +| `auto.detailsdrawertsx.ms` | ms | `src/components/pages/apiManagement/DetailsDrawer.tsx:77` | +| `auto.detailsdrawertsx.status_code` | Status code | `src/components/pages/apiManagement/DetailsDrawer.tsx:83` | +| `auto.detailsdrawertsx.headers` | Headers | `src/components/pages/apiManagement/DetailsDrawer.tsx:91` | +| `auto.detailsdrawertsx.request_payload` | Request payload | `src/components/pages/apiManagement/DetailsDrawer.tsx:103` | +| `auto.detailsdrawertsx.response_payload` | Response payload | `src/components/pages/apiManagement/DetailsDrawer.tsx:115` | +| `auto.recommendedquestionstsx.recommended_questions` | Recommended questions | `src/components/pages/home/RecommendedQuestions.tsx:95` | +| `auto.cachesettingsdrawertsx.cancel` | Cancel | `src/components/pages/home/dashboardGrid/CacheSettingsDrawer.tsx:258` | +| `auto.cachesettingsdrawertsx.submit` | Submit | `src/components/pages/home/dashboardGrid/CacheSettingsDrawer.tsx:266` | +| `auto.cachesettingsdrawertsx.refresh_settings` | Refresh settings | `src/components/pages/home/dashboardGrid/CacheSettingsDrawer.tsx:303` | +| `auto.cachesettingsdrawertsx.next_scheduled_refresh` | Next scheduled refresh: | `src/components/pages/home/dashboardGrid/CacheSettingsDrawer.tsx:331` | +| `auto.cachesettingsdrawertsx.` | ( | `src/components/pages/home/dashboardGrid/CacheSettingsDrawer.tsx:333` | +| `auto.dashboardheadertsx.next_schedule` | Next schedule: | `src/components/pages/home/dashboardGrid/DashboardHeader.tsx:63` | +| `auto.dashboardheadertsx.cron_expression` | Cron expression: | `src/components/pages/home/dashboardGrid/DashboardHeader.tsx:68` | +| `auto.emptydashboardtsx.no_charts_have_been_added_yet` | No charts have been added yet | `src/components/pages/home/dashboardGrid/EmptyDashboard.tsx:49` | +| `auto.emptydashboardtsx.follow_these_steps_to_pin_charts_to_your` | Follow these steps to pin charts to your dashboard. | `src/components/pages/home/dashboardGrid/EmptyDashboard.tsx:52` | +| `auto.emptydashboardtsx.learn_more` | Learn more | `src/components/pages/home/dashboardGrid/EmptyDashboard.tsx:59` | +| `auto.indextsx.last_refreshed` | Last refreshed: | `src/components/pages/home/dashboardGrid/index.tsx:394` | +| `auto.errorboundarytsx.fix_it` | Fix it | `src/components/pages/home/preparation/ErrorBoundary.tsx:47` | +| `auto.preparationstatustsx.cancel` | Cancel | `src/components/pages/home/preparation/PreparationStatus.tsx:52` | +| `auto.preparationstatustsx.cancelled_by_user` | Cancelled by user | `src/components/pages/home/preparation/PreparationStatus.tsx:58` | +| `auto.preparationstatustsx.rerun` | Re-run | `src/components/pages/home/preparation/PreparationStatus.tsx:67` | +| `auto.indextsx.answer_preparation_steps` | Answer preparation steps | `src/components/pages/home/preparation/index.tsx:96` | +| `auto.fixedsqlfinishedtsx.userprovided_sql_applied` | User-Provided SQL applied | `src/components/pages/home/preparation/step/FixedSQLFinished.tsx:7` | +| `auto.fixedsqlfinishedtsx.system_encountered_an_issue_generating_s` | System encountered an issue generating SQL. The manually submitted query + is now being processed. | `src/components/pages/home/preparation/step/FixedSQLFinished.tsx:10` | +| `auto.generatingtsx.generating_sql_statement` | Generating SQL statement | `src/components/pages/home/preparation/step/Generating.tsx:16` | +| `auto.generatingtsx.successfully_generated_sql_statement` | Successfully generated SQL statement | `src/components/pages/home/preparation/step/Generating.tsx:26` | +| `auto.generatingtsx.wrapping_up` | Wrapping up | `src/components/pages/home/preparation/step/Generating.tsx:29` | +| `auto.organizingtsx.thinking` | Thinking | `src/components/pages/home/preparation/step/Organizing.tsx:48` | +| `auto.retrievingtsx.models_applied` | models applied | `src/components/pages/home/preparation/step/Retrieving.tsx:27` | +| `auto.retrievingtsx.top` | Top | `src/components/pages/home/preparation/step/Retrieving.tsx:29` | +| `auto.retrievingtsx.model_candidates_identified` | model candidates identified | `src/components/pages/home/preparation/step/Retrieving.tsx:29` | +| `auto.retrievingtsx.searching` | Searching | `src/components/pages/home/preparation/step/Retrieving.tsx:38` | +| `auto.sqlpairfinishedtsx.using_questionsql_pair` | Using question-SQL pair | `src/components/pages/home/preparation/step/SQLPairFinished.tsx:7` | +| `auto.sqlpairfinishedtsx.matching_questionsql_pair_found_returnin` | Matching question-SQL pair found. Returning results instantly. | `src/components/pages/home/preparation/step/SQLPairFinished.tsx:11` | +| `auto.viewfinishedtsx.using_presaved_view` | Using pre-saved view | `src/components/pages/home/preparation/step/ViewFinished.tsx:6` | +| `auto.viewfinishedtsx.matching_saved_view_found_returning_resu` | Matching saved view found. Returning results instantly. | `src/components/pages/home/preparation/step/ViewFinished.tsx:8` | +| `auto.demoprompttsx.try_asking` | Try asking... | `src/components/pages/home/prompt/DemoPrompt.tsx:42` | +| `auto.inputtsx.ask` | Ask | `src/components/pages/home/prompt/Input.tsx:76` | +| `auto.recommendedquestionsprompttsx.know_more_about_your_data` | Know more about your data. | `src/components/pages/home/prompt/RecommendedQuestionsPrompt.tsx:120` | +| `auto.recommendedquestionsprompttsx.try_asking_some_of_the_following_questio` | Try asking some of the following questions | `src/components/pages/home/prompt/RecommendedQuestionsPrompt.tsx:123` | +| `auto.resulttsx.stop` | Stop | `src/components/pages/home/prompt/Result.tsx:96` | +| `auto.resulttsx.close` | Close | `src/components/pages/home/prompt/Result.tsx:128` | +| `auto.resulttsx.user_intent_recognized` | User Intent Recognized | `src/components/pages/home/prompt/Result.tsx:219` | +| `auto.resulttsx.for_the_most_accurate_semantics_please_v` | For the most accurate semantics, please visit the modeling page. | `src/components/pages/home/prompt/Result.tsx:233` | +| `auto.answerresulttsx.store_this_answer_as_a_questionsql_pair_` | Store this answer as a Question-SQL pair to help Wren AI improve SQL + generation. | `src/components/pages/home/promptThread/AnswerResult.tsx:44` | +| `auto.answerresulttsx.learn_more` | Learn more | `src/components/pages/home/promptThread/AnswerResult.tsx:53` | +| `auto.answerresulttsx.adjusted_answer` | Adjusted answer | `src/components/pages/home/promptThread/AnswerResult.tsx:168` | +| `auto.answerresulttsx.answer` | Answer | `src/components/pages/home/promptThread/AnswerResult.tsx:304` | +| `auto.answerresulttsx.view_sql` | View SQL | `src/components/pages/home/promptThread/AnswerResult.tsx:316` | +| `auto.answerresulttsx.chart` | Chart | `src/components/pages/home/promptThread/AnswerResult.tsx:328` | +| `auto.answerresulttsx.beta` | Beta | `src/components/pages/home/promptThread/AnswerResult.tsx:328` | +| `auto.answerresulttsx.save_to_knowledge` | Save to knowledge | `src/components/pages/home/promptThread/AnswerResult.tsx:359` | +| `auto.textbasedanswertsx.adjust_the_answer` | Adjust the answer | `src/components/pages/home/promptThread/TextBasedAnswer.tsx:176` | +| `auto.textbasedanswertsx.regenerate` | Regenerate | `src/components/pages/home/promptThread/TextBasedAnswer.tsx:222` | +| `auto.textbasedanswertsx.view_results` | View results | `src/components/pages/home/promptThread/TextBasedAnswer.tsx:243` | +| `auto.textbasedanswertsx.considering_the_limit_of_the_context_win` | Considering the limit of the context window, we retrieve up to + 500 rows of results to generate the answer. | `src/components/pages/home/promptThread/TextBasedAnswer.tsx:249` | +| `auto.textbasedanswertsx.click` | Click | `src/components/pages/home/promptThread/TextBasedAnswer.tsx:266` | +| `auto.textbasedanswertsx.view_sql` | View SQL | `src/components/pages/home/promptThread/TextBasedAnswer.tsx:266` | +| `auto.textbasedanswertsx.to_review_the_stepbystep_query_logic_and` | to review the step-by-step query logic + and verify why the data is unavailable. | `src/components/pages/home/promptThread/TextBasedAnswer.tsx:266` | +| `auto.viewblocktsx.generated_from_saved_view` | Generated from saved view | `src/components/pages/home/promptThread/ViewBlock.tsx:20` | +| `auto.viewblocktsx.save_as_view` | Save as View | `src/components/pages/home/promptThread/ViewBlock.tsx:41` | +| `auto.viewsqltabcontenttsx.you_copied_wren_sql_this_dialect_is_for_` | You copied Wren SQL. This dialect is for the Wren Engine and may not + run directly on your database. | `src/components/pages/home/promptThread/ViewSQLTabContent.tsx:95` | +| `auto.viewsqltabcontenttsx.click` | Click “ | `src/components/pages/home/promptThread/ViewSQLTabContent.tsx:100` | +| `auto.viewsqltabcontenttsx.show_original_sql` | Show original SQL | `src/components/pages/home/promptThread/ViewSQLTabContent.tsx:100` | +| `auto.viewsqltabcontenttsx.to_get_the_executable_version` | ” to get the executable version. | `src/components/pages/home/promptThread/ViewSQLTabContent.tsx:100` | +| `auto.viewsqltabcontenttsx.youre_viewing_wren_sql_by_default_if_you` | You’re viewing Wren SQL by default. If you want to run this query on + your own database, click “Show original SQL” to get the exact + syntax. | `src/components/pages/home/promptThread/ViewSQLTabContent.tsx:115` | +| `auto.viewsqltabcontenttsx.learn_more_about_wren_sql` | Learn more about Wren SQL | `src/components/pages/home/promptThread/ViewSQLTabContent.tsx:124` | +| `auto.viewsqltabcontenttsx.wren_sql` | Wren SQL | `src/components/pages/home/promptThread/ViewSQLTabContent.tsx:149` | +| `auto.viewsqltabcontenttsx.adjust_sql` | Adjust SQL | `src/components/pages/home/promptThread/ViewSQLTabContent.tsx:182` | +| `auto.viewsqltabcontenttsx.view_results` | View results | `src/components/pages/home/promptThread/ViewSQLTabContent.tsx:211` | +| `auto.viewsqltabcontenttsx.showing_up_to_500_rows` | Showing up to 500 rows | `src/components/pages/home/promptThread/ViewSQLTabContent.tsx:229` | +| `auto.globallabeltsx.global` | Global | `src/components/pages/knowledge/GlobalLabel.tsx:10` | +| `auto.instructiondrawertsx.instruction_details` | Instruction details | `src/components/pages/knowledge/InstructionDrawer.tsx:26` | +| `auto.instructiondrawertsx.matching_questions` | Matching questions | `src/components/pages/knowledge/InstructionDrawer.tsx:32` | +| `auto.instructiondrawertsx.applies_to_all_questions` | (applies to all questions) | `src/components/pages/knowledge/InstructionDrawer.tsx:39` | +| `auto.instructiondrawertsx.created_time` | Created time | `src/components/pages/knowledge/InstructionDrawer.tsx:55` | +| `auto.sqlpairdrawertsx.question` | Question | `src/components/pages/knowledge/SQLPairDrawer.tsx:22` | +| `auto.sqlpairdrawertsx.sql_statement` | SQL statement | `src/components/pages/knowledge/SQLPairDrawer.tsx:26` | +| `auto.sqlpairdrawertsx.created_time` | Created time | `src/components/pages/knowledge/SQLPairDrawer.tsx:34` | +| `auto.metadatadrawertsx.edit` | Edit | `src/components/pages/modeling/MetadataDrawer.tsx:38` | +| `auto.modeldrawertsx.cancel` | Cancel | `src/components/pages/modeling/ModelDrawer.tsx:49` | +| `auto.modeldrawertsx.submit` | Submit | `src/components/pages/modeling/ModelDrawer.tsx:57` | +| `auto.editbasicmetadatatsx.name` | Name | `src/components/pages/modeling/metadata/EditBasicMetadata.tsx:45` | +| `auto.editbasicmetadatatsx.alias` | Alias | `src/components/pages/modeling/metadata/EditBasicMetadata.tsx:53` | +| `auto.editbasicmetadatatsx.description` | Description | `src/components/pages/modeling/metadata/EditBasicMetadata.tsx:85` | +| `auto.editmodelmetadatatsx.columns` | Columns ( | `src/components/pages/modeling/metadata/EditModelMetadata.tsx:88` | +| `auto.editmodelmetadatatsx.` | ) | `src/components/pages/modeling/metadata/EditModelMetadata.tsx:88` | +| `auto.editmodelmetadatatsx.calculated_fields` | Calculated fields ( | `src/components/pages/modeling/metadata/EditModelMetadata.tsx:123` | +| `auto.editmodelmetadatatsx.relationships` | Relationships ( | `src/components/pages/modeling/metadata/EditModelMetadata.tsx:140` | +| `auto.editviewmetadatatsx.columns` | Columns ( | `src/components/pages/modeling/metadata/EditViewMetadata.tsx:85` | +| `auto.editviewmetadatatsx.` | ) | `src/components/pages/modeling/metadata/EditViewMetadata.tsx:85` | +| `auto.modelmetadatatsx.name` | Name | `src/components/pages/modeling/metadata/ModelMetadata.tsx:49` | +| `auto.modelmetadatatsx.alias` | Alias | `src/components/pages/modeling/metadata/ModelMetadata.tsx:55` | +| `auto.modelmetadatatsx.description` | Description | `src/components/pages/modeling/metadata/ModelMetadata.tsx:62` | +| `auto.modelmetadatatsx.columns` | Columns ( | `src/components/pages/modeling/metadata/ModelMetadata.tsx:69` | +| `auto.modelmetadatatsx.` | ) | `src/components/pages/modeling/metadata/ModelMetadata.tsx:69` | +| `auto.modelmetadatatsx.calculated_fields` | Calculated fields ( | `src/components/pages/modeling/metadata/ModelMetadata.tsx:77` | +| `auto.modelmetadatatsx.relationships` | Relationships ( | `src/components/pages/modeling/metadata/ModelMetadata.tsx:86` | +| `auto.modelmetadatatsx.data_preview_100_rows` | Data preview (100 rows) | `src/components/pages/modeling/metadata/ModelMetadata.tsx:94` | +| `auto.modelmetadatatsx.preview_data` | Preview data | `src/components/pages/modeling/metadata/ModelMetadata.tsx:100` | +| `auto.viewmetadatatsx.name` | Name | `src/components/pages/modeling/metadata/ViewMetadata.tsx:32` | +| `auto.viewmetadatatsx.description` | Description | `src/components/pages/modeling/metadata/ViewMetadata.tsx:38` | +| `auto.viewmetadatatsx.columns` | Columns ( | `src/components/pages/modeling/metadata/ViewMetadata.tsx:45` | +| `auto.viewmetadatatsx.` | ) | `src/components/pages/modeling/metadata/ViewMetadata.tsx:45` | +| `auto.viewmetadatatsx.sql_statement` | SQL statement | `src/components/pages/modeling/metadata/ViewMetadata.tsx:56` | +| `auto.viewmetadatatsx.data_preview_100_rows` | Data preview (100 rows) | `src/components/pages/modeling/metadata/ViewMetadata.tsx:63` | +| `auto.viewmetadatatsx.preview_data` | Preview data | `src/components/pages/modeling/metadata/ViewMetadata.tsx:66` | +| `auto.connectdatasourcetsx.connect_the_data_source` | Connect the data source | `src/components/pages/setup/ConnectDataSource.tsx:45` | +| `auto.connectdatasourcetsx.vote_for_your_favorite_data_sources_on` | Vote for your favorite data sources on | `src/components/pages/setup/ConnectDataSource.tsx:48` | +| `auto.connectdatasourcetsx.github` | GitHub | `src/components/pages/setup/ConnectDataSource.tsx:54` | +| `auto.connectdatasourcetsx.` | . | `src/components/pages/setup/ConnectDataSource.tsx:56` | +| `auto.connectdatasourcetsx.learn_more_information_in_the` | Learn more information in the | `src/components/pages/setup/ConnectDataSource.tsx:74` | +| `auto.connectdatasourcetsx.setup_guide` | setup guide | `src/components/pages/setup/ConnectDataSource.tsx:80` | +| `auto.connectdatasourcetsx.back` | Back | `src/components/pages/setup/ConnectDataSource.tsx:110` | +| `auto.connectdatasourcetsx.next` | Next | `src/components/pages/setup/ConnectDataSource.tsx:121` | +| `auto.definerelationstsx.autogenerated` | (auto-generated) | `src/components/pages/setup/DefineRelations.tsx:93` | +| `auto.definerelationstsx.add` | Add | `src/components/pages/setup/DefineRelations.tsx:144` | +| `auto.definerelationstsx.define_relationships` | Define relationships | `src/components/pages/setup/DefineRelations.tsx:275` | +| `auto.definerelationstsx.you_can_create_relationships_between_sel` | You can create relationships between selected tables. We provide + suggested relationships based on primary and foreign keys defined in + your data source. The relationships are then added to data models. | `src/components/pages/setup/DefineRelations.tsx:278` | +| `auto.definerelationstsx.back` | Back | `src/components/pages/setup/DefineRelations.tsx:310` | +| `auto.definerelationstsx.skip_this_step` | Skip this step | `src/components/pages/setup/DefineRelations.tsx:323` | +| `auto.definerelationstsx.finish` | Finish | `src/components/pages/setup/DefineRelations.tsx:335` | +| `auto.selectmodelstsx.select_tables_to_create_data_models` | Select tables to create data models | `src/components/pages/setup/SelectModels.tsx:48` | +| `auto.selectmodelstsx.we_will_create_data_models_based_on_sele` | We will create data models based on selected tables to help AI better + understand your data. | `src/components/pages/setup/SelectModels.tsx:51` | +| `auto.selectmodelstsx.learn_more` | Learn more | `src/components/pages/setup/SelectModels.tsx:59` | +| `auto.selectmodelstsx.about_data_models` | about data models. | `src/components/pages/setup/SelectModels.tsx:61` | +| `auto.selectmodelstsx.back` | Back | `src/components/pages/setup/SelectModels.tsx:90` | +| `auto.selectmodelstsx.next` | Next | `src/components/pages/setup/SelectModels.tsx:101` | +| `auto.startertsx.connect_a_data_source` | Connect a data source | `src/components/pages/setup/Starter.tsx:43` | +| `auto.startertsx.vote_for_your_favorite_data_sources_on` | Vote for your favorite data sources on | `src/components/pages/setup/Starter.tsx:46` | +| `auto.startertsx.github` | GitHub | `src/components/pages/setup/Starter.tsx:52` | +| `auto.startertsx.` | . | `src/components/pages/setup/Starter.tsx:54` | +| `auto.startertsx.play_around_with_sample_data` | Play around with sample data | `src/components/pages/setup/Starter.tsx:67` | +| `auto.athenapropertiestsx.the_s3_path_where_athena_stores_query_re` | The S3 path where Athena stores query results and metadata. | `src/components/pages/setup/dataSources/AthenaProperties.tsx:164` | +| `auto.athenapropertiestsx.find_this_in_athena_console_under` | Find this in Athena console under | `src/components/pages/setup/dataSources/AthenaProperties.tsx:166` | +| `auto.athenapropertiestsx.settings_query_result_location` | Settings → Query result location | `src/components/pages/setup/dataSources/AthenaProperties.tsx:167` | +| `auto.athenapropertiestsx.` | . | `src/components/pages/setup/dataSources/AthenaProperties.tsx:167` | +| `auto.athenapropertiestsx.aws_credentials` | AWS credentials | `src/components/pages/setup/dataSources/AthenaProperties.tsx:198` | +| `auto.athenapropertiestsx.oidc_web_identity_token` | OIDC (web identity token) | `src/components/pages/setup/dataSources/AthenaProperties.tsx:201` | +| `auto.athenapropertiestsx.instance_profile` | Instance Profile | `src/components/pages/setup/dataSources/AthenaProperties.tsx:204` | +| `auto.athenapropertiestsx.we_will_automatically_detect_aws_credent` | We will automatically detect AWS credentials from the Instance Profile + role assigned to this compute environment (EC2, ECS, EKS). | `src/components/pages/setup/dataSources/AthenaProperties.tsx:220` | +| `toast.bigquerypropertiestsx.failed_to_handle_file_please_upload_a_va` | Failed to handle file. Please upload a valid credentials file. | `src/components/pages/setup/dataSources/BigQueryProperties.tsx:37` | +| `auto.bigquerypropertiestsx.click_to_upload_json_key_file` | Click to upload JSON key file | `src/components/pages/setup/dataSources/BigQueryProperties.tsx:56` | +| `auto.databrickspropertiestsx.personal_access_token_pat` | Personal Access Token (PAT) | `src/components/pages/setup/dataSources/DatabricksProperties.tsx:47` | +| `auto.databrickspropertiestsx.service_principal` | Service Principal | `src/components/pages/setup/dataSources/DatabricksProperties.tsx:50` | +| `auto.duckdbpropertiestsx.duckdb_offers_various_configuration_opti` | DuckDB offers various configuration options that can modify the + system's behavior. | `src/components/pages/setup/dataSources/DuckDBProperties.tsx:45` | +| `auto.duckdbpropertiestsx.learn_more` | Learn more | `src/components/pages/setup/dataSources/DuckDBProperties.tsx:52` | +| `auto.duckdbpropertiestsx.add_an_option` | Add an option | `src/components/pages/setup/dataSources/DuckDBProperties.tsx:128` | +| `auto.duckdbpropertiestsx.duckdb_has_an_extension_mechanism_that_e` | DuckDB has an extension mechanism that enables the dynamic loading + of extensions. | `src/components/pages/setup/dataSources/DuckDBProperties.tsx:139` | +| `auto.duckdbpropertiestsx.add_an_extension` | Add an extension | `src/components/pages/setup/dataSources/DuckDBProperties.tsx:178` | +| `auto.redshiftpropertiestsx.username_and_password` | Username and password | `src/components/pages/setup/dataSources/RedshiftProperties.tsx:223` | +| `auto.redshiftpropertiestsx.aws_credentials` | AWS credentials | `src/components/pages/setup/dataSources/RedshiftProperties.tsx:226` | +| `toast.snowflakepropertiestsx.failed_to_handle_file_please_upload_a_va` | Failed to handle file. Please upload a valid private key file. | `src/components/pages/setup/dataSources/SnowflakeProperties.tsx:42` | +| `auto.snowflakepropertiestsx.upload_private_key` | Upload private key | `src/components/pages/setup/dataSources/SnowflakeProperties.tsx:61` | +| `auto.snowflakepropertiestsx.specifies_the_virtual_warehouse_for_quer` | Specifies the virtual warehouse for query execution. If blank, the + account's default warehouse is used (if configured). | `src/components/pages/setup/dataSources/SnowflakeProperties.tsx:137` | +| `auto.snowflakepropertiestsx.authentication_method` | Authentication method | `src/components/pages/setup/dataSources/SnowflakeProperties.tsx:159` | +| `auto.snowflakepropertiestsx.username_and_password_authentication_wil` | Username and password authentication will be | `src/components/pages/setup/dataSources/SnowflakeProperties.tsx:161` | +| `auto.snowflakepropertiestsx.deprecated_by_november_2025` | deprecated by November 2025 | `src/components/pages/setup/dataSources/SnowflakeProperties.tsx:162` | +| `auto.snowflakepropertiestsx.we_recommend_switching_to_key_pair_authe` | . We + recommend switching to key pair authentication. | `src/components/pages/setup/dataSources/SnowflakeProperties.tsx:162` | +| `auto.snowflakepropertiestsx.learn_more` | Learn more | `src/components/pages/setup/dataSources/SnowflakeProperties.tsx:170` | +| `auto.snowflakepropertiestsx.password_authentication` | Password authentication | `src/components/pages/setup/dataSources/SnowflakeProperties.tsx:178` | +| `auto.snowflakepropertiestsx.key_pair_authentication` | Key pair authentication | `src/components/pages/setup/dataSources/SnowflakeProperties.tsx:181` | +| `auto.snowflakepropertiestsx.upload_your_private_key_file_for_key_pai` | Upload your private key file for key pair authentication. | `src/components/pages/setup/dataSources/SnowflakeProperties.tsx:215` | +| `auto.utilstsx.` | . | `src/components/pages/setup/utils.tsx:157` | +| `auto.utilstsx.if_you_are_having_trouble_connecting_to_` | If you are having trouble connecting to your PostgreSQL database, please + refer to our | `src/components/pages/setup/utils.tsx:158` | +| `auto.utilstsx.documentation` | documentation | `src/components/pages/setup/utils.tsx:165` | +| `auto.utilstsx.for_detailed_instructions` | for detailed instructions. | `src/components/pages/setup/utils.tsx:167` | +| `auto.descriptiveselectortsx.description` | Description | `src/components/selectors/DescriptiveSelector.tsx:34` | +| `auto.descriptiveselectortsx.example` | Example | `src/components/selectors/DescriptiveSelector.tsx:40` | +| `auto.fieldselecttsx.relationships` | Relationships | `src/components/selectors/lineageSelector/FieldSelect.tsx:133` | +| `auto.indextsx.settings` | Settings | `src/components/settings/index.tsx:130` | +| `auto.indextsx.wren_ai_version` | Wren AI version: | `src/components/settings/index.tsx:142` | +| `auto.apimanagementtsx.api_history` | API history | `src/components/sidebar/APIManagement.tsx:35` | +| `auto.apimanagementtsx.api_reference` | API reference | `src/components/sidebar/APIManagement.tsx:50` | +| `auto.threadtreetsx.new` | New | `src/components/sidebar/home/ThreadTree.tsx:72` | +| `auto.treetitletsx.rename` | Rename | `src/components/sidebar/home/TreeTitle.tsx:69` | +| `auto.indextsx.discord` | Discord | `src/components/sidebar/index.tsx:104` | +| `auto.indextsx.github` | GitHub | `src/components/sidebar/index.tsx:116` | +| `auto.grouptreetitletsx.` | ( | `src/components/sidebar/modeling/GroupTreeTitle.tsx:55` | +| `auto.modeltreetsx.new` | New | `src/components/sidebar/modeling/ModelTree.tsx:126` | +| `auto.viewtreetsx.pose_your_questions_at` | Pose your questions at | `src/components/sidebar/modeling/ViewTree.tsx:30` | +| `auto.viewtreetsx.homepage` | homepage | `src/components/sidebar/modeling/ViewTree.tsx:36` | +| `auto.viewtreetsx.and_get_some_helpful_answers_to_save_as_` | , and get some helpful answers to save as views. | `src/components/sidebar/modeling/ViewTree.tsx:38` | +| `auto.viewtreetsx.new` | New | `src/components/sidebar/modeling/ViewTree.tsx:62` | +| `auto.fieldtabletsx.nested_columns` | Nested columns | `src/components/table/FieldTable.tsx:35` | +| `auto.fieldtabletsx.columns` | column(s) | `src/components/table/FieldTable.tsx:38` | +| `auto.multiselectboxtsx.tables` | table(s) | `src/components/table/MultiSelectBox.tsx:88` | +| `auto.historytsx.` | - | `src/pages/api-management/history.tsx:118` | +| `auto.historytsx.details` | Details | `src/pages/api-management/history.tsx:157` | +| `auto.historytsx.api_history` | API history | `src/pages/api-management/history.tsx:169` | +| `auto.historytsx.here_you_can_view_the_full_history_of_ap` | Here you can view the full history of API calls, including request + inputs, responses, and execution details. | `src/pages/api-management/history.tsx:175` | +| `auto.historytsx.learn_more` | Learn more. | `src/pages/api-management/history.tsx:183` | +| `auto.instructionstsx.` | + | `src/pages/knowledge/instructions.tsx:144` | +| `toast.errorhandlertsx.no_internet_please_check_your_network_co` | No internet. Please check your network connection and try again. | `src/utils/errorHandler.tsx:460` | +| `auto.tabletsx.reset` | Reset | `src/utils/table.tsx:75` | +| `auto.tabletsx.search` | Search | `src/utils/table.tsx:78` | +| `auto.tabletsx.ok` | OK | `src/utils/table.tsx:125` | diff --git a/wren-ui/messages/en.json b/wren-ui/messages/en.json new file mode 100644 index 0000000000..4b8dcee286 --- /dev/null +++ b/wren-ui/messages/en.json @@ -0,0 +1,591 @@ +{ + "app": { + "title": "Kernel IQ" + }, + "nav": { + "home": "Home", + "modeling": "Modeling", + "knowledge": "Knowledge", + "api": "API" + }, + "home": { + "knowMore": "Know more about your data", + "thinkingQuestions": "Thinking of good questions for you... (about 1 minute)", + "retryQuestions": "We couldn't think of questions right now.", + "retryQuestionsLater": "Let's try again later.", + "dashboard": "Dashboard" + }, + "knowledge": { + "questionSqlPairs": "Question-SQL pairs", + "instructions": "Instructions" + }, + "common": { + "learnMore": "Learn more." + }, + "actions": { + "save": "Save", + "cancel": "Cancel", + "reset": "Reset", + "submit": "Submit" + }, + "settings": { + "change": "Change" + }, + "chart": { + "regenerate": "Regenerate", + "adjust": "Adjust", + "regenerateConfirmTitle": "Are you sure you want to regenerate the chart?", + "pinConfirmTitle": "Are you sure you want to pin this chart to the dashboard?" + }, + "sql": { + "wrenSql": "Wren SQL", + "wrenSqlLead": "The SQL statement used here follows", + "wrenSqlDescription": "based on ANSI SQL and optimized for Kernel IQ.", + "learnSyntax": "Learn more about the syntax.", + "previewData": "Preview data", + "dataPreview50": "Data preview (50 rows)", + "invalidSyntax": "Invalid SQL syntax", + "importFromDataSource": "Import from {name} SQL" + }, + "saveAsView": { + "title": "Save as View", + "hint": "After saving, make sure you go to \"Modeling Page\" to deploy all saved views.", + "name": "Name", + "sqlStatement": "SQL Statement" + }, + "adjustSql": { + "title": "Adjust SQL" + }, + "instructionModal": { + "addTitle": "Add an instruction", + "updateTitle": "Update an instruction", + "instructionPlaceholder": "Enter a rule that Kernel IQ should follow when generating SQL queries.", + "applyTo": "Apply instruction to", + "allQueries": "all queries", + "or": "or", + "onlyWhenSimilarDetected": "only when similar user questions are detected", + "globalOption": "Global (applies to all questions)", + "matchedOption": "Matched to specific questions", + "matchingQuestionsHelp": "Kernel IQ will match user queries based on similarity and apply this instruction when relevant.", + "questionPlaceholder": "Enter an example question that should trigger this instruction.", + "addQuestion": "Add a question" + }, + "questionSqlPairModal": { + "addTitle": "Add question-SQL pair", + "updateTitle": "Update question-SQL pair", + "generateQuestionHint": "Let AI create a matching question for this SQL statement.", + "generateQuestion": "Generate question" + }, + "calculatedFieldModal": { + "addTitle": "Add calculated field", + "updateTitle": "Update calculated field", + "primaryKeyGuide": "How to set primary key in a model.", + "selectExpression": "Select an expression" + }, + "projectSettings": { + "projectLanguage": "Project language", + "projectLanguageHelp": "This setting will affect the language in which the AI responds to you.", + "selectLanguage": "Select a language", + "resetProject": "Reset project", + "resetWarning": "Please be aware that resetting will delete all current settings and records, including those in the Modeling Page and Home Page threads.", + "resetConfirmTitle": "Are you sure you want to reset?" + }, + "dataSourceSettings": { + "changeSampleDataset": "Change sample dataset", + "changeSampleDatasetWarning": "Please be aware that choosing another sample dataset will delete all thread records in the Home page.", + "changeSampleDatasetConfirm": "Are you sure you want to change to \"{name}\" dataset?" + }, + "toasts": { + "viewCreated": "Successfully created view.", + "sqlUpdated": "Successfully updated the SQL statement", + "questionSqlPairCreated": "Successfully created question-sql pair.", + "calculatedFieldCreated": "Successfully created calculated field.", + "calculatedFieldUpdated": "Successfully updated calculated field.", + "calculatedFieldDeleted": "Successfully deleted calculated field.", + "modelCreated": "Successfully created model.", + "modelDeleted": "Successfully deleted model.", + "modelUpdated": "Successfully updated model.", + "viewDeleted": "Successfully deleted view.", + "modelMetadataUpdated": "Successfully updated model metadata.", + "relationshipCreated": "Successfully created relationship.", + "relationshipDeleted": "Successfully deleted relationship.", + "relationshipUpdated": "Successfully updated relationship.", + "viewMetadataUpdated": "Successfully updated view metadata.", + "questionSqlPairDeleted": "Successfully deleted question-sql pair.", + "questionSqlPairUpdated": "Successfully updated question-sql pair.", + "instructionCreated": "Successfully created instruction.", + "instructionUpdated": "Successfully updated instruction.", + "instructionDeleted": "Successfully deleted instruction.", + "dashboardFetchFailed": "Failed to fetch dashboard items.", + "dashboardScheduleUpdated": "Successfully updated dashboard schedule.", + "dashboardLayoutUpdateFailed": "Failed to update dashboard item layouts.", + "dashboardItemDeleted": "Successfully deleted dashboard item.", + "projectLanguageUpdated": "Successfully updated project language.", + "dataSourceUpdated": "Successfully update data source.", + "chartPinned": "Successfully pinned chart to dashboard.", + "schemaChangeDetected": "Schema change detected.", + "noSchemaChange": "There is no schema change.", + "sourceTableDeletedResolved": "Source table deleted resolved successfully.", + "sourceColumnDeletedResolved": "Source column deleted resolved successfully." + }, + "modeling": { + "title": "Modeling" + }, + "page": { + "manageQuestionSqlPairs": "Manage question-SQL pairs", + "addQuestionSqlPair": "Add question-SQL pair", + "question": "Question", + "sqlStatement": "SQL statement", + "createdTime": "Created time", + "questionSqlDescription": "On this page, you can manage your saved question-SQL pairs. These pairs help Kernel IQ learn how your organization writes SQL, allowing it to generate queries that better align with your expectations.", + "manageInstruction": "Manage instruction", + "addInstruction": "Add an instruction", + "instructionDetails": "Instruction details", + "matchingQuestions": "Matching questions", + "moreQuestion": "more question", + "moreQuestions": "more questions", + "instructionDescription": "On this page, you can manage saved instructions that guide Kernel IQ in generating SQL queries. These instructions help Kernel IQ understand your data model and business rules, improving query accuracy and reducing the need for manual refinements." + }, + "toast": { + "ibisadaptorts": { + "model_not_found": "Model not found", + "sqlparserparsingexception": "sql.parser.ParsingException", + "": ": " + }, + "deploytsx": { + "failed_to_deploy_please_check_the_log_fo": "Failed to deploy. Please check the log for more details." + }, + "bigquerypropertiestsx": { + "failed_to_handle_file_please_upload_a_va": "Failed to handle file. Please upload a valid credentials file." + }, + "snowflakepropertiestsx": { + "failed_to_handle_file_please_upload_a_va": "Failed to handle file. Please upload a valid private key file." + }, + "errorhandlertsx": { + "no_internet_please_check_your_network_co": "No internet. Please check your network connection and try again." + } + }, + "auto": { + "ellipsiswrappertsx": { + "": "...", + "more": "more" + }, + "pageloadingtsx": { + "loading": "Loading..." + }, + "indextsx": { + "no_available_data": "No available data", + "there_are_too_many_categories_to_display": "There are too many categories to display effectively. Click\n 'Show top 25' to view the top results, or ask a follow-up\n question to focus on a specific group or filter results.", + "show_top_25": "Show top 25", + "learning": "Learning", + "finished": "Finished", + "last_refreshed": "Last refreshed:", + "answer_preparation_steps": "Answer preparation steps", + "settings": "Settings", + "wren_ai_version": "Kernel IQ version:", + "discord": "Discord", + "github": "GitHub" + }, + "deploytsx": { + "deploying": "Deploying...", + "synced": "Synced", + "undeployed_changes": "Undeployed changes", + "deploy": "Deploy" + }, + "customdropdowntsx": { + "update_columns": "Update Columns", + "edit": "Edit", + "cache_settings": "Cache settings", + "show_categories": "Show categories", + "hide_categories": "Hide categories", + "view": "View" + }, + "columntsx": { + "and": "and", + "more": "more" + }, + "modelnodetsx": { + "columns": "Columns", + "calculated_fields": "Calculated Fields", + "relationships": "Relationships" + }, + "utilstsx": { + "cached": "Cached", + "": ".", + "if_you_are_having_trouble_connecting_to_": "If you are having trouble connecting to your PostgreSQL database, please\n refer to our", + "documentation": "documentation", + "for_detailed_instructions": "for detailed instructions." + }, + "markdowneditortsx": { + "": "(", + "characters": "characters" + }, + "storiestsx": { + "data_modeling_guide": "Data modeling guide", + "data_modeling_adds_a_logical_layer_over_": "Data modeling adds a logical layer over your original data schema,\n organizing relationships, semantics, and calculations. This helps AI\n align with business logic, retrieve precise data, and generate\n meaningful insights.", + "more_details": "More details", + "we_use": "We use", + "dataset_to_present_the_guide_to_know_mor": "Dataset to present the guide.\n To know more, please visit", + "about_the": "about the", + "dataset": "Dataset.", + "create_a_model": "Create a model", + "click_the_add_icon_to_start_create_your_": "Click the add icon to start create your first model.", + "edit_a_model": "Edit a model", + "click_the_more_icon_to_update_the_column": "Click the more icon to update the columns of model or delete it.", + "edit_metadata": "Edit metadata", + "you_could_edit_alias_alternative_name_an": "You could edit alias (alternative name) and descriptions of models\n and columns.", + "deploy_modeling": "Deploy modeling", + "after_editing_the_models_remember_to_dep": "After editing the models, remember to deploy the changes.", + "ask_questions": "Ask questions", + "when_you_finish_editing_your_models_you_": "When you finish editing your models, you can visit “Home” and start\n asking questions.", + "project_language": "Project language", + "switch_the_language": "Switch the language", + "choose_your_preferred_language_once_set_": "Choose your preferred language. Once set up, AI will respond in your\n chosen language.", + "you_can_go_to_project_settings_to_change": "You can go to project settings to change it if you change your mind.", + "build_knowledge_base_questionsql_pairs": "Build knowledge base: Question-SQL pairs", + "create_and_manage": "Create and manage", + "questionsql_pairs": "Question-SQL pairs", + "to_refine_wren_ais_sql_generation_you_ca": "to refine Kernel IQ’s SQL\n generation. You can manually add pairs here or go to Home, ask a\n question, and save the correct answer to Knowledge. The more you\n save, the smarter Kernel IQ becomes!", + "build_knowledge_base_instructions": "Build knowledge base: Instructions", + "in_addition_to_questionsql_pairs_you_can": "In addition to Question-SQL pairs, you can create instructions to\n define", + "business_rules": "business rules", + "and": "and", + "query_logic": "query logic", + "these_rules_guide_wren_ai_in_applying_co": ". These rules\n guide Kernel IQ in applying consistent filters, constraints, and best\n practices to SQL queries.", + "save_to_knowledge": "Save to knowledge", + "if_the_aigenerated_answer_is_correct_sav": "If the AI-generated answer is correct, save it as a", + "questionsql_pair": "Question-SQL pair", + "to_improve_ai_learning_if_its_incorrect_": "to improve AI learning. If it's incorrect,\n refine it with follow-ups before saving to ensure accuracy." + }, + "adjustreasoningstepsmodaltsx": { + "select_the_tables_needed_to_answer_your_": "Select the tables needed to answer your question.", + "tables_not_selected_wont_be_used_in_sql_": "Tables not selected won't be used in SQL generation.", + "protip_use_to_choose_model_in_the_textar": "Protip: Use @ to choose model in the textarea.", + "edit_the_reasoning_logic_below_each_step": "Edit the reasoning logic below. Each step should build toward\n answering the question accurately." + }, + "adjustsqlmodaltsx": { + "the_sql_statement_used_here_follows": "The SQL statement used here follows", + "wren_sql": "Wren SQL", + "which_is": ", which is" + }, + "deletemodaltsx": { + "delete": "Delete" + }, + "fixsqlmodaltsx": { + "the_following_sql_statement_needs_to_be_": "The following SQL statement needs to be fixed:", + "data_preview_50_rows": "Data preview (50 rows)", + "preview_data": "Preview data" + }, + "instructionmodaltsx": { + "choose_whether_this_instruction_applies_": "Choose whether this instruction applies to", + "": "." + }, + "questionsqlpairmodaltsx": { + "": "," + }, + "schemachangemodaltsx": { + "calculated_field": "Calculated Field", + "relationship": "Relationship", + "tables_affected": "table(s) affected", + "resolve": "Resolve", + "schema_changes": "Schema Changes", + "we_have_detected_schema_changes_from_you": "We have detected schema changes from your connected data source. Please\n review the impacts of these changes." + }, + "detailsdrawertsx": { + "api_type": "API type", + "thread_id": "Thread ID", + "created_at": "Created at", + "duration": "Duration", + "ms": "ms", + "status_code": "Status code", + "headers": "Headers", + "request_payload": "Request payload", + "response_payload": "Response payload" + }, + "recommendedquestionstsx": { + "recommended_questions": "Recommended questions" + }, + "cachesettingsdrawertsx": { + "cancel": "Cancel", + "submit": "Submit", + "refresh_settings": "Refresh settings", + "next_scheduled_refresh": "Next scheduled refresh:", + "": "(" + }, + "dashboardheadertsx": { + "next_schedule": "Next schedule:", + "cron_expression": "Cron expression:" + }, + "emptydashboardtsx": { + "no_charts_have_been_added_yet": "No charts have been added yet", + "follow_these_steps_to_pin_charts_to_your": "Follow these steps to pin charts to your dashboard.", + "learn_more": "Learn more" + }, + "errorboundarytsx": { + "fix_it": "Fix it" + }, + "preparationstatustsx": { + "cancel": "Cancel", + "cancelled_by_user": "Cancelled by user", + "rerun": "Re-run" + }, + "fixedsqlfinishedtsx": { + "userprovided_sql_applied": "User-Provided SQL applied", + "system_encountered_an_issue_generating_s": "System encountered an issue generating SQL. The manually submitted query\n is now being processed." + }, + "generatingtsx": { + "generating_sql_statement": "Generating SQL statement", + "successfully_generated_sql_statement": "Successfully generated SQL statement", + "wrapping_up": "Wrapping up" + }, + "organizingtsx": { + "thinking": "Thinking" + }, + "retrievingtsx": { + "models_applied": "models applied", + "top": "Top", + "model_candidates_identified": "model candidates identified", + "searching": "Searching" + }, + "sqlpairfinishedtsx": { + "using_questionsql_pair": "Using question-SQL pair", + "matching_questionsql_pair_found_returnin": "Matching question-SQL pair found. Returning results instantly." + }, + "viewfinishedtsx": { + "using_presaved_view": "Using pre-saved view", + "matching_saved_view_found_returning_resu": "Matching saved view found. Returning results instantly." + }, + "demoprompttsx": { + "try_asking": "Try asking..." + }, + "inputtsx": { + "ask": "Ask" + }, + "recommendedquestionsprompttsx": { + "know_more_about_your_data": "Know more about your data.", + "try_asking_some_of_the_following_questio": "Try asking some of the following questions" + }, + "resulttsx": { + "stop": "Stop", + "close": "Close", + "user_intent_recognized": "User Intent Recognized", + "for_the_most_accurate_semantics_please_v": "For the most accurate semantics, please visit the modeling page." + }, + "answerresulttsx": { + "store_this_answer_as_a_questionsql_pair_": "Store this answer as a Question-SQL pair to help Kernel IQ improve SQL\n generation.", + "learn_more": "Learn more", + "adjusted_answer": "Adjusted answer", + "answer": "Answer", + "view_sql": "View SQL", + "chart": "Chart", + "beta": "Beta", + "save_to_knowledge": "Save to knowledge" + }, + "textbasedanswertsx": { + "adjust_the_answer": "Adjust the answer", + "regenerate": "Regenerate", + "view_results": "View results", + "considering_the_limit_of_the_context_win": "Considering the limit of the context window, we retrieve up to\n 500 rows of results to generate the answer.", + "click": "Click", + "view_sql": "View SQL", + "to_review_the_stepbystep_query_logic_and": "to review the step-by-step query logic\n and verify why the data is unavailable." + }, + "viewblocktsx": { + "generated_from_saved_view": "Generated from saved view", + "save_as_view": "Save as View" + }, + "viewsqltabcontenttsx": { + "you_copied_wren_sql_this_dialect_is_for_": "You copied Wren SQL. This dialect is for the Wren Engine and may not\n run directly on your database.", + "click": "Click “", + "show_original_sql": "Show original SQL", + "to_get_the_executable_version": "” to get the executable version.", + "youre_viewing_wren_sql_by_default_if_you": "You’re viewing Wren SQL by default. If you want to run this query on\n your own database, click “Show original SQL” to get the exact\n syntax.", + "learn_more_about_wren_sql": "Learn more about Wren SQL", + "wren_sql": "Wren SQL", + "adjust_sql": "Adjust SQL", + "view_results": "View results", + "showing_up_to_500_rows": "Showing up to 500 rows" + }, + "globallabeltsx": { + "global": "Global" + }, + "instructiondrawertsx": { + "instruction_details": "Instruction details", + "matching_questions": "Matching questions", + "applies_to_all_questions": "(applies to all questions)", + "created_time": "Created time" + }, + "sqlpairdrawertsx": { + "question": "Question", + "sql_statement": "SQL statement", + "created_time": "Created time" + }, + "metadatadrawertsx": { + "edit": "Edit" + }, + "modeldrawertsx": { + "cancel": "Cancel", + "submit": "Submit" + }, + "editbasicmetadatatsx": { + "name": "Name", + "alias": "Alias", + "description": "Description" + }, + "editmodelmetadatatsx": { + "columns": "Columns (", + "": ")", + "calculated_fields": "Calculated fields (", + "relationships": "Relationships (" + }, + "editviewmetadatatsx": { + "columns": "Columns (", + "": ")" + }, + "modelmetadatatsx": { + "name": "Name", + "alias": "Alias", + "description": "Description", + "columns": "Columns (", + "": ")", + "calculated_fields": "Calculated fields (", + "relationships": "Relationships (", + "data_preview_100_rows": "Data preview (100 rows)", + "preview_data": "Preview data" + }, + "viewmetadatatsx": { + "name": "Name", + "description": "Description", + "columns": "Columns (", + "": ")", + "sql_statement": "SQL statement", + "data_preview_100_rows": "Data preview (100 rows)", + "preview_data": "Preview data" + }, + "connectdatasourcetsx": { + "connect_the_data_source": "Connect the data source", + "vote_for_your_favorite_data_sources_on": "Vote for your favorite data sources on", + "github": "GitHub", + "": ".", + "learn_more_information_in_the": "Learn more information in the", + "setup_guide": "setup guide", + "back": "Back", + "next": "Next" + }, + "definerelationstsx": { + "autogenerated": "(auto-generated)", + "add": "Add", + "define_relationships": "Define relationships", + "you_can_create_relationships_between_sel": "You can create relationships between selected tables. We provide\n suggested relationships based on primary and foreign keys defined in\n your data source. The relationships are then added to data models.", + "back": "Back", + "skip_this_step": "Skip this step", + "finish": "Finish" + }, + "selectmodelstsx": { + "select_tables_to_create_data_models": "Select tables to create data models", + "we_will_create_data_models_based_on_sele": "We will create data models based on selected tables to help AI better\n understand your data.", + "learn_more": "Learn more", + "about_data_models": "about data models.", + "back": "Back", + "next": "Next" + }, + "startertsx": { + "connect_a_data_source": "Connect a data source", + "vote_for_your_favorite_data_sources_on": "Vote for your favorite data sources on", + "github": "GitHub", + "": ".", + "play_around_with_sample_data": "Play around with sample data" + }, + "athenapropertiestsx": { + "the_s3_path_where_athena_stores_query_re": "The S3 path where Athena stores query results and metadata.", + "find_this_in_athena_console_under": "Find this in Athena console under", + "settings_query_result_location": "Settings → Query result location", + "": ".", + "aws_credentials": "AWS credentials", + "oidc_web_identity_token": "OIDC (web identity token)", + "instance_profile": "Instance Profile", + "we_will_automatically_detect_aws_credent": "We will automatically detect AWS credentials from the Instance Profile\n role assigned to this compute environment (EC2, ECS, EKS)." + }, + "bigquerypropertiestsx": { + "click_to_upload_json_key_file": "Click to upload JSON key file" + }, + "databrickspropertiestsx": { + "personal_access_token_pat": "Personal Access Token (PAT)", + "service_principal": "Service Principal" + }, + "duckdbpropertiestsx": { + "duckdb_offers_various_configuration_opti": "DuckDB offers various configuration options that can modify the\n system's behavior.", + "learn_more": "Learn more", + "add_an_option": "Add an option", + "duckdb_has_an_extension_mechanism_that_e": "DuckDB has an extension mechanism that enables the dynamic loading\n of extensions.", + "add_an_extension": "Add an extension" + }, + "redshiftpropertiestsx": { + "username_and_password": "Username and password", + "aws_credentials": "AWS credentials" + }, + "snowflakepropertiestsx": { + "upload_private_key": "Upload private key", + "specifies_the_virtual_warehouse_for_quer": "Specifies the virtual warehouse for query execution. If blank, the\n account's default warehouse is used (if configured).", + "authentication_method": "Authentication method", + "username_and_password_authentication_wil": "Username and password authentication will be", + "deprecated_by_november_2025": "deprecated by November 2025", + "we_recommend_switching_to_key_pair_authe": ". We\n recommend switching to key pair authentication.", + "learn_more": "Learn more", + "password_authentication": "Password authentication", + "key_pair_authentication": "Key pair authentication", + "upload_your_private_key_file_for_key_pai": "Upload your private key file for key pair authentication." + }, + "descriptiveselectortsx": { + "description": "Description", + "example": "Example" + }, + "fieldselecttsx": { + "relationships": "Relationships" + }, + "apimanagementtsx": { + "api_history": "API history", + "api_reference": "API reference" + }, + "threadtreetsx": { + "new": "New" + }, + "treetitletsx": { + "rename": "Rename" + }, + "grouptreetitletsx": { + "": "(" + }, + "modeltreetsx": { + "new": "New" + }, + "viewtreetsx": { + "pose_your_questions_at": "Pose your questions at", + "homepage": "homepage", + "and_get_some_helpful_answers_to_save_as_": ", and get some helpful answers to save as views.", + "new": "New" + }, + "fieldtabletsx": { + "nested_columns": "Nested columns", + "columns": "column(s)" + }, + "multiselectboxtsx": { + "tables": "table(s)" + }, + "historytsx": { + "": "-", + "details": "Details", + "api_history": "API history", + "here_you_can_view_the_full_history_of_ap": "Here you can view the full history of API calls, including request\n inputs, responses, and execution details.", + "learn_more": "Learn more." + }, + "instructionstsx": { + "": "+" + }, + "tabletsx": { + "reset": "Reset", + "search": "Search", + "ok": "OK" + } + } +} diff --git a/wren-ui/messages/fr.json b/wren-ui/messages/fr.json new file mode 100644 index 0000000000..9c3554eee5 --- /dev/null +++ b/wren-ui/messages/fr.json @@ -0,0 +1,134 @@ +{ + "app": { + "title": "Kernel IQ" + }, + "nav": { + "home": "Accueil", + "modeling": "Modélisation", + "knowledge": "Connaissances", + "api": "API" + }, + "home": { + "knowMore": "Explorez davantage vos données", + "thinkingQuestions": "Recherche de questions pertinentes pour vous... (environ 1 minute)", + "retryQuestions": "Impossible de générer des questions pour le moment.", + "retryQuestionsLater": "Veuillez réessayer plus tard.", + "dashboard": "Tableau de bord" + }, + "knowledge": { + "questionSqlPairs": "Paires Question-SQL", + "instructions": "Instructions" + }, + "common": { + "learnMore": "En savoir plus." + }, + "actions": { + "save": "Enregistrer", + "cancel": "Annuler", + "reset": "Réinitialiser", + "submit": "Valider" + }, + "settings": { + "change": "Modifier" + }, + "chart": { + "regenerate": "Régénérer", + "adjust": "Ajuster", + "regenerateConfirmTitle": "Voulez-vous vraiment régénérer ce graphique ?", + "pinConfirmTitle": "Voulez-vous vraiment ajouter ce graphique au tableau de bord ?" + }, + "sql": { + "wrenSql": "Wren SQL", + "wrenSqlLead": "La requête SQL utilisée ici suit", + "wrenSqlDescription": "la norme ANSI SQL et est optimisée pour Kernel IQ.", + "learnSyntax": "En savoir plus sur la syntaxe.", + "previewData": "Aperçu des données", + "dataPreview50": "Aperçu des données (50 lignes)", + "invalidSyntax": "Syntaxe SQL invalide", + "importFromDataSource": "Importer depuis le SQL de {name}" + }, + "saveAsView": { + "title": "Enregistrer comme vue", + "hint": "Après l'enregistrement, allez dans la page « Modélisation » pour déployer toutes les vues enregistrées.", + "name": "Nom", + "sqlStatement": "Requête SQL" + }, + "adjustSql": { + "title": "Modifier le SQL" + }, + "instructionModal": { + "addTitle": "Ajouter une instruction", + "updateTitle": "Modifier une instruction", + "instructionPlaceholder": "Saisissez une règle que Kernel IQ devra suivre lors de la génération des requêtes SQL.", + "applyTo": "Appliquer l’instruction à", + "allQueries": "toutes les requêtes", + "or": "ou", + "onlyWhenSimilarDetected": "uniquement lorsque des questions similaires sont détectées", + "globalOption": "Global (s’applique à toutes les questions)", + "matchedOption": "Associé à des questions spécifiques", + "matchingQuestionsHelp": "Kernel IQ analysera les requêtes utilisateur par similarité et appliquera cette instruction lorsque c’est pertinent.", + "questionPlaceholder": "Saisissez un exemple de question qui doit déclencher cette instruction.", + "addQuestion": "Ajouter une question" + }, + "questionSqlPairModal": { + "addTitle": "Ajouter une paire Question-SQL", + "updateTitle": "Modifier une paire Question-SQL", + "generateQuestionHint": "Laissez l’IA générer une question correspondant à cette requête SQL.", + "generateQuestion": "Générer une question" + }, + "calculatedFieldModal": { + "addTitle": "Ajouter un champ calculé", + "updateTitle": "Modifier un champ calculé", + "primaryKeyGuide": "Comment définir une clé primaire dans un modèle.", + "selectExpression": "Sélectionner une expression" + }, + "projectSettings": { + "projectLanguage": "Langue du projet", + "projectLanguageHelp": "Ce paramètre détermine la langue utilisée par l’IA pour vous répondre.", + "selectLanguage": "Choisir une langue", + "resetProject": "Réinitialiser le projet", + "resetWarning": "Attention : la réinitialisation supprimera tous les paramètres et enregistrements actuels, y compris ceux des pages Modélisation et Accueil.", + "resetConfirmTitle": "Voulez-vous vraiment réinitialiser le projet ?" + }, + "dataSourceSettings": { + "changeSampleDataset": "Changer le jeu de données d’exemple", + "changeSampleDatasetWarning": "Attention : choisir un autre jeu de données supprimera toutes les discussions de la page Accueil.", + "changeSampleDatasetConfirm": "Voulez-vous vraiment passer au jeu de données « {name} » ?" + }, + "toasts": { + "viewCreated": "Vue créée avec succès.", + "sqlUpdated": "Requête SQL mise à jour avec succès.", + "questionSqlPairCreated": "Paire Question-SQL créée avec succès.", + "calculatedFieldCreated": "Champ calculé créé avec succès.", + "calculatedFieldUpdated": "Champ calculé mis à jour avec succès.", + "calculatedFieldDeleted": "Champ calculé supprimé avec succès.", + "modelCreated": "Modèle créé avec succès.", + "modelDeleted": "Modèle supprimé avec succès.", + "modelUpdated": "Modèle mis à jour avec succès.", + "viewDeleted": "Vue supprimée avec succès.", + "modelMetadataUpdated": "Métadonnées du modèle mises à jour.", + "relationshipCreated": "Relation créée avec succès.", + "relationshipDeleted": "Relation supprimée avec succès.", + "relationshipUpdated": "Relation mise à jour avec succès.", + "viewMetadataUpdated": "Métadonnées de la vue mises à jour.", + "questionSqlPairDeleted": "Paire Question-SQL supprimée.", + "questionSqlPairUpdated": "Paire Question-SQL mise à jour.", + "instructionCreated": "Instruction créée avec succès.", + "instructionUpdated": "Instruction mise à jour avec succès.", + "instructionDeleted": "Instruction supprimée avec succès.", + "dashboardFetchFailed": "Impossible de récupérer les éléments du tableau de bord.", + "dashboardScheduleUpdated": "Planification du tableau de bord mise à jour.", + "dashboardLayoutUpdateFailed": "Échec de la mise à jour de la disposition des éléments du tableau de bord.", + "dashboardItemDeleted": "Élément du tableau de bord supprimé.", + "projectLanguageUpdated": "Langue du projet mise à jour.", + "dataSourceUpdated": "Source de données mise à jour.", + "chartPinned": "Graphique ajouté au tableau de bord.", + "schemaChangeDetected": "Modification du schéma détectée.", + "noSchemaChange": "Aucune modification du schéma.", + "sourceTableDeletedResolved": "Suppression de la table source résolue avec succès.", + "sourceColumnDeletedResolved": "Suppression de la colonne source résolue avec succès." + }, + "modeling": { + "title": "Modélisation" + } +} \ No newline at end of file diff --git a/wren-ui/next.config.js b/wren-ui/next.config.js index c2791bec9b..718b962d8a 100644 --- a/wren-ui/next.config.js +++ b/wren-ui/next.config.js @@ -13,6 +13,11 @@ const resolveAlias = { const nextConfig = withLess({ output: 'standalone', staticPageGenerationTimeout: 1000, + i18n: { + locales: ['en', 'fr'], + defaultLocale: 'en', + localeDetection: true, + }, compiler: { // Enables the styled-components SWC transform styledComponents: { diff --git a/wren-ui/package.json b/wren-ui/package.json index 2e73dcc44f..1eb3627f3d 100644 --- a/wren-ui/package.json +++ b/wren-ui/package.json @@ -7,6 +7,7 @@ "build": "NODE_OPTIONS=--max-old-space-size=8192 next build", "start": "TZ=UTC next start", "lint": "yarn check-types && next lint", + "extract-i18n": "ts-node --compiler-options '{\"module\":\"commonjs\"}' scripts/extract-i18n.ts", "test": "jest", "test:e2e": "npx playwright install chromium && npx playwright test", "check-types": "tsc --noEmit", @@ -30,6 +31,7 @@ "micro": "^9.4.1", "micro-cors": "^0.1.1", "next": "14.2.35", + "next-intl": "^3.26.5", "pg": "^8.8.0", "pg-cursor": "^2.7.4", "posthog-node": "^4.3.2", diff --git a/wren-ui/scripts/extract-i18n.ts b/wren-ui/scripts/extract-i18n.ts new file mode 100644 index 0000000000..062369d9a1 --- /dev/null +++ b/wren-ui/scripts/extract-i18n.ts @@ -0,0 +1,156 @@ +import fs from 'fs'; +import path from 'path'; +import ts from 'typescript'; + +type Entry = { + key: string; + value: string; + file: string; + line: number; +}; + +const ROOT = path.resolve(__dirname, '..'); +const SRC_DIR = path.join(ROOT, 'src'); +const MESSAGES_PATH = path.join(ROOT, 'messages', 'en.json'); +const REPORT_PATH = path.join(ROOT, 'i18n-extract-report.md'); + +const shouldSkipText = (text: string) => { + const trimmed = text.trim(); + if (!trimmed) return true; + if (/^https?:\/\//.test(trimmed)) return true; + if (/^[A-Za-z0-9_\-/.]+$/.test(trimmed) && trimmed.includes('/')) return true; + return false; +}; + +const normalizeKeyPart = (value: string) => { + return value + .toLowerCase() + .replace(/[^a-z0-9\s]/g, '') + .trim() + .replace(/\s+/g, '_') + .slice(0, 40); +}; + +const walk = (dir: string): string[] => { + const out: string[] = []; + const entries = fs.readdirSync(dir, { withFileTypes: true }); + for (const entry of entries) { + const fullPath = path.join(dir, entry.name); + if (entry.isDirectory()) { + if (entry.name === 'node_modules' || entry.name === '.next') continue; + out.push(...walk(fullPath)); + continue; + } + + if (/\.(ts|tsx)$/.test(entry.name)) { + out.push(fullPath); + } + } + + return out; +}; + +const findEntries = (filePath: string): Entry[] => { + const source = fs.readFileSync(filePath, 'utf8'); + const sourceFile = ts.createSourceFile(filePath, source, ts.ScriptTarget.Latest, true); + const entries: Entry[] = []; + + const visit = (node: ts.Node) => { + if (ts.isJsxText(node)) { + const value = node.getText(sourceFile).trim(); + if (!shouldSkipText(value)) { + const line = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)).line + 1; + entries.push({ + key: `auto.${normalizeKeyPart(path.basename(filePath))}.${normalizeKeyPart(value)}`, + value, + file: path.relative(ROOT, filePath), + line, + }); + } + } + + if ( + ts.isStringLiteral(node) && + ts.isCallExpression(node.parent) && + ts.isPropertyAccessExpression(node.parent.expression) + ) { + const expr = node.parent.expression; + const fnName = `${expr.expression.getText(sourceFile)}.${expr.name.getText(sourceFile)}`; + if (fnName.startsWith('message.') && !shouldSkipText(node.text)) { + const line = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)).line + 1; + entries.push({ + key: `toast.${normalizeKeyPart(path.basename(filePath))}.${normalizeKeyPart(node.text)}`, + value: node.text, + file: path.relative(ROOT, filePath), + line, + }); + } + } + + ts.forEachChild(node, visit); + }; + + visit(sourceFile); + return entries; +}; + +const setByPath = (obj: Record, dottedPath: string, value: string) => { + const keys = dottedPath.split('.'); + let current = obj; + + keys.forEach((key, index) => { + if (index === keys.length - 1) { + if (!current[key]) { + current[key] = value; + } + return; + } + + if (!current[key] || typeof current[key] !== 'object') { + current[key] = {}; + } + current = current[key]; + }); +}; + +const main = () => { + const files = walk(SRC_DIR); + const extracted = files.flatMap(findEntries); + + const unique = new Map(); + extracted.forEach((entry) => { + if (!unique.has(entry.key)) { + unique.set(entry.key, entry); + } + }); + + const nextEntries = [...unique.values()]; + const messages = JSON.parse(fs.readFileSync(MESSAGES_PATH, 'utf8')) as Record; + + nextEntries.forEach((entry) => { + setByPath(messages, entry.key, entry.value); + }); + + fs.writeFileSync(MESSAGES_PATH, `${JSON.stringify(messages, null, 2)}\n`, 'utf8'); + + const reportLines = [ + '# i18n extraction report', + '', + `Found ${nextEntries.length} entries`, + '', + '| key | value | location |', + '| --- | --- | --- |', + ...nextEntries.map( + (entry) => + `| \`${entry.key}\` | ${entry.value.replace(/\|/g, '\\|')} | \`${entry.file}:${entry.line}\` |`, + ), + '', + ]; + + fs.writeFileSync(REPORT_PATH, reportLines.join('\n'), 'utf8'); + console.log(`Extracted ${nextEntries.length} strings.`); + console.log(`Updated: ${path.relative(ROOT, MESSAGES_PATH)}`); + console.log(`Report: ${path.relative(ROOT, REPORT_PATH)}`); +}; + +main(); diff --git a/wren-ui/src/apollo/server/adaptors/wrenAIAdaptor.ts b/wren-ui/src/apollo/server/adaptors/wrenAIAdaptor.ts index 2d0675633e..90febc137e 100644 --- a/wren-ui/src/apollo/server/adaptors/wrenAIAdaptor.ts +++ b/wren-ui/src/apollo/server/adaptors/wrenAIAdaptor.ts @@ -151,13 +151,13 @@ export class WrenAIAdaptor implements IWrenAIAdaptor { }); if (response.status === 200) { - logger.info(`Wren AI: Deleted semantics for project ${projectId}`); + logger.info(`Kernel IQ: Deleted semantics for project ${projectId}`); } else { throw new Error(`Failed to delete semantics. ${response.data?.error}`); } } catch (error: any) { throw new Error( - `Wren AI: Failed to delete semantics: ${getAIServiceError(error)}`, + `Kernel IQ: Failed to delete semantics: ${getAIServiceError(error)}`, ); } } @@ -242,7 +242,7 @@ export class WrenAIAdaptor implements IWrenAIAdaptor { }); return { queryId: res.data.query_id }; } catch (err: any) { - logger.debug(`Got error when asking wren AI: ${getAIServiceError(err)}`); + logger.debug(`Got error when asking Kernel IQ: ${getAIServiceError(err)}`); throw err; } } @@ -344,25 +344,25 @@ export class WrenAIAdaptor implements IWrenAIAdaptor { ); const deployId = res.data.id; logger.debug( - `Wren AI: Deploying wren AI, hash: ${hash}, deployId: ${deployId}`, + `Kernel IQ: Deploying Kernel IQ, hash: ${hash}, deployId: ${deployId}`, ); const deploySuccess = await this.waitDeployFinished(deployId); if (deploySuccess) { - logger.debug(`Wren AI: Deploy wren AI success, hash: ${hash}`); + logger.debug(`Kernel IQ: Deploy Kernel IQ success, hash: ${hash}`); return { status: WrenAIDeployStatusEnum.SUCCESS }; } else { return { status: WrenAIDeployStatusEnum.FAILED, - error: `Wren AI: Deploy wren AI failed or timeout, hash: ${hash}`, + error: `Kernel IQ: Deploy Kernel IQ failed or timeout, hash: ${hash}`, }; } } catch (err: any) { logger.debug( - `Got error when deploying to wren AI, hash: ${hash}. Error: ${err.message}`, + `Got error when deploying to Kernel IQ, hash: ${hash}. Error: ${err.message}`, ); return { status: WrenAIDeployStatusEnum.FAILED, - error: `Wren AI Error: deployment hash:${hash}, ${err.message}`, + error: `Kernel IQ Error: deployment hash:${hash}, ${err.message}`, }; } } @@ -377,14 +377,14 @@ export class WrenAIAdaptor implements IWrenAIAdaptor { max_categories: input.maxCategories, configuration: input.configuration, }; - logger.info(`Wren AI: Generating recommendation questions`); + logger.info(`Kernel IQ: Generating recommendation questions`); try { const res = await axios.post( `${this.wrenAIBaseEndpoint}/v1/question-recommendations`, body, ); logger.info( - `Wren AI: Generating recommendation questions, queryId: ${res.data.id}`, + `Kernel IQ: Generating recommendation questions, queryId: ${res.data.id}`, ); return { queryId: res.data.id }; } catch (err: any) { @@ -775,7 +775,7 @@ export class WrenAIAdaptor implements IWrenAIAdaptor { for (let waitTime = 1; waitTime <= 7; waitTime++) { try { const status = await this.getDeployStatus(deployId); - logger.debug(`Wren AI: Deploy status: ${status}`); + logger.debug(`Kernel IQ: Deploy status: ${status}`); if (status === WrenAISystemStatus.FINISHED) { deploySuccess = true; break; @@ -784,7 +784,7 @@ export class WrenAIAdaptor implements IWrenAIAdaptor { } else if (status === WrenAISystemStatus.INDEXING) { // do nothing } else { - logger.debug(`Wren AI: Unknown Wren AI deploy status: ${status}`); + logger.debug(`Kernel IQ: Unknown Kernel IQ deploy status: ${status}`); return; } } catch (err: any) { diff --git a/wren-ui/src/apollo/server/config.ts b/wren-ui/src/apollo/server/config.ts index ad43e2da84..408c73a1eb 100644 --- a/wren-ui/src/apollo/server/config.ts +++ b/wren-ui/src/apollo/server/config.ts @@ -17,7 +17,7 @@ export interface IConfig { // wren engine wrenEngineEndpoint: string; - // wren AI + // Kernel IQ wrenAIEndpoint: string; generationModel?: string; @@ -67,7 +67,7 @@ const defaultConfig = { // wren engine wrenEngineEndpoint: 'http://localhost:8080', - // wren AI + // Kernel IQ wrenAIEndpoint: 'http://localhost:5555', // ibis server @@ -104,7 +104,7 @@ const config = { // wren engine wrenEngineEndpoint: process.env.WREN_ENGINE_ENDPOINT, - // wren AI + // Kernel IQ wrenAIEndpoint: process.env.WREN_AI_ENDPOINT, generationModel: process.env.GENERATION_MODEL, diff --git a/wren-ui/src/components/HeaderBar.tsx b/wren-ui/src/components/HeaderBar.tsx index a3a0292c49..7fa14e8e39 100644 --- a/wren-ui/src/components/HeaderBar.tsx +++ b/wren-ui/src/components/HeaderBar.tsx @@ -1,9 +1,11 @@ import { useRouter } from 'next/router'; import { Button, Layout, Space } from 'antd'; import styled from 'styled-components'; +import { useTranslations } from 'next-intl'; import LogoBar from '@/components/LogoBar'; import { Path } from '@/utils/enum'; import Deploy from '@/components/deploy/Deploy'; +import { pushWithLocale } from '@/i18n/navigation'; const { Header } = Layout; @@ -33,6 +35,7 @@ const StyledHeader = styled(Header)` export default function HeaderBar() { const router = useRouter(); + const t = useTranslations(); const { pathname } = router; const showNav = !pathname.startsWith(Path.Onboarding); const isModeling = pathname.startsWith(Path.Modeling); @@ -51,33 +54,35 @@ export default function HeaderBar() { shape="round" size="small" $isHighlight={pathname.startsWith(Path.Home)} - onClick={() => router.push(Path.Home)} + onClick={() => pushWithLocale(router, Path.Home)} > - Home + {t('nav.home')} router.push(Path.Modeling)} + onClick={() => pushWithLocale(router, Path.Modeling)} > - Modeling + {t('nav.modeling')} router.push(Path.KnowledgeQuestionSQLPairs)} + onClick={() => + pushWithLocale(router, Path.KnowledgeQuestionSQLPairs) + } > - Knowledge + {t('nav.knowledge')} router.push(Path.APIManagementHistory)} + onClick={() => pushWithLocale(router, Path.APIManagementHistory)} > - API + {t('nav.api')} )} diff --git a/wren-ui/src/components/LogoBar.tsx b/wren-ui/src/components/LogoBar.tsx index 4b89c55dd9..3896826a3a 100644 --- a/wren-ui/src/components/LogoBar.tsx +++ b/wren-ui/src/components/LogoBar.tsx @@ -1,12 +1,16 @@ -import Image from 'next/image'; - export default function LogoBar() { return ( - Wren AI + + Kernel IQ + ); } diff --git a/wren-ui/src/components/learning/guide/stories.tsx b/wren-ui/src/components/learning/guide/stories.tsx index 8634e85ccb..645ec72ae1 100644 --- a/wren-ui/src/components/learning/guide/stories.tsx +++ b/wren-ui/src/components/learning/guide/stories.tsx @@ -397,10 +397,10 @@ const playKnowledgeGuide = ( ), description: renderToString( <> - Create and manage Question-SQL pairs to refine Wren AI’s SQL + Create and manage Question-SQL pairs to refine Kernel IQ’s SQL generation. You can manually add pairs here or go to Home, ask a question, and save the correct answer to Knowledge. The more you - save, the smarter Wren AI becomes! + save, the smarter Kernel IQ becomes! , ), onPopoverRender: (popoverDom: DriverPopoverDOM) => { @@ -427,7 +427,7 @@ const playKnowledgeGuide = ( <> In addition to Question-SQL pairs, you can create instructions to define business rules and query logic. These rules - guide Wren AI in applying consistent filters, constraints, and best + guide Kernel IQ in applying consistent filters, constraints, and best practices to SQL queries. , ), diff --git a/wren-ui/src/components/modals/AdjustSQLModal.tsx b/wren-ui/src/components/modals/AdjustSQLModal.tsx index cc432cb6dd..e2b85d64c8 100644 --- a/wren-ui/src/components/modals/AdjustSQLModal.tsx +++ b/wren-ui/src/components/modals/AdjustSQLModal.tsx @@ -1,5 +1,6 @@ import { useEffect, useState } from 'react'; import { Alert, Button, Form, Modal, Typography } from 'antd'; +import { useTranslations } from 'next-intl'; import InfoCircleOutlined from '@ant-design/icons/InfoCircleOutlined'; import { ERROR_TEXTS } from '@/utils/error'; import { ModalAction } from '@/hooks/useModalAction'; @@ -20,6 +21,7 @@ type Props = ModalAction & { export default function AdjustSQLModal(props: Props) { const { defaultValue, loading, onClose, onSubmit, visible } = props; + const t = useTranslations(); const [form] = Form.useForm(); const [error, setError] = @@ -62,7 +64,7 @@ export default function AdjustSQLModal(props: Props) { const handleError = (error) => { const graphQLError = parseGraphQLError(error); - setError({ ...graphQLError, shortMessage: 'Invalid SQL syntax' }); + setError({ ...graphQLError, shortMessage: t('sql.invalidSyntax') }); console.error(graphQLError); }; @@ -119,7 +121,7 @@ export default function AdjustSQLModal(props: Props) { return ( The SQL statement used here follows Wren SQL, which is - based on ANSI SQL and optimized for Wren AI.{` `} + {t('sql.wrenSqlDescription')}{` `} - Learn more about the syntax. + {t('sql.learnSyntax')}
- +
@@ -169,7 +171,7 @@ export default function AdjustSQLModal(props: Props) { >
- Data preview (50 rows) + {t('sql.dataPreview50')} {showPreview && (
diff --git a/wren-ui/src/components/modals/CalculatedFieldModal.tsx b/wren-ui/src/components/modals/CalculatedFieldModal.tsx index 8ca1698cb1..c2a40e2088 100644 --- a/wren-ui/src/components/modals/CalculatedFieldModal.tsx +++ b/wren-ui/src/components/modals/CalculatedFieldModal.tsx @@ -1,5 +1,6 @@ import { useCallback, useEffect, useMemo, useState } from 'react'; import { Modal, Form, Input, Typography, Button, Alert } from 'antd'; +import { useTranslations } from 'next-intl'; import LinkOutlined from '@ant-design/icons/LinkOutlined'; import { FORM_MODE } from '@/utils/enum'; import { ERROR_TEXTS } from '@/utils/error'; @@ -49,6 +50,7 @@ export default function AddCalculatedFieldModal(props: Props) { payload, formMode, } = props; + const t = useTranslations(); const isEditMode = formMode === FORM_MODE.EDIT; const [error, setError] = @@ -137,7 +139,11 @@ export default function AddCalculatedFieldModal(props: Props) { return ( - How to set primary key in a model. + {t('calculatedFieldModal.primaryKeyGuide')}
- +
@@ -169,7 +175,7 @@ export default function AddCalculatedFieldModal(props: Props) { > { return ( diff --git a/wren-ui/src/components/modals/InstructionModal.tsx b/wren-ui/src/components/modals/InstructionModal.tsx index dccb9dfda6..5507ac25b6 100644 --- a/wren-ui/src/components/modals/InstructionModal.tsx +++ b/wren-ui/src/components/modals/InstructionModal.tsx @@ -1,5 +1,6 @@ import { useEffect } from 'react'; import { Button, Form, Input, Modal, Row, Col, Radio } from 'antd'; +import { useTranslations } from 'next-intl'; import DeleteOutlined from '@ant-design/icons/DeleteOutlined'; import PlusOutlined from '@ant-design/icons/PlusOutlined'; import { isEmpty } from 'lodash'; @@ -16,6 +17,7 @@ type Props = ModalAction & { export default function InstructionModal(props: Props) { const { defaultValue, formMode, loading, onClose, onSubmit, visible } = props; + const t = useTranslations(); const isCreateMode = formMode === FORM_MODE.CREATE; @@ -49,7 +51,11 @@ export default function InstructionModal(props: Props) { return ( form.resetFields()} > Choose whether this instruction applies to{' '} - all queries or{' '} + {t('instructionModal.allQueries')}{' '} + {t('instructionModal.or')}{' '} - only when similar user questions are detected + {t('instructionModal.onlyWhenSimilarDetected')} . @@ -105,18 +112,18 @@ export default function InstructionModal(props: Props) { > - Global (applies to all questions) + {t('instructionModal.globalOption')} - Matched to specific questions + {t('instructionModal.matchedOption')} {!isDefault && ( {(fields, { add, remove }) => ( @@ -140,7 +147,9 @@ export default function InstructionModal(props: Props) { ]} > @@ -167,7 +176,7 @@ export default function InstructionModal(props: Props) { disabled={fields.length >= MAX_QUESTIONS} className="mb-1" > - Add a question + {t('instructionModal.addQuestion')} diff --git a/wren-ui/src/components/modals/QuestionSQLPairModal.tsx b/wren-ui/src/components/modals/QuestionSQLPairModal.tsx index 4e2d4b66cf..d20cb013ec 100644 --- a/wren-ui/src/components/modals/QuestionSQLPairModal.tsx +++ b/wren-ui/src/components/modals/QuestionSQLPairModal.tsx @@ -1,6 +1,7 @@ import { useEffect, useMemo, useState } from 'react'; import styled from 'styled-components'; import { Alert, Button, Form, Input, Modal, Typography } from 'antd'; +import { useTranslations } from 'next-intl'; import { Logo } from '@/components/Logo'; import InfoCircleOutlined from '@ant-design/icons/InfoCircleOutlined'; import SelectOutlined from '@ant-design/icons/SelectOutlined'; @@ -36,22 +37,24 @@ const StyledForm = styled(Form)` const Toolbar = (props: { dataSource: string; onClick: () => void }) => { const { dataSource, onClick } = props; + const t = useTranslations(); const name = getDataSourceName(dataSource); return (
- Wren SQL + {t('sql.wrenSql')}
); }; export default function QuestionSQLPairModal(props: Props) { + const t = useTranslations(); const { defaultValue, formMode, @@ -123,7 +126,7 @@ export default function QuestionSQLPairModal(props: Props) { const handleError = (error) => { const graphQLError = parseGraphQLError(error); - setError({ ...graphQLError, shortMessage: 'Invalid SQL syntax' }); + setError({ ...graphQLError, shortMessage: t('sql.invalidSyntax') }); console.error(graphQLError); }; @@ -191,7 +194,11 @@ export default function QuestionSQLPairModal(props: Props) { return ( <> - The SQL statement used here follows Wren SQL, which is - based on ANSI SQL and optimized for Wren AI.{` `} + {t('sql.wrenSqlLead')} {t('sql.wrenSql')},{' '} + {t('sql.wrenSqlDescription')}{` `} - Learn more about the syntax. + {t('sql.learnSyntax')}
- +
@@ -247,9 +254,9 @@ export default function QuestionSQLPairModal(props: Props) { className="d-flex justify-space-between" style={{ width: '100%' }} > - Question + {t('page.question')}
- Let AI create a matching question for this SQL statement. + {t('questionSqlPairModal.generateQuestionHint')}
@@ -275,7 +284,7 @@ export default function QuestionSQLPairModal(props: Props) {
- Data preview (50 rows) + {t('sql.dataPreview50')} {showPreview && (
diff --git a/wren-ui/src/components/modals/SaveAsViewModal.tsx b/wren-ui/src/components/modals/SaveAsViewModal.tsx index 7fc137d995..22471be22f 100644 --- a/wren-ui/src/components/modals/SaveAsViewModal.tsx +++ b/wren-ui/src/components/modals/SaveAsViewModal.tsx @@ -1,4 +1,5 @@ import { Button, Form, Input, Modal, Typography } from 'antd'; +import { useTranslations } from 'next-intl'; import InfoCircleOutlined from '@ant-design/icons/InfoCircleOutlined'; import { ModalAction } from '@/hooks/useModalAction'; import { createViewNameValidator } from '@/utils/validator'; @@ -15,6 +16,7 @@ type Props = ModalAction<{ sql: string }> & { export default function SaveAsViewModal(props: Props) { const { visible, loading, onSubmit, onClose, defaultValue, payload } = props; + const t = useTranslations(); const [form] = Form.useForm(); const [validateViewMutation] = useValidateViewMutation({ fetchPolicy: 'no-cache', @@ -38,7 +40,7 @@ export default function SaveAsViewModal(props: Props) { return ( - After saving, make sure you go to "Modeling Page" to deploy all - saved views. + {t('saveAsView.hint')}
- +
@@ -70,7 +71,7 @@ export default function SaveAsViewModal(props: Props) { > - + diff --git a/wren-ui/src/components/pages/home/promptThread/AnswerResult.tsx b/wren-ui/src/components/pages/home/promptThread/AnswerResult.tsx index 6a0e628206..82711f1eba 100644 --- a/wren-ui/src/components/pages/home/promptThread/AnswerResult.tsx +++ b/wren-ui/src/components/pages/home/promptThread/AnswerResult.tsx @@ -41,7 +41,7 @@ const adjustmentType = { const knowledgeTooltip = ( <> - Store this answer as a Question-SQL pair to help Wren AI improve SQL + Store this answer as a Question-SQL pair to help Kernel IQ improve SQL generation.
{ }; export default function ChartAnswer(props: AnswerResultProps) { + const t = useTranslations(); const { onGenerateChartAnswer, onAdjustChartAnswer } = usePromptThreadStore(); const { threadResponse } = props; const [regenerating, setRegenerating] = useState(false); @@ -96,7 +98,7 @@ export default function ChartAnswer(props: AnswerResultProps) { const [createDashboardItem] = useCreateDashboardItemMutation({ onError: (error) => console.error(error), onCompleted: () => { - message.success('Successfully pinned chart to dashboard.'); + message.success(t('toasts.chartPinned')); }, }); @@ -169,7 +171,7 @@ export default function ChartAnswer(props: AnswerResultProps) { const onReload = () => { Modal.confirm({ - title: 'Are you sure you want to regenerate the chart?', + title: t('chart.regenerateConfirmTitle'), onOk: onRegenerate, }); }; @@ -180,8 +182,8 @@ export default function ChartAnswer(props: AnswerResultProps) { const onPin = () => { Modal.confirm({ - title: 'Are you sure you want to pin this chart to the dashboard?', - okText: 'Save', + title: t('chart.pinConfirmTitle'), + okText: t('actions.save'), onOk: async () => await createDashboardItem({ variables: { @@ -211,7 +213,7 @@ export default function ChartAnswer(props: AnswerResultProps) { const regenerateBtn = (
); @@ -266,14 +268,14 @@ export default function ChartAnswer(props: AnswerResultProps) { {isAdjusted && (
)} diff --git a/wren-ui/src/components/settings/DataSourceSettings.tsx b/wren-ui/src/components/settings/DataSourceSettings.tsx index c16f6337aa..0f5a1d30c6 100644 --- a/wren-ui/src/components/settings/DataSourceSettings.tsx +++ b/wren-ui/src/components/settings/DataSourceSettings.tsx @@ -2,6 +2,7 @@ import { useRouter } from 'next/router'; import Image from 'next/image'; import { useEffect, useMemo } from 'react'; import { Button, Form, Modal, message, Alert } from 'antd'; +import { useTranslations } from 'next-intl'; import { makeIterable } from '@/utils/iteration'; import { DATA_SOURCES, FORM_MODE, Path } from '@/utils/enum'; import { getDataSource, getTemplates } from '@/components/pages/setup/utils'; @@ -32,6 +33,7 @@ interface Props { const SampleDatasetIterator = makeIterable(ButtonItem); const SampleDatasetPanel = (props: Props) => { + const t = useTranslations(); const router = useRouter(); const { sampleDataset, closeModal } = props; const templates = getTemplates(); @@ -49,9 +51,11 @@ const SampleDatasetPanel = (props: Props) => { if (!isCurrentTemplate) { const template = templates.find((item) => item.value === name); Modal.confirm({ - title: `Are you sure you want to change to "${template.label}" dataset?`, + title: t('dataSourceSettings.changeSampleDatasetConfirm', { + name: template.label, + }), okButtonProps: { danger: true }, - okText: 'Change', + okText: t('settings.change'), onOk: async () => { await startSampleDataset({ variables: { data: { name } } }); }, @@ -61,7 +65,7 @@ const SampleDatasetPanel = (props: Props) => { return ( <> -
Change sample dataset
+
{t('dataSourceSettings.changeSampleDataset')}
{ />
- Please be aware that choosing another sample dataset will delete all - thread records in the Home page. + {t('dataSourceSettings.changeSampleDatasetWarning')}
); }; const DataSourcePanel = (props: Props) => { + const t = useTranslations(); const { type, properties, refetchSettings } = props; const current = getDataSource(type as unknown as DATA_SOURCES); @@ -87,7 +91,7 @@ const DataSourcePanel = (props: Props) => { onError: (error) => console.error(error), onCompleted: async () => { refetchSettings(); - message.success('Successfully update data source.'); + message.success(t('toasts.dataSourceUpdated')); }, }); @@ -143,7 +147,7 @@ const DataSourcePanel = (props: Props) => {
diff --git a/wren-ui/src/components/settings/ProjectSettings.tsx b/wren-ui/src/components/settings/ProjectSettings.tsx index 923874857b..ef7aa7e900 100644 --- a/wren-ui/src/components/settings/ProjectSettings.tsx +++ b/wren-ui/src/components/settings/ProjectSettings.tsx @@ -1,5 +1,6 @@ import { Button, Modal, Select, Row, Col, Form, message } from 'antd'; import { useRouter } from 'next/router'; +import { useTranslations } from 'next-intl'; import { Path } from '@/utils/enum'; import { useResetCurrentProjectMutation, @@ -15,6 +16,7 @@ interface Props { export default function ProjectSettings(props: Props) { const { data } = props; const router = useRouter(); + const t = useTranslations(); const [form] = Form.useForm(); const [resetCurrentProject, { client }] = useResetCurrentProjectMutation({ onError: (error) => console.error(error), @@ -27,15 +29,15 @@ export default function ProjectSettings(props: Props) { refetchQueries: ['GetSettings'], onError: (error) => console.error(error), onCompleted: () => { - message.success('Successfully updated project language.'); + message.success(t('toasts.projectLanguageUpdated')); }, }); const reset = () => { Modal.confirm({ - title: 'Are you sure you want to reset?', + title: t('projectSettings.resetConfirmTitle'), okButtonProps: { danger: true }, - okText: 'Reset', + okText: t('actions.reset'), onOk: async () => { await resetCurrentProject(); client.clearStore(); @@ -61,14 +63,14 @@ export default function ProjectSettings(props: Props) { initialValues={{ language: data.language }} >