From 47c318bcd6dcc88774c30fb601c6637e1c04b830 Mon Sep 17 00:00:00 2001 From: sufyan Date: Sun, 1 Mar 2026 11:13:03 -0500 Subject: [PATCH 01/15] wip: start implementing ai autocomplete endpoint --- apps/api/.example.env | 2 + apps/api/package.json | 2 + apps/api/src/routers/autocomplete.ts | 42 ++++++++++++ apps/api/src/utils/config.ts | 2 + apps/web/README.md | 6 +- apps/web/package.json | 1 + pnpm-lock.yaml | 95 ++++++++++++++++++++++++---- 7 files changed, 135 insertions(+), 15 deletions(-) create mode 100644 apps/api/src/routers/autocomplete.ts diff --git a/apps/api/.example.env b/apps/api/.example.env index c913405..5c3fdfb 100644 --- a/apps/api/.example.env +++ b/apps/api/.example.env @@ -31,3 +31,5 @@ POLAR_ACCESS_TOKEN="" POLAR_WEBHOOK_SECRET="" POLAR_PRO_PRODUCT_ID="" POLAR_PRO_ANNUAL_PRODUCT_ID="" + +OPENAI_API_KEY="" diff --git a/apps/api/package.json b/apps/api/package.json index 5c1be7f..fc7a706 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -24,6 +24,8 @@ "@polar-sh/better-auth": "^1.8.1", "@polar-sh/sdk": "^0.42.1", "@sentry/bun": "^10.32.1", + "@tanstack/ai": "^0.6.1", + "@tanstack/ai-openai": "^0.6.0", "@tursodatabase/api": "^1.9.0", "@upstash/redis": "^1.36.0", "better-auth": "1.4.19", diff --git a/apps/api/src/routers/autocomplete.ts b/apps/api/src/routers/autocomplete.ts new file mode 100644 index 0000000..1d31337 --- /dev/null +++ b/apps/api/src/routers/autocomplete.ts @@ -0,0 +1,42 @@ +import Elysia from "elysia"; +import { betterAuthGuard } from "../middleware"; + +export const autocompleteRouter = new Elysia({ prefix: "/autocomplete" }) + .use(betterAuthGuard) + .get( + "/user", + async ({ user, status }) => { + const userId = user.id; + + const results = await db + .select() + .from(databases) + .where(eq(databases.user_id, userId)) + .limit(1); + + if (!results[0]) { + return status(404, { message: "No database found for user" }); + } + + const userDb = results[0]; + + if ( + userDb?.access_token && + isJwtExpiringSoon({ token: userDb.access_token }) + ) { + const newToken = await createUserAccessToken({ + dbName: userDb.db_name, + }); + + await db + .update(databases) + .set({ access_token: newToken.jwt }) + .where(eq(databases.id, userDb.id)); + + return { ...userDb, access_token: newToken.jwt }; + } + + return userDb; + }, + { auth: "user" } + ); diff --git a/apps/api/src/utils/config.ts b/apps/api/src/utils/config.ts index 16008a2..40de180 100644 --- a/apps/api/src/utils/config.ts +++ b/apps/api/src/utils/config.ts @@ -44,6 +44,8 @@ const EnvironmentVariablesSchema = z.object({ POLAR_WEBHOOK_SECRET: z.string().min(1), POLAR_PRO_PRODUCT_ID: z.string().min(1), POLAR_PRO_ANNUAL_PRODUCT_ID: z.string().min(1), + + OPENAI_API_KEY: z.string().min(1), }); export type EnvironmentVariables = z.infer; diff --git a/apps/web/README.md b/apps/web/README.md index 5cabdad..e5045fd 100644 --- a/apps/web/README.md +++ b/apps/web/README.md @@ -97,7 +97,7 @@ To add a new color theme: } ``` -2. **Register the theme** in `src/atoms/theme.ts`: +1. **Register the theme** in `src/atoms/theme.ts`: ```typescript export enum ColorTheme { @@ -107,7 +107,7 @@ export enum ColorTheme { } ``` -3. **Add translation** in `src/components/ThemeMenu.tsx`: +1. **Add translation** in `src/components/ThemeMenu.tsx`: ```typescript const ColorThemeLabel: FC<{ theme: ColorTheme }> = ({ theme }) => { @@ -119,7 +119,7 @@ const ColorThemeLabel: FC<{ theme: ColorTheme }> = ({ theme }) => { }; ``` -4. **Extract translations**: `pnpm run i18n:extract` +1. **Extract translations**: `pnpm run i18n:extract` ## Environment Variables diff --git a/apps/web/package.json b/apps/web/package.json index 25b975e..9f78d84 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -31,6 +31,7 @@ "@sentry/vite-plugin": "^4.6.0", "@tailwindcss/postcss": "^4.1.7", "@tailwindcss/vite": "4.1.7", + "@tanstack/ai-react": "^0.6.1", "@tanstack/pacer": "^0.16.3", "@tanstack/react-query": "^5.82.2", "@tanstack/react-query-devtools": "^5.82.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ad279eb..e62cf67 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -44,6 +44,12 @@ importers: '@sentry/bun': specifier: ^10.32.1 version: 10.32.1 + '@tanstack/ai': + specifier: ^0.6.1 + version: 0.6.1 + '@tanstack/ai-openai': + specifier: ^0.6.0 + version: 0.6.0(@tanstack/ai@0.6.1)(zod@4.0.17) '@tursodatabase/api': specifier: ^1.9.0 version: 1.9.0 @@ -461,6 +467,9 @@ importers: '@tailwindcss/vite': specifier: 4.1.7 version: 4.1.7(vite@6.4.1) + '@tanstack/ai-react': + specifier: ^0.6.1 + version: 0.6.1(@tanstack/ai@0.6.1)(@types/react@19.1.17)(react@19.0.0) '@tanstack/pacer': specifier: ^0.16.3 version: 0.16.3 @@ -1329,7 +1338,7 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/traverse': 7.28.3 - '@babel/types': 7.28.5 + '@babel/types': 7.29.0 transitivePeerDependencies: - supports-color @@ -1448,7 +1457,7 @@ packages: resolution: {integrity: sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.28.5 + '@babel/types': 7.29.0 /@babel/helper-optimise-call-expression@7.27.1: resolution: {integrity: sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==} @@ -1602,9 +1611,9 @@ packages: resolution: {integrity: sha512-zdf983tNfLZFletc0RRXYrHrucBEg95NIFMkn6K9dbeMYnsgHaSBGcQqdsCSStG2PYwRre0Qc2NNSCXbG+xc6g==} engines: {node: '>=6.9.0'} dependencies: - '@babel/template': 7.27.2 + '@babel/template': 7.28.6 '@babel/traverse': 7.28.3 - '@babel/types': 7.28.5 + '@babel/types': 7.29.0 transitivePeerDependencies: - supports-color @@ -3875,7 +3884,7 @@ packages: peerDependencies: elysia: '>=1.4.19' dependencies: - elysia: 1.4.26(@sinclair/typebox@0.34.48)(exact-mirror@0.2.7)(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.2) + elysia: 1.4.26(@sinclair/typebox@0.34.48)(exact-mirror@0.2.7)(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.8.3) dev: false /@emmetio/abbreviation@2.3.3: @@ -5893,7 +5902,7 @@ packages: react-hook-form: ^7.55.0 dependencies: '@standard-schema/utils': 0.3.0 - react-hook-form: 7.56.4(react@19.1.0) + react-hook-form: 7.56.4(react@19.0.0) dev: false /@img/colour@1.0.0: @@ -6824,7 +6833,6 @@ packages: transitivePeerDependencies: - supports-color - typescript - dev: true /@lingui/babel-plugin-lingui-macro@5.3.2(babel-plugin-macros@3.1.0)(typescript@5.9.2): resolution: {integrity: sha512-NdXrq8aZlPjN4jeA/LkSLNyx5vPGmrW+r2ywMNQDPQPVP28Hq8c3hF9SQc1t7hwBorGQ3qzIQ7i2Vm6Y8PnjQw==} @@ -6845,6 +6853,7 @@ packages: transitivePeerDependencies: - supports-color - typescript + dev: true /@lingui/babel-plugin-lingui-macro@5.3.2(babel-plugin-macros@3.1.0)(typescript@5.9.3): resolution: {integrity: sha512-NdXrq8aZlPjN4jeA/LkSLNyx5vPGmrW+r2ywMNQDPQPVP28Hq8c3hF9SQc1t7hwBorGQ3qzIQ7i2Vm6Y8PnjQw==} @@ -7014,7 +7023,6 @@ packages: jiti: 1.21.7 transitivePeerDependencies: - typescript - dev: true /@lingui/conf@5.3.2(typescript@5.9.2): resolution: {integrity: sha512-c0Dfovr9BLuwAnY5GADxKcwBUQdVl0Jo/JUa3cumIXFhHzZGb78kfhCHjWWQdX8+WQD8qzSl/YkVDbxhcQJGmg==} @@ -7071,7 +7079,7 @@ packages: optional: true dependencies: '@babel/runtime': 7.26.7 - '@lingui/babel-plugin-lingui-macro': 5.3.2(babel-plugin-macros@3.1.0)(typescript@5.9.2) + '@lingui/babel-plugin-lingui-macro': 5.3.2(babel-plugin-macros@3.1.0)(typescript@5.8.3) '@lingui/message-utils': 5.3.2 babel-plugin-macros: 3.1.0 unraw: 3.0.0 @@ -12621,11 +12629,56 @@ packages: vite: 6.4.1(@types/node@20.10.6) dev: false + /@tanstack/ai-client@0.5.1: + resolution: {integrity: sha512-96Qm8sQYBgfLIUR3f09aaLERsNtg+lpZ1J2jiqFTc8YiL+21Ya2Q1JDU3Opd8nNDIhvjwv1tdNxXAsZnwGKKKQ==} + dependencies: + '@tanstack/ai': 0.6.1 + dev: false + + /@tanstack/ai-openai@0.6.0(@tanstack/ai@0.6.1)(zod@4.0.17): + resolution: {integrity: sha512-CSDgYr63ftw+nGb1IpB+3qIOngLE1pZjasiaeOdDQ6CbSEJDNcR7VNmyTx3RsoTh9fChKbLhJzYpem1Mpag2og==} + peerDependencies: + '@tanstack/ai': ^0.6.1 + zod: ^4.0.0 + dependencies: + '@tanstack/ai': 0.6.1 + openai: 6.25.0(zod@4.0.17) + zod: 4.0.17 + transitivePeerDependencies: + - ws + dev: false + + /@tanstack/ai-react@0.6.1(@tanstack/ai@0.6.1)(@types/react@19.1.17)(react@19.0.0): + resolution: {integrity: sha512-9cGHe1z5NSV5QpFRV5CX2CBXco393JfVxEl4DbGkO9bHsc4cHOUm3sglYZ01Ebcq/pDVoUFDrkHaBxn511GrxA==} + peerDependencies: + '@tanstack/ai': ^0.6.1 + '@types/react': '>=18.0.0' + react: '>=18.0.0' + dependencies: + '@tanstack/ai': 0.6.1 + '@tanstack/ai-client': 0.5.1 + '@types/react': 19.1.17 + react: 19.0.0 + dev: false + + /@tanstack/ai@0.6.1: + resolution: {integrity: sha512-k+4JrjBm5O1j5ccxErlUVC2IC2rJIqQCK45loLckeLow0cJ5rWdKtG03UwR+9VjppDdL6oO27jyk5CzU6ym+HQ==} + engines: {node: '>=18'} + dependencies: + '@tanstack/devtools-event-client': 0.4.0 + partial-json: 0.1.7 + dev: false + /@tanstack/devtools-event-client@0.3.5: resolution: {integrity: sha512-RL1f5ZlfZMpghrCIdzl6mLOFLTuhqmPNblZgBaeKfdtk5rfbjykurv+VfYydOFXj0vxVIoA2d/zT7xfD7Ph8fw==} engines: {node: '>=18'} dev: false + /@tanstack/devtools-event-client@0.4.0: + resolution: {integrity: sha512-RPfGuk2bDZgcu9bAJodvO2lnZeHuz4/71HjZ0bGb/SPg8+lyTA+RLSKQvo7fSmPSi8/vcH3aKQ8EM9ywf1olaw==} + engines: {node: '>=18'} + dev: false + /@tanstack/history@1.115.0: resolution: {integrity: sha512-K7JJNrRVvyjAVnbXOH2XLRhFXDkeP54Kt2P4FR1Kl2KDGlIbkua5VqZQD2rot3qaDrpufyUa63nuLai1kOLTsQ==} engines: {node: '>=12'} @@ -15134,7 +15187,6 @@ packages: parse-json: 5.2.0 path-type: 4.0.0 typescript: 5.8.3 - dev: true /cosmiconfig@8.3.6(typescript@5.9.2): resolution: {integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==} @@ -15862,7 +15914,7 @@ packages: typescript: 5.8.3 dev: false - /elysia@1.4.26(@sinclair/typebox@0.34.48)(exact-mirror@0.2.7)(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.2): + /elysia@1.4.26(@sinclair/typebox@0.34.48)(exact-mirror@0.2.7)(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.8.3): resolution: {integrity: sha512-oGhEFYwt+4M/U9w34XTdBen2KOQIa/PXne40zUkTWRgJlVJNBhepxOdjWeY1U0CbYoEOyZaj1tc79wOsuCxMYw==} peerDependencies: '@sinclair/typebox': '>= 0.34.0 < 1' @@ -15884,7 +15936,7 @@ packages: file-type: 21.3.0 memoirist: 0.4.0 openapi-types: 12.1.3 - typescript: 5.9.2 + typescript: 5.8.3 dev: false /emittery@0.13.1: @@ -21024,6 +21076,21 @@ packages: is-docker: 2.2.1 is-wsl: 2.2.0 + /openai@6.25.0(zod@4.0.17): + resolution: {integrity: sha512-mEh6VZ2ds2AGGokWARo18aPISI1OhlgdEIC1ewhkZr8pSIT31dec0ecr9Nhxx0JlybyOgoAT1sWeKtwPZzJyww==} + hasBin: true + peerDependencies: + ws: ^8.18.0 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + ws: + optional: true + zod: + optional: true + dependencies: + zod: 4.0.17 + dev: false + /openapi-types@12.1.3: resolution: {integrity: sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==} dev: false @@ -21191,6 +21258,10 @@ packages: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} + /partial-json@0.1.7: + resolution: {integrity: sha512-Njv/59hHaokb/hRUjce3Hdv12wd60MtM9Z5Olmn+nehe0QDAsRtRbJPvJ0Z91TusF0SuZRIvnM+S4l6EIP8leA==} + dev: false + /password-prompt@1.1.3: resolution: {integrity: sha512-HkrjG2aJlvF0t2BMH0e2LB/EHf3Lcq3fNMzy4GYHcQblAvOl+QQji1Lx7WRBMqpVK8p+KR7bCg7oqAMXtdgqyw==} dependencies: From 6f14232edcf798a3103e7877981500a5ba4c9baa Mon Sep 17 00:00:00 2001 From: shunsei Date: Sun, 1 Mar 2026 11:41:13 -0500 Subject: [PATCH 02/15] fix: dont create polar user on sign up in dev/local env so that sign up isn't blocked on polar set up --- apps/api/src/auth.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/api/src/auth.ts b/apps/api/src/auth.ts index eeb8bc0..fbf6b9e 100644 --- a/apps/api/src/auth.ts +++ b/apps/api/src/auth.ts @@ -308,7 +308,7 @@ export const auth = betterAuth({ }), polar({ client: polarClient, - createCustomerOnSignUp: true, + createCustomerOnSignUp: config.NODE_ENV === "production", use: [ checkout({ products: [ From 77bda4fce82bdab49a5de91b89b17d77dba99231 Mon Sep 17 00:00:00 2001 From: sufyan Date: Sun, 1 Mar 2026 19:01:49 -0500 Subject: [PATCH 03/15] feat: upgrade zod to v4.3 and implement ai autocomplete endpoint --- apps/api/package.json | 5 +- apps/api/src/routers/ai.ts | 54 +++ apps/api/src/routers/autocomplete.ts | 42 --- apps/mobile/package.json | 2 +- apps/web/package.json | 2 +- packages/db-operations/package.json | 2 +- .../drizzle-user-db-schemas/src/dictionary.ts | 7 + packages/drizzle-user-db-schemas/src/index.ts | 2 + pnpm-lock.yaml | 351 ++++++++---------- 9 files changed, 231 insertions(+), 236 deletions(-) create mode 100644 apps/api/src/routers/ai.ts delete mode 100644 apps/api/src/routers/autocomplete.ts diff --git a/apps/api/package.json b/apps/api/package.json index fc7a706..c444de9 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -25,7 +25,7 @@ "@polar-sh/sdk": "^0.42.1", "@sentry/bun": "^10.32.1", "@tanstack/ai": "^0.6.1", - "@tanstack/ai-openai": "^0.6.0", + "@tanstack/ai-openai": "^0.6.1", "@tursodatabase/api": "^1.9.0", "@upstash/redis": "^1.36.0", "better-auth": "1.4.19", @@ -38,9 +38,10 @@ "pino": "^9.6.0", "resend": "^4.6.0", "tsx": "^4.7.1", - "zod": "4.0.17" + "zod": "4.3.6" }, "devDependencies": { + "@bahar/drizzle-user-db-schemas": "workspace:*", "@bahar/typescript-config": "workspace:*", "bun-types": "^1.3.5", "drizzle-kit": "0.31.9", diff --git a/apps/api/src/routers/ai.ts b/apps/api/src/routers/ai.ts new file mode 100644 index 0000000..028d3ca --- /dev/null +++ b/apps/api/src/routers/ai.ts @@ -0,0 +1,54 @@ +import { InsertDictionaryEntrySchema } from "@bahar/drizzle-user-db-schemas"; +import { chat } from "@tanstack/ai"; +import { openaiText } from "@tanstack/ai-openai"; +import Elysia from "elysia"; +import { betterAuthGuard } from "../middleware"; + +const AUTOCOMPLETE_SYSTEM_PROMPT = ` + You are an Arabic linguistics expert. + + Given an Arabic word or expression, its English translation, and the type (ism, fi'l, harf or expression), generate accurate dictionary data for an Arabic language learning app. + + Rules: + - All Arabic text MUST include full tashkeel (harakat/diacritical marks) + - Root letters: provide the trilateral or quadrilateral root as space-separated letters (e.g. "ك ت ب") + - Only populate morphology fields relevant to the word type: ism fields for nouns, verb fields for verbs, neither for harf/expressions + - For verbs: identify the correct form (I–X), provide the Arabic pattern (e.g. فَعَلَ), past/present/imperative with full tashkeel + - For nouns: provide plural forms (if applicable), gender, and inflection type + - Definition: must be in Arabic + - Generate 2–3 example sentences at varying difficulty, each with translation and context label (if necessary) + - Omit any field you are not confident about rather than guessing +`; + +export const autocompleteRouter = new Elysia({ prefix: "/ai" }) + .use(betterAuthGuard) + .post( + "/autocomplete", + async ({ body: { translation, type, word } }) => { + const dictionaryEntrySuggestion = await chat({ + adapter: openaiText("gpt-4.1-nano") as never, + systemPrompts: [AUTOCOMPLETE_SYSTEM_PROMPT], + messages: [ + { + role: "user", + content: `Word: "${word}", Translation: "${translation}", Type: "${type}"`, + }, + ], + outputSchema: InsertDictionaryEntrySchema.pick({ + definition: true, + examples: true, + morphology: true, + root: true, + }), + }); + + return dictionaryEntrySuggestion; + }, + { + body: InsertDictionaryEntrySchema.pick({ + word: true, + translation: true, + type: true, + }), + } + ); diff --git a/apps/api/src/routers/autocomplete.ts b/apps/api/src/routers/autocomplete.ts deleted file mode 100644 index 1d31337..0000000 --- a/apps/api/src/routers/autocomplete.ts +++ /dev/null @@ -1,42 +0,0 @@ -import Elysia from "elysia"; -import { betterAuthGuard } from "../middleware"; - -export const autocompleteRouter = new Elysia({ prefix: "/autocomplete" }) - .use(betterAuthGuard) - .get( - "/user", - async ({ user, status }) => { - const userId = user.id; - - const results = await db - .select() - .from(databases) - .where(eq(databases.user_id, userId)) - .limit(1); - - if (!results[0]) { - return status(404, { message: "No database found for user" }); - } - - const userDb = results[0]; - - if ( - userDb?.access_token && - isJwtExpiringSoon({ token: userDb.access_token }) - ) { - const newToken = await createUserAccessToken({ - dbName: userDb.db_name, - }); - - await db - .update(databases) - .set({ access_token: newToken.jwt }) - .where(eq(databases.id, userDb.id)); - - return { ...userDb, access_token: newToken.jwt }; - } - - return userDb; - }, - { auth: "user" } - ); diff --git a/apps/mobile/package.json b/apps/mobile/package.json index 3827792..995f709 100644 --- a/apps/mobile/package.json +++ b/apps/mobile/package.json @@ -67,7 +67,7 @@ "sonner-native": "^0.21.0", "ts-fsrs": "^5.2.3", "uniwind": "^1.2.2", - "zod": "4.0.17" + "zod": "4.3.6" }, "devDependencies": { "@babel/core": "^7.25.2", diff --git a/apps/web/package.json b/apps/web/package.json index 9f78d84..bfff7fa 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -52,7 +52,7 @@ "react-dom": "19.0.0", "react-hook-form": "^7.56.4", "ts-fsrs": "^5.2.3", - "zod": "4.0.17" + "zod": "4.3.6" }, "devDependencies": { "@bahar/design-system": "workspace:*", diff --git a/packages/db-operations/package.json b/packages/db-operations/package.json index d3dd5be..d5769a0 100644 --- a/packages/db-operations/package.json +++ b/packages/db-operations/package.json @@ -14,7 +14,7 @@ "@bahar/drizzle-user-db-schemas": "workspace:*", "@bahar/result": "workspace:*", "@bahar/typescript-config": "workspace:*", - "zod": "4.0.17" + "zod": "4.3.6" }, "dependencies": { "nanoid": "^5.0.7" diff --git a/packages/drizzle-user-db-schemas/src/dictionary.ts b/packages/drizzle-user-db-schemas/src/dictionary.ts index 3e68b31..cb6eb57 100644 --- a/packages/drizzle-user-db-schemas/src/dictionary.ts +++ b/packages/drizzle-user-db-schemas/src/dictionary.ts @@ -1,4 +1,5 @@ import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core"; +import { createInsertSchema, createSelectSchema } from "drizzle-zod"; import { type Antonym, type Example, @@ -46,3 +47,9 @@ export type RawDictionaryEntry = Omit< examples: string | null; morphology: string | null; }; + +export const InsertDictionaryEntrySchema = + createInsertSchema(dictionaryEntries); + +export const SelectDictionaryEntrySchema = + createSelectSchema(dictionaryEntries); diff --git a/packages/drizzle-user-db-schemas/src/index.ts b/packages/drizzle-user-db-schemas/src/index.ts index 380e0cf..1010a8c 100644 --- a/packages/drizzle-user-db-schemas/src/index.ts +++ b/packages/drizzle-user-db-schemas/src/index.ts @@ -8,8 +8,10 @@ export { decks, type InsertDeck, type RawDeck, type SelectDeck } from "./decks"; export { dictionaryEntries, type InsertDictionaryEntry, + InsertDictionaryEntrySchema, type RawDictionaryEntry, type SelectDictionaryEntry, + SelectDictionaryEntrySchema, } from "./dictionary"; export { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e62cf67..db03af0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -37,7 +37,7 @@ importers: version: 0.10.0 '@polar-sh/better-auth': specifier: ^1.8.1 - version: 1.8.1(@polar-sh/sdk@0.42.5)(@stripe/react-stripe-js@4.0.2)(@stripe/stripe-js@7.9.0)(better-auth@1.4.19)(react-dom@19.1.0)(react-is@19.2.4)(react@19.1.0)(redux@5.0.1)(zod@4.0.17) + version: 1.8.1(@polar-sh/sdk@0.42.5)(@stripe/react-stripe-js@4.0.2)(@stripe/stripe-js@7.9.0)(better-auth@1.4.19)(react-dom@19.1.0)(react-is@19.2.4)(react@19.1.0)(redux@5.0.1)(zod@4.3.6) '@polar-sh/sdk': specifier: ^0.42.1 version: 0.42.5 @@ -49,7 +49,7 @@ importers: version: 0.6.1 '@tanstack/ai-openai': specifier: ^0.6.0 - version: 0.6.0(@tanstack/ai@0.6.1)(zod@4.0.17) + version: 0.6.0(@tanstack/ai@0.6.1)(zod@4.3.6) '@tursodatabase/api': specifier: ^1.9.0 version: 1.9.0 @@ -67,7 +67,7 @@ importers: version: 0.45.1(@libsql/client@0.10.0)(@opentelemetry/api@1.9.0)(@upstash/redis@1.36.0)(bun-types@1.3.5)(kysely@0.28.5) drizzle-zod: specifier: ^0.8.3 - version: 0.8.3(drizzle-orm@0.45.1)(zod@4.0.17) + version: 0.8.3(drizzle-orm@0.45.1)(zod@4.3.6) elysia: specifier: ^1.4.19 version: 1.4.19(@sinclair/typebox@0.34.48)(exact-mirror@0.2.7)(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.8.3) @@ -87,9 +87,12 @@ importers: specifier: ^4.7.1 version: 4.7.1 zod: - specifier: 4.0.17 - version: 4.0.17 + specifier: 4.3.6 + version: 4.3.6 devDependencies: + '@bahar/drizzle-user-db-schemas': + specifier: workspace:* + version: link:../../packages/drizzle-user-db-schemas '@bahar/typescript-config': specifier: workspace:* version: link:../../packages/config-typescript @@ -177,7 +180,7 @@ importers: version: 3.0.0(expo@54.0.25) '@elysiajs/eden': specifier: ^1.4.6 - version: 1.4.6(elysia@1.4.26) + version: 1.4.6(elysia@1.4.27) '@expo/vector-icons': specifier: ^15.0.3 version: 15.0.3(expo-font@14.0.9)(react-native@0.81.5)(react@19.1.0) @@ -329,8 +332,8 @@ importers: specifier: ^1.2.2 version: 1.2.2(react-native@0.81.5)(react@19.1.0)(tailwindcss@4.1.17) zod: - specifier: 4.0.17 - version: 4.0.17 + specifier: 4.3.6 + version: 4.3.6 devDependencies: '@babel/core': specifier: ^7.25.2 @@ -367,7 +370,7 @@ importers: version: 5.3.2(@lingui/babel-plugin-lingui-macro@5.3.2)(react@19.1.0) '@lingui/metro-transformer': specifier: ^5.3.2 - version: 5.3.2(expo@54.0.25)(metro@0.84.0)(react-native@0.81.5)(typescript@5.9.2) + version: 5.3.2(expo@54.0.25)(metro@0.84.2)(react-native@0.81.5)(typescript@5.9.2) '@tailwindcss/postcss': specifier: ^4.1.7 version: 4.1.17 @@ -388,7 +391,7 @@ importers: version: 29.7.0 jest-expo: specifier: ~54.0.13 - version: 54.0.13(@babel/core@7.26.0)(expo@54.0.25)(jest@29.7.0)(react-dom@19.1.0)(react-native@0.81.5)(react@19.1.0)(webpack@5.105.2) + version: 54.0.13(@babel/core@7.26.0)(expo@54.0.25)(jest@29.7.0)(react-dom@19.1.0)(react-native@0.81.5)(react@19.1.0)(webpack@5.105.3) postcss: specifier: ^8.5.0 version: 8.5.3 @@ -421,7 +424,7 @@ importers: version: link:../../packages/web-ui '@elysiajs/eden': specifier: ^1.4.6 - version: 1.4.6(elysia@1.4.26) + version: 1.4.6(elysia@1.4.27) '@hookform/resolvers': specifier: ^5.2.2 version: 5.2.2(react-hook-form@7.56.4) @@ -454,7 +457,7 @@ importers: version: 3.1.16 '@polar-sh/better-auth': specifier: ^1.8.1 - version: 1.8.1(@polar-sh/sdk@0.42.5)(@stripe/react-stripe-js@4.0.2)(@stripe/stripe-js@7.9.0)(@types/react-dom@19.0.0)(@types/react@19.1.17)(better-auth@1.4.19)(react-dom@19.0.0)(react-is@19.2.4)(react@19.0.0)(redux@5.0.1)(zod@4.0.17) + version: 1.8.1(@polar-sh/sdk@0.42.5)(@stripe/react-stripe-js@4.0.2)(@stripe/stripe-js@7.9.0)(@types/react-dom@19.0.0)(@types/react@19.1.17)(better-auth@1.4.19)(react-dom@19.0.0)(react-is@19.2.4)(react@19.0.0)(redux@5.0.1)(zod@4.3.6) '@sentry/react': specifier: ^10.25.0 version: 10.25.0(react@19.0.0) @@ -484,7 +487,7 @@ importers: version: 1.120.13(react-dom@19.0.0)(react@19.0.0) '@tanstack/zod-adapter': specifier: ^1.150.0 - version: 1.150.0(@tanstack/react-router@1.120.13)(zod@4.0.17) + version: 1.150.0(@tanstack/react-router@1.120.13)(zod@4.3.6) '@tursodatabase/sync-wasm': specifier: ^0.3.2 version: 0.3.2 @@ -531,8 +534,8 @@ importers: specifier: ^5.2.3 version: 5.2.3 zod: - specifier: 4.0.17 - version: 4.0.17 + specifier: 4.3.6 + version: 4.3.6 devDependencies: '@bahar/design-system': specifier: workspace:* @@ -613,8 +616,8 @@ importers: specifier: workspace:* version: link:../config-typescript zod: - specifier: 4.0.17 - version: 4.0.17 + specifier: 4.3.6 + version: 4.3.6 packages/design-system: dependencies: @@ -3487,7 +3490,7 @@ packages: '@better-auth/utils': 0.3.0 '@better-fetch/fetch': 1.1.21 '@standard-schema/spec': 1.1.0 - better-call: 1.1.8(zod@4.0.17) + better-call: 1.1.8(zod@4.3.6) jose: 6.1.3 kysely: 0.28.5 nanostores: 1.1.0 @@ -3507,11 +3510,11 @@ packages: '@better-auth/utils': 0.3.0 '@better-fetch/fetch': 1.1.21 '@standard-schema/spec': 1.1.0 - better-call: 1.1.7(zod@4.0.17) + better-call: 1.1.7(zod@4.3.6) jose: 6.1.3 kysely: 0.28.5 nanostores: 1.1.0 - zod: 4.2.1 + zod: 4.3.6 dev: false /@better-auth/expo@1.4.19(@better-auth/core@1.4.19)(better-auth@1.4.19): @@ -3562,11 +3565,11 @@ packages: '@better-auth/core': 1.4.9(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.7)(jose@6.1.3)(kysely@0.28.5)(nanostores@1.1.0) '@better-fetch/fetch': 1.1.21 better-auth: 1.4.9(react-dom@19.1.0)(react@19.1.0) - better-call: 1.1.7(zod@4.2.1) + better-call: 1.1.7(zod@4.3.6) expo-constants: 18.0.10(expo@54.0.25)(react-native@0.81.5) expo-linking: 8.0.9(expo@54.0.25)(react-native@0.81.5)(react@19.1.0) expo-web-browser: 15.0.9(expo@54.0.25)(react-native@0.81.5) - zod: 4.2.1 + zod: 4.3.6 dev: false /@better-auth/telemetry@1.4.19(@better-auth/core@1.4.19): @@ -3879,12 +3882,12 @@ packages: elysia: 1.4.19(@sinclair/typebox@0.34.48)(exact-mirror@0.2.7)(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.8.3) dev: false - /@elysiajs/eden@1.4.6(elysia@1.4.26): + /@elysiajs/eden@1.4.6(elysia@1.4.27): resolution: {integrity: sha512-Tsa4NwXEWg/u73vWiYZQ3L5/ecgZSxqiEjYwpS+4qBKXeTZqZKl2hcgHJSVBL+InEDMi35Xugct7qyAXE5oM4Q==} peerDependencies: elysia: '>=1.4.19' dependencies: - elysia: 1.4.26(@sinclair/typebox@0.34.48)(exact-mirror@0.2.7)(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.8.3) + elysia: 1.4.27(@sinclair/typebox@0.34.48)(exact-mirror@0.2.7)(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.2) dev: false /@emmetio/abbreviation@2.3.3: @@ -5902,7 +5905,7 @@ packages: react-hook-form: ^7.55.0 dependencies: '@standard-schema/utils': 0.3.0 - react-hook-form: 7.56.4(react@19.0.0) + react-hook-form: 7.56.4(react@19.1.0) dev: false /@img/colour@1.0.0: @@ -6833,6 +6836,7 @@ packages: transitivePeerDependencies: - supports-color - typescript + dev: true /@lingui/babel-plugin-lingui-macro@5.3.2(babel-plugin-macros@3.1.0)(typescript@5.9.2): resolution: {integrity: sha512-NdXrq8aZlPjN4jeA/LkSLNyx5vPGmrW+r2ywMNQDPQPVP28Hq8c3hF9SQc1t7hwBorGQ3qzIQ7i2Vm6Y8PnjQw==} @@ -6853,7 +6857,6 @@ packages: transitivePeerDependencies: - supports-color - typescript - dev: true /@lingui/babel-plugin-lingui-macro@5.3.2(babel-plugin-macros@3.1.0)(typescript@5.9.3): resolution: {integrity: sha512-NdXrq8aZlPjN4jeA/LkSLNyx5vPGmrW+r2ywMNQDPQPVP28Hq8c3hF9SQc1t7hwBorGQ3qzIQ7i2Vm6Y8PnjQw==} @@ -7023,6 +7026,7 @@ packages: jiti: 1.21.7 transitivePeerDependencies: - typescript + dev: true /@lingui/conf@5.3.2(typescript@5.9.2): resolution: {integrity: sha512-c0Dfovr9BLuwAnY5GADxKcwBUQdVl0Jo/JUa3cumIXFhHzZGb78kfhCHjWWQdX8+WQD8qzSl/YkVDbxhcQJGmg==} @@ -7079,7 +7083,7 @@ packages: optional: true dependencies: '@babel/runtime': 7.26.7 - '@lingui/babel-plugin-lingui-macro': 5.3.2(babel-plugin-macros@3.1.0)(typescript@5.8.3) + '@lingui/babel-plugin-lingui-macro': 5.3.2(babel-plugin-macros@3.1.0)(typescript@5.9.2) '@lingui/message-utils': 5.3.2 babel-plugin-macros: 3.1.0 unraw: 3.0.0 @@ -7171,7 +7175,7 @@ packages: bundledDependencies: - '@messageformat/date-skeleton' - /@lingui/metro-transformer@5.3.2(expo@54.0.25)(metro@0.84.0)(react-native@0.81.5)(typescript@5.9.2): + /@lingui/metro-transformer@5.3.2(expo@54.0.25)(metro@0.84.2)(react-native@0.81.5)(typescript@5.9.2): resolution: {integrity: sha512-wUnTwPauS1+9Vcy86GbUvxwS0nxfLlDVnN/UIZQhXbW5xsfTikXwifUvFd8RoaaUad9OGSo9NWZcX+QVCfsebg==} engines: {node: '>=16.0.0'} peerDependencies: @@ -7193,7 +7197,7 @@ packages: '@lingui/conf': 5.3.2(typescript@5.9.2) expo: 54.0.25(@babel/core@7.26.0)(@expo/metro-runtime@6.1.2)(expo-router@6.0.15)(react-native-webview@13.15.0)(react-native@0.81.5)(react@19.1.0) memoize-one: 6.0.0 - metro: 0.84.0 + metro: 0.84.2 react-native: 0.81.5(@babel/core@7.26.0)(@types/react@19.1.17)(react@19.1.0) transitivePeerDependencies: - supports-color @@ -7761,7 +7765,7 @@ packages: requiresBuild: true optional: true - /@polar-sh/better-auth@1.8.1(@polar-sh/sdk@0.42.5)(@stripe/react-stripe-js@4.0.2)(@stripe/stripe-js@7.9.0)(@types/react-dom@19.0.0)(@types/react@19.1.17)(better-auth@1.4.19)(react-dom@19.0.0)(react-is@19.2.4)(react@19.0.0)(redux@5.0.1)(zod@4.0.17): + /@polar-sh/better-auth@1.8.1(@polar-sh/sdk@0.42.5)(@stripe/react-stripe-js@4.0.2)(@stripe/stripe-js@7.9.0)(@types/react-dom@19.0.0)(@types/react@19.1.17)(better-auth@1.4.19)(react-dom@19.0.0)(react-is@19.2.4)(react@19.0.0)(redux@5.0.1)(zod@4.3.6): resolution: {integrity: sha512-wZjF1xcxw1+blnR8JspPwZ0WhwoHkG4C2oFhVzb1RJKQfwTBjSmnrBftjaV6D3WFHDnrs0wFPnW/YHXzg8paOA==} engines: {node: '>=16'} peerDependencies: @@ -7772,7 +7776,7 @@ packages: '@polar-sh/checkout': 0.2.0(@stripe/react-stripe-js@4.0.2)(@stripe/stripe-js@7.9.0)(@types/react-dom@19.0.0)(@types/react@19.1.17)(react-dom@19.0.0)(react-is@19.2.4)(react@19.0.0)(redux@5.0.1) '@polar-sh/sdk': 0.42.5 better-auth: 1.4.19(drizzle-orm@0.45.1)(react-dom@19.0.0)(react@19.0.0) - zod: 4.0.17 + zod: 4.3.6 transitivePeerDependencies: - '@stripe/react-stripe-js' - '@stripe/stripe-js' @@ -7784,7 +7788,7 @@ packages: - redux dev: false - /@polar-sh/better-auth@1.8.1(@polar-sh/sdk@0.42.5)(@stripe/react-stripe-js@4.0.2)(@stripe/stripe-js@7.9.0)(better-auth@1.4.19)(react-dom@19.1.0)(react-is@19.2.4)(react@19.1.0)(redux@5.0.1)(zod@4.0.17): + /@polar-sh/better-auth@1.8.1(@polar-sh/sdk@0.42.5)(@stripe/react-stripe-js@4.0.2)(@stripe/stripe-js@7.9.0)(better-auth@1.4.19)(react-dom@19.1.0)(react-is@19.2.4)(react@19.1.0)(redux@5.0.1)(zod@4.3.6): resolution: {integrity: sha512-wZjF1xcxw1+blnR8JspPwZ0WhwoHkG4C2oFhVzb1RJKQfwTBjSmnrBftjaV6D3WFHDnrs0wFPnW/YHXzg8paOA==} engines: {node: '>=16'} peerDependencies: @@ -7795,7 +7799,7 @@ packages: '@polar-sh/checkout': 0.2.0(@stripe/react-stripe-js@4.0.2)(@stripe/stripe-js@7.9.0)(react-dom@19.1.0)(react-is@19.2.4)(react@19.1.0)(redux@5.0.1) '@polar-sh/sdk': 0.42.5 better-auth: 1.4.19(drizzle-kit@0.31.9)(drizzle-orm@0.45.1)(react-dom@19.1.0)(react@19.1.0) - zod: 4.0.17 + zod: 4.3.6 transitivePeerDependencies: - '@stripe/react-stripe-js' - '@stripe/stripe-js' @@ -12635,15 +12639,15 @@ packages: '@tanstack/ai': 0.6.1 dev: false - /@tanstack/ai-openai@0.6.0(@tanstack/ai@0.6.1)(zod@4.0.17): + /@tanstack/ai-openai@0.6.0(@tanstack/ai@0.6.1)(zod@4.3.6): resolution: {integrity: sha512-CSDgYr63ftw+nGb1IpB+3qIOngLE1pZjasiaeOdDQ6CbSEJDNcR7VNmyTx3RsoTh9fChKbLhJzYpem1Mpag2og==} peerDependencies: '@tanstack/ai': ^0.6.1 zod: ^4.0.0 dependencies: '@tanstack/ai': 0.6.1 - openai: 6.25.0(zod@4.0.17) - zod: 4.0.17 + openai: 6.25.0(zod@4.3.6) + zod: 4.3.6 transitivePeerDependencies: - ws dev: false @@ -12811,7 +12815,7 @@ packages: '@tanstack/virtual-file-routes': 1.87.6 prettier: 3.4.2 tsx: 4.19.2 - zod: 3.24.1 + zod: 3.25.76 dev: true /@tanstack/router-plugin@1.91.1(vite@6.4.1): @@ -12847,7 +12851,7 @@ packages: chokidar: 3.6.0 unplugin: 1.16.0 vite: 6.4.1(@types/node@20.10.6) - zod: 3.24.1 + zod: 3.25.76 transitivePeerDependencies: - supports-color dev: true @@ -12869,7 +12873,7 @@ packages: engines: {node: '>=12'} dev: true - /@tanstack/zod-adapter@1.150.0(@tanstack/react-router@1.120.13)(zod@4.0.17): + /@tanstack/zod-adapter@1.150.0(@tanstack/react-router@1.120.13)(zod@4.3.6): resolution: {integrity: sha512-MdkmF6tqxxskG3K3LHVN+PAj8m7kHMhlArDcI4Mi+Fx5CG3BCJcpYGv4aZJhvL0CxHw3N6qyn6SIzG9FraXhWA==} engines: {node: '>=12'} peerDependencies: @@ -12877,7 +12881,7 @@ packages: zod: ^3.23.8 dependencies: '@tanstack/react-router': 1.120.13(react-dom@19.0.0)(react@19.0.0) - zod: 4.0.17 + zod: 4.3.6 dev: false /@tokenizer/inflate@0.4.1: @@ -13136,12 +13140,6 @@ packages: dependencies: undici-types: 5.26.5 - /@types/node@20.19.33: - resolution: {integrity: sha512-Rs1bVAIdBs5gbTIKza/tgpMuG1k3U/UMJLWecIMxNdJFDMzcM5LOiLVRYh3PilWEYDIeUDv7bpiHPLPsbydGcw==} - dependencies: - undici-types: 6.21.0 - dev: true - /@types/parse-json@4.0.2: resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} @@ -14293,7 +14291,7 @@ packages: '@better-fetch/fetch': 1.1.21 '@noble/ciphers': 2.1.1 '@noble/hashes': 2.0.1 - better-call: 1.1.8(zod@4.0.17) + better-call: 1.1.8(zod@4.3.6) defu: 6.1.4 drizzle-kit: 0.31.9 drizzle-orm: 0.45.1(@libsql/client@0.10.0)(@opentelemetry/api@1.9.0)(@upstash/redis@1.36.0)(bun-types@1.3.5)(kysely@0.28.5) @@ -14373,7 +14371,7 @@ packages: '@better-fetch/fetch': 1.1.21 '@noble/ciphers': 2.1.1 '@noble/hashes': 2.0.1 - better-call: 1.1.8(zod@4.0.17) + better-call: 1.1.8(zod@4.3.6) defu: 6.1.4 drizzle-orm: 0.45.1(@libsql/client@0.10.0)(@opentelemetry/api@1.9.0)(@upstash/redis@1.36.0)(bun-types@1.3.5)(kysely@0.28.5) jose: 6.1.3 @@ -14449,32 +14447,17 @@ packages: '@better-fetch/fetch': 1.1.21 '@noble/ciphers': 2.1.1 '@noble/hashes': 2.0.1 - better-call: 1.1.7(zod@4.0.17) + better-call: 1.1.7(zod@4.3.6) defu: 6.1.4 jose: 6.1.3 kysely: 0.28.5 nanostores: 1.1.0 react: 19.1.0 react-dom: 19.1.0(react@19.1.0) - zod: 4.2.1 - dev: false - - /better-call@1.1.7(zod@4.0.17): - resolution: {integrity: sha512-6gaJe1bBIEgVebQu/7q9saahVzvBsGaByEnE8aDVncZEDiJO7sdNB28ot9I6iXSbR25egGmmZ6aIURXyQHRraQ==} - peerDependencies: - zod: ^4.0.0 - peerDependenciesMeta: - zod: - optional: true - dependencies: - '@better-auth/utils': 0.3.0 - '@better-fetch/fetch': 1.1.21 - rou3: 0.7.12 - set-cookie-parser: 2.7.1 - zod: 4.0.17 + zod: 4.3.6 dev: false - /better-call@1.1.7(zod@4.2.1): + /better-call@1.1.7(zod@4.3.6): resolution: {integrity: sha512-6gaJe1bBIEgVebQu/7q9saahVzvBsGaByEnE8aDVncZEDiJO7sdNB28ot9I6iXSbR25egGmmZ6aIURXyQHRraQ==} peerDependencies: zod: ^4.0.0 @@ -14486,22 +14469,7 @@ packages: '@better-fetch/fetch': 1.1.21 rou3: 0.7.12 set-cookie-parser: 2.7.1 - zod: 4.2.1 - dev: false - - /better-call@1.1.8(zod@4.0.17): - resolution: {integrity: sha512-XMQ2rs6FNXasGNfMjzbyroSwKwYbZ/T3IxruSS6U2MJRsSYh3wYtG3o6H00ZlKZ/C/UPOAD97tqgQJNsxyeTXw==} - peerDependencies: - zod: ^4.0.0 - peerDependenciesMeta: - zod: - optional: true - dependencies: - '@better-auth/utils': 0.3.0 - '@better-fetch/fetch': 1.1.21 - rou3: 0.7.12 - set-cookie-parser: 2.7.1 - zod: 4.0.17 + zod: 4.3.6 dev: false /better-call@1.1.8(zod@4.3.6): @@ -14594,10 +14562,9 @@ packages: resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} dependencies: balanced-match: 1.0.2 - dev: false - /brace-expansion@5.0.3: - resolution: {integrity: sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==} + /brace-expansion@5.0.4: + resolution: {integrity: sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==} engines: {node: 18 || 20 || >=22} dependencies: balanced-match: 4.0.4 @@ -14647,7 +14614,7 @@ packages: hasBin: true dependencies: baseline-browser-mapping: 2.10.0 - caniuse-lite: 1.0.30001774 + caniuse-lite: 1.0.30001775 electron-to-chromium: 1.5.302 node-releases: 2.0.27 update-browserslist-db: 1.2.3(browserslist@4.28.1) @@ -14724,8 +14691,8 @@ packages: /caniuse-lite@1.0.30001737: resolution: {integrity: sha512-BiloLiXtQNrY5UyF0+1nSJLXUENuhka2pzy2Fx5pGxqavdrxSCW4U6Pn/PoG3Efspi2frRbHpBV2XsrPE6EDlw==} - /caniuse-lite@1.0.30001774: - resolution: {integrity: sha512-DDdwPGz99nmIEv216hKSgLD+D4ikHQHjBC/seF98N9CPqRX4M5mSxT9eTV6oyisnJcuzxtZy4n17yKKQYmYQOA==} + /caniuse-lite@1.0.30001775: + resolution: {integrity: sha512-s3Qv7Lht9zbVKE9XoTyRG6wVDCKdtOFIjBGg3+Yhn6JaytuNKPIjBMTMIY1AnOH3seL5mvF+x33oGAyK3hVt3A==} /ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} @@ -15187,6 +15154,7 @@ packages: parse-json: 5.2.0 path-type: 4.0.0 typescript: 5.8.3 + dev: true /cosmiconfig@8.3.6(typescript@5.9.2): resolution: {integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==} @@ -15852,6 +15820,16 @@ packages: zod: 4.0.17 dev: false + /drizzle-zod@0.8.3(drizzle-orm@0.45.1)(zod@4.3.6): + resolution: {integrity: sha512-66yVOuvGhKJnTdiqj1/Xaaz9/qzOdRJADpDa68enqS6g3t0kpNkwNYjUuaeXgZfO/UWuIM9HIhSlJ6C5ZraMww==} + peerDependencies: + drizzle-orm: '>=0.36.0' + zod: ^3.25.0 || ^4.0.0 + dependencies: + drizzle-orm: 0.45.1(@libsql/client@0.10.0)(@opentelemetry/api@1.9.0)(@upstash/redis@1.36.0)(bun-types@1.3.5)(kysely@0.28.5) + zod: 4.3.6 + dev: false + /dset@3.1.4: resolution: {integrity: sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==} engines: {node: '>=4'} @@ -15914,8 +15892,8 @@ packages: typescript: 5.8.3 dev: false - /elysia@1.4.26(@sinclair/typebox@0.34.48)(exact-mirror@0.2.7)(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.8.3): - resolution: {integrity: sha512-oGhEFYwt+4M/U9w34XTdBen2KOQIa/PXne40zUkTWRgJlVJNBhepxOdjWeY1U0CbYoEOyZaj1tc79wOsuCxMYw==} + /elysia@1.4.27(@sinclair/typebox@0.34.48)(exact-mirror@0.2.7)(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.2): + resolution: {integrity: sha512-2UlmNEjPJVA/WZVPYKy+KdsrfFwwNlqSBW1lHz6i2AHc75k7gV4Rhm01kFeotH7PDiHIX2G8X3KnRPc33SGVIg==} peerDependencies: '@sinclair/typebox': '>= 0.34.0 < 1' '@types/bun': '>= 1.2.0' @@ -15936,7 +15914,7 @@ packages: file-type: 21.3.0 memoirist: 0.4.0 openapi-types: 12.1.3 - typescript: 5.8.3 + typescript: 5.9.2 dev: false /emittery@0.13.1: @@ -15982,8 +15960,8 @@ packages: graceful-fs: 4.2.11 tapable: 2.2.3 - /enhanced-resolve@5.19.0: - resolution: {integrity: sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==} + /enhanced-resolve@5.20.0: + resolution: {integrity: sha512-/ce7+jQ1PQ6rVXwe+jKEg5hW5ciicHwIQUagZkp6IufBoY3YDgdTTY1azVs0qoRgVmvsNB+rbjLJxDAeHHtwsQ==} engines: {node: '>=10.13.0'} dependencies: graceful-fs: 4.2.11 @@ -17115,11 +17093,10 @@ packages: - supports-color dev: false - /filelist@1.0.5: - resolution: {integrity: sha512-ct/ckWBV/9Dg3MlvCXsLcSUyoWwv9mCKqlhLNB2DAuXR/NZolSXlQqP5dyy6guWlPXBhodZyZ5lGPQcbQDxrEQ==} - engines: {node: 20 || >=22} + /filelist@1.0.6: + resolution: {integrity: sha512-5giy2PkLYY1cP39p17Ech+2xlpTRL9HLspOfEgm0L6CwBXBTgsK5ou0JtzYuepxkaQ/tvhCFIJ5uXo0OrM2DxA==} dependencies: - minimatch: 10.2.3 + minimatch: 5.1.9 dev: true /fill-range@7.0.1: @@ -17459,7 +17436,7 @@ packages: dependencies: foreground-child: 3.3.1 jackspeak: 4.2.3 - minimatch: 10.2.3 + minimatch: 10.2.4 minipass: 7.1.3 package-json-from-dist: 1.0.1 path-scurry: 2.0.2 @@ -18417,7 +18394,7 @@ packages: hasBin: true dependencies: async: 3.2.6 - filelist: 1.0.5 + filelist: 1.0.6 picocolors: 1.1.1 dev: true @@ -18589,7 +18566,7 @@ packages: jest-mock: 29.7.0 jest-util: 29.7.0 - /jest-expo@54.0.13(@babel/core@7.26.0)(expo@54.0.25)(jest@29.7.0)(react-dom@19.1.0)(react-native@0.81.5)(react@19.1.0)(webpack@5.105.2): + /jest-expo@54.0.13(@babel/core@7.26.0)(expo@54.0.25)(jest@29.7.0)(react-dom@19.1.0)(react-native@0.81.5)(react@19.1.0)(webpack@5.105.3): resolution: {integrity: sha512-V0xefV7VJ9RD6v6Jo64I8RzQCchgEWVn6ip5r+u4TlgsGau0DA8CAqzitn4ShoSKlmjmpuaMqcGxeCz1p9Cfvg==} hasBin: true peerDependencies: @@ -18609,7 +18586,7 @@ packages: json5: 2.2.3 lodash: 4.17.21 react-native: 0.81.5(@babel/core@7.26.0)(@types/react@19.1.17)(react@19.1.0) - react-server-dom-webpack: 19.0.0(react-dom@19.1.0)(react@19.1.0)(webpack@5.105.2) + react-server-dom-webpack: 19.0.0(react-dom@19.1.0)(react@19.1.0)(webpack@5.105.3) react-test-renderer: 19.1.0(react@19.1.0) server-only: 0.0.1 stacktrace-js: 2.0.2 @@ -18879,7 +18856,7 @@ packages: resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} engines: {node: '>= 10.13.0'} dependencies: - '@types/node': 20.19.33 + '@types/node': 20.10.6 merge-stream: 2.0.0 supports-color: 8.1.1 dev: true @@ -19818,8 +19795,8 @@ packages: transitivePeerDependencies: - supports-color - /metro-babel-transformer@0.84.0: - resolution: {integrity: sha512-91uPQECjnYBNwyCJwsriG18N9HaQ0VcxGb7A0iWBsrNF49wbRblokm7YBz31O5r9cix0DxH2BiwreNWPP5q65w==} + /metro-babel-transformer@0.84.2: + resolution: {integrity: sha512-UZqjh1VMRDm0WasifM0aN+JreCn3CW0BaPoZgDXb0xOMFSF9dKZJsKhcrpzkjL1+qwmHFYjlhGiQ+tvXdSx+OQ==} engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} dependencies: '@babel/core': 7.29.0 @@ -19836,8 +19813,8 @@ packages: dependencies: flow-enums-runtime: 0.0.6 - /metro-cache-key@0.84.0: - resolution: {integrity: sha512-hREMJDJQ3MZW8dXco06HcmhoET6eJjvaPAml3eScTZsp5XBWhknocEiR5zlqx3zKhs3x3K7DK2C8f0uf9X3h0A==} + /metro-cache-key@0.84.2: + resolution: {integrity: sha512-+yJxLYu5nhKp7jZD6wtx4dMoSqLzK6MeYVkjMaUgjuh2Lu8DwGrxRnbmIVnn5Z9AQOs/K4eOWmuD7N2p64UCMw==} engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} dependencies: flow-enums-runtime: 0.0.6 @@ -19854,14 +19831,14 @@ packages: transitivePeerDependencies: - supports-color - /metro-cache@0.84.0: - resolution: {integrity: sha512-qIjsTdzWDZMJrztup4u0AnokxIee73fbti2MkV7MgSQ85zSIUSgjV3++oCaQ2m+qzhy+XCasG3n51B+avVDMhw==} + /metro-cache@0.84.2: + resolution: {integrity: sha512-jPX2fwOc/MmP2KRScSg2jFtVN9BTd+QN6j/3qZ+HIbEAsePLONozbKR2kCIBGvVeBTe7js48WXziI4+AdfwfFQ==} engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} dependencies: exponential-backoff: 3.1.3 flow-enums-runtime: 0.0.6 https-proxy-agent: 7.0.6 - metro-core: 0.84.0 + metro-core: 0.84.2 transitivePeerDependencies: - supports-color dev: true @@ -19883,17 +19860,17 @@ packages: - supports-color - utf-8-validate - /metro-config@0.84.0: - resolution: {integrity: sha512-wXhIQebmW8jyNr2xht1tKFRio9hSThpYzkiDBBMggk/LYw/6KbaUyl1EKJmpm5M/KJ4XwrhL3yTTMi2MqfWaDw==} + /metro-config@0.84.2: + resolution: {integrity: sha512-ze7IgJwLJoXoTxeXW86xqqKoxXjE0gZg5w8kW2mawaWLSfuvI0KgVaaERXgoVuWl+DQU2q22tIeAEdsCyUZvBQ==} engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} dependencies: connect: 3.7.0 flow-enums-runtime: 0.0.6 jest-validate: 29.7.0 - metro: 0.84.0 - metro-cache: 0.84.0 - metro-core: 0.84.0 - metro-runtime: 0.84.0 + metro: 0.84.2 + metro-cache: 0.84.2 + metro-core: 0.84.2 + metro-runtime: 0.84.2 yaml: 2.8.2 transitivePeerDependencies: - bufferutil @@ -19909,13 +19886,13 @@ packages: lodash.throttle: 4.1.1 metro-resolver: 0.83.2 - /metro-core@0.84.0: - resolution: {integrity: sha512-HWDvRDFTNcNZqgSs2DQX379BAJHYdE6bsX4SNQztz9KUqDx5egrQPzIahtYP5irP/RbksTqKbGeXtJxVz2557A==} + /metro-core@0.84.2: + resolution: {integrity: sha512-s9Ko372nzfbu5Y2uhWDlB/g3E6mba3Es95QzF/8IwNM4ynZgqM9rfnU0PR54onGvDGDfj44jbooSxaA1D09rDA==} engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} dependencies: flow-enums-runtime: 0.0.6 lodash.throttle: 4.1.1 - metro-resolver: 0.84.0 + metro-resolver: 0.84.2 dev: true /metro-file-map@0.83.2: @@ -19934,8 +19911,8 @@ packages: transitivePeerDependencies: - supports-color - /metro-file-map@0.84.0: - resolution: {integrity: sha512-euSnhAgRaaZdK1bdcPiez0MPErg+a0h6rrop+xcQI0mNQEm1GT6R5h+yycfMMQvPkZnfzpPkhjH+pr/x7BK4WQ==} + /metro-file-map@0.84.2: + resolution: {integrity: sha512-ZgX1lXO9YJCgTY6OSuwvRcHdhXjAFd1DdYC4g2B+d7yAtLUW1/OqwTLpW6ixl1zqZDDQSDSYZXDsN7DL2IumBw==} engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} dependencies: debug: 4.4.3 @@ -19958,8 +19935,8 @@ packages: flow-enums-runtime: 0.0.6 terser: 5.43.1 - /metro-minify-terser@0.84.0: - resolution: {integrity: sha512-STWICiHB3Lywl+K5eOl7Xm8/5+S9ch1YLXinXN0hDijq3SOh2UTGspxUZhWmqOvkDt/nd8dG/zSJO7JfcisV5A==} + /metro-minify-terser@0.84.2: + resolution: {integrity: sha512-1TNGPN4oUose+XSHsdDUvcvPHQxKP5lZNbiS6UteTXX+6zFNu+IzxqSokyrDoj9BSjVbdClrB3okuI+Fpls3LA==} engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} dependencies: flow-enums-runtime: 0.0.6 @@ -19972,8 +19949,8 @@ packages: dependencies: flow-enums-runtime: 0.0.6 - /metro-resolver@0.84.0: - resolution: {integrity: sha512-RTzim9q3rTz5AsRB/RBsTvy+GqHt6LzlIHx8YERv7eGDLjjr291tX2+2g//wbn/uNR/nLtdzJ08FfW1s6qZo/Q==} + /metro-resolver@0.84.2: + resolution: {integrity: sha512-2i6OQJIv18+olvLnmcM20uhi1T729+25izZozqOugSaV0YGzMV/EXkYFqxkXC9iNsantGcI/w9PgaI89wLK6JQ==} engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} dependencies: flow-enums-runtime: 0.0.6 @@ -19986,8 +19963,8 @@ packages: '@babel/runtime': 7.28.3 flow-enums-runtime: 0.0.6 - /metro-runtime@0.84.0: - resolution: {integrity: sha512-PJfD4arkFJrdnmJwrela+my+IgJIXSshA2gI3QiOWCzujBZX6XvsT0tKSwzw3FNMfU10OllO0X5tPcdTGTesjg==} + /metro-runtime@0.84.2: + resolution: {integrity: sha512-NzzORY2+mmN3tLhsZ7N4GDOBERusalyM1o1k36euulUIEe8UkDhwzcsRexvxKaSkrGLiRQ9PYDLp9uxPkQ+A0Q==} engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} dependencies: '@babel/runtime': 7.28.6 @@ -20011,17 +19988,17 @@ packages: transitivePeerDependencies: - supports-color - /metro-source-map@0.84.0: - resolution: {integrity: sha512-09CAPDBWO7gveW4GdLbWQJObxNrkElL5LQATG2xsU8wE7/TZgHc/MhEs8hm73ZC8lnIvCn5V7VS5lNlE6Od+Ww==} + /metro-source-map@0.84.2: + resolution: {integrity: sha512-m6rRVBefzaAyn6dBk5GOabVchCQ3VIS1/MhCj61dJB5cqLOOx34BV3DRFwnDBkuPw2RR/LUoul0U1sixlS9VQg==} engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} dependencies: '@babel/traverse': 7.29.0 '@babel/types': 7.29.0 flow-enums-runtime: 0.0.6 invariant: 2.2.4 - metro-symbolicate: 0.84.0 + metro-symbolicate: 0.84.2 nullthrows: 1.1.1 - ob1: 0.84.0 + ob1: 0.84.2 source-map: 0.5.7 vlq: 1.0.1 transitivePeerDependencies: @@ -20042,14 +20019,14 @@ packages: transitivePeerDependencies: - supports-color - /metro-symbolicate@0.84.0: - resolution: {integrity: sha512-JehuiPnqtS5I2luZdk7UHUY7bjNY/4xX1cJ8ezXWutTitiLp489Fsx+aErDTVoWcAx15lrjWa8IpTwoR0JLtZg==} + /metro-symbolicate@0.84.2: + resolution: {integrity: sha512-o0RY49012YcGE1E4GsZtgzFCBPeoxlASzIsD5CNOTmAoKDIroHfTFFiYCGPLCGwRwQjMaCChhoH0TZCjAyyCKA==} engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} hasBin: true dependencies: flow-enums-runtime: 0.0.6 invariant: 2.2.4 - metro-source-map: 0.84.0 + metro-source-map: 0.84.2 nullthrows: 1.1.1 source-map: 0.5.7 vlq: 1.0.1 @@ -20070,8 +20047,8 @@ packages: transitivePeerDependencies: - supports-color - /metro-transform-plugins@0.84.0: - resolution: {integrity: sha512-B/5eGY4w9YA7wZ5DkWYsW4ZQ/6KkPH97A/F9s6Jj2s9f586p3tGa2sbsm8WXFXNk26tprHda8EOaO6dNSw/TmA==} + /metro-transform-plugins@0.84.2: + resolution: {integrity: sha512-/821YLQv4PgD1NOruzPkr0r3HDALXqwCEECewyEQZ5hmSb8jzf1VdEpf3F8fx8zI4/5dHY/rARDVVuHCEb/Xrg==} engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} dependencies: '@babel/core': 7.29.0 @@ -20106,8 +20083,8 @@ packages: - supports-color - utf-8-validate - /metro-transform-worker@0.84.0: - resolution: {integrity: sha512-5fwkH5SrrM4RvASbZMQmA0SCiSWeseNbOE99etYjGrns/yFLxO7+oyGPQcoMNo3hMQlQ2Vyd2UcKNc+D81xSew==} + /metro-transform-worker@0.84.2: + resolution: {integrity: sha512-aR09svo3WC7OTYk5YB0VY0iSXOGrPdfmQWIxG8ADD2cKf/B95VR+y4GgVUbqB31buNvgtU+iCx9186i/YaNGlw==} engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} dependencies: '@babel/core': 7.29.0 @@ -20115,13 +20092,13 @@ packages: '@babel/parser': 7.29.0 '@babel/types': 7.29.0 flow-enums-runtime: 0.0.6 - metro: 0.84.0 - metro-babel-transformer: 0.84.0 - metro-cache: 0.84.0 - metro-cache-key: 0.84.0 - metro-minify-terser: 0.84.0 - metro-source-map: 0.84.0 - metro-transform-plugins: 0.84.0 + metro: 0.84.2 + metro-babel-transformer: 0.84.2 + metro-cache: 0.84.2 + metro-cache-key: 0.84.2 + metro-minify-terser: 0.84.2 + metro-source-map: 0.84.2 + metro-transform-plugins: 0.84.2 nullthrows: 1.1.1 transitivePeerDependencies: - bufferutil @@ -20179,8 +20156,8 @@ packages: - supports-color - utf-8-validate - /metro@0.84.0: - resolution: {integrity: sha512-Dy3KZphEH0xUO3rxRSwrCdge2vVjBAbSlPAKcL8qRnNEBlHz/3jPbmbb2fs9BVOrqBTi8EVDu/jdpCdWvg1ygA==} + /metro@0.84.2: + resolution: {integrity: sha512-Qw7sl+e34cf/0LYEvDfVPiWvXmkvpuVgFqjzhPCc9Mw30NsvRFYZEH6I9zEHlpjugIveV+Jzdqt3YSPMU+Hx/w==} engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} hasBin: true dependencies: @@ -20205,18 +20182,18 @@ packages: jest-worker: 29.7.0 jsc-safe-url: 0.2.4 lodash.throttle: 4.1.1 - metro-babel-transformer: 0.84.0 - metro-cache: 0.84.0 - metro-cache-key: 0.84.0 - metro-config: 0.84.0 - metro-core: 0.84.0 - metro-file-map: 0.84.0 - metro-resolver: 0.84.0 - metro-runtime: 0.84.0 - metro-source-map: 0.84.0 - metro-symbolicate: 0.84.0 - metro-transform-plugins: 0.84.0 - metro-transform-worker: 0.84.0 + metro-babel-transformer: 0.84.2 + metro-cache: 0.84.2 + metro-cache-key: 0.84.2 + metro-config: 0.84.2 + metro-core: 0.84.2 + metro-file-map: 0.84.2 + metro-resolver: 0.84.2 + metro-runtime: 0.84.2 + metro-source-map: 0.84.2 + metro-symbolicate: 0.84.2 + metro-transform-plugins: 0.84.2 + metro-transform-worker: 0.84.2 mime-types: 3.0.2 nullthrows: 1.1.1 serialize-error: 2.1.0 @@ -20675,11 +20652,11 @@ packages: '@isaacs/brace-expansion': 5.0.0 dev: true - /minimatch@10.2.3: - resolution: {integrity: sha512-Rwi3pnapEqirPSbWbrZaa6N3nmqq4Xer/2XooiOKyV3q12ML06f7MOuc5DVH8ONZIFhwIYQ3yzPH4nt7iWHaTg==} + /minimatch@10.2.4: + resolution: {integrity: sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==} engines: {node: 18 || 20 || >=22} dependencies: - brace-expansion: 5.0.3 + brace-expansion: 5.0.4 dev: true /minimatch@3.1.2: @@ -20687,6 +20664,13 @@ packages: dependencies: brace-expansion: 1.1.11 + /minimatch@5.1.9: + resolution: {integrity: sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==} + engines: {node: '>=10'} + dependencies: + brace-expansion: 2.0.2 + dev: true + /minimatch@8.0.4: resolution: {integrity: sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==} engines: {node: '>=16 || 14 >=14.17'} @@ -20968,8 +20952,8 @@ packages: dependencies: flow-enums-runtime: 0.0.6 - /ob1@0.84.0: - resolution: {integrity: sha512-NBpmKuboMBiWd1V6U6ISIqLg8Az5BHARnKdS/k8IS7spNt931++4BflqI/TMt4otQ387Q5PFB1fzSLRNPC3HZA==} + /ob1@0.84.2: + resolution: {integrity: sha512-JID0ti8tDRQZJdQ3l+UeVAsKP+dW5Ucmktes/J9FwqP5KarafoTMqWvw4LRKrMtA7yWT3r/+E2w5wapd89GToA==} engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} dependencies: flow-enums-runtime: 0.0.6 @@ -21076,7 +21060,7 @@ packages: is-docker: 2.2.1 is-wsl: 2.2.0 - /openai@6.25.0(zod@4.0.17): + /openai@6.25.0(zod@4.3.6): resolution: {integrity: sha512-mEh6VZ2ds2AGGokWARo18aPISI1OhlgdEIC1ewhkZr8pSIT31dec0ecr9Nhxx0JlybyOgoAT1sWeKtwPZzJyww==} hasBin: true peerDependencies: @@ -21088,7 +21072,7 @@ packages: zod: optional: true dependencies: - zod: 4.0.17 + zod: 4.3.6 dev: false /openapi-types@12.1.3: @@ -22156,7 +22140,7 @@ packages: use-sidecar: 1.1.3(@types/react@19.1.17)(react@19.1.0) dev: false - /react-server-dom-webpack@19.0.0(react-dom@19.1.0)(react@19.1.0)(webpack@5.105.2): + /react-server-dom-webpack@19.0.0(react-dom@19.1.0)(react@19.1.0)(webpack@5.105.3): resolution: {integrity: sha512-hLug9KEXLc8vnU9lDNe2b2rKKDaqrp5gNiES4uyu2Up3FZfZJZmdwLFXlWzdA9gTB/6/cWduSB2K1Lfag2pSvw==} engines: {node: '>=0.10.0'} peerDependencies: @@ -22168,7 +22152,7 @@ packages: neo-async: 2.6.2 react: 19.1.0 react-dom: 19.1.0(react@19.1.0) - webpack: 5.105.2 + webpack: 5.105.3 webpack-sources: 3.3.3 dev: true @@ -23757,7 +23741,7 @@ packages: ansi-escapes: 4.3.2 supports-hyperlinks: 2.3.0 - /terser-webpack-plugin@5.3.16(webpack@5.105.2): + /terser-webpack-plugin@5.3.16(webpack@5.105.3): resolution: {integrity: sha512-h9oBFCWrq78NyWWVcSwZarJkZ01c2AyGrzs1crmHZO3QUg9D61Wu4NPjBy69n7JqylFF5y+CsUZYmYEIZ3mR+Q==} engines: {node: '>= 10.13.0'} peerDependencies: @@ -23778,7 +23762,7 @@ packages: schema-utils: 4.3.3 serialize-javascript: 6.0.2 terser: 5.46.0 - webpack: 5.105.2 + webpack: 5.105.3 dev: true /terser@5.43.1: @@ -23915,7 +23899,7 @@ packages: resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} dev: false - /trpc-cli@0.12.1(@trpc/server@11.8.1)(zod@4.2.1): + /trpc-cli@0.12.1(@trpc/server@11.8.1)(zod@4.3.6): resolution: {integrity: sha512-/D/mIQf3tUrS7ZKJZ1gmSPJn2psAABJfkC5Eevm55SZ4s6KwANOUNlwhAGXN9HT4VSJVfoF2jettevE9vHPQlg==} engines: {node: '>=18'} hasBin: true @@ -23942,7 +23926,7 @@ packages: dependencies: '@trpc/server': 11.8.1(typescript@5.9.3) commander: 14.0.2 - zod: 4.2.1 + zod: 4.3.6 dev: true /ts-fsrs@5.2.3: @@ -24168,8 +24152,8 @@ packages: jsonc-parser: 3.3.1 nypm: 0.6.2 picocolors: 1.1.1 - trpc-cli: 0.12.1(@trpc/server@11.8.1)(zod@4.2.1) - zod: 4.2.1 + trpc-cli: 0.12.1(@trpc/server@11.8.1)(zod@4.3.6) + zod: 4.3.6 transitivePeerDependencies: - '@orpc/server' - '@valibot/to-json-schema' @@ -24199,10 +24183,6 @@ packages: /undici-types@5.26.5: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} - /undici-types@6.21.0: - resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} - dev: true - /undici@5.29.0: resolution: {integrity: sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==} engines: {node: '>=14.0'} @@ -25037,8 +25017,8 @@ packages: resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} dev: true - /webpack@5.105.2: - resolution: {integrity: sha512-dRXm0a2qcHPUBEzVk8uph0xWSjV/xZxenQQbLwnwP7caQCYpqG1qddwlyEkIDkYn0K8tvmcrZ+bOrzoQ3HxCDw==} + /webpack@5.105.3: + resolution: {integrity: sha512-LLBBA4oLmT7sZdHiYE/PeVuifOxYyE2uL/V+9VQP7YSYdJU7bSf7H8bZRRxW8kEPMkmVjnrXmoR3oejIdX0xbg==} engines: {node: '>=10.13.0'} hasBin: true peerDependencies: @@ -25057,7 +25037,7 @@ packages: acorn-import-phases: 1.0.4(acorn@8.16.0) browserslist: 4.28.1 chrome-trace-event: 1.0.4 - enhanced-resolve: 5.19.0 + enhanced-resolve: 5.20.0 es-module-lexer: 2.0.0 eslint-scope: 5.1.1 events: 3.3.0 @@ -25069,7 +25049,7 @@ packages: neo-async: 2.6.2 schema-utils: 4.3.3 tapable: 2.3.0 - terser-webpack-plugin: 5.3.16(webpack@5.105.2) + terser-webpack-plugin: 5.3.16(webpack@5.105.3) watchpack: 2.5.1 webpack-sources: 3.3.4 transitivePeerDependencies: @@ -25692,22 +25672,15 @@ packages: resolution: {integrity: sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug==} dev: true - /zod@3.24.1: - resolution: {integrity: sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==} - dev: true - /zod@3.25.76: resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} /zod@4.0.17: resolution: {integrity: sha512-1PHjlYRevNxxdy2JZ8JcNAw7rX8V9P1AKkP+x/xZfxB0K5FYfuV+Ug6P/6NVSR2jHQ+FzDDoDHS04nYUsOIyLQ==} - - /zod@4.2.1: - resolution: {integrity: sha512-0wZ1IRqGGhMP76gLqz8EyfBXKk0J2qo2+H3fi4mcUP/KtTocoX08nmIAHl1Z2kJIZbZee8KOpBCSNPRgauucjw==} + dev: false /zod@4.3.6: resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==} - dev: false /zwitch@2.0.4: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} From c6bd2f7bad6c736285231509a3e8289009b599dc Mon Sep 17 00:00:00 2001 From: sufyan Date: Tue, 3 Mar 2026 17:57:12 -0500 Subject: [PATCH 04/15] wip: first pass ai integration --- apps/api/package.json | 2 +- apps/api/src/index.ts | 2 + apps/api/src/middleware.ts | 67 +- apps/api/src/routers/ai.ts | 135 +- bahar.pen | 4763 ++++++++++++++++- packages/drizzle-user-db-schemas/src/types.ts | 116 +- pnpm-lock.yaml | 4 +- 7 files changed, 4982 insertions(+), 107 deletions(-) diff --git a/apps/api/package.json b/apps/api/package.json index c444de9..38f6cc1 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -25,7 +25,7 @@ "@polar-sh/sdk": "^0.42.1", "@sentry/bun": "^10.32.1", "@tanstack/ai": "^0.6.1", - "@tanstack/ai-openai": "^0.6.1", + "@tanstack/ai-openai": "^0.6.0", "@tursodatabase/api": "^1.9.0", "@upstash/redis": "^1.36.0", "better-auth": "1.4.19", diff --git a/apps/api/src/index.ts b/apps/api/src/index.ts index 34da8e5..3a333d4 100644 --- a/apps/api/src/index.ts +++ b/apps/api/src/index.ts @@ -12,6 +12,7 @@ Sentry.init({ import { cors } from "@elysiajs/cors"; import { Elysia } from "elysia"; import { betterAuthGuard, httpLogger } from "./middleware"; +import { aiRouter } from "./routers/ai"; import { databasesRouter } from "./routers/databases"; import { migrationsRouter } from "./routers/migrations"; import { getAllowedDomains } from "./utils"; @@ -53,6 +54,7 @@ const app = new Elysia() .get("/health", () => "OK") .use(migrationsRouter) .use(databasesRouter) + .use(aiRouter) .onError(({ error, code }) => { Sentry.captureException(error); diff --git a/apps/api/src/middleware.ts b/apps/api/src/middleware.ts index 4a9f0df..1b86e97 100644 --- a/apps/api/src/middleware.ts +++ b/apps/api/src/middleware.ts @@ -1,10 +1,31 @@ import * as Sentry from "@sentry/bun"; import Elysia from "elysia"; -import { auth } from "./auth"; +import { auth, type User } from "./auth"; +import { redisClient } from "./clients/redis"; import { getTraceContext } from "./utils/logger"; export { httpLogger } from "./middleware/http-logger"; +export type RateLimiterOpts = { + prefix: string; + maxReqs: number; + windowSecs: number; +}; + +type NonNullablePlan = NonNullable | "free"; + +/** + * Subscription plan levels as a hierarchy so that + * newer plans have access to lower plans. + */ +const PLAN_LEVELS = { + free: 0, + pro: 1, + // the `satisfies` here ensures that if we add new plans, + // then this will throw a type error until we've added + // it to the map here. This is why we don't use an enum here +} as const satisfies Record; + export const betterAuthGuard = new Elysia({ name: "better-auth" }) .mount(auth.handler) .macro({ @@ -31,4 +52,48 @@ export const betterAuthGuard = new Elysia({ name: "better-auth" }) }; }, }), + planGuard: (plan: User["plan"]) => ({ + async resolve(opts) { + // `user` becomes available in context from the auth macro + const { user, status } = opts as typeof opts & { user: User }; + + // allow any user to access free tier, + // no plan means free tier + if (!plan) return; + + const userPlanLevel = PLAN_LEVELS[user.plan ?? "free"]; + const requiredPlanLevel = PLAN_LEVELS[plan]; + + if ( + userPlanLevel >= requiredPlanLevel && + user.subscriptionStatus === "active" + ) { + return; + } + + return status(403, { + message: `${plan} plan required.`, + }); + }, + }), + userRateLimit: ({ prefix, maxReqs, windowSecs }: RateLimiterOpts) => ({ + async resolve(opts) { + // `user` becomes available in context from the auth macro + const { status, user } = opts as typeof opts & { user: User }; + + const key = `${prefix}:${user.id}`; + const count = (await redisClient.get(key)) as number; + + if (!count) { + await redisClient.set(key, 1, { ex: windowSecs }); + return; + } + + if (count >= maxReqs) { + return status(429, { message: "Rate limit exceeded" }); + } + + await redisClient.incr(key); + }, + }), }); diff --git a/apps/api/src/routers/ai.ts b/apps/api/src/routers/ai.ts index 028d3ca..9da083b 100644 --- a/apps/api/src/routers/ai.ts +++ b/apps/api/src/routers/ai.ts @@ -1,54 +1,99 @@ -import { InsertDictionaryEntrySchema } from "@bahar/drizzle-user-db-schemas"; +import { + ExampleSchema, + InsertDictionaryEntrySchema, + IsmMorphologySchema, + RootLettersSchema, + VerbMorphologySchema, + type WordType, +} from "@bahar/drizzle-user-db-schemas"; import { chat } from "@tanstack/ai"; import { openaiText } from "@tanstack/ai-openai"; import Elysia from "elysia"; -import { betterAuthGuard } from "../middleware"; +import { z } from "zod"; +import { betterAuthGuard, type RateLimiterOpts } from "../middleware"; -const AUTOCOMPLETE_SYSTEM_PROMPT = ` - You are an Arabic linguistics expert. +const baseFields = { + definition: z + .string() + .optional() + .describe( + "Arabic dictionary definition in the style of المعجم الوسيط — a synonym or brief explanation, not a translation." + ), + root: RootLettersSchema.optional().describe( + 'Trilateral or quadrilateral root letters as individual characters, e.g. ["ك", "ت", "ب"].' + ), + examples: z.array(ExampleSchema).optional(), +}; + +const IsmOutputSchema = z.object({ + ...baseFields, + morphology: IsmMorphologySchema.optional(), +}); + +const VerbOutputSchema = z.object({ + ...baseFields, + morphology: VerbMorphologySchema.optional(), +}); + +const SimpleOutputSchema = z.object({ + ...baseFields, +}); - Given an Arabic word or expression, its English translation, and the type (ism, fi'l, harf or expression), generate accurate dictionary data for an Arabic language learning app. +/** + * Separate function to return the full schema for a specific entry type. + * + * This is so that we can pass a smaller schema to the model for better performance. + */ +const getOutputSchema = (type: WordType) => { + switch (type) { + case "ism": + return IsmOutputSchema; + case "fi'l": + return VerbOutputSchema; + default: + return SimpleOutputSchema; + } +}; + +const AUTOCOMPLETE_SYSTEM_PROMPT = ` + You are an Arabic linguistics expert generating dictionary data for a language learning app. Rules: - - All Arabic text MUST include full tashkeel (harakat/diacritical marks) - - Root letters: provide the trilateral or quadrilateral root as space-separated letters (e.g. "ك ت ب") - - Only populate morphology fields relevant to the word type: ism fields for nouns, verb fields for verbs, neither for harf/expressions - - For verbs: identify the correct form (I–X), provide the Arabic pattern (e.g. فَعَلَ), past/present/imperative with full tashkeel - - For nouns: provide plural forms (if applicable), gender, and inflection type - - Definition: must be in Arabic - - Generate 2–3 example sentences at varying difficulty, each with translation and context label (if necessary) - - Omit any field you are not confident about rather than guessing + - All Arabic text MUST include full tashkeel, but omit final case endings (إعراب). Exception: diptotes (الممنوع من الصرف) should show a dhamma (not tanween) on the final letter. + - Omit any field you are not confident about rather than guessing. `; -export const autocompleteRouter = new Elysia({ prefix: "/ai" }) - .use(betterAuthGuard) - .post( - "/autocomplete", - async ({ body: { translation, type, word } }) => { - const dictionaryEntrySuggestion = await chat({ - adapter: openaiText("gpt-4.1-nano") as never, - systemPrompts: [AUTOCOMPLETE_SYSTEM_PROMPT], - messages: [ - { - role: "user", - content: `Word: "${word}", Translation: "${translation}", Type: "${type}"`, - }, - ], - outputSchema: InsertDictionaryEntrySchema.pick({ - definition: true, - examples: true, - morphology: true, - root: true, - }), - }); - - return dictionaryEntrySuggestion; - }, - { - body: InsertDictionaryEntrySchema.pick({ - word: true, - translation: true, - type: true, - }), - } - ); +const aiRateLimiterOpts: RateLimiterOpts = { + maxReqs: 10, + windowSecs: 60, + prefix: "ratelimit:ai:autocomplete", +}; + +export const aiRouter = new Elysia({ prefix: "/ai" }).use(betterAuthGuard).post( + "/autocomplete", + async ({ body: { translation, type, word } }) => { + const dictionaryEntrySuggestion = await chat({ + adapter: openaiText("gpt-4.1-nano") as never, + systemPrompts: [AUTOCOMPLETE_SYSTEM_PROMPT], + messages: [ + { + role: "user", + content: `Word: "${word}", Translation: "${translation}", Type: "${type}"`, + }, + ], + outputSchema: getOutputSchema(type), + }); + + return dictionaryEntrySuggestion; + }, + { + auth: "user", + planGuard: "pro", + userRateLimit: aiRateLimiterOpts, + body: InsertDictionaryEntrySchema.pick({ + word: true, + translation: true, + type: true, + }), + } +); diff --git a/bahar.pen b/bahar.pen index 6c38e7d..a8a367d 100644 --- a/bahar.pen +++ b/bahar.pen @@ -8160,18 +8160,4757 @@ ] }, { - "type": "rectangle", - "id": "VrJME", - "x": -363, - "y": 1000, - "fill": { - "type": "image", - "enabled": true, - "url": "android-chrome-512x512.png", - "mode": "fill" - }, - "width": 302, - "height": 280 + "type": "frame", + "id": "Ldu8R", + "x": 3080, + "y": 3930, + "name": "Add Word — Current State", + "clip": true, + "width": 1440, + "height": 1200, + "fill": "#FFFFFF", + "children": [ + { + "type": "frame", + "id": "EUwce", + "name": "Sidebar", + "width": 56, + "height": "fill_container", + "fill": "#FCFCFC", + "stroke": { + "align": "inside", + "thickness": { + "right": 1 + }, + "fill": "#E0E2EC" + }, + "layout": "vertical", + "gap": 16, + "padding": [ + 16, + 0 + ], + "children": [ + { + "type": "frame", + "id": "br99w", + "name": "cLogo", + "width": 28, + "height": 28, + "fill": { + "type": "image", + "enabled": true, + "url": "./apps/web/src/assets/logo.svg", + "mode": "fit" + }, + "justifyContent": "center", + "alignItems": "center" + }, + { + "type": "frame", + "id": "issGk", + "name": "cNavGrp", + "layout": "vertical", + "gap": 4, + "children": [ + { + "type": "frame", + "id": "enicq", + "name": "cNavHome", + "width": 36, + "height": 36, + "fill": "#4F46E518", + "cornerRadius": 8, + "justifyContent": "center", + "alignItems": "center", + "children": [ + { + "type": "icon_font", + "id": "zeGFH", + "name": "cNavHomeI", + "width": 20, + "height": 20, + "iconFontName": "book-open", + "iconFontFamily": "lucide", + "fill": "#4F46E5" + } + ] + }, + { + "type": "frame", + "id": "c5bf3", + "name": "cNavDecks", + "width": 36, + "height": 36, + "cornerRadius": 8, + "justifyContent": "center", + "alignItems": "center", + "children": [ + { + "type": "icon_font", + "id": "mB0tS", + "name": "cNavDecksI", + "width": 20, + "height": 20, + "iconFontName": "layers", + "iconFontFamily": "lucide", + "fill": "#6B6F80" + } + ] + } + ] + }, + { + "type": "frame", + "id": "g87HK", + "name": "cSpacer", + "width": 36, + "height": "fill_container" + }, + { + "type": "frame", + "id": "i53H6", + "name": "cSettBtn", + "width": 36, + "height": 36, + "cornerRadius": 8, + "justifyContent": "center", + "alignItems": "center", + "children": [ + { + "type": "icon_font", + "id": "zdyXp", + "name": "cSettI", + "width": 20, + "height": 20, + "iconFontName": "settings", + "iconFontFamily": "lucide", + "fill": "#6B6F80" + } + ] + } + ] + }, + { + "type": "frame", + "id": "kzbDr", + "name": "Main Content", + "width": "fill_container", + "height": "fill_container", + "fill": "#FFFFFF", + "layout": "vertical", + "gap": 20, + "padding": [ + 24, + 40 + ], + "children": [ + { + "type": "frame", + "id": "5OhGc", + "name": "cBreadcrumbs", + "gap": 6, + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "eamfg", + "name": "cBcHome", + "fill": "#6B6F80", + "content": "Home", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "500" + }, + { + "type": "text", + "id": "XVdh9", + "name": "cBcSep", + "fill": "#6B6F80", + "content": "/", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "normal" + }, + { + "type": "text", + "id": "HNcXh", + "name": "cBcCurrent", + "fill": "#1B1B2F", + "content": "Add word", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "500" + } + ] + }, + { + "type": "frame", + "id": "9nfiU", + "name": "cHeaderRow", + "width": "fill_container", + "justifyContent": "space_between", + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "gFZvk", + "name": "cTitle", + "fill": "#1B1B2F", + "content": "Add a new word to your dictionary", + "fontFamily": "Inter", + "fontSize": 22, + "fontWeight": "600", + "letterSpacing": -0.3 + }, + { + "type": "frame", + "id": "e9Lmn", + "name": "cBtnRow", + "gap": 8, + "children": [ + { + "type": "frame", + "id": "SKjVE", + "name": "cDiscardBtn", + "cornerRadius": 8, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#E2E3EA" + }, + "padding": [ + 8, + 16 + ], + "justifyContent": "center", + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "rwInB", + "name": "cDiscardText", + "fill": "#6B6F80", + "content": "Discard", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "500" + } + ] + }, + { + "type": "frame", + "id": "CUr1a", + "name": "cSaveBtn", + "fill": "#1B1B2F", + "cornerRadius": 8, + "padding": [ + 8, + 16 + ], + "justifyContent": "center", + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "uR8tV", + "name": "cSaveText", + "fill": "#FFFFFF", + "content": "Save", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "600" + } + ] + } + ] + } + ] + }, + { + "type": "frame", + "id": "jjG94", + "name": "Form Grid", + "width": "fill_container", + "gap": 24, + "children": [ + { + "type": "frame", + "id": "QASe0", + "name": "Left Column", + "width": "fill_container", + "layout": "vertical", + "gap": 20, + "children": [ + { + "type": "frame", + "id": "IbZMX", + "name": "Basic Details", + "width": "fill_container", + "cornerRadius": 12, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#E2E3EA" + }, + "layout": "vertical", + "children": [ + { + "type": "frame", + "id": "FbuOs", + "name": "bdHeader", + "width": "fill_container", + "layout": "vertical", + "gap": 2, + "padding": [ + 20, + 24, + 12, + 24 + ], + "children": [ + { + "type": "text", + "id": "RzkiG", + "name": "bdTitle", + "fill": "#1B1B2F", + "content": "Basic Details", + "fontFamily": "Inter", + "fontSize": 16, + "fontWeight": "600" + } + ] + }, + { + "type": "frame", + "id": "CP0B8", + "name": "bdBody", + "width": "fill_container", + "layout": "vertical", + "gap": 16, + "padding": [ + 0, + 24, + 24, + 24 + ], + "children": [ + { + "type": "frame", + "id": "9NrTg", + "name": "bdWordField", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "0eXZJ", + "name": "bdWordLbl", + "fill": "#3D3F4A", + "content": "Word*", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "500" + }, + { + "type": "frame", + "id": "nD2f2", + "name": "bdWordIn", + "width": "fill_container", + "height": 44, + "fill": "#FFFFFF", + "cornerRadius": 8, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#E2E3EA" + }, + "padding": [ + 0, + 12 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "4ZQYW", + "name": "bdWordPlc", + "fill": "#A0A3B1", + "content": "Enter Arabic word...", + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "normal" + } + ] + } + ] + }, + { + "type": "frame", + "id": "3U5nh", + "name": "bdTransField", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "96K1s", + "name": "bdTransLbl", + "fill": "#3D3F4A", + "content": "Translation*", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "500" + }, + { + "type": "frame", + "id": "6W40P", + "name": "bdTransIn", + "width": "fill_container", + "height": 44, + "fill": "#FFFFFF", + "cornerRadius": 8, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#E2E3EA" + }, + "padding": [ + 0, + 12 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "tMa4A", + "name": "bdTransPlc", + "fill": "#A0A3B1", + "content": "Enter English translation...", + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "normal" + } + ] + }, + { + "type": "text", + "id": "kb8x2", + "name": "bdTransDesc", + "fill": "#6B6F80", + "content": "An English translation of the word.", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "normal" + } + ] + } + ] + } + ] + }, + { + "type": "frame", + "id": "lhifS", + "name": "Additional Details", + "width": "fill_container", + "cornerRadius": 12, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#E2E3EA" + }, + "layout": "vertical", + "children": [ + { + "type": "frame", + "id": "0Pf6d", + "name": "adHeader", + "width": "fill_container", + "layout": "vertical", + "gap": 2, + "padding": [ + 20, + 24, + 12, + 24 + ], + "children": [ + { + "type": "text", + "id": "FNnCm", + "name": "adTitle", + "fill": "#1B1B2F", + "content": "Additional Details", + "fontFamily": "Inter", + "fontSize": 16, + "fontWeight": "600" + }, + { + "type": "text", + "id": "o5F0j", + "name": "adDesc", + "fill": "#6B6F80", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Information such as the word's root, meaning, and examples.", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "YY79W", + "name": "adBody", + "width": "fill_container", + "layout": "vertical", + "gap": 16, + "padding": [ + 0, + 24, + 24, + 24 + ], + "children": [ + { + "type": "frame", + "id": "d5Ksg", + "name": "adDefField", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "7JHPE", + "name": "adDefLbl", + "fill": "#3D3F4A", + "content": "Definition", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "500" + }, + { + "type": "frame", + "id": "RwoZ5", + "name": "adDefIn", + "width": "fill_container", + "height": 44, + "fill": "#FFFFFF", + "cornerRadius": 8, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#E2E3EA" + }, + "padding": [ + 0, + 12 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "x5BlS", + "name": "adDefPlc", + "fill": "#A0A3B1", + "content": "Arabic definition...", + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "normal" + } + ] + }, + { + "type": "text", + "id": "Lg2jk", + "name": "adDefDesc", + "fill": "#6B6F80", + "content": "An Arabic definition of the word.", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "d80RP", + "name": "adRootField", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "zRaGq", + "name": "adRootLbl", + "fill": "#3D3F4A", + "content": "Root letters", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "500" + }, + { + "type": "frame", + "id": "p9S5H", + "name": "adRootIn", + "width": "fill_container", + "height": 44, + "fill": "#FFFFFF", + "cornerRadius": 8, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#E2E3EA" + }, + "padding": [ + 0, + 12 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "hapTd", + "name": "adRootPlc", + "fill": "#A0A3B1", + "content": "ف ع ل", + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "normal" + } + ] + }, + { + "type": "text", + "id": "a7Q9N", + "name": "adRootDesc", + "fill": "#6B6F80", + "content": "The root letters of the word.", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "g6jNw", + "name": "adExWrap", + "width": "fill_container", + "layout": "vertical", + "gap": 8, + "children": [ + { + "type": "frame", + "id": "ve13M", + "name": "adExHeader", + "width": "fill_container", + "justifyContent": "space_between", + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "a8INN", + "name": "adExTitle", + "fill": "#1B1B2F", + "content": "Examples", + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "600" + } + ] + }, + { + "type": "text", + "id": "zjKGt", + "name": "adExDesc", + "fill": "#6B6F80", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Example usages of the word in different contexts.", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "normal" + }, + { + "type": "frame", + "id": "2b7hU", + "name": "adExAddBtn", + "cornerRadius": 8, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#E2E3EA" + }, + "gap": 4, + "padding": [ + 6, + 12 + ], + "alignItems": "center", + "children": [ + { + "type": "icon_font", + "id": "EPxrG", + "name": "adExAddIcon", + "width": 14, + "height": 14, + "iconFontName": "plus", + "iconFontFamily": "lucide", + "fill": "#6B6F80" + }, + { + "type": "text", + "id": "gJwEq", + "name": "adExAddText", + "fill": "#6B6F80", + "content": "Add example", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "500" + } + ] + } + ] + } + ] + } + ] + }, + { + "type": "frame", + "id": "tslV6", + "name": "Morphology", + "width": "fill_container", + "cornerRadius": 12, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#E2E3EA" + }, + "layout": "vertical", + "children": [ + { + "type": "frame", + "id": "tVcs3", + "name": "morphHeader", + "width": "fill_container", + "layout": "vertical", + "gap": 2, + "padding": [ + 20, + 24, + 12, + 24 + ], + "children": [ + { + "type": "text", + "id": "2fn68", + "name": "morphTitle", + "fill": "#1B1B2F", + "content": "Morphology", + "fontFamily": "Inter", + "fontSize": 16, + "fontWeight": "600" + }, + { + "type": "text", + "id": "Gjwb6", + "name": "morphDesc", + "fill": "#6B6F80", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "The morphological breakdown of the word.", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "hklHQ", + "name": "morphBody", + "width": "fill_container", + "layout": "vertical", + "gap": 12, + "padding": [ + 0, + 24, + 24, + 24 + ], + "children": [ + { + "type": "frame", + "id": "Re9Lw", + "name": "morphRow1", + "width": "fill_container", + "gap": 12, + "children": [ + { + "type": "frame", + "id": "v44fq", + "name": "mSingF", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "v0wQX", + "name": "mSingLbl", + "fill": "#3D3F4A", + "content": "Singular", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "500" + }, + { + "type": "frame", + "id": "bQdm8", + "name": "mSingIn", + "width": "fill_container", + "height": 44, + "fill": "#FFFFFF", + "cornerRadius": 8, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#E2E3EA" + }, + "padding": [ + 0, + 12 + ], + "alignItems": "center" + } + ] + }, + { + "type": "frame", + "id": "hFMcV", + "name": "mDualF", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "xoFoW", + "name": "mDualLbl", + "fill": "#3D3F4A", + "content": "Dual", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "500" + }, + { + "type": "frame", + "id": "7gEv5", + "name": "mDualIn", + "width": "fill_container", + "height": 44, + "fill": "#FFFFFF", + "cornerRadius": 8, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#E2E3EA" + }, + "padding": [ + 0, + 12 + ], + "alignItems": "center" + } + ] + } + ] + }, + { + "type": "frame", + "id": "xHpts", + "name": "mRow2", + "width": "fill_container", + "gap": 12, + "children": [ + { + "type": "frame", + "id": "789rI", + "name": "mGenderF", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "6iRyM", + "name": "mGenderLbl", + "fill": "#3D3F4A", + "content": "Gender", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "500" + }, + { + "type": "frame", + "id": "VHtRY", + "name": "mGenderIn", + "width": "fill_container", + "height": 44, + "fill": "#FFFFFF", + "cornerRadius": 8, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#E2E3EA" + }, + "padding": [ + 0, + 12 + ], + "justifyContent": "space_between", + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "8J8DJ", + "name": "mGenderVal", + "fill": "#1B1B2F", + "content": "Masculine", + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "normal" + }, + { + "type": "icon_font", + "id": "QardB", + "name": "mGenderChev", + "width": 16, + "height": 16, + "iconFontName": "chevron-down", + "iconFontFamily": "lucide", + "fill": "#6B6F80" + } + ] + } + ] + }, + { + "type": "frame", + "id": "jDJtU", + "name": "mInflF", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "M7MIX", + "name": "mInflLbl", + "fill": "#3D3F4A", + "content": "Inflection", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "500" + }, + { + "type": "frame", + "id": "W6hML", + "name": "mInflIn", + "width": "fill_container", + "height": 44, + "fill": "#FFFFFF", + "cornerRadius": 8, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#E2E3EA" + }, + "padding": [ + 0, + 12 + ], + "justifyContent": "space_between", + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "4CT3o", + "name": "mInflVal", + "fill": "#1B1B2F", + "content": "Triptote", + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "normal" + }, + { + "type": "icon_font", + "id": "U5pxT", + "name": "mInflChev", + "width": 16, + "height": 16, + "iconFontName": "chevron-down", + "iconFontFamily": "lucide", + "fill": "#6B6F80" + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "type": "frame", + "id": "2aKQK", + "name": "Right Sidebar", + "width": 280, + "layout": "vertical", + "gap": 20, + "children": [ + { + "type": "frame", + "id": "I8FNF", + "name": "Category", + "width": "fill_container", + "cornerRadius": 12, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#E2E3EA" + }, + "layout": "vertical", + "children": [ + { + "type": "frame", + "id": "Kjujy", + "name": "catHeader", + "width": "fill_container", + "layout": "vertical", + "gap": 2, + "padding": [ + 20, + 24, + 12, + 24 + ], + "children": [ + { + "type": "text", + "id": "kFVGg", + "name": "catTitle", + "fill": "#1B1B2F", + "content": "Category", + "fontFamily": "Inter", + "fontSize": 16, + "fontWeight": "600" + }, + { + "type": "text", + "id": "9Ua4b", + "name": "catDesc", + "fill": "#6B6F80", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "How the word is categorized.", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "uEehB", + "name": "catBody", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "padding": [ + 0, + 24, + 24, + 24 + ], + "children": [ + { + "type": "text", + "id": "sF16e", + "name": "catLbl", + "fill": "#3D3F4A", + "content": "Type", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "500" + }, + { + "type": "frame", + "id": "iqaYU", + "name": "catSelect", + "width": "fill_container", + "height": 44, + "fill": "#FFFFFF", + "cornerRadius": 8, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#E2E3EA" + }, + "padding": [ + 0, + 12 + ], + "justifyContent": "space_between", + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "WDLZm", + "name": "catVal", + "fill": "#1B1B2F", + "content": "Ism", + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "normal" + }, + { + "type": "icon_font", + "id": "25BSc", + "name": "catChev", + "width": 16, + "height": 16, + "iconFontName": "chevron-down", + "iconFontFamily": "lucide", + "fill": "#6B6F80" + } + ] + } + ] + } + ] + }, + { + "type": "frame", + "id": "ImF0L", + "name": "Tags", + "width": "fill_container", + "cornerRadius": 12, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#E2E3EA" + }, + "layout": "vertical", + "children": [ + { + "type": "frame", + "id": "ICu4k", + "name": "tagHeader", + "width": "fill_container", + "layout": "vertical", + "gap": 2, + "padding": [ + 20, + 24, + 12, + 24 + ], + "children": [ + { + "type": "text", + "id": "hFG7b", + "name": "tagTitle", + "fill": "#1B1B2F", + "content": "Tags", + "fontFamily": "Inter", + "fontSize": 16, + "fontWeight": "600" + }, + { + "type": "text", + "id": "n2mOB", + "name": "tagDesc", + "fill": "#6B6F80", + "content": "Add tags to your word.", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "wNo8q", + "name": "tagBody", + "width": "fill_container", + "layout": "vertical", + "gap": 10, + "padding": [ + 0, + 24, + 24, + 24 + ], + "children": [ + { + "type": "frame", + "id": "yHmVL", + "name": "tagInput", + "width": "fill_container", + "height": 44, + "fill": "#FFFFFF", + "cornerRadius": 8, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#E2E3EA" + }, + "padding": [ + 0, + 12 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "h8epW", + "name": "tagPlc", + "fill": "#A0A3B1", + "content": "Search for a tag...", + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "4iJHJ", + "name": "tagRecent", + "width": "fill_container", + "layout": "vertical", + "gap": 8, + "children": [ + { + "type": "text", + "id": "ewdqU", + "name": "tagRecentLbl", + "fill": "#6B6F80", + "content": "Recently used", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "500" + }, + { + "type": "frame", + "id": "GfzJZ", + "name": "tagPills", + "width": "fill_container", + "gap": 6, + "children": [ + { + "type": "frame", + "id": "b4nQy", + "name": "tagP1", + "fill": "#F4F4F8", + "cornerRadius": 6, + "padding": [ + 4, + 10 + ], + "children": [ + { + "type": "text", + "id": "IwR8Q", + "name": "tagP1T", + "fill": "#3D3F4A", + "content": "transitive", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "es7dT", + "name": "tagP2", + "fill": "#F4F4F8", + "cornerRadius": 6, + "padding": [ + 4, + 10 + ], + "children": [ + { + "type": "text", + "id": "0rCon", + "name": "tagP2T", + "fill": "#3D3F4A", + "content": "form-I", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "normal" + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "type": "frame", + "id": "EOoXc", + "x": 0, + "y": 3930, + "name": "Add Word — AI Button", + "clip": true, + "width": 1440, + "height": 1200, + "fill": "#FFFFFF", + "children": [ + { + "type": "frame", + "id": "6VqIS", + "name": "Sidebar", + "width": 56, + "height": "fill_container", + "fill": "#FCFCFC", + "stroke": { + "align": "inside", + "thickness": { + "right": 1 + }, + "fill": "#E0E2EC" + }, + "layout": "vertical", + "gap": 16, + "padding": [ + 16, + 0 + ], + "children": [ + { + "type": "frame", + "id": "khRKm", + "name": "cLogo", + "width": 28, + "height": 28, + "fill": { + "type": "image", + "enabled": true, + "url": "./apps/web/src/assets/logo.svg", + "mode": "fit" + }, + "justifyContent": "center", + "alignItems": "center" + }, + { + "type": "frame", + "id": "ilntI", + "name": "cNavGrp", + "layout": "vertical", + "gap": 4, + "children": [ + { + "type": "frame", + "id": "qC4KW", + "name": "cNavHome", + "width": 36, + "height": 36, + "fill": "#4F46E518", + "cornerRadius": 8, + "justifyContent": "center", + "alignItems": "center", + "children": [ + { + "type": "icon_font", + "id": "F1gRS", + "name": "cNavHomeI", + "width": 20, + "height": 20, + "iconFontName": "book-open", + "iconFontFamily": "lucide", + "fill": "#4F46E5" + } + ] + }, + { + "type": "frame", + "id": "pham9", + "name": "cNavDecks", + "width": 36, + "height": 36, + "cornerRadius": 8, + "justifyContent": "center", + "alignItems": "center", + "children": [ + { + "type": "icon_font", + "id": "5nZ2p", + "name": "cNavDecksI", + "width": 20, + "height": 20, + "iconFontName": "layers", + "iconFontFamily": "lucide", + "fill": "#6B6F80" + } + ] + } + ] + }, + { + "type": "frame", + "id": "XbLl5", + "name": "cSpacer", + "width": 36, + "height": "fill_container" + }, + { + "type": "frame", + "id": "ukkVf", + "name": "cSettBtn", + "width": 36, + "height": 36, + "cornerRadius": 8, + "justifyContent": "center", + "alignItems": "center", + "children": [ + { + "type": "icon_font", + "id": "h4vkF", + "name": "cSettI", + "width": 20, + "height": 20, + "iconFontName": "settings", + "iconFontFamily": "lucide", + "fill": "#6B6F80" + } + ] + } + ] + }, + { + "type": "frame", + "id": "RfLwL", + "name": "Main Content", + "width": "fill_container", + "height": "fill_container", + "fill": "#FFFFFF", + "layout": "vertical", + "gap": 20, + "padding": [ + 24, + 40 + ], + "children": [ + { + "type": "frame", + "id": "t8vot", + "name": "cBreadcrumbs", + "gap": 6, + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "IzQc1", + "name": "cBcHome", + "fill": "#6B6F80", + "content": "Home", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "500" + }, + { + "type": "text", + "id": "OWd36", + "name": "cBcSep", + "fill": "#6B6F80", + "content": "/", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "normal" + }, + { + "type": "text", + "id": "wJozn", + "name": "cBcCurrent", + "fill": "#1B1B2F", + "content": "Add word", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "500" + } + ] + }, + { + "type": "frame", + "id": "uGaVi", + "name": "cHeaderRow", + "width": "fill_container", + "justifyContent": "space_between", + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "kVbIh", + "name": "cTitle", + "fill": "#1B1B2F", + "content": "Add a new word to your dictionary", + "fontFamily": "Inter", + "fontSize": 22, + "fontWeight": "600", + "letterSpacing": -0.3 + }, + { + "type": "frame", + "id": "MFiBR", + "name": "cBtnRow", + "gap": 8, + "children": [ + { + "type": "frame", + "id": "vFFKd", + "name": "AI Autofill Btn", + "fill": { + "type": "gradient", + "gradientType": "linear", + "enabled": true, + "rotation": 90, + "size": { + "height": 1 + }, + "colors": [ + { + "color": "#4F46E5", + "position": 0 + }, + { + "color": "#6D5BF7", + "position": 1 + } + ] + }, + "cornerRadius": 8, + "effect": { + "type": "shadow", + "shadowType": "outer", + "color": "#4F46E514", + "offset": { + "x": 0, + "y": 1 + }, + "blur": 4 + }, + "gap": 6, + "padding": [ + 8, + 14 + ], + "justifyContent": "center", + "alignItems": "center", + "children": [ + { + "type": "icon_font", + "id": "nosrM", + "name": "aiHBIcon", + "width": 14, + "height": 14, + "iconFontName": "sparkles", + "iconFontFamily": "lucide", + "fill": "#FFFFFF" + }, + { + "type": "text", + "id": "Kf2BT", + "name": "aiHBText", + "fill": "#FFFFFF", + "content": "Auto-fill with AI", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "600" + }, + { + "type": "frame", + "id": "Zfsvk", + "name": "aiHBBadge", + "fill": "#FFFFFF20", + "cornerRadius": 3, + "padding": [ + 1, + 5 + ], + "children": [ + { + "type": "text", + "id": "3LC23", + "name": "aiHBBadgeT", + "fill": "#FFFFFF", + "content": "PRO", + "fontFamily": "Inter", + "fontSize": 9, + "fontWeight": "700", + "letterSpacing": 0.5 + } + ] + } + ] + }, + { + "type": "frame", + "id": "ymASC", + "name": "cDiscardBtn", + "cornerRadius": 8, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#E2E3EA" + }, + "padding": [ + 8, + 16 + ], + "justifyContent": "center", + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "1XaTm", + "name": "cDiscardText", + "fill": "#6B6F80", + "content": "Discard", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "500" + } + ] + }, + { + "type": "frame", + "id": "C7k1b", + "name": "cSaveBtn", + "fill": "#1B1B2F", + "cornerRadius": 8, + "padding": [ + 8, + 16 + ], + "justifyContent": "center", + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "fqnha", + "name": "cSaveText", + "fill": "#FFFFFF", + "content": "Save", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "600" + } + ] + } + ] + } + ] + }, + { + "type": "frame", + "id": "239tb", + "name": "Form Grid", + "width": "fill_container", + "gap": 24, + "children": [ + { + "type": "frame", + "id": "jQmzs", + "name": "Left Column", + "width": "fill_container", + "layout": "vertical", + "gap": 20, + "children": [ + { + "type": "frame", + "id": "HEyEo", + "name": "Basic Details", + "width": "fill_container", + "cornerRadius": 12, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#E2E3EA" + }, + "layout": "vertical", + "children": [ + { + "type": "frame", + "id": "yxkwd", + "name": "bdHeader", + "width": "fill_container", + "layout": "vertical", + "gap": 2, + "padding": [ + 20, + 24, + 12, + 24 + ], + "children": [ + { + "type": "text", + "id": "wKknF", + "name": "bdTitle", + "fill": "#1B1B2F", + "content": "Basic Details", + "fontFamily": "Inter", + "fontSize": 16, + "fontWeight": "600" + } + ] + }, + { + "type": "frame", + "id": "FSkBp", + "name": "bdBody", + "width": "fill_container", + "layout": "vertical", + "gap": 16, + "padding": [ + 0, + 24, + 24, + 24 + ], + "children": [ + { + "type": "frame", + "id": "b0sYp", + "name": "bdWordField", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "lkP3t", + "name": "bdWordLbl", + "fill": "#3D3F4A", + "content": "Word*", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "500" + }, + { + "type": "frame", + "id": "lNioE", + "name": "bdWordIn", + "width": "fill_container", + "height": 44, + "fill": "#FFFFFF", + "cornerRadius": 8, + "stroke": { + "align": "inside", + "thickness": 1.5, + "fill": "#4F46E5" + }, + "padding": [ + 0, + 12 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "p4CaF", + "name": "bdWordPlc", + "fill": "#1B1B2F", + "content": "كَتَبَ", + "fontFamily": "Inter", + "fontSize": 16, + "fontWeight": "normal" + } + ] + } + ] + }, + { + "type": "frame", + "id": "AFcwl", + "name": "bdTransField", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "dcbG6", + "name": "bdTransLbl", + "fill": "#3D3F4A", + "content": "Translation*", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "500" + }, + { + "type": "frame", + "id": "1C9tl", + "name": "bdTransIn", + "width": "fill_container", + "height": 44, + "fill": "#FFFFFF", + "cornerRadius": 8, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#E2E3EA" + }, + "padding": [ + 0, + 12 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "8cFQb", + "name": "bdTransPlc", + "fill": "#1B1B2F", + "content": "to write", + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "normal" + } + ] + }, + { + "type": "text", + "id": "vyuiq", + "name": "bdTransDesc", + "fill": "#6B6F80", + "content": "An English translation of the word.", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "normal" + } + ] + } + ] + } + ] + }, + { + "type": "frame", + "id": "uwlqN", + "name": "Additional Details", + "width": "fill_container", + "fill": "#FAFAFF", + "cornerRadius": 12, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#D4D0F8" + }, + "layout": "vertical", + "children": [ + { + "type": "frame", + "id": "GWMn6", + "name": "adHeader", + "width": "fill_container", + "layout": "vertical", + "gap": 2, + "padding": [ + 20, + 24, + 12, + 24 + ], + "children": [ + { + "type": "frame", + "id": "wi3a6", + "name": "adAiRow", + "width": "fill_container", + "justifyContent": "space_between", + "alignItems": "center", + "children": [ + { + "type": "frame", + "id": "JJJdr", + "name": "adAiBadge", + "gap": 6, + "alignItems": "center", + "children": [ + { + "type": "icon_font", + "id": "vWonn", + "name": "adAiIcon", + "width": 13, + "height": 13, + "iconFontName": "sparkles", + "iconFontFamily": "lucide", + "fill": "#4F46E5" + }, + { + "type": "text", + "id": "9zzgO", + "name": "adAiText", + "fill": "#4F46E5", + "content": "AI-Generated", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "600" + } + ] + }, + { + "type": "frame", + "id": "XyVfX", + "name": "adClearBtn", + "gap": 4, + "alignItems": "center", + "children": [ + { + "type": "icon_font", + "id": "kQ9X1", + "name": "adClearIcon", + "width": 12, + "height": 12, + "iconFontName": "rotate-ccw", + "iconFontFamily": "lucide", + "fill": "#8B85D0" + }, + { + "type": "text", + "id": "J5r5w", + "name": "adClearText", + "fill": "#8B85D0", + "content": "Clear all", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "500" + } + ] + } + ] + }, + { + "type": "text", + "id": "M66mC", + "name": "adTitle", + "fill": "#1B1B2F", + "content": "Additional Details", + "fontFamily": "Inter", + "fontSize": 16, + "fontWeight": "600" + }, + { + "type": "text", + "id": "Yo2Hp", + "name": "adDesc", + "fill": "#6B6F80", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Information such as the word's root, meaning, and examples.", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "Wuz98", + "name": "adBody", + "width": "fill_container", + "layout": "vertical", + "gap": 16, + "padding": [ + 0, + 24, + 24, + 24 + ], + "children": [ + { + "type": "frame", + "id": "gOhCe", + "name": "adDefField", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "Px6Ny", + "name": "adDefLbl", + "fill": "#3D3F4A", + "content": "Definition", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "500" + }, + { + "type": "frame", + "id": "wbksG", + "name": "Def Input Row", + "width": "fill_container", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "frame", + "id": "gn8OH", + "name": "adDefIn", + "width": "fill_container", + "height": 44, + "fill": "#FFFFFF", + "cornerRadius": 8, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#D4D0F8" + }, + "padding": [ + 0, + 12 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "2SIZq", + "name": "adDefPlc", + "fill": "#1B1B2F", + "content": "سَطَّرَ، خَطَّ بِالقَلَم", + "fontFamily": "Inter", + "fontSize": 16, + "fontWeight": "normal" + } + ] + }, + { + "type": "icon_font", + "id": "0CNqg", + "name": "defSparkle", + "width": 16, + "height": 16, + "iconFontName": "sparkles", + "iconFontFamily": "lucide", + "fill": "#8B85D0" + } + ] + }, + { + "type": "text", + "id": "mjkT3", + "name": "adDefDesc", + "fill": "#6B6F80", + "content": "An Arabic definition of the word.", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "1xPSv", + "name": "adRootField", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "Awls1", + "name": "adRootLbl", + "fill": "#3D3F4A", + "content": "Root letters", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "500" + }, + { + "type": "frame", + "id": "hGqi3", + "name": "Root Input Row", + "width": "fill_container", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "frame", + "id": "S4Gw0", + "name": "adRootIn", + "width": "fill_container", + "height": 44, + "fill": "#FFFFFF", + "cornerRadius": 8, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#D4D0F8" + }, + "padding": [ + 0, + 12 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "PJhYb", + "name": "adRootPlc", + "fill": "#1B1B2F", + "content": "ك ت ب", + "fontFamily": "Inter", + "fontSize": 16, + "fontWeight": "normal" + } + ] + }, + { + "type": "icon_font", + "id": "slNtB", + "name": "rootSparkle", + "width": 16, + "height": 16, + "iconFontName": "sparkles", + "iconFontFamily": "lucide", + "fill": "#8B85D0" + } + ] + }, + { + "type": "text", + "id": "QEZcs", + "name": "adRootDesc", + "fill": "#6B6F80", + "content": "The root letters of the word.", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "7eClp", + "name": "adExWrap", + "width": "fill_container", + "layout": "vertical", + "gap": 8, + "children": [ + { + "type": "frame", + "id": "dMuDz", + "name": "adExHeader", + "width": "fill_container", + "justifyContent": "space_between", + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "yIPLT", + "name": "adExTitle", + "fill": "#1B1B2F", + "content": "Examples", + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "600" + } + ] + }, + { + "type": "text", + "id": "Q8K51", + "name": "adExDesc", + "fill": "#6B6F80", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Example usages of the word in different contexts.", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "normal" + }, + { + "type": "frame", + "id": "PTeUb", + "name": "Example 1", + "width": "fill_container", + "fill": "#FFFFFF", + "cornerRadius": 8, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#D4D0F8" + }, + "layout": "vertical", + "gap": 4, + "padding": [ + 10, + 14 + ], + "children": [ + { + "type": "frame", + "id": "z2Cy6", + "name": "ex1TopRow", + "width": "fill_container", + "justifyContent": "space_between", + "alignItems": "center", + "children": [ + { + "type": "frame", + "id": "oHsEZ", + "name": "ex1Label", + "gap": 4, + "alignItems": "center", + "children": [ + { + "type": "ellipse", + "id": "DSRGB", + "name": "ex1Dot", + "fill": "#4F46E5", + "width": 5, + "height": 5 + }, + { + "type": "text", + "id": "jqdP3", + "name": "ex1CtxT", + "fill": "#4F46E5", + "content": "formal", + "fontFamily": "Inter", + "fontSize": 11, + "fontWeight": "500" + } + ] + }, + { + "type": "icon_font", + "id": "bHsM0", + "name": "ex1Reset", + "width": 14, + "height": 14, + "iconFontName": "x", + "iconFontFamily": "lucide", + "fill": "#8B85D0" + } + ] + }, + { + "type": "text", + "id": "7JSCV", + "name": "ex1Ar", + "fill": "#1B1B2F", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "كَتَبَ الطَّالِبُ رِسَالَةً إِلَى صَدِيقِهِ", + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "normal" + }, + { + "type": "text", + "id": "EvVvn", + "name": "ex1En", + "fill": "#6B6F80", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "The student wrote a letter to his friend.", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "F27eW", + "name": "Example 2", + "width": "fill_container", + "fill": "#FFFFFF", + "cornerRadius": 8, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#D4D0F8" + }, + "layout": "vertical", + "gap": 4, + "padding": [ + 10, + 14 + ], + "children": [ + { + "type": "frame", + "id": "h4xpO", + "name": "ex2TopRow", + "width": "fill_container", + "justifyContent": "space_between", + "alignItems": "center", + "children": [ + { + "type": "frame", + "id": "Wex5w", + "name": "ex2Label", + "gap": 4, + "alignItems": "center", + "children": [ + { + "type": "ellipse", + "id": "Prp6i", + "name": "ex2Dot", + "fill": "#22C55E", + "width": 5, + "height": 5 + }, + { + "type": "text", + "id": "n9A9J", + "name": "ex2CtxT", + "fill": "#22C55E", + "content": "modern", + "fontFamily": "Inter", + "fontSize": 11, + "fontWeight": "500" + } + ] + }, + { + "type": "icon_font", + "id": "1RkKE", + "name": "ex2Reset", + "width": 14, + "height": 14, + "iconFontName": "x", + "iconFontFamily": "lucide", + "fill": "#8B85D0" + } + ] + }, + { + "type": "text", + "id": "3KTIF", + "name": "ex2Ar", + "fill": "#1B1B2F", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "يَكْتُبُ المُؤَلِّفُ كِتَابًا جَدِيدًا كُلَّ عَام", + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "normal" + }, + { + "type": "text", + "id": "48pDE", + "name": "ex2En", + "fill": "#6B6F80", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "The author writes a new book every year.", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "normal" + } + ] + } + ] + } + ] + } + ] + }, + { + "type": "frame", + "id": "coMHf", + "name": "Morphology", + "width": "fill_container", + "fill": "#FAFAFF", + "cornerRadius": 12, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#D4D0F8" + }, + "layout": "vertical", + "children": [ + { + "type": "frame", + "id": "Scwys", + "name": "morphHeader", + "width": "fill_container", + "layout": "vertical", + "gap": 2, + "padding": [ + 20, + 24, + 12, + 24 + ], + "children": [ + { + "type": "frame", + "id": "enxPF", + "name": "mAiRow", + "width": "fill_container", + "justifyContent": "space_between", + "alignItems": "center", + "children": [ + { + "type": "frame", + "id": "FyDtg", + "name": "mAiBadge", + "gap": 6, + "alignItems": "center", + "children": [ + { + "type": "icon_font", + "id": "2P8df", + "name": "mAiIcon", + "width": 13, + "height": 13, + "iconFontName": "sparkles", + "iconFontFamily": "lucide", + "fill": "#4F46E5" + }, + { + "type": "text", + "id": "hHW0D", + "name": "mAiText", + "fill": "#4F46E5", + "content": "AI-Generated", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "600" + } + ] + }, + { + "type": "frame", + "id": "kWpIs", + "name": "mClearBtn", + "gap": 4, + "alignItems": "center", + "children": [ + { + "type": "icon_font", + "id": "16mVx", + "name": "mClearIcon", + "width": 12, + "height": 12, + "iconFontName": "rotate-ccw", + "iconFontFamily": "lucide", + "fill": "#8B85D0" + }, + { + "type": "text", + "id": "ZICG2", + "name": "mClearText", + "fill": "#8B85D0", + "content": "Clear all", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "500" + } + ] + } + ] + }, + { + "type": "text", + "id": "SbysH", + "name": "morphTitle", + "fill": "#1B1B2F", + "content": "Morphology", + "fontFamily": "Inter", + "fontSize": 16, + "fontWeight": "600" + }, + { + "type": "text", + "id": "IQigT", + "name": "morphDesc", + "fill": "#6B6F80", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "The morphological breakdown of the word.", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "htFLn", + "name": "morphBody", + "width": "fill_container", + "layout": "vertical", + "gap": 12, + "padding": [ + 0, + 24, + 24, + 24 + ], + "children": [ + { + "type": "frame", + "id": "zZOV9", + "name": "morphRow1", + "width": "fill_container", + "gap": 12, + "children": [ + { + "type": "frame", + "id": "yQFDr", + "name": "mSingF", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "lu7zi", + "name": "mSingLbl", + "fill": "#3D3F4A", + "content": "Singular", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "500" + }, + { + "type": "frame", + "id": "i48jU", + "name": "Sing Input Row", + "width": "fill_container", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "frame", + "id": "HMwvc", + "name": "mSingIn", + "width": "fill_container", + "height": 44, + "fill": "#FFFFFF", + "cornerRadius": 8, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#D4D0F8" + }, + "padding": [ + 0, + 12 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "JxBmc", + "name": "singVal", + "fill": "#1B1B2F", + "content": "كِتَاب", + "fontFamily": "Inter", + "fontSize": 16, + "fontWeight": "normal" + } + ] + }, + { + "type": "icon_font", + "id": "b6ucK", + "name": "singSparkle", + "width": 16, + "height": 16, + "iconFontName": "sparkles", + "iconFontFamily": "lucide", + "fill": "#8B85D0" + } + ] + } + ] + }, + { + "type": "frame", + "id": "9r9Ow", + "name": "mDualF", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "pvSAN", + "name": "mDualLbl", + "fill": "#3D3F4A", + "content": "Dual", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "500" + }, + { + "type": "frame", + "id": "ixLPz", + "name": "Dual Input Row", + "width": "fill_container", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "frame", + "id": "Gpb8z", + "name": "mDualIn", + "width": "fill_container", + "height": 44, + "fill": "#FFFFFF", + "cornerRadius": 8, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#D4D0F8" + }, + "padding": [ + 0, + 12 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "h0rrS", + "name": "dualVal", + "fill": "#1B1B2F", + "content": "كِتَابَان", + "fontFamily": "Inter", + "fontSize": 16, + "fontWeight": "normal" + } + ] + }, + { + "type": "icon_font", + "id": "d1Fal", + "name": "dualSparkle", + "width": 16, + "height": 16, + "iconFontName": "sparkles", + "iconFontFamily": "lucide", + "fill": "#8B85D0" + } + ] + } + ] + } + ] + }, + { + "type": "frame", + "id": "LjAhZ", + "name": "mRow2", + "width": "fill_container", + "gap": 12, + "children": [ + { + "type": "frame", + "id": "NAJk8", + "name": "mGenderF", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "pks93", + "name": "mGenderLbl", + "fill": "#3D3F4A", + "content": "Gender", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "500" + }, + { + "type": "frame", + "id": "HeGTz", + "name": "Gender Input Row", + "width": "fill_container", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "frame", + "id": "8NnnW", + "name": "mGenderIn", + "width": "fill_container", + "height": 44, + "fill": "#FFFFFF", + "cornerRadius": 8, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#D4D0F8" + }, + "padding": [ + 0, + 12 + ], + "justifyContent": "space_between", + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "swVnK", + "name": "mGenderVal", + "fill": "#1B1B2F", + "content": "Masculine", + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "normal" + } + ] + }, + { + "type": "icon_font", + "id": "8FJW8", + "name": "genderSparkle", + "width": 16, + "height": 16, + "iconFontName": "sparkles", + "iconFontFamily": "lucide", + "fill": "#8B85D0" + } + ] + } + ] + }, + { + "type": "frame", + "id": "X3pbL", + "name": "mInflF", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "ykBU7", + "name": "mInflLbl", + "fill": "#3D3F4A", + "content": "Inflection", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "500" + }, + { + "type": "frame", + "id": "aZofN", + "name": "Infl Input Row", + "width": "fill_container", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "frame", + "id": "YTvNt", + "name": "mInflIn", + "width": "fill_container", + "height": 44, + "fill": "#FFFFFF", + "cornerRadius": 8, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#D4D0F8" + }, + "padding": [ + 0, + 12 + ], + "justifyContent": "space_between", + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "pas2Q", + "name": "mInflVal", + "fill": "#1B1B2F", + "content": "Triptote", + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "normal" + } + ] + }, + { + "type": "icon_font", + "id": "yRfBG", + "name": "inflSparkle", + "width": 16, + "height": 16, + "iconFontName": "sparkles", + "iconFontFamily": "lucide", + "fill": "#8B85D0" + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "type": "frame", + "id": "cmW3V", + "name": "Right Sidebar", + "width": 280, + "layout": "vertical", + "gap": 20, + "children": [ + { + "type": "frame", + "id": "jF8PD", + "name": "Category", + "width": "fill_container", + "cornerRadius": 12, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#E2E3EA" + }, + "layout": "vertical", + "children": [ + { + "type": "frame", + "id": "9HKJH", + "name": "catHeader", + "width": "fill_container", + "layout": "vertical", + "gap": 2, + "padding": [ + 20, + 24, + 12, + 24 + ], + "children": [ + { + "type": "text", + "id": "ieq6U", + "name": "catTitle", + "fill": "#1B1B2F", + "content": "Category", + "fontFamily": "Inter", + "fontSize": 16, + "fontWeight": "600" + }, + { + "type": "text", + "id": "8fjnn", + "name": "catDesc", + "fill": "#6B6F80", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "How the word is categorized.", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "3oKIz", + "name": "catBody", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "padding": [ + 0, + 24, + 24, + 24 + ], + "children": [ + { + "type": "text", + "id": "16a6o", + "name": "catLbl", + "fill": "#3D3F4A", + "content": "Type", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "500" + }, + { + "type": "frame", + "id": "S4NWc", + "name": "catSelect", + "width": "fill_container", + "height": 44, + "fill": "#FFFFFF", + "cornerRadius": 8, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#E2E3EA" + }, + "padding": [ + 0, + 12 + ], + "justifyContent": "space_between", + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "TXoKP", + "name": "catVal", + "fill": "#1B1B2F", + "content": "Ism", + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "normal" + }, + { + "type": "icon_font", + "id": "QXqGC", + "name": "catChev", + "width": 16, + "height": 16, + "iconFontName": "chevron-down", + "iconFontFamily": "lucide", + "fill": "#6B6F80" + } + ] + } + ] + } + ] + }, + { + "type": "frame", + "id": "4JBYW", + "name": "Tags", + "width": "fill_container", + "cornerRadius": 12, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#E2E3EA" + }, + "layout": "vertical", + "children": [ + { + "type": "frame", + "id": "ANznn", + "name": "tagHeader", + "width": "fill_container", + "layout": "vertical", + "gap": 2, + "padding": [ + 20, + 24, + 12, + 24 + ], + "children": [ + { + "type": "text", + "id": "PgK6L", + "name": "tagTitle", + "fill": "#1B1B2F", + "content": "Tags", + "fontFamily": "Inter", + "fontSize": 16, + "fontWeight": "600" + }, + { + "type": "text", + "id": "pdj6Y", + "name": "tagDesc", + "fill": "#6B6F80", + "content": "Add tags to your word.", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "p5axP", + "name": "tagBody", + "width": "fill_container", + "layout": "vertical", + "gap": 10, + "padding": [ + 0, + 24, + 24, + 24 + ], + "children": [ + { + "type": "frame", + "id": "Stpa5", + "name": "tagInput", + "width": "fill_container", + "height": 44, + "fill": "#FFFFFF", + "cornerRadius": 8, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#E2E3EA" + }, + "padding": [ + 0, + 12 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "k0RQs", + "name": "tagPlc", + "fill": "#A0A3B1", + "content": "Search for a tag...", + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "6NgNU", + "name": "tagRecent", + "width": "fill_container", + "layout": "vertical", + "gap": 8, + "children": [ + { + "type": "text", + "id": "a9FJj", + "name": "tagRecentLbl", + "fill": "#6B6F80", + "content": "Recently used", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "500" + }, + { + "type": "frame", + "id": "jfXfF", + "name": "tagPills", + "width": "fill_container", + "gap": 6, + "children": [ + { + "type": "frame", + "id": "Sdop6", + "name": "tagP1", + "fill": "#F4F4F8", + "cornerRadius": 6, + "padding": [ + 4, + 10 + ], + "children": [ + { + "type": "text", + "id": "XASQm", + "name": "tagP1T", + "fill": "#3D3F4A", + "content": "transitive", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "YRttD", + "name": "tagP2", + "fill": "#F4F4F8", + "cornerRadius": 6, + "padding": [ + 4, + 10 + ], + "children": [ + { + "type": "text", + "id": "ZDFvh", + "name": "tagP2T", + "fill": "#3D3F4A", + "content": "form-I", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "normal" + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "type": "frame", + "id": "48UPU", + "x": 1540, + "y": 3930, + "name": "Add Word — Auto Suggest", + "clip": true, + "width": 1440, + "height": 1200, + "fill": "#FFFFFF", + "children": [ + { + "type": "frame", + "id": "1MsIp", + "name": "Sidebar", + "width": 56, + "height": "fill_container", + "fill": "#FCFCFC", + "stroke": { + "align": "inside", + "thickness": { + "right": 1 + }, + "fill": "#E0E2EC" + }, + "layout": "vertical", + "gap": 16, + "padding": [ + 16, + 0 + ], + "children": [ + { + "type": "frame", + "id": "3GlcW", + "name": "cLogo", + "width": 28, + "height": 28, + "fill": { + "type": "image", + "enabled": true, + "url": "./apps/web/src/assets/logo.svg", + "mode": "fit" + }, + "justifyContent": "center", + "alignItems": "center" + }, + { + "type": "frame", + "id": "9QMZM", + "name": "cNavGrp", + "layout": "vertical", + "gap": 4, + "children": [ + { + "type": "frame", + "id": "Yda3c", + "name": "cNavHome", + "width": 36, + "height": 36, + "fill": "#4F46E518", + "cornerRadius": 8, + "justifyContent": "center", + "alignItems": "center", + "children": [ + { + "type": "icon_font", + "id": "784Ci", + "name": "cNavHomeI", + "width": 20, + "height": 20, + "iconFontName": "book-open", + "iconFontFamily": "lucide", + "fill": "#4F46E5" + } + ] + }, + { + "type": "frame", + "id": "4JLGH", + "name": "cNavDecks", + "width": 36, + "height": 36, + "cornerRadius": 8, + "justifyContent": "center", + "alignItems": "center", + "children": [ + { + "type": "icon_font", + "id": "Fb0rQ", + "name": "cNavDecksI", + "width": 20, + "height": 20, + "iconFontName": "layers", + "iconFontFamily": "lucide", + "fill": "#6B6F80" + } + ] + } + ] + }, + { + "type": "frame", + "id": "E0Vrs", + "name": "cSpacer", + "width": 36, + "height": "fill_container" + }, + { + "type": "frame", + "id": "6GGhO", + "name": "cSettBtn", + "width": 36, + "height": 36, + "cornerRadius": 8, + "justifyContent": "center", + "alignItems": "center", + "children": [ + { + "type": "icon_font", + "id": "n5vfB", + "name": "cSettI", + "width": 20, + "height": 20, + "iconFontName": "settings", + "iconFontFamily": "lucide", + "fill": "#6B6F80" + } + ] + } + ] + }, + { + "type": "frame", + "id": "q9S2p", + "name": "Main Content", + "width": "fill_container", + "height": "fill_container", + "fill": "#FFFFFF", + "layout": "vertical", + "gap": 20, + "padding": [ + 24, + 40 + ], + "children": [ + { + "type": "frame", + "id": "rurQf", + "name": "cBreadcrumbs", + "gap": 6, + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "X3CB7", + "name": "cBcHome", + "fill": "#6B6F80", + "content": "Home", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "500" + }, + { + "type": "text", + "id": "O4WEn", + "name": "cBcSep", + "fill": "#6B6F80", + "content": "/", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "normal" + }, + { + "type": "text", + "id": "Y3pGv", + "name": "cBcCurrent", + "fill": "#1B1B2F", + "content": "Add word", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "500" + } + ] + }, + { + "type": "frame", + "id": "GCyvF", + "name": "cHeaderRow", + "width": "fill_container", + "justifyContent": "space_between", + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "53Ol8", + "name": "cTitle", + "fill": "#1B1B2F", + "content": "Add a new word to your dictionary", + "fontFamily": "Inter", + "fontSize": 22, + "fontWeight": "600", + "letterSpacing": -0.3 + }, + { + "type": "frame", + "id": "PDL0d", + "name": "cBtnRow", + "gap": 8, + "children": [ + { + "type": "frame", + "id": "WqKUC", + "name": "cDiscardBtn", + "cornerRadius": 8, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#E2E3EA" + }, + "padding": [ + 8, + 16 + ], + "justifyContent": "center", + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "DbBou", + "name": "cDiscardText", + "fill": "#6B6F80", + "content": "Discard", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "500" + } + ] + }, + { + "type": "frame", + "id": "o9OFO", + "name": "cSaveBtn", + "fill": "#1B1B2F", + "cornerRadius": 8, + "padding": [ + 8, + 16 + ], + "justifyContent": "center", + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "5XKV8", + "name": "cSaveText", + "fill": "#FFFFFF", + "content": "Save", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "600" + } + ] + } + ] + } + ] + }, + { + "type": "frame", + "id": "4ROjN", + "name": "Form Grid", + "width": "fill_container", + "gap": 24, + "children": [ + { + "type": "frame", + "id": "GL54t", + "name": "Left Column", + "width": "fill_container", + "layout": "vertical", + "gap": 20, + "children": [ + { + "type": "frame", + "id": "RF3t2", + "name": "Basic Details", + "width": "fill_container", + "cornerRadius": 12, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#E2E3EA" + }, + "layout": "vertical", + "children": [ + { + "type": "frame", + "id": "PYGU0", + "name": "bdHeader", + "width": "fill_container", + "layout": "vertical", + "gap": 2, + "padding": [ + 20, + 24, + 12, + 24 + ], + "children": [ + { + "type": "text", + "id": "ceak7", + "name": "bdTitle", + "fill": "#1B1B2F", + "content": "Basic Details", + "fontFamily": "Inter", + "fontSize": 16, + "fontWeight": "600" + } + ] + }, + { + "type": "frame", + "id": "Ww7jR", + "name": "bdBody", + "width": "fill_container", + "layout": "vertical", + "gap": 16, + "padding": [ + 0, + 24, + 24, + 24 + ], + "children": [ + { + "type": "frame", + "id": "Q0d9s", + "name": "bdWordField", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "hDCgn", + "name": "bdWordLbl", + "fill": "#3D3F4A", + "content": "Word*", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "500" + }, + { + "type": "frame", + "id": "SXZmW", + "name": "bdWordIn", + "width": "fill_container", + "height": 44, + "fill": "#FFFFFF", + "cornerRadius": 8, + "stroke": { + "align": "inside", + "thickness": 1.5, + "fill": "#4F46E5" + }, + "padding": [ + 0, + 12 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "6he37", + "name": "bdWordPlc", + "fill": "#1B1B2F", + "content": "كَتَبَ", + "fontFamily": "Inter", + "fontSize": 16, + "fontWeight": "normal" + } + ] + } + ] + }, + { + "type": "frame", + "id": "rN3x8", + "name": "bdTransField", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "8yCQ5", + "name": "bdTransLbl", + "fill": "#3D3F4A", + "content": "Translation*", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "500" + }, + { + "type": "frame", + "id": "U6Sgn", + "name": "bdTransIn", + "width": "fill_container", + "height": 44, + "fill": "#FFFFFF", + "cornerRadius": 8, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#E2E3EA" + }, + "padding": [ + 0, + 12 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "G9XGn", + "name": "bdTransPlc", + "fill": "#1B1B2F", + "content": "to write", + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "normal" + } + ] + }, + { + "type": "text", + "id": "lo0c4", + "name": "bdTransDesc", + "fill": "#6B6F80", + "content": "An English translation of the word.", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "normal" + } + ] + } + ] + } + ] + }, + { + "type": "frame", + "id": "Pz0rJ", + "name": "Additional Details", + "width": "fill_container", + "cornerRadius": 12, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#E2E3EA" + }, + "layout": "vertical", + "children": [ + { + "type": "frame", + "id": "xoP3x", + "name": "adHeader", + "width": "fill_container", + "layout": "vertical", + "gap": 2, + "padding": [ + 20, + 24, + 12, + 24 + ], + "children": [ + { + "type": "text", + "id": "mlIDV", + "name": "adTitle", + "fill": "#1B1B2F", + "content": "Additional Details", + "fontFamily": "Inter", + "fontSize": 16, + "fontWeight": "600" + }, + { + "type": "text", + "id": "37i3P", + "name": "adDesc", + "fill": "#6B6F80", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Information such as the word's root, meaning, and examples.", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "UCCGp", + "name": "adBody", + "width": "fill_container", + "layout": "vertical", + "gap": 16, + "padding": [ + 0, + 24, + 24, + 24 + ], + "children": [ + { + "type": "frame", + "id": "UuWqf", + "name": "adDefField", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "lzlon", + "name": "adDefLbl", + "fill": "#3D3F4A", + "content": "Definition", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "500" + }, + { + "type": "frame", + "id": "y6OoF", + "name": "adDefIn", + "width": "fill_container", + "height": 44, + "fill": "#FFFFFF", + "cornerRadius": 8, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#E2E3EA" + }, + "padding": [ + 0, + 12 + ], + "justifyContent": "space_between", + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "rbDb3", + "name": "adDefPlc", + "fill": "#8B85D0", + "content": "سَطَّرَ، خَطَّ بِالقَلَم", + "fontFamily": "Inter", + "fontSize": 16, + "fontWeight": "normal", + "fontStyle": "italic" + }, + { + "type": "icon_font", + "id": "5m5D7", + "name": "defHint", + "width": 14, + "height": 14, + "iconFontName": "sparkles", + "iconFontFamily": "lucide", + "fill": "#8B85D040" + } + ] + }, + { + "type": "text", + "id": "UFGe2", + "name": "adDefDesc", + "fill": "#6B6F80", + "content": "An Arabic definition of the word.", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "WK8Dx", + "name": "adRootField", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "vLBmX", + "name": "adRootLbl", + "fill": "#3D3F4A", + "content": "Root letters", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "500" + }, + { + "type": "frame", + "id": "Q14oa", + "name": "adRootIn", + "width": "fill_container", + "height": 44, + "fill": "#FFFFFF", + "cornerRadius": 8, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#E2E3EA" + }, + "padding": [ + 0, + 12 + ], + "justifyContent": "space_between", + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "3rP0U", + "name": "adRootPlc", + "fill": "#8B85D0", + "content": "ك ت ب", + "fontFamily": "Inter", + "fontSize": 16, + "fontWeight": "normal", + "fontStyle": "italic" + }, + { + "type": "frame", + "id": "Yx8Aa", + "name": "rootHint", + "gap": 4, + "alignItems": "center", + "children": [ + { + "type": "icon_font", + "id": "6sUIl", + "name": "rootHintI", + "width": 12, + "height": 12, + "iconFontName": "sparkles", + "iconFontFamily": "lucide", + "fill": "#8B85D0" + }, + { + "type": "text", + "id": "Tu7D8", + "name": "rootHintT", + "fill": "#8B85D0", + "content": "Tab ↵", + "fontFamily": "Inter", + "fontSize": 11, + "fontWeight": "500" + } + ] + } + ] + }, + { + "type": "text", + "id": "Htn1N", + "name": "adRootDesc", + "fill": "#6B6F80", + "content": "The root letters of the word.", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "FK0bQ", + "name": "adExWrap", + "width": "fill_container", + "layout": "vertical", + "gap": 8, + "children": [ + { + "type": "frame", + "id": "a1hEJ", + "name": "sugHint", + "gap": 4, + "alignItems": "center", + "children": [ + { + "type": "icon_font", + "id": "J9mr5", + "name": "sugHintI", + "width": 12, + "height": 12, + "iconFontName": "sparkles", + "iconFontFamily": "lucide", + "fill": "#8B85D0" + }, + { + "type": "text", + "id": "j5RDI", + "name": "sugHintT", + "fill": "#8B85D0", + "content": "2 suggestions available", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "500" + } + ] + }, + { + "type": "frame", + "id": "oEauC", + "name": "adExHeader", + "width": "fill_container", + "justifyContent": "space_between", + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "3Gij7", + "name": "adExTitle", + "fill": "#1B1B2F", + "content": "Examples", + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "600" + } + ] + }, + { + "type": "text", + "id": "XwBrL", + "name": "adExDesc", + "fill": "#6B6F80", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Example usages of the word in different contexts.", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "normal" + }, + { + "type": "frame", + "id": "triB7", + "name": "Suggestion 1", + "width": "fill_container", + "fill": "#FAFAFF", + "cornerRadius": 8, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#E2E3EA" + }, + "layout": "vertical", + "gap": 4, + "padding": [ + 10, + 14 + ], + "children": [ + { + "type": "text", + "id": "kexqs", + "name": "exS1Ar", + "fill": "#8B85D0", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "كَتَبَ الطَّالِبُ رِسَالَةً إِلَى صَدِيقِهِ", + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "normal", + "fontStyle": "italic" + }, + { + "type": "text", + "id": "6mVWl", + "name": "exS1En", + "fill": "#8B85D080", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "The student wrote a letter to his friend.", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "normal", + "fontStyle": "italic" + }, + { + "type": "frame", + "id": "ZoEtc", + "name": "exS1Actions", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "frame", + "id": "dMppy", + "name": "exS1AccBtn", + "fill": "#4F46E510", + "cornerRadius": 5, + "gap": 4, + "padding": [ + 3, + 8 + ], + "alignItems": "center", + "children": [ + { + "type": "icon_font", + "id": "g7VMQ", + "name": "exS1AccI", + "width": 12, + "height": 12, + "iconFontName": "check", + "iconFontFamily": "lucide", + "fill": "#4F46E5" + }, + { + "type": "text", + "id": "lj9LE", + "name": "exS1AccT", + "fill": "#4F46E5", + "content": "Accept", + "fontFamily": "Inter", + "fontSize": 11, + "fontWeight": "600" + } + ] + }, + { + "type": "text", + "id": "wtsDD", + "name": "exS1Dis", + "fill": "#6B6F80", + "content": "Dismiss", + "fontFamily": "Inter", + "fontSize": 11, + "fontWeight": "500" + } + ] + } + ] + }, + { + "type": "frame", + "id": "cyZUW", + "name": "Suggestion 2", + "width": "fill_container", + "fill": "#FAFAFF", + "cornerRadius": 8, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#E2E3EA" + }, + "layout": "vertical", + "gap": 4, + "padding": [ + 10, + 14 + ], + "children": [ + { + "type": "text", + "id": "waFgW", + "name": "exS2Ar", + "fill": "#8B85D0", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "يَكْتُبُ المُؤَلِّفُ كِتَابًا جَدِيدًا كُلَّ عَام", + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "normal", + "fontStyle": "italic" + }, + { + "type": "text", + "id": "nIQSi", + "name": "exS2En", + "fill": "#8B85D080", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "The author writes a new book every year.", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "normal", + "fontStyle": "italic" + }, + { + "type": "frame", + "id": "fm0bE", + "name": "exS2Actions", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "frame", + "id": "w7Yq6", + "name": "exS2AccBtn", + "fill": "#4F46E510", + "cornerRadius": 5, + "gap": 4, + "padding": [ + 3, + 8 + ], + "alignItems": "center", + "children": [ + { + "type": "icon_font", + "id": "InR49", + "name": "exS2AccI", + "width": 12, + "height": 12, + "iconFontName": "check", + "iconFontFamily": "lucide", + "fill": "#4F46E5" + }, + { + "type": "text", + "id": "6wDOx", + "name": "exS2AccT", + "fill": "#4F46E5", + "content": "Accept", + "fontFamily": "Inter", + "fontSize": 11, + "fontWeight": "600" + } + ] + }, + { + "type": "text", + "id": "2pbrZ", + "name": "exS2Dis", + "fill": "#6B6F80", + "content": "Dismiss", + "fontFamily": "Inter", + "fontSize": 11, + "fontWeight": "500" + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "type": "frame", + "id": "3Ezpq", + "name": "Morphology", + "width": "fill_container", + "cornerRadius": 12, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#E2E3EA" + }, + "layout": "vertical", + "children": [ + { + "type": "frame", + "id": "x0m2W", + "name": "morphHeader", + "width": "fill_container", + "layout": "vertical", + "gap": 2, + "padding": [ + 20, + 24, + 12, + 24 + ], + "children": [ + { + "type": "text", + "id": "4V8GX", + "name": "morphTitle", + "fill": "#1B1B2F", + "content": "Morphology", + "fontFamily": "Inter", + "fontSize": 16, + "fontWeight": "600" + }, + { + "type": "text", + "id": "FuE5e", + "name": "morphDesc", + "fill": "#6B6F80", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "The morphological breakdown of the word.", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "Xnc8F", + "name": "morphBody", + "width": "fill_container", + "layout": "vertical", + "gap": 12, + "padding": [ + 0, + 24, + 24, + 24 + ], + "children": [ + { + "type": "frame", + "id": "A0sk3", + "name": "morphRow1", + "width": "fill_container", + "gap": 12, + "children": [ + { + "type": "frame", + "id": "xe0Cv", + "name": "mSingF", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "Q6M7R", + "name": "mSingLbl", + "fill": "#3D3F4A", + "content": "Singular", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "500" + }, + { + "type": "frame", + "id": "sXLzh", + "name": "mSingIn", + "width": "fill_container", + "height": 44, + "fill": "#FFFFFF", + "cornerRadius": 8, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#E2E3EA" + }, + "padding": [ + 0, + 12 + ], + "justifyContent": "space_between", + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "8FwiK", + "name": "singGhost", + "fill": "#8B85D0", + "content": "كِتَاب", + "fontFamily": "Inter", + "fontSize": 16, + "fontWeight": "normal", + "fontStyle": "italic" + }, + { + "type": "icon_font", + "id": "Y4QJx", + "name": "singHint", + "width": 12, + "height": 12, + "iconFontName": "sparkles", + "iconFontFamily": "lucide", + "fill": "#8B85D040" + } + ] + } + ] + }, + { + "type": "frame", + "id": "YV5eA", + "name": "mDualF", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "3V1wD", + "name": "mDualLbl", + "fill": "#3D3F4A", + "content": "Dual", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "500" + }, + { + "type": "frame", + "id": "ySuAP", + "name": "mDualIn", + "width": "fill_container", + "height": 44, + "fill": "#FFFFFF", + "cornerRadius": 8, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#E2E3EA" + }, + "padding": [ + 0, + 12 + ], + "justifyContent": "space_between", + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "GvFXZ", + "name": "dualGhost", + "fill": "#8B85D0", + "content": "كِتَابَان", + "fontFamily": "Inter", + "fontSize": 16, + "fontWeight": "normal", + "fontStyle": "italic" + }, + { + "type": "icon_font", + "id": "klz47", + "name": "dualHint", + "width": 12, + "height": 12, + "iconFontName": "sparkles", + "iconFontFamily": "lucide", + "fill": "#8B85D040" + } + ] + } + ] + } + ] + }, + { + "type": "frame", + "id": "cGoex", + "name": "mRow2", + "width": "fill_container", + "gap": 12, + "children": [ + { + "type": "frame", + "id": "346Ge", + "name": "mGenderF", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "iK4Em", + "name": "mGenderLbl", + "fill": "#3D3F4A", + "content": "Gender", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "500" + }, + { + "type": "frame", + "id": "66dJW", + "name": "mGenderIn", + "width": "fill_container", + "height": 44, + "fill": "#FFFFFF", + "cornerRadius": 8, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#E2E3EA" + }, + "padding": [ + 0, + 12 + ], + "justifyContent": "space_between", + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "Qy29T", + "name": "mGenderVal", + "fill": "#1B1B2F", + "content": "Masculine", + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "normal" + }, + { + "type": "icon_font", + "id": "Zg5Jz", + "name": "mGenderChev", + "width": 16, + "height": 16, + "iconFontName": "chevron-down", + "iconFontFamily": "lucide", + "fill": "#6B6F80" + } + ] + } + ] + }, + { + "type": "frame", + "id": "KySg0", + "name": "mInflF", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "ONvHU", + "name": "mInflLbl", + "fill": "#3D3F4A", + "content": "Inflection", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "500" + }, + { + "type": "frame", + "id": "k5IX7", + "name": "mInflIn", + "width": "fill_container", + "height": 44, + "fill": "#FFFFFF", + "cornerRadius": 8, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#E2E3EA" + }, + "padding": [ + 0, + 12 + ], + "justifyContent": "space_between", + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "F6u9R", + "name": "mInflVal", + "fill": "#1B1B2F", + "content": "Triptote", + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "normal" + }, + { + "type": "icon_font", + "id": "RpWBw", + "name": "mInflChev", + "width": 16, + "height": 16, + "iconFontName": "chevron-down", + "iconFontFamily": "lucide", + "fill": "#6B6F80" + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "type": "frame", + "id": "N3F43", + "name": "Right Sidebar", + "width": 280, + "layout": "vertical", + "gap": 20, + "children": [ + { + "type": "frame", + "id": "Fk56D", + "name": "Category", + "width": "fill_container", + "cornerRadius": 12, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#E2E3EA" + }, + "layout": "vertical", + "children": [ + { + "type": "frame", + "id": "xn10n", + "name": "catHeader", + "width": "fill_container", + "layout": "vertical", + "gap": 2, + "padding": [ + 20, + 24, + 12, + 24 + ], + "children": [ + { + "type": "text", + "id": "3ODkz", + "name": "catTitle", + "fill": "#1B1B2F", + "content": "Category", + "fontFamily": "Inter", + "fontSize": 16, + "fontWeight": "600" + }, + { + "type": "text", + "id": "jauGV", + "name": "catDesc", + "fill": "#6B6F80", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "How the word is categorized.", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "icgg7", + "name": "catBody", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "padding": [ + 0, + 24, + 24, + 24 + ], + "children": [ + { + "type": "text", + "id": "9YMFH", + "name": "catLbl", + "fill": "#3D3F4A", + "content": "Type", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "500" + }, + { + "type": "frame", + "id": "tAlRO", + "name": "catSelect", + "width": "fill_container", + "height": 44, + "fill": "#FFFFFF", + "cornerRadius": 8, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#E2E3EA" + }, + "padding": [ + 0, + 12 + ], + "justifyContent": "space_between", + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "27Txi", + "name": "catVal", + "fill": "#1B1B2F", + "content": "Ism", + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "normal" + }, + { + "type": "icon_font", + "id": "wJCqY", + "name": "catChev", + "width": 16, + "height": 16, + "iconFontName": "chevron-down", + "iconFontFamily": "lucide", + "fill": "#6B6F80" + } + ] + } + ] + } + ] + }, + { + "type": "frame", + "id": "tIvJI", + "name": "Tags", + "width": "fill_container", + "cornerRadius": 12, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#E2E3EA" + }, + "layout": "vertical", + "children": [ + { + "type": "frame", + "id": "hjHUW", + "name": "tagHeader", + "width": "fill_container", + "layout": "vertical", + "gap": 2, + "padding": [ + 20, + 24, + 12, + 24 + ], + "children": [ + { + "type": "text", + "id": "Yakak", + "name": "tagTitle", + "fill": "#1B1B2F", + "content": "Tags", + "fontFamily": "Inter", + "fontSize": 16, + "fontWeight": "600" + }, + { + "type": "text", + "id": "e4rTM", + "name": "tagDesc", + "fill": "#6B6F80", + "content": "Add tags to your word.", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "T7HNU", + "name": "tagBody", + "width": "fill_container", + "layout": "vertical", + "gap": 10, + "padding": [ + 0, + 24, + 24, + 24 + ], + "children": [ + { + "type": "frame", + "id": "3jkXi", + "name": "tagInput", + "width": "fill_container", + "height": 44, + "fill": "#FFFFFF", + "cornerRadius": 8, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#E2E3EA" + }, + "padding": [ + 0, + 12 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "rwIed", + "name": "tagPlc", + "fill": "#A0A3B1", + "content": "Search for a tag...", + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "QELWC", + "name": "tagRecent", + "width": "fill_container", + "layout": "vertical", + "gap": 8, + "children": [ + { + "type": "text", + "id": "qW4ar", + "name": "tagRecentLbl", + "fill": "#6B6F80", + "content": "Recently used", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "500" + }, + { + "type": "frame", + "id": "ARQSC", + "name": "tagPills", + "width": "fill_container", + "gap": 6, + "children": [ + { + "type": "frame", + "id": "SK0N9", + "name": "tagP1", + "fill": "#F4F4F8", + "cornerRadius": 6, + "padding": [ + 4, + 10 + ], + "children": [ + { + "type": "text", + "id": "1Z6CU", + "name": "tagP1T", + "fill": "#3D3F4A", + "content": "transitive", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "7r3gy", + "name": "tagP2", + "fill": "#F4F4F8", + "cornerRadius": 6, + "padding": [ + 4, + 10 + ], + "children": [ + { + "type": "text", + "id": "xIsM0", + "name": "tagP2T", + "fill": "#3D3F4A", + "content": "form-I", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "normal" + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] } ] } \ No newline at end of file diff --git a/packages/drizzle-user-db-schemas/src/types.ts b/packages/drizzle-user-db-schemas/src/types.ts index dcefef4..a01f070 100644 --- a/packages/drizzle-user-db-schemas/src/types.ts +++ b/packages/drizzle-user-db-schemas/src/types.ts @@ -22,57 +22,81 @@ export const AntonymSchema = z.object({ export type Antonym = z.infer; export const ExampleSchema = z.object({ - sentence: z.string(), - context: z.string().optional(), - translation: z.string().optional(), + sentence: z.string().describe("Example sentence in Arabic with full tashkeel."), + context: z + .string() + .optional() + .describe("Register or setting, e.g. formal, colloquial, literary, Quranic, modern."), + translation: z.string().optional().describe("English translation of the sentence."), }); export type Example = z.infer; -export const MorphologySchema = z - .object({ - ism: z - .object({ - singular: z.string().optional(), - dual: z.string().optional(), - plurals: z - .array( - z.object({ - word: z.string(), - details: z.string().optional(), - }) - ) - .optional(), - gender: z.enum(["masculine", "feminine"]).optional(), - inflection: z.enum(["indeclinable", "diptote", "triptote"]).optional(), +export const IsmMorphologySchema = z.object({ + singular: z.string().optional().describe("Singular form with full tashkeel."), + dual: z.string().optional().describe("Dual form (المثنى) with full tashkeel."), + plurals: z + .array( + z.object({ + word: z.string(), + details: z + .string() + .optional() + .describe( + "Optional context about the plural such as usage notes. Omit if straightforward." + ), + }) + ) + .optional(), + gender: z.enum(["masculine", "feminine"]).optional(), + inflection: z.enum(["indeclinable", "diptote", "triptote"]).optional(), +}); + +export const VerbMorphologySchema = z.object({ + huroof: z + .array( + z.object({ + harf: z.string(), + meaning: z.string().optional(), }) - .optional(), - verb: z - .object({ - huroof: z - .array( - z.object({ - harf: z.string(), - meaning: z.string().optional(), - }) - ) - .optional(), - past_tense: z.string().optional(), - present_tense: z.string().optional(), - active_participle: z.string().optional(), - passive_participle: z.string().optional(), - imperative: z.string().optional(), - masadir: z - .array( - z.object({ - word: z.string(), - details: z.string().optional(), - }) - ) - .optional(), - form: z.string().optional(), - form_arabic: z.string().optional(), + ) + .optional() + .describe( + "Prepositions (huroof al-jarr) that pair with this verb to alter its meaning, e.g. رَغِبَ في (to desire) vs رَغِبَ عن (to shun). Omit if no notable particle pairings." + ), + past_tense: z.string().optional().describe("Third-person masculine singular past (الماضي) with full tashkeel."), + present_tense: z.string().optional().describe("Third-person masculine singular present (المضارع) with full tashkeel."), + active_participle: z.string().optional().describe("Active participle (اسم الفاعل) with full tashkeel."), + passive_participle: z.string().optional().describe("Passive participle (اسم المفعول) with full tashkeel."), + imperative: z.string().optional().describe("Imperative (الأمر) with full tashkeel."), + masadir: z + .array( + z.object({ + word: z.string(), + details: z + .string() + .optional() + .describe( + "Optional usage notes, e.g. 'formal register' or 'more common than X'. Omit if straightforward." + ), }) - .optional(), + ) + .optional(), + form: z + .string() + .optional() + .describe("Verb form in Roman numerals (I–XII)."), + form_arabic: z + .string() + .optional() + .describe( + "The Arabic wazn (model pattern) for this verb form, e.g. فَعَلَ for Form I, أَفْعَلَ for Form IV, تَفَاعَلَ for Form VI." + ), +}); + +export const MorphologySchema = z + .object({ + ism: IsmMorphologySchema.optional(), + verb: VerbMorphologySchema.optional(), }) .optional(); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index db03af0..1683cbd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -648,7 +648,7 @@ importers: version: 0.8.3(drizzle-orm@0.45.1)(zod@4.0.17) zod: specifier: 4.0.17 - version: 4.0.17 + version: 4.3.6 devDependencies: '@bahar/typescript-config': specifier: workspace:* @@ -7863,7 +7863,7 @@ packages: resolution: {integrity: sha512-GzC3/ElCtMO55+KeXwFTANlydZzw5qI3DU/F9vAFIsUKuegSmh+Xu03KCL+ct9/imJOvLUQucYhUSsNKqo2j2Q==} dependencies: standardwebhooks: 1.0.0 - zod: 4.0.17 + zod: 4.3.6 dev: false /@polar-sh/ui@0.1.2(@types/react-dom@19.0.0)(@types/react@19.1.17)(react-dom@19.0.0)(react-is@19.2.4)(react@19.0.0)(redux@5.0.1): From 9bdefa4d5cd8ad3b4130eddfce4e82281c6455e9 Mon Sep 17 00:00:00 2001 From: sufyan Date: Tue, 24 Mar 2026 08:14:48 -0400 Subject: [PATCH 05/15] feat: implement AI autofill and example generation for dictionary entries - Add autofill button (definition, root, morphology) on both add and edit pages - Add separate "Generate example" button in the examples section - Use gpt-4o via Cloudflare AI Gateway with caching for autofill, no-cache for examples - Add layered rate limiting (5/min, 50/hr, 150/day) with array support in middleware - Gate AI features behind Pro plan with tooltips for non-Pro users - Add error toasts for rate limits and failures - Fix inflection/gender Select components to use controlled `value` prop - Improve AI prompt: Arabic-only definitions, attested plurals only, omit gender for masadir - Remove unused AI adapter packages (anthropic, gemini, openai) - Add shimmer loading animation - Translate all new strings to Arabic Co-Authored-By: Claude Opus 4.6 (1M context) --- apps/api/.example.env | 4 +- apps/api/package.json | 2 +- apps/api/src/middleware.ts | 28 +- apps/api/src/routers/ai.ts | 171 ++++++-- apps/api/src/utils/config.ts | 4 +- .../add/AdditionalDetailsFormSection.tsx | 113 ++++- .../add/IsmMorphologyCardSection.tsx | 4 +- .../_app-layout/dictionary/add/route.lazy.tsx | 201 ++++++++- .../_app-layout/dictionary/edit/$wordId.tsx | 200 ++++++++- packages/design-system/globals.css | 10 + packages/drizzle-user-db-schemas/package.json | 2 +- packages/drizzle-user-db-schemas/src/types.ts | 61 ++- packages/i18n/locales/ar.po | 310 +++++++------ packages/i18n/locales/ar.ts | 2 +- packages/i18n/locales/en.po | 310 +++++++------ packages/i18n/locales/en.ts | 2 +- pnpm-lock.yaml | 413 +++++++++++++++++- 17 files changed, 1477 insertions(+), 360 deletions(-) diff --git a/apps/api/.example.env b/apps/api/.example.env index 5c3fdfb..721499c 100644 --- a/apps/api/.example.env +++ b/apps/api/.example.env @@ -32,4 +32,6 @@ POLAR_WEBHOOK_SECRET="" POLAR_PRO_PRODUCT_ID="" POLAR_PRO_ANNUAL_PRODUCT_ID="" -OPENAI_API_KEY="" +CF_AI_GATEWAY_TOKEN="" +CLOUDFLARE_ACCOUNT_ID="" +CLOUDFLARE_AI_GATEWAY_ID="" diff --git a/apps/api/package.json b/apps/api/package.json index 38f6cc1..02840c2 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -19,13 +19,13 @@ }, "dependencies": { "@better-auth/expo": "1.4.19", + "@cloudflare/tanstack-ai": "^0.1.5", "@elysiajs/cors": "^1.4.0", "@libsql/client": "^0.10.0", "@polar-sh/better-auth": "^1.8.1", "@polar-sh/sdk": "^0.42.1", "@sentry/bun": "^10.32.1", "@tanstack/ai": "^0.6.1", - "@tanstack/ai-openai": "^0.6.0", "@tursodatabase/api": "^1.9.0", "@upstash/redis": "^1.36.0", "better-auth": "1.4.19", diff --git a/apps/api/src/middleware.ts b/apps/api/src/middleware.ts index 1b86e97..acd3abf 100644 --- a/apps/api/src/middleware.ts +++ b/apps/api/src/middleware.ts @@ -76,24 +76,28 @@ export const betterAuthGuard = new Elysia({ name: "better-auth" }) }); }, }), - userRateLimit: ({ prefix, maxReqs, windowSecs }: RateLimiterOpts) => ({ + userRateLimit: ( + limits: RateLimiterOpts | RateLimiterOpts[] + ) => ({ async resolve(opts) { - // `user` becomes available in context from the auth macro const { status, user } = opts as typeof opts & { user: User }; + const limitsArray = Array.isArray(limits) ? limits : [limits]; - const key = `${prefix}:${user.id}`; - const count = (await redisClient.get(key)) as number; + for (const { prefix, maxReqs, windowSecs } of limitsArray) { + const key = `${prefix}:${user.id}`; + const count = (await redisClient.get(key)) as number; - if (!count) { - await redisClient.set(key, 1, { ex: windowSecs }); - return; - } + if (!count) { + await redisClient.set(key, 1, { ex: windowSecs }); + continue; + } - if (count >= maxReqs) { - return status(429, { message: "Rate limit exceeded" }); - } + if (count >= maxReqs) { + return status(429, { message: "Rate limit exceeded" }); + } - await redisClient.incr(key); + await redisClient.incr(key); + } }, }), }); diff --git a/apps/api/src/routers/ai.ts b/apps/api/src/routers/ai.ts index 9da083b..6fdda63 100644 --- a/apps/api/src/routers/ai.ts +++ b/apps/api/src/routers/ai.ts @@ -6,25 +6,45 @@ import { VerbMorphologySchema, type WordType, } from "@bahar/drizzle-user-db-schemas"; +import { + type AiGatewayAdapterConfig, + createOpenAiChat, +} from "@cloudflare/tanstack-ai"; import { chat } from "@tanstack/ai"; -import { openaiText } from "@tanstack/ai-openai"; import Elysia from "elysia"; import { z } from "zod"; import { betterAuthGuard, type RateLimiterOpts } from "../middleware"; +import { config } from "../utils/config"; + +const aiGatewayConfig: AiGatewayAdapterConfig = { + accountId: config.CLOUDFLARE_ACCOUNT_ID, + gatewayId: config.CLOUDFLARE_AI_GATEWAY_ID, + cfApiKey: config.CF_AI_GATEWAY_TOKEN, +}; + +const aiAdapter = createOpenAiChat("gpt-4o", { + ...aiGatewayConfig, +}); + +const aiAdapterNoCache = createOpenAiChat("gpt-4o", { + ...aiGatewayConfig, + skipCache: true, +}); const baseFields = { definition: z .string() .optional() .describe( - "Arabic dictionary definition in the style of المعجم الوسيط — a synonym or brief explanation, not a translation." + "Arabic-only dictionary definition in the style of المعجم الوسيط — a synonym or brief explanation in Arabic. No English words, translations, or parenthetical notes." ), root: RootLettersSchema.optional().describe( - 'Trilateral or quadrilateral root letters as individual characters, e.g. ["ك", "ت", "ب"].' + 'The base trilateral or quadrilateral root (الجذر), not augmented letters. e.g. استغفر → ["غ", "ف", "ر"], تعلّم → ["ع", "ل", "م"].' ), - examples: z.array(ExampleSchema).optional(), }; +const ExampleOutputSchema = ExampleSchema.omit({ context: true }); + const IsmOutputSchema = z.object({ ...baseFields, morphology: IsmMorphologySchema.optional(), @@ -56,44 +76,115 @@ const getOutputSchema = (type: WordType) => { }; const AUTOCOMPLETE_SYSTEM_PROMPT = ` - You are an Arabic linguistics expert generating dictionary data for a language learning app. +You are an Arabic linguistics expert generating dictionary data for a language learning app. + +Tashkeel rules — apply to ALL Arabic text you produce (isolated words, definitions, etc.): +- Include full بنائية tashkeel on every word. +- NEVER add إعراب on the final letter. Strip all tanween (ًٌٍ) and any final ُ/َ/ِ that only exists for case/mood. This applies to EVERY Arabic word you output. + ✓ كِتَاب ✗ كِتَابٌ + ✓ يَكْتُب ✗ يَكْتُبُ (present tense: no final dhamma) + ✓ كَاتِب ✗ كَاتِبٌ (participle: no tanween) + ✓ مَكْتُوب ✗ مَكْتُوبٌ + ✓ كُتُب ✗ كُتُبٌ (plural: no tanween) + ✓ كِتَابَة ✗ كِتَابَةٌ (masdar: no tanween) + ✓ يَسْتَغْفِر ✗ يَسْتَغْفِرُ (no final dhamma) + Exception: diptotes (الممنوع من الصرف) show dhamma only. +- Isolated words must be indefinite — no ال. + +Definition rules: +- The definition MUST be entirely in Arabic — no English, no transliterations, no parenthetical translations. +- Write a brief Arabic synonym or explanation as it would appear in المعجم الوسيط. - Rules: - - All Arabic text MUST include full tashkeel, but omit final case endings (إعراب). Exception: diptotes (الممنوع من الصرف) should show a dhamma (not tanween) on the final letter. - - Omit any field you are not confident about rather than guessing. +Morphology rules: +- Plurals must be real, well-known, attested forms. Do NOT invent or guess broken plurals. + Example: كِتَاب → كُتُب (correct). Do NOT generate fabricated patterns like كتوب or أكتاب. +- Only include plural forms you are certain are standard Arabic. Omit the field entirely if unsure. +- Each plural entry stands alone. The "details" field is for usage context only (e.g. "formal", "colloquial"). Do NOT mention other plural forms, do NOT compare plurals, do NOT say "also exists" or "less common than". +- Omit the gender field for masadir (verbal nouns) and abstract nouns where gender is not meaningful (e.g. تقوى، صبر، عِلم). + +Optional "details" and "context" fields: +- These fields (on plurals, masadir, examples, etc.) should be LEFT EMPTY by default. +- Only fill them when there is genuinely non-obvious information, such as a word being archaic, dialect-specific, or restricted to a specific register. +- Straightforward, common forms need no annotation. When in doubt, omit. + +Other rules: +- Omit any field you are not confident about rather than guessing. `; -const aiRateLimiterOpts: RateLimiterOpts = { - maxReqs: 10, - windowSecs: 60, - prefix: "ratelimit:ai:autocomplete", -}; +const EXAMPLES_SYSTEM_PROMPT = ` +You are an Arabic linguistics expert generating a single example sentence for a language learning app. -export const aiRouter = new Elysia({ prefix: "/ai" }).use(betterAuthGuard).post( - "/autocomplete", - async ({ body: { translation, type, word } }) => { - const dictionaryEntrySuggestion = await chat({ - adapter: openaiText("gpt-4.1-nano") as never, - systemPrompts: [AUTOCOMPLETE_SYSTEM_PROMPT], - messages: [ - { - role: "user", - content: `Word: "${word}", Translation: "${translation}", Type: "${type}"`, - }, - ], - outputSchema: getOutputSchema(type), - }); - - return dictionaryEntrySuggestion; - }, +Generate one example sentence for the given word. Use functional tashkeel only: +- Mark shadda (ّ) always — it changes meaning. +- Vocalize ambiguous words where the consonant skeleton has multiple readings (e.g. عَلِمَ vs عَلَّمَ). +- Vocalize key vocabulary the learner is likely studying. +- Leave common, unambiguous words completely bare (في، من، على، هو، كان، etc.). +- Do NOT add i'rab (case/mood endings) to sentence words. +- Example: "قَرَأت كِتَابًا في تاريخ العالم" — only the verb and key noun are vocalized. +- Always include an English translation. +- Use the word in a natural, varied context. +`; + +const aiRateLimits: RateLimiterOpts[] = [ + { prefix: "ratelimit:ai:autocomplete:min", maxReqs: 5, windowSecs: 60 }, + { prefix: "ratelimit:ai:autocomplete:hr", maxReqs: 50, windowSecs: 60 * 60 }, { - auth: "user", - planGuard: "pro", - userRateLimit: aiRateLimiterOpts, - body: InsertDictionaryEntrySchema.pick({ - word: true, - translation: true, - type: true, - }), - } -); + prefix: "ratelimit:ai:autocomplete:day", + maxReqs: 150, + windowSecs: 60 * 60 * 24, + }, +]; + +export const aiRouter = new Elysia({ prefix: "/ai" }) + .use(betterAuthGuard) + .post( + "/autocomplete", + async ({ body: { translation, type, word } }) => { + return chat({ + adapter: aiAdapter as never, + systemPrompts: [AUTOCOMPLETE_SYSTEM_PROMPT], + messages: [ + { + role: "user", + content: `Word: "${word}", Translation: "${translation}", Type: "${type}"`, + }, + ], + outputSchema: getOutputSchema(type), + }); + }, + { + auth: "user", + planGuard: "pro", + userRateLimit: aiRateLimits, + body: InsertDictionaryEntrySchema.pick({ + word: true, + translation: true, + type: true, + }), + } + ) + .post( + "/examples", + async ({ body: { word, translation } }) => { + return chat({ + adapter: aiAdapterNoCache as never, + systemPrompts: [EXAMPLES_SYSTEM_PROMPT], + messages: [ + { + role: "user", + content: `Word: "${word}", Translation: "${translation}"`, + }, + ], + outputSchema: ExampleOutputSchema, + }); + }, + { + auth: "user", + planGuard: "pro", + userRateLimit: aiRateLimits, + body: InsertDictionaryEntrySchema.pick({ + word: true, + translation: true, + }), + } + ); diff --git a/apps/api/src/utils/config.ts b/apps/api/src/utils/config.ts index 40de180..feea0e6 100644 --- a/apps/api/src/utils/config.ts +++ b/apps/api/src/utils/config.ts @@ -45,7 +45,9 @@ const EnvironmentVariablesSchema = z.object({ POLAR_PRO_PRODUCT_ID: z.string().min(1), POLAR_PRO_ANNUAL_PRODUCT_ID: z.string().min(1), - OPENAI_API_KEY: z.string().min(1), + CF_AI_GATEWAY_TOKEN: z.string().min(1), + CLOUDFLARE_ACCOUNT_ID: z.string().min(1), + CLOUDFLARE_AI_GATEWAY_ID: z.string().min(1), }); export type EnvironmentVariables = z.infer; diff --git a/apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx b/apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx index 3c6bfc1..d978edc 100644 --- a/apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx +++ b/apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx @@ -22,15 +22,30 @@ import { } from "@bahar/web-ui/components/form"; import { Input } from "@bahar/web-ui/components/input"; import { Separator } from "@bahar/web-ui/components/separator"; -import { Trans } from "@lingui/react/macro"; -import { Plus } from "lucide-react"; +import { cn } from "@bahar/design-system"; +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from "@bahar/web-ui/components/tooltip"; +import { Trans, useLingui } from "@lingui/react/macro"; +import { useMutation } from "@tanstack/react-query"; +import { Plus, Sparkles } from "lucide-react"; import { AnimatePresence, motion } from "motion/react"; import { useFieldArray, useFormContext } from "react-hook-form"; +import { toast } from "sonner"; +import { api } from "@/lib/api"; +import { authClient } from "@/lib/auth-client"; import type { FormSchema } from "@/lib/schemas/dictionary"; import type { z } from "@/lib/zod"; export const AdditionalDetailsFormSection = () => { + const { t } = useLingui(); const form = useFormContext>(); + const { data: userData } = authClient.useSession(); + const isProUser = + userData?.user.plan === "pro" && + userData.user.subscriptionStatus !== "canceled"; const { fields: examplesFields, @@ -56,6 +71,33 @@ export const AdditionalDetailsFormSection = () => { const hasMorphology = type === "fi'l" || type === "ism"; const hasAntonyms = type === "ism" || type === "fi'l" || type === "harf"; + const word = form.watch("word"); + const translation = form.watch("translation"); + + const generateExample = useMutation({ + mutationFn: async () => { + const { data, error } = await api.ai.examples.post({ word, translation }); + if (error) throw error; + return data; + }, + onError: (error) => { + const status = (error as { status?: number }).status; + if (status === 429) { + toast.error(t`Rate limit reached`, { + description: t`Please wait before trying again.`, + }); + } else { + toast.error(t`Failed to generate example`, { + description: t`Something went wrong. Please try again.`, + }); + } + }, + onSuccess: (data) => { + if (!data?.sentence) return; + appendExample(data); + }, + }); + return ( @@ -268,18 +310,61 @@ export const AdditionalDetailsFormSection = () => { })} - +
+ + + + + + + + + + {!isProUser && ( + + Upgrade to Pro to generate examples. + + )} + +
{hasAntonyms && ( diff --git a/apps/web/src/components/features/dictionary/add/IsmMorphologyCardSection.tsx b/apps/web/src/components/features/dictionary/add/IsmMorphologyCardSection.tsx index b91ec08..569362a 100644 --- a/apps/web/src/components/features/dictionary/add/IsmMorphologyCardSection.tsx +++ b/apps/web/src/components/features/dictionary/add/IsmMorphologyCardSection.tsx @@ -212,9 +212,9 @@ export const IsmMorphologyCardSection = () => { { return ( @@ -80,6 +88,10 @@ const BackButton = () => { const Add = () => { const { addDictionaryEntry } = useAddDictionaryEntry(); + const { data: userData } = authClient.useSession(); + const isProUser = + userData?.user.plan === "pro" && + userData.user.subscriptionStatus !== "canceled"; const { t } = useLingui(); const form = useForm>({ @@ -174,6 +186,103 @@ const Add = () => { } }, [form.formState, form.reset]); + const canAutofill = + form.watch("word") && form.watch("translation") && form.watch("type"); + + const autofill = useMutation({ + mutationFn: async () => { + const { data, error } = await api.ai.autocomplete.post({ + word: form.getValues("word"), + translation: form.getValues("translation"), + type: form.getValues("type"), + }); + if (error) throw error; + return data; + }, + onError: (error) => { + const status = (error as { status?: number }).status; + if (status === 429) { + toast.error(t`Rate limit reached`, { + description: t`Please wait before trying again.`, + }); + } else { + toast.error(t`Autofill failed`, { + description: t`Something went wrong. Please try again.`, + }); + } + }, + onSuccess: (data) => { + if (!data) return; + + if (data.definition) { + form.setValue("definition", data.definition); + } + if (data.root && data.root.length > 0) { + form.setValue("root", data.root.join(" ")); + } + + if ("morphology" in data && data.morphology) { + const type = form.getValues("type"); + const m = data.morphology as Record; + + if (type === "ism") { + const ism = m as { + singular?: string; + dual?: string; + plurals?: { word: string; details?: string }[]; + gender?: "masculine" | "feminine"; + inflection?: "indeclinable" | "diptote" | "triptote"; + }; + if (ism.singular) + form.setValue("morphology.ism.singular", ism.singular); + if (ism.dual) form.setValue("morphology.ism.dual", ism.dual); + if (ism.plurals?.length) + form.setValue("morphology.ism.plurals", ism.plurals); + if (ism.gender) form.setValue("morphology.ism.gender", ism.gender); + if (ism.inflection) + form.setValue("morphology.ism.inflection", ism.inflection); + } + + if (type === "fi'l") { + const verb = m as { + past_tense?: string; + present_tense?: string; + active_participle?: string; + passive_participle?: string; + imperative?: string; + masadir?: { word: string; details?: string }[]; + form?: string; + form_arabic?: string; + huroof?: { harf: string; meaning?: string }[]; + }; + if (verb.past_tense) + form.setValue("morphology.verb.past_tense", verb.past_tense); + if (verb.present_tense) + form.setValue("morphology.verb.present_tense", verb.present_tense); + if (verb.active_participle) + form.setValue( + "morphology.verb.active_participle", + verb.active_participle + ); + if (verb.passive_participle) + form.setValue( + "morphology.verb.passive_participle", + verb.passive_participle + ); + if (verb.imperative) + form.setValue("morphology.verb.imperative", verb.imperative); + if (verb.masadir?.length) + form.setValue("morphology.verb.masadir", verb.masadir); + if (verb.form) form.setValue("morphology.verb.form", verb.form); + if (verb.form_arabic) + form.setValue("morphology.verb.form_arabic", verb.form_arabic); + if (verb.huroof?.length) + form.setValue("morphology.verb.huroof", verb.huroof); + } + } + }, + }); + return (
@@ -189,6 +298,51 @@ const Add = () => {
+ + + + + + + + {!isProUser ? ( + + Upgrade to Pro to use AI autofill. + + ) : ( + !canAutofill && ( + + + Fill in the word, translation, and type first. + + + ) + )} + +
+ + + + + + + + {!isProUser ? ( + + Upgrade to Pro to use AI autofill. + + ) : ( + !canAutofill && ( + + + Fill in the word, translation, and type first. + + + ) + )} + +
diff --git a/apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx b/apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx index 8ee465c..8a1cfd2 100644 --- a/apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx +++ b/apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx @@ -19,6 +19,11 @@ import { DialogTrigger, } from "@bahar/web-ui/components/dialog"; import { Form } from "@bahar/web-ui/components/form"; +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from "@bahar/web-ui/components/tooltip"; import { zodResolver } from "@hookform/resolvers/zod"; import { Trans, useLingui } from "@lingui/react/macro"; import { useMutation, useQuery } from "@tanstack/react-query"; @@ -28,7 +33,7 @@ import { useNavigate, useRouter, } from "@tanstack/react-router"; -import { ChevronLeft, ChevronRight } from "lucide-react"; +import { ChevronLeft, ChevronRight, Sparkles } from "lucide-react"; import { type FC, useEffect } from "react"; import { type SubmitHandler, useForm } from "react-hook-form"; import { toast } from "sonner"; @@ -41,6 +46,8 @@ import { import { TagsFormSection } from "@/components/features/dictionary/add/TagsFormSection"; import { Page } from "@/components/Page"; import { useDeleteDictionaryEntry, useEditDictionaryEntry } from "@/hooks/db"; +import { api } from "@/lib/api"; +import { authClient } from "@/lib/auth-client"; import { useDir } from "@/hooks/useDir"; import { dictionaryEntriesTable } from "@/lib/db/operations/dictionary-entries"; import { flashcardsTable } from "@/lib/db/operations/flashcards"; @@ -260,6 +267,10 @@ const getDefaultFormValues = ( const Edit = () => { const { editDictionaryEntry } = useEditDictionaryEntry(); const { wordId } = Route.useParams(); + const { data: userData } = authClient.useSession(); + const isProUser = + userData?.user.plan === "pro" && + userData.user.subscriptionStatus !== "canceled"; const { data } = useQuery({ queryFn: () => dictionaryEntriesTable.entry.query(wordId), @@ -333,6 +344,103 @@ const Edit = () => { } }; + const canAutofill = + form.watch("word") && form.watch("translation") && form.watch("type"); + + const autofill = useMutation({ + mutationFn: async () => { + const { data, error } = await api.ai.autocomplete.post({ + word: form.getValues("word"), + translation: form.getValues("translation"), + type: form.getValues("type"), + }); + if (error) throw error; + return data; + }, + onError: (error) => { + const status = (error as { status?: number }).status; + if (status === 429) { + toast.error(t`Rate limit reached`, { + description: t`Please wait before trying again.`, + }); + } else { + toast.error(t`Autofill failed`, { + description: t`Something went wrong. Please try again.`, + }); + } + }, + onSuccess: (data) => { + if (!data) return; + + if (data.definition) { + form.setValue("definition", data.definition); + } + if (data.root && data.root.length > 0) { + form.setValue("root", data.root.join(" ")); + } + + if ("morphology" in data && data.morphology) { + const type = form.getValues("type"); + const m = data.morphology as Record; + + if (type === "ism") { + const ism = m as { + singular?: string; + dual?: string; + plurals?: { word: string; details?: string }[]; + gender?: "masculine" | "feminine"; + inflection?: "indeclinable" | "diptote" | "triptote"; + }; + if (ism.singular) + form.setValue("morphology.ism.singular", ism.singular); + if (ism.dual) form.setValue("morphology.ism.dual", ism.dual); + if (ism.plurals?.length) + form.setValue("morphology.ism.plurals", ism.plurals); + if (ism.gender) form.setValue("morphology.ism.gender", ism.gender); + if (ism.inflection) + form.setValue("morphology.ism.inflection", ism.inflection); + } + + if (type === "fi'l") { + const verb = m as { + past_tense?: string; + present_tense?: string; + active_participle?: string; + passive_participle?: string; + imperative?: string; + masadir?: { word: string; details?: string }[]; + form?: string; + form_arabic?: string; + huroof?: { harf: string; meaning?: string }[]; + }; + if (verb.past_tense) + form.setValue("morphology.verb.past_tense", verb.past_tense); + if (verb.present_tense) + form.setValue("morphology.verb.present_tense", verb.present_tense); + if (verb.active_participle) + form.setValue( + "morphology.verb.active_participle", + verb.active_participle + ); + if (verb.passive_participle) + form.setValue( + "morphology.verb.passive_participle", + verb.passive_participle + ); + if (verb.imperative) + form.setValue("morphology.verb.imperative", verb.imperative); + if (verb.masadir?.length) + form.setValue("morphology.verb.masadir", verb.masadir); + if (verb.form) form.setValue("morphology.verb.form", verb.form); + if (verb.form_arabic) + form.setValue("morphology.verb.form_arabic", verb.form_arabic); + if (verb.huroof?.length) + form.setValue("morphology.verb.huroof", verb.huroof); + } + } + }, + }); + const content = data!.word; return ( @@ -350,6 +458,51 @@ const Edit = () => {
+ + + + + + + + {!isProUser ? ( + + Upgrade to Pro to use AI autofill. + + ) : ( + !canAutofill && ( + + + Fill in the word, translation, and type first. + + + ) + )} + +
+ + + + + + + + {!isProUser ? ( + + Upgrade to Pro to use AI autofill. + + ) : ( + !canAutofill && ( + + + Fill in the word, translation, and type first. + + + ) + )} + +
diff --git a/packages/design-system/globals.css b/packages/design-system/globals.css index 670ea2f..9321642 100644 --- a/packages/design-system/globals.css +++ b/packages/design-system/globals.css @@ -57,6 +57,7 @@ --animate-caret-blink: caret-blink 1.2s ease-out infinite; --animate-accordion-down: accordion-down 0.2s ease-out; --animate-accordion-up: accordion-up 0.2s ease-out; + --animate-shimmer: shimmer 1.5s infinite; } /* Animation keyframes */ @@ -89,3 +90,12 @@ height: 0; } } + +@keyframes shimmer { + 0% { + transform: translateX(-100%); + } + 100% { + transform: translateX(200%); + } +} diff --git a/packages/drizzle-user-db-schemas/package.json b/packages/drizzle-user-db-schemas/package.json index a914cf4..61a5365 100644 --- a/packages/drizzle-user-db-schemas/package.json +++ b/packages/drizzle-user-db-schemas/package.json @@ -9,7 +9,7 @@ "drizzle:gen": "drizzle-kit generate" }, "peerDependencies": { - "zod": "4.0.17", + "zod": ">=4.0.0", "drizzle-orm": "^0.45.1", "drizzle-zod": "^0.8.3" }, diff --git a/packages/drizzle-user-db-schemas/src/types.ts b/packages/drizzle-user-db-schemas/src/types.ts index a01f070..20bc3f2 100644 --- a/packages/drizzle-user-db-schemas/src/types.ts +++ b/packages/drizzle-user-db-schemas/src/types.ts @@ -22,18 +22,28 @@ export const AntonymSchema = z.object({ export type Antonym = z.infer; export const ExampleSchema = z.object({ - sentence: z.string().describe("Example sentence in Arabic with full tashkeel."), + sentence: z + .string() + .describe("Example sentence in Arabic with full tashkeel."), context: z .string() .optional() - .describe("Register or setting, e.g. formal, colloquial, literary, Quranic, modern."), - translation: z.string().optional().describe("English translation of the sentence."), + .describe( + "Leave empty unless the register is non-obvious (e.g. colloquial, Quranic, archaic). Omit for standard modern Arabic. This is NOT a translation." + ), + translation: z + .string() + .optional() + .describe("English translation of the sentence."), }); export type Example = z.infer; export const IsmMorphologySchema = z.object({ singular: z.string().optional().describe("Singular form with full tashkeel."), - dual: z.string().optional().describe("Dual form (المثنى) with full tashkeel."), + dual: z + .string() + .optional() + .describe("Dual form (المثنى) with full tashkeel."), plurals: z .array( z.object({ @@ -42,11 +52,14 @@ export const IsmMorphologySchema = z.object({ .string() .optional() .describe( - "Optional context about the plural such as usage notes. Omit if straightforward." + "Leave empty for standard plurals. Only fill for genuinely non-obvious info (e.g. archaic, dialect-specific). Do NOT mention other plural forms here." ), }) ) - .optional(), + .optional() + .describe( + "Only well-known, attested plural forms. Do NOT invent or guess broken plurals. Omit entirely if unsure." + ), gender: z.enum(["masculine", "feminine"]).optional(), inflection: z.enum(["indeclinable", "diptote", "triptote"]).optional(), }); @@ -63,11 +76,30 @@ export const VerbMorphologySchema = z.object({ .describe( "Prepositions (huroof al-jarr) that pair with this verb to alter its meaning, e.g. رَغِبَ في (to desire) vs رَغِبَ عن (to shun). Omit if no notable particle pairings." ), - past_tense: z.string().optional().describe("Third-person masculine singular past (الماضي) with full tashkeel."), - present_tense: z.string().optional().describe("Third-person masculine singular present (المضارع) with full tashkeel."), - active_participle: z.string().optional().describe("Active participle (اسم الفاعل) with full tashkeel."), - passive_participle: z.string().optional().describe("Passive participle (اسم المفعول) with full tashkeel."), - imperative: z.string().optional().describe("Imperative (الأمر) with full tashkeel."), + past_tense: z + .string() + .optional() + .describe( + "Third-person masculine singular past (الماضي) with full tashkeel." + ), + present_tense: z + .string() + .optional() + .describe( + "Third-person masculine singular present (المضارع) with full tashkeel." + ), + active_participle: z + .string() + .optional() + .describe("Active participle (اسم الفاعل) with full tashkeel."), + passive_participle: z + .string() + .optional() + .describe("Passive participle (اسم المفعول) with full tashkeel."), + imperative: z + .string() + .optional() + .describe("Imperative (الأمر) with full tashkeel."), masadir: z .array( z.object({ @@ -76,15 +108,12 @@ export const VerbMorphologySchema = z.object({ .string() .optional() .describe( - "Optional usage notes, e.g. 'formal register' or 'more common than X'. Omit if straightforward." + "Leave empty for standard masadir. Only fill for genuinely non-obvious info (e.g. archaic, dialect-specific). Do NOT compare to other masadir forms." ), }) ) .optional(), - form: z - .string() - .optional() - .describe("Verb form in Roman numerals (I–XII)."), + form: z.string().optional().describe("Verb form in Roman numerals (I–XII)."), form_arabic: z .string() .optional() diff --git a/packages/i18n/locales/ar.po b/packages/i18n/locales/ar.po index b7c1294..678c4d5 100644 --- a/packages/i18n/locales/ar.po +++ b/packages/i18n/locales/ar.po @@ -52,7 +52,7 @@ msgstr "{0} إجمالي" msgid "{hydrationSkippedCount, plural, one {# entry was skipped due to data issues. Your data is preserved, but you won't be able to search for the entry that wasn't loaded.} other {# entries were skipped due to data issues. Your data is preserved, but you won't be able to search for any entries that weren't loaded.}}" msgstr "{hydrationSkippedCount, plural, one {تم تخطي إدخال واحد بسبب مشاكل في البيانات. بياناتك محفوظة، لكن لن تتمكن من البحث عن الإدخال الذي لم يتم تحميله.} two {تم تخطي إدخالين بسبب مشاكل في البيانات. بياناتك محفوظة، لكن لن تتمكن من البحث عن الإدخالات التي لم يتم تحميلها.} few {تم تخطي # إدخالات بسبب مشاكل في البيانات. بياناتك محفوظة، لكن لن تتمكن من البحث عن الإدخالات التي لم يتم تحميلها.} many {تم تخطي # إدخالًا بسبب مشاكل في البيانات. بياناتك محفوظة، لكن لن تتمكن من البحث عن الإدخالات التي لم يتم تحميلها.} other {تم تخطي # إدخال بسبب مشاكل في البيانات. بياناتك محفوظة، لكن لن تتمكن من البحث عن الإدخالات التي لم يتم تحميلها.}}" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:123 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:130 msgid "{skippedCount} entries were skipped due to data corruption." msgstr "تم تخطي {skippedCount} إدخالات بسبب تلف البيانات." @@ -108,7 +108,7 @@ msgstr "أضف ترحيل SQL جديد." msgid "Add a new word" msgstr "أضف كلمة جديدة" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:188 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:297 msgid "Add a new word to your dictionary" msgstr "أضف كلمة جديدة إلى معجمك" @@ -121,7 +121,7 @@ msgstr "أضف علامة واضغط Enter" msgid "Add all" msgstr "إضافة الكل" -#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:355 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:440 msgid "Add antonym" msgstr "أضف ضدا" @@ -130,7 +130,7 @@ msgstr "أضف ضدا" msgid "Add Antonym" msgstr "أضف ضد" -#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:281 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:324 msgid "Add example" msgstr "أضف مثلا" @@ -184,13 +184,13 @@ msgid "Add tags to your word." msgstr "أضف علامات إلى كلمتك." #: ../../apps/web/src/routes/_authorized-layout/_search-layout/index.lazy.tsx:113 -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:48 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:56 #: ../../apps/mobile/src/app/(search)/(home)/index.tsx:156 #: ../../apps/mobile/src/app/(search)/(home)/add-word.tsx:71 msgid "Add word" msgstr "أضف كلمة" -#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:63 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:105 #: ../../apps/mobile/src/app/(search)/(home)/add-word.tsx:437 #: ../../apps/mobile/src/app/(search)/(home)/edit-word/[id].tsx:547 msgid "Additional Details" @@ -204,11 +204,11 @@ msgstr "مرة أخرى" msgid "All done for today!" msgstr "انتهيت لليوم!" -#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:95 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:137 msgid "An Arabic definition of the word." msgstr "تعريف عربية للكلمة." -#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:216 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:258 msgid "An English translation of the sentence." msgstr "ترجمة إنجليزية للجملة." @@ -220,7 +220,7 @@ msgstr "ترجمة إنجليزية للكلمة." msgid "An unexpected error occurred. You can try reloading the page to fix it." msgstr "حدث خطأ غير متوقع. يمكنك محاولة إعادة تحميل الصفحة لإصلاحه." -#: ../../apps/web/src/components/features/settings/BillingSettingsCard.tsx:99 +#: ../../apps/web/src/components/features/settings/BillingSettingsCard.tsx:101 msgid "Annual — $7/mo" msgstr "سنوي — $٧/شهر" @@ -231,7 +231,7 @@ msgid "Answer" msgstr "الجواب" #. placeholder {0}: index + 1 -#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:300 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:385 msgid "Antonym {0}" msgstr "الضد {0}" @@ -240,7 +240,7 @@ msgstr "الضد {0}" msgid "Antonym word" msgstr "كلمة مضادة" -#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:288 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:373 #: ../../apps/mobile/src/app/(search)/(home)/add-word.tsx:555 #: ../../apps/mobile/src/app/(search)/(home)/edit-word/[id].tsx:665 msgid "Antonyms" @@ -255,7 +255,7 @@ msgstr "أية تفاصيل إضافية عن هذه الصيغة مثلا تك msgid "Any plural forms of the word." msgstr "أية صيغ جمع للكلمة." -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:419 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:426 msgid "Any words that have the same ID will be overwritten." msgstr "سيستبدل كل كلمات التي لديها نفس المعرف." @@ -263,7 +263,7 @@ msgstr "سيستبدل كل كلمات التي لديها نفس المعرف." msgid "App language" msgstr "لغة التطبيق" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:199 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:206 #: ../../apps/mobile/src/app/(search)/settings.tsx:236 msgid "Appearance" msgstr "المظهر" @@ -296,7 +296,7 @@ msgstr "الكلمة بالعربية" msgid "Are you sure you want to delete \"{0}\"?" msgstr "هل أنت متأكد من حذف \"{0}\"؟" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:140 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:147 msgid "Are you sure you want to delete this word? It will be removed from your dictionary and its flashcards will be deleted.<0/><1/><2>This action cannot be undone." msgstr "هل أنت متأكد أنك تريد حذف هذه الكلمة؟ سيتم إزالتها من معجمك وسيتم حذف البطاقات بها.<0/><1/><2>لا يمكن التراجع عن هذا الإجراء." @@ -304,16 +304,28 @@ msgstr "هل أنت متأكد أنك تريد حذف هذه الكلمة؟ سي msgid "Are you sure you want to delete this word? This action cannot be undone." msgstr "هل أنت متأكد من حذف هذه الكلمة؟ لا يمكن التراجع عن هذا الإجراء." -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:496 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:503 msgid "Are you sure you want to delete your dictionary? All your words will be deleted permanently. This action cannot be undone. Please make sure to export your dictionary before deleting it." msgstr "هل أنت متأكد من رغبتك في حذف معجمك؟ سيحذف جميع كلماتك بشكل دائم. لا يمكن التراجع عن هذا الإجراء. صدر معجمك قبل حذفه من فضلك." -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:88 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:95 msgid "Are you sure you want to reset this flashcard's progress? The word entry in the dictionary will not be modified, but its corresponding flashcards will be treated as new ones.<0/><1/><2>This action cannot be undone." msgstr "هل أنت متأكد أنك تريد إعادة تعيين تقدم بطاقة هذه؟ لن يتم تعديل إدخال الكلمة في المعجم، ولكن سيتم التعامل مع بطاقات بها على أنها بطاقات جديدة.<0/><1/><2>لا يمكن التراجع عن هذا الإجراء." -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:216 -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:74 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:485 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:538 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:325 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:382 +msgid "Autofill" +msgstr "تعبئة تلقائية" + +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:367 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:209 +msgid "Autofill failed" +msgstr "فشلت التعبئة التلقائية" + +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:223 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:82 msgid "Back" msgstr "رجوع" @@ -347,24 +359,24 @@ msgstr "تفاصيل أساسية" msgid "BETA" msgstr "بيتا" -#: ../../apps/web/src/components/features/settings/BillingSettingsCard.tsx:111 +#: ../../apps/web/src/components/features/settings/BillingSettingsCard.tsx:113 msgid "Billed $84/year" msgstr "يُدفع $٨٤/سنة" -#: ../../apps/web/src/components/features/settings/BillingSettingsCard.tsx:86 +#: ../../apps/web/src/components/features/settings/BillingSettingsCard.tsx:88 msgid "Billed monthly" msgstr "يُدفع شهريًا" -#: ../../apps/web/src/components/features/settings/BillingSettingsCard.tsx:39 +#: ../../apps/web/src/components/features/settings/BillingSettingsCard.tsx:41 msgid "Billing" msgstr "الفوترة" -#: ../../apps/web/src/routes/_unauthorized-layout/login/route.lazy.tsx:159 +#: ../../apps/web/src/routes/_unauthorized-layout/login/route.lazy.tsx:164 msgid "By signing in, you agree to our <0>Privacy Policy" msgstr "بتسجيل الدخول، فإنك توافق على <0>سياسة الخصوصية" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:514 -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:594 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:521 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:601 #: ../../apps/mobile/src/app/(search)/settings.tsx:128 #: ../../apps/mobile/src/app/(search)/decks.tsx:283 #: ../../apps/mobile/src/app/(search)/(home)/add-word.tsx:995 @@ -415,7 +427,7 @@ msgstr "امسح المتراكمات" #~ msgid "Clearing..." #~ msgstr "جارٍ المسح..." -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:217 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:224 msgid "Color theme" msgstr "سمة الألوان" @@ -423,7 +435,7 @@ msgstr "سمة الألوان" msgid "Contact support" msgstr "اتصل بالدعم" -#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:231 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:273 msgid "Context" msgstr "السياق" @@ -432,7 +444,7 @@ msgstr "السياق" msgid "Continue" msgstr "استمر" -#: ../../apps/web/src/routes/_unauthorized-layout/login/route.lazy.tsx:137 +#: ../../apps/web/src/routes/_unauthorized-layout/login/route.lazy.tsx:142 #: ../../apps/mobile/src/app/(auth)/login.tsx:105 msgid "Continue with Email" msgstr "استمرّ مع بريد الإلكتروني" @@ -478,7 +490,7 @@ msgstr "إنشاء مجموعة" msgid "Create your first deck" msgstr "أنشئ مجموعتك الأولى" -#: ../../apps/web/src/components/features/settings/BillingSettingsCard.tsx:51 +#: ../../apps/web/src/components/features/settings/BillingSettingsCard.tsx:53 msgid "Current plan" msgstr "الخطة الحالية" @@ -486,7 +498,7 @@ msgstr "الخطة الحالية" msgid "Customize how flashcards appear." msgstr "خصص كيفيّة ظهور البطاقات." -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:203 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:210 msgid "Customize how the application looks for you." msgstr "قم بتخصيص كيف يظهر التطبيق بالنسبة لك." @@ -499,7 +511,7 @@ msgstr "منطقة الخطر" msgid "Dark" msgstr "غامق" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:530 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:537 msgid "Debugging" msgstr "استكشاف الأخطاء" @@ -549,17 +561,17 @@ msgid "Default" msgstr "افتراضي" #: ../../apps/web/src/components/search/InfiniteScroll.tsx:138 -#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:81 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:123 #: ../../apps/mobile/src/components/dictionary/DictionaryEntryCard.tsx:117 #: ../../apps/mobile/src/app/(search)/(home)/add-word.tsx:444 #: ../../apps/mobile/src/app/(search)/(home)/edit-word/[id].tsx:554 msgid "Definition" msgstr "التعريف" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:485 -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:508 -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:129 -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:161 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:492 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:515 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:136 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:168 #: ../../apps/web/src/routes/_authorized-layout/_app-layout/decks/route.lazy.tsx:207 #: ../../apps/mobile/src/app/(search)/decks.tsx:285 #: ../../apps/mobile/src/app/(search)/(home)/edit-word/[id].tsx:393 @@ -582,7 +594,7 @@ msgstr "حذف المعجم" msgid "Delete Everything" msgstr "حذف كل شيء" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:136 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:143 msgid "Delete this word?" msgstr "حذف هذه الكلمة؟" @@ -590,7 +602,7 @@ msgstr "حذف هذه الكلمة؟" msgid "Delete word" msgstr "حذف الكلمة" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:492 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:499 msgid "Delete your dictionary?" msgstr "هل تريد أن تحذف معجمك؟" @@ -607,7 +619,7 @@ msgstr "تفاصيل" msgid "Details:" msgstr "التفاصيل:" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:234 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:241 msgid "Dictionary" msgstr "معجم" @@ -619,8 +631,8 @@ msgstr "تم حذف المعجم" msgid "Diptote" msgstr "ممنوع من الصرف" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:194 -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:221 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:348 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:420 msgid "Discard" msgstr "ألغ" @@ -653,7 +665,7 @@ msgstr "سهل" msgid "Edit" msgstr "عدَل" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:188 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:195 msgid "Edit {word}" msgstr "حرّر {word}" @@ -674,7 +686,7 @@ msgstr "عدّل مجموعتك" msgid "Edit your deck by choosing filters. The deck will be composed of the cards that match the filters." msgstr "عدّل مجموعتك من خلال اختيار الفلاتر. ستتكون المجموعة من البطاقات التي تطابق الفلاتر." -#: ../../apps/web/src/routes/_unauthorized-layout/login/route.lazy.tsx:111 +#: ../../apps/web/src/routes/_unauthorized-layout/login/route.lazy.tsx:116 #: ../../apps/mobile/src/app/(auth)/login.tsx:68 msgid "Email" msgstr "البريد الإلكتروني" @@ -716,46 +728,46 @@ msgid "Entry {arrayIndex}" msgstr "العنصر {arrayIndex}" #. placeholder {0}: index + 1 -#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:166 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:208 #: ../../apps/mobile/src/app/(search)/(home)/add-word.tsx:499 #: ../../apps/mobile/src/app/(search)/(home)/edit-word/[id].tsx:609 msgid "Example {0}" msgstr "المثال {0}" -#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:158 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:200 msgid "Example usages of the word in different contexts." msgstr "استخدامات مثالية للكلمة في سياقات مختلفة." #: ../../apps/web/src/components/search/InfiniteScroll.tsx:292 -#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:154 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:196 #: ../../apps/mobile/src/components/dictionary/DictionaryEntryCard.tsx:262 #: ../../apps/mobile/src/app/(search)/(home)/add-word.tsx:490 #: ../../apps/mobile/src/app/(search)/(home)/edit-word/[id].tsx:600 msgid "Examples" msgstr "أمثلة" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:429 -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:465 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:436 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:472 msgid "Export" msgstr "صدر" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:122 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:129 msgid "Export completed with issues" msgstr "اكتمل التصدير مع وجود مشاكل" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:132 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:139 msgid "Export failed!" msgstr "فشل التصدير!" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:473 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:480 msgid "Export with flashcards" msgstr "تصدير مع البطاقات" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:436 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:443 msgid "Export your dictionary" msgstr "تصدير معجمك" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:440 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:447 msgid "Exporting dictionary with flaschards will save your flashcard progress along with all the content in your dictionary. Use this option if you want to make a backup of your data.<0/><1/>Exporting your dictionary without flashcards will not save any flashcard progress. Use this option if you want to share your dictionary.<2/><3/><4>Warning: Importing your file without flashcards will reset all of your flashcards." msgstr "تصدير المعجم مع البطاقات سيحفظ تقدم البطاقات بالإضافة إلى كل المحتوى في معجمك. استخدم هذا الخيار إذا كنت ترغب في إنشاء نسخة احتياطية من بياناتك.<0/><1/>تصدير المعجم بدون البطاقات لن يحفظ أي تقدم للبطاقات. استخدم هذا الخيار إذا كنت ترغب في مشاركة معجمك.<2/><3/><4>تحذير: استيراد ملفك بدون البطاقات سيؤدي إلى إعادة تعيين جميع البطاقات." @@ -771,7 +783,7 @@ msgstr "عبارة" msgid "Failed to add word" msgstr "فشل إضافة الكلمة" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:165 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:177 msgid "Failed to add word!" msgstr "فشل إضافة الكلمة!" @@ -799,11 +811,15 @@ msgstr "فشل حذف المعجم" msgid "Failed to delete word" msgstr "فشل حذف الكلمة" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:172 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:179 msgid "Failed to delete!" msgstr "فشل الحذف!" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:581 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:90 +msgid "Failed to generate example" +msgstr "فشل توليد المثال" + +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:588 msgid "Failed to reset local data" msgstr "فشل في إعادة تعيين البيانات المحلية" @@ -827,7 +843,7 @@ msgstr "فشل في تحديث إعدادات البطاقة." msgid "Failed to update settings" msgstr "فشل تحديث الإعدادات" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:330 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:341 msgid "Failed to update the word!" msgstr "فشل في تحديث الكلمة!" @@ -852,6 +868,13 @@ msgstr "مؤنّث" msgid "Fi'l" msgstr "فعل" +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:498 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:551 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:338 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:395 +msgid "Fill in the word, translation, and type first." +msgstr "أدخل الكلمة والترجمة والنوع أولاً." + #: ../../apps/web/src/components/features/dictionary/filters/TagsFilter.tsx:51 msgid "Filter by tags..." msgstr "رشّح حسب العلامات..." @@ -888,7 +911,7 @@ msgstr "مثلا الكلمة" msgid "Form" msgstr "الوزن" -#: ../../apps/web/src/components/features/settings/BillingSettingsCard.tsx:25 +#: ../../apps/web/src/components/features/settings/BillingSettingsCard.tsx:30 msgid "Free" msgstr "مجاني" @@ -900,7 +923,19 @@ msgstr "مجاني" msgid "Gender" msgstr "جنس" -#: ../../apps/web/src/routes/_unauthorized-layout/login/route.lazy.tsx:155 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:355 +msgid "Generate example" +msgstr "توليد مثال" + +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:483 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:536 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:323 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:380 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:353 +msgid "Generating..." +msgstr "جارٍ التوليد..." + +#: ../../apps/web/src/routes/_unauthorized-layout/login/route.lazy.tsx:160 #: ../../apps/mobile/src/components/GithubLoginButton.tsx:24 msgid "GitHub" msgstr "GitHub" @@ -910,7 +945,7 @@ msgstr "GitHub" msgid "Go back" msgstr "ارجع" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/checkout-success/route.lazy.tsx:36 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/checkout-success/route.lazy.tsx:44 msgid "Go to dictionary" msgstr "الذهاب إلى القاموس" @@ -961,8 +996,8 @@ msgstr "إخفاء المرشحات" msgid "Hint" msgstr "تلميح" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:179 -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:39 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:186 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:47 #: ../../apps/web/src/components/MobileHeader.tsx:154 #: ../../apps/web/src/components/DesktopNavigation.tsx:53 #: ../../apps/web/src/components/DesktopNavigation.tsx:59 @@ -992,7 +1027,7 @@ msgstr "المعرف:" msgid "if needed." msgstr "إذا لزم الأمر." -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:534 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:541 msgid "If you're experiencing sync issues or data not loading correctly, you can reset your local data and re-sync from the server." msgstr "إذا كنت تواجه مشاكل في المزامنة أو عدم تحميل البيانات بشكل صحيح، يمكنك إعادة تعيين بياناتك المحلية وإعادة المزامنة من الخادم." @@ -1004,12 +1039,12 @@ msgstr "إذا كنت تواجه مشاكل في المزامنة أو عدم ت msgid "Imperative" msgstr "الأمر" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:393 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:400 msgid "Import" msgstr "استورد" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:365 -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:371 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:372 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:378 msgid "Import failed!" msgstr "فشل الاستيراد!" @@ -1017,7 +1052,7 @@ msgstr "فشل الاستيراد!" msgid "Include English to Arabic flashcards" msgstr "تضمين بطاقات الإنجليزية إلى العربية" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:253 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:260 msgid "Incorrect file type" msgstr "نوع الملف غير صحيح" @@ -1031,7 +1066,7 @@ msgstr "مبنى" msgid "Inflection" msgstr "إعراب" -#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:67 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:109 msgid "Information such as the word's root, meaning, and examples." msgstr "معلومات مثلا الجذر أو المعنى أو الأمثلة." @@ -1063,7 +1098,7 @@ msgstr "قيمة غير صالحة. يجب أن تكون إحدى القيم ا msgid "Ism" msgstr "اسم" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:224 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:231 #: ../../apps/mobile/src/app/(search)/settings.tsx:258 msgid "Language" msgstr "اللغة" @@ -1090,7 +1125,7 @@ msgstr "جارٍ التحميل..." #~ msgid "Local data reset successfully!" #~ msgstr "تمت إعادة تعيين البيانات المحلية بنجاح!" -#: ../../apps/web/src/routes/_unauthorized-layout/login/route.lazy.tsx:93 +#: ../../apps/web/src/routes/_unauthorized-layout/login/route.lazy.tsx:98 #: ../../apps/mobile/src/app/(auth)/login.tsx:63 msgid "Log in to your existing account or sign up for a new one" msgstr "قم بتسجيل الدخول إلى حسابك الحالي أو قم بالتسجيل للحصول على حساب جديد" @@ -1101,7 +1136,7 @@ msgstr "قم بتسجيل الدخول إلى حسابك الحالي أو قم msgid "Logout" msgstr "تسجيل الخروج" -#: ../../apps/web/src/components/features/settings/BillingSettingsCard.tsx:61 +#: ../../apps/web/src/components/features/settings/BillingSettingsCard.tsx:63 msgid "Manage Subscription" msgstr "إدارة الاشتراك" @@ -1109,11 +1144,11 @@ msgstr "إدارة الاشتراك" msgid "Manage your decks and study them." msgstr "إدارة مجموعاتك ودراستها." -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:238 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:245 msgid "Manage your dictionary." msgstr "إدارة معجمك." -#: ../../apps/web/src/components/features/settings/BillingSettingsCard.tsx:43 +#: ../../apps/web/src/components/features/settings/BillingSettingsCard.tsx:45 msgid "Manage your subscription." msgstr "إدارة اشتراكك." @@ -1154,7 +1189,7 @@ msgstr "القائمة" msgid "Migration successfully registered." msgstr "تم تسجيل الترحيل بنجاح." -#: ../../apps/web/src/components/features/settings/BillingSettingsCard.tsx:82 +#: ../../apps/web/src/components/features/settings/BillingSettingsCard.tsx:84 msgid "Monthly — $10/mo" msgstr "شهري — $١٠/شهر" @@ -1227,7 +1262,7 @@ msgstr "اسم" msgid "Noun Morphology" msgstr "صرف الاسم" -#: ../../apps/web/src/routes/_unauthorized-layout/login/route.lazy.tsx:149 +#: ../../apps/web/src/routes/_unauthorized-layout/login/route.lazy.tsx:154 #: ../../apps/mobile/src/app/(auth)/login.tsx:111 msgid "Or continue with" msgstr "أو استمر مع" @@ -1272,11 +1307,11 @@ msgstr "يرجى الاتصال <0>بالدعم مع التفاصيل الت msgid "Please enter a deck name" msgstr "الرجاء إدخال اسم المجموعة" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:254 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:261 msgid "Please select a JSON file with your dictionary." msgstr "اختر ملف JSON لمعجمك من فضلك." -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:582 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:589 msgid "Please try again or reload the page." msgstr "حاول مرة أخرى أو أعد تحميل الصفحة." @@ -1287,6 +1322,12 @@ msgstr "حاول مرة أخرى أو أعد تحميل الصفحة." msgid "Please try again." msgstr "حاول مرّة أخرى." +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:364 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:206 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:87 +msgid "Please wait before trying again." +msgstr "يرجى الانتظار قبل المحاولة مرة أخرى." + #: ../../apps/web/src/components/search/InfiniteScroll.tsx:188 #: ../../apps/mobile/src/components/dictionary/DictionaryEntryCard.tsx:159 msgid "Plural" @@ -1337,10 +1378,16 @@ msgstr "المضارع" msgid "Present Tense" msgstr "المضارع" -#: ../../apps/web/src/components/features/settings/BillingSettingsCard.tsx:23 +#: ../../apps/web/src/components/features/settings/BillingSettingsCard.tsx:27 msgid "Pro" msgstr "برو" +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:363 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:205 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:86 +msgid "Rate limit reached" +msgstr "تم الوصول إلى الحد الأقصى" + #: ../../apps/web/src/components/features/dictionary/filters/DictionaryFilters.tsx:36 msgid "Recently added" msgstr "المضافة حديثًا" @@ -1364,8 +1411,8 @@ msgstr "أعد التحميل" #: ../../apps/web/src/components/features/dictionary/add/VerbMorphologyCardSection.tsx:251 #: ../../apps/web/src/components/features/dictionary/add/VerbMorphologyCardSection.tsx:408 #: ../../apps/web/src/components/features/dictionary/add/IsmMorphologyCardSection.tsx:183 -#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:263 -#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:337 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:305 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:422 msgid "Remove" msgstr "احذف" @@ -1377,28 +1424,28 @@ msgstr "حقل مطلوب" msgid "Reschedule all backlog cards by grading them as \"Hard\"." msgstr "أعد جدولة جميع البطاقات المتراكمة بتقييمها كـ \"صعب\"." -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:588 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:595 msgid "Reset and re-sync" msgstr "إعادة التعيين والمزامنة" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:77 -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:111 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:84 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:118 msgid "Reset flashcard" msgstr "أعد البطاقة" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:84 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:91 msgid "Reset flashcard progress?" msgstr "إعادة تعيين تقدم البطاقة؟" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:546 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:553 msgid "Reset local data" msgstr "إعادة تعيين البيانات المحلية" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:553 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:560 msgid "Reset local data and re-sync?" msgstr "إعادة تعيين البيانات المحلية والمزامنة؟" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:186 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:193 msgid "Resetting local data..." msgstr "جارٍ إعادة تعيين البيانات المحلية..." @@ -1429,7 +1476,7 @@ msgstr "راجع البطاقات بالتكرار المتباعد" msgid "Review your Arabic flashcards and grade your understanding with Again, Hard, Good, or Easy options to adjust scheduling." msgstr "راجع بطاقاتك العربية وقيم فهمك باستخدام خيارات مرة أخرى أو صعب أو جيد أو سهل لتعديل الجدولة." -#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:120 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:162 msgid "Root letters" msgstr "الجذر" @@ -1438,17 +1485,17 @@ msgstr "الجذر" msgid "Root Letters" msgstr "الحروف الأصلية" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:356 -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:385 -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:199 -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:226 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:509 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:583 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:353 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:425 #: ../../apps/web/src/components/features/settings/FlashcardSettingsCardSection.tsx:232 #: ../../apps/web/src/components/features/settings/AdminSettingsCardSection.tsx:146 #: ../../apps/mobile/src/app/(search)/(home)/add-word.tsx:1005 msgid "Save" msgstr "احفظ" -#: ../../apps/web/src/components/features/settings/BillingSettingsCard.tsx:105 +#: ../../apps/web/src/components/features/settings/BillingSettingsCard.tsx:107 msgid "Save 30%" msgstr "وفّر ٣٠٪" @@ -1504,7 +1551,7 @@ msgstr "حدد أنواع الكلمات التي تريد تضمينها في msgid "Select type" msgstr "اختر الجنس" -#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:176 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:218 msgid "Sentence" msgstr "جملة" @@ -1513,7 +1560,7 @@ msgstr "جملة" msgid "Separate letters with spaces or commas" msgstr "افصل الحروف بمسافات أو فواصل" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:193 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:200 #: ../../apps/web/src/components/MobileHeader.tsx:178 #: ../../apps/web/src/components/DesktopNavigation.tsx:107 #: ../../apps/mobile/src/app/(search)/settings.tsx:175 @@ -1569,6 +1616,12 @@ msgstr "تعذر تحميل بعض إدخالات المعجم" msgid "Something went wrong" msgstr "حدث خطأ ما" +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:368 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:210 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:91 +msgid "Something went wrong. Please try again." +msgstr "حدث خطأ ما. يرجى المحاولة مرة أخرى." + #: ../../apps/web/src/components/features/dictionary/filters/DictionaryFilters.tsx:161 msgid "Sort by" msgstr "ترتيب حسب" @@ -1585,27 +1638,27 @@ msgstr "لا يزال لا يعمل؟" msgid "Study" msgstr "أدرس" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:157 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:169 msgid "Successfully added word!" msgstr "تم إضافة الكلمة بنجاح!" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:166 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:173 msgid "Successfully deleted!" msgstr "نجح الحذف!" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:126 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:133 msgid "Successfully exported!" msgstr "تم التصدير بنجاح!" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:342 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:349 msgid "Successfully imported!" msgstr "تم الاستيراد بنجاح!" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:106 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:113 msgid "Successfully reset the flashcard." msgstr "تمت إعادة تعيين البطاقة بنجاح." -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:322 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:333 msgid "Successfully updated the word!" msgstr "حدثت الكلمة بنجاح!" @@ -1629,7 +1682,7 @@ msgstr "نظام" msgid "Tags" msgstr "علامات" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/checkout-success/route.lazy.tsx:26 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/checkout-success/route.lazy.tsx:34 msgid "Thank you for subscribing to Bahar Pro. You now have access to all Pro features." msgstr "شكرًا لاشتراكك في بهار برو. يمكنك الآن الوصول إلى جميع ميزات برو." @@ -1652,7 +1705,7 @@ msgstr "هذا ليس JSON صالح." msgid "The app may be open in another tab. Try closing other tabs and refreshing this page." msgstr "قد يكون التطبيق مفتوحًا في علامة تبويب أخرى. حاول إغلاق علامات التبويب الأخرى وتحديث هذه الصفحة." -#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:245 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:287 msgid "The context of the sentence, ex. formal or colloquial." msgstr "سياق الجملة مثلا رسمي أو عامي." @@ -1681,24 +1734,24 @@ msgstr "معنى الفعل إذا استعمل مع الحرف." msgid "The morphological breakdown of the word." msgstr "التصريف." -#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:135 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:177 msgid "The root letters of the word. The input can be separated by commas, spaces or have no delimeter ex. فعل or ف, ع, ل or ف ع ل." msgstr "الحروف الجذرية للكلمة. يمكن فصل المدخلات بفواصل أو مسافات أو لا تحتوي على محدد مثلا فعل أو ف، ع، ل أو ف ع ل." -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:158 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:170 msgid "The word has been added to your dictionary." msgstr "تمت إضافة الكلمة إلى معجمك." -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:323 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:334 msgid "The word has been updated." msgstr "حدثت الكلمة." -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:210 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:217 #: ../../apps/mobile/src/app/(search)/settings.tsx:243 msgid "Theme" msgstr "المظهر" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:166 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:178 msgid "There was an error adding your word. Please try again." msgstr "حدث خطأ أثناء إضافة كلمتك. حاول مرة اخرى." @@ -1710,15 +1763,15 @@ msgstr "حدث خطأ أثناء مسح المتراكمات." msgid "There was an error creating the deck" msgstr "حدث خطأ أثناء إنشاء المجموعة" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:173 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:180 msgid "There was an error deleting your dictionary. Please try again later." msgstr "حدث خطأ أثناء حذف معجمك. حاول مرة أخرى لاحقا من فضلك." -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:133 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:140 msgid "There was an error exporting your dictionary. Please try again later." msgstr "حدث خطأ أثناء تصدير معجمك. حاول مرة أخرى لاحقا من فضلك." -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:372 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:379 msgid "There was an error importing your dictionary. Please try again later." msgstr "حدث خطأ أثناء استيراد لمعجمك. حاول مرة أخرى لاحقا." @@ -1742,7 +1795,7 @@ msgstr "حدث خطأ أثناء تحديث المجموعة" msgid "There was an error updating your flashcard settings." msgstr "حدث خطأ أثناء تحديث إعدادات بطاقاتك." -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:331 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:342 msgid "There was an error updating your word. Please try again." msgstr "حدث خطأ أثناء تحديث كلمتك. حاول مرة أخرى." @@ -1773,7 +1826,7 @@ msgstr "هناك مشكلة مؤقتة في تحميل حسابك. حاول إع msgid "This field is required." msgstr "هذه الخانة لازم." -#: ../../apps/web/src/routes/_unauthorized-layout/login/route.lazy.tsx:119 +#: ../../apps/web/src/routes/_unauthorized-layout/login/route.lazy.tsx:124 #: ../../apps/mobile/src/app/(auth)/login.tsx:94 msgid "This is case insensitive." msgstr "هذا حالة غير حساسة." @@ -1786,7 +1839,7 @@ msgstr "هذا هو اسم مجموعتك." msgid "This refers to how many case endings the word can take." msgstr "هذا هو إعراب الكلمة." -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:557 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:564 msgid "This will delete the local copy of your data stored in this browser and download a fresh copy from the server. Your data on the server will not be affected. Use this if you're experiencing sync errors or seeing outdated data." msgstr "سيؤدي هذا إلى حذف النسخة المحلية من بياناتك المخزنة في هذا المتصفح وتنزيل نسخة جديدة من الخادم. لن تتأثر بياناتك على الخادم. استخدم هذا إذا كنت تواجه أخطاء في المزامنة أو ترى بيانات قديمة." @@ -1815,7 +1868,7 @@ msgid "Total" msgstr "الإجمالي" #: ../../apps/web/src/components/features/dictionary/add/BasicDetailsFormSection.tsx:64 -#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:202 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:244 #: ../../apps/mobile/src/app/(search)/(home)/add-word.tsx:381 #: ../../apps/mobile/src/app/(search)/(home)/edit-word/[id].tsx:491 msgid "Translation" @@ -1857,10 +1910,21 @@ msgstr "غير قادر على الاتصال بقاعدة البيانات ال msgid "Unknown error." msgstr "خطأ غير معروف." -#: ../../apps/web/src/components/features/settings/BillingSettingsCard.tsx:69 +#: ../../apps/web/src/components/features/settings/BillingSettingsCard.tsx:71 msgid "Upgrade to Pro" msgstr "الترقية إلى برو" +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:363 +msgid "Upgrade to Pro to generate examples." +msgstr "قم بالترقية إلى برو لتوليد الأمثلة." + +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:493 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:546 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:333 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:390 +msgid "Upgrade to Pro to use AI autofill." +msgstr "قم بالترقية إلى برو لاستخدام التعبئة التلقائية." + #. placeholder {0}: String(err.minimum) #: ../../apps/web/src/lib/error.ts:128 msgid "Value must be {0} or greater" @@ -1913,7 +1977,7 @@ msgstr "لا يمكننا الوصول إلى خوادمنا الآن. تحقق msgid "We're having trouble with your account setup. Please try again." msgstr "نواجه مشكلة في إعداد حسابك. حاول مرة أخرى من فضلك." -#: ../../apps/web/src/routes/_unauthorized-layout/login/route.lazy.tsx:89 +#: ../../apps/web/src/routes/_unauthorized-layout/login/route.lazy.tsx:94 #: ../../apps/mobile/src/app/(auth)/login.tsx:59 msgid "Welcome to Bahar!" msgstr "مرحباً بكم في بحر!" @@ -1921,7 +1985,7 @@ msgstr "مرحباً بكم في بحر!" #: ../../apps/web/src/components/features/dictionary/add/VerbMorphologyCardSection.tsx:192 #: ../../apps/web/src/components/features/dictionary/add/IsmMorphologyCardSection.tsx:125 #: ../../apps/web/src/components/features/dictionary/add/BasicDetailsFormSection.tsx:40 -#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:310 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:395 #: ../../apps/mobile/src/app/(search)/(home)/add-word.tsx:357 #: ../../apps/mobile/src/app/(search)/(home)/edit-word/[id].tsx:467 msgid "Word" @@ -1947,7 +2011,7 @@ msgstr "تم تحديث الكلمة بنجاح" msgid "Words that have any of these tags will be included in the deck." msgstr "الكلمات التي تحتوي على أي من هذه العلامات ستُدرج في المجموعة." -#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:292 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:377 msgid "Words that have the opposite meaning." msgstr "الكلمات التي لها معنى عكسي." @@ -1968,7 +2032,7 @@ msgstr "ليس لديك أي مجموعات بعد." msgid "You have no words in your dictionary yet." msgstr "ليس لديك أي كلمات في قاموسك بعد." -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/checkout-success/route.lazy.tsx:22 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/checkout-success/route.lazy.tsx:30 msgid "You're all set!" msgstr "أنت جاهز!" @@ -1993,15 +2057,15 @@ msgstr "لم يتم تحديث مجموعتك. يرجى المحاولة مرة msgid "Your Dictionary" msgstr "معجمك" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:167 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:174 msgid "Your dictionary has been deleted." msgstr "حذف معجمك." -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:127 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:134 msgid "Your dictionary has been downloaded." msgstr "تم تحميل معجمك." -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:343 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:350 msgid "Your dictionary has been updated!" msgstr "تم تحديث معجمك!" @@ -2009,7 +2073,7 @@ msgstr "تم تحديث معجمك!" msgid "Your dictionary is empty" msgstr "معجمك فارغ" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:366 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:373 msgid "Your dictionary is not valid. Please fix the errors and upload it again." msgstr "معجمك غير صالح. صوب الأخطاء و استورد مرة أخرى من فضلك." diff --git a/packages/i18n/locales/ar.ts b/packages/i18n/locales/ar.ts index 1368f68..cb2428c 100644 --- a/packages/i18n/locales/ar.ts +++ b/packages/i18n/locales/ar.ts @@ -1 +1 @@ -/*eslint-disable*/import type{Messages}from"@lingui/core";export const messages=JSON.parse("{\"Wg0uLA\":[[\"0\",\"plural\",{\"one\":[\"علامة واحدة محددة\"],\"two\":[\"علامتان محددتان\"],\"few\":[\"#\",\" علامات محددة\"],\"many\":[\"#\",\" علامة محددة\"],\"other\":[\"#\",\" علامة محددة\"]}]],\"5rgLzy\":[[\"0\",\"plural\",{\"one\":[\"بطاقة متبقية\"],\"other\":[\"بطاقات متبقية\"]}]],\"/hTM9k\":[[\"0\"],\" / \",[\"1\"],\" دفعات\"],\"mHye52\":[[\"0\"],\" / \",[\"1\"],\" بطاقات\"],\"baIPh3\":[[\"0\"],\" بطاقات مستحقة\"],\"beWT44\":[\"تمت إعادة جدولة \",[\"0\"],\" بطاقات.\"],\"JJcBCm\":[[\"0\"],\" إجمالي\"],\"JtTuS0\":[[\"hydrationSkippedCount\",\"plural\",{\"one\":[\"تم تخطي إدخال واحد بسبب مشاكل في البيانات. بياناتك محفوظة، لكن لن تتمكن من البحث عن الإدخال الذي لم يتم تحميله.\"],\"two\":[\"تم تخطي إدخالين بسبب مشاكل في البيانات. بياناتك محفوظة، لكن لن تتمكن من البحث عن الإدخالات التي لم يتم تحميلها.\"],\"few\":[\"تم تخطي \",\"#\",\" إدخالات بسبب مشاكل في البيانات. بياناتك محفوظة، لكن لن تتمكن من البحث عن الإدخالات التي لم يتم تحميلها.\"],\"many\":[\"تم تخطي \",\"#\",\" إدخالًا بسبب مشاكل في البيانات. بياناتك محفوظة، لكن لن تتمكن من البحث عن الإدخالات التي لم يتم تحميلها.\"],\"other\":[\"تم تخطي \",\"#\",\" إدخال بسبب مشاكل في البيانات. بياناتك محفوظة، لكن لن تتمكن من البحث عن الإدخالات التي لم يتم تحميلها.\"]}]],\"UGMDWm\":[\"تم تخطي \",[\"skippedCount\"],\" إدخالات بسبب تلف البيانات.\"],\"gp8eDB\":[[\"totalHits\",\"plural\",{\"one\":[\"نتيجة\"],\"two\":[\"نتيجتان\"],\"few\":[\"نتائج\"],\"many\":[\"نتيجة\"],\"other\":[\"نتيجة\"]}]],\"QSRKsm\":[[\"totalResults\",\"plural\",{\"one\":[[\"totalResults\"],\" نتيجة\"],\"two\":[[\"totalResults\"],\" نتيجتان\"],\"few\":[[\"totalResults\"],\" نتائج\"],\"many\":[[\"totalResults\"],\" نتيجة\"],\"other\":[[\"totalResults\"],\" نتيجة\"]}]],\"gD09hk\":[[\"val\",\"plural\",{\"one\":[\"لا يمكن تجاوز حرف واحد\"],\"two\":[\"لا يمكن تجاوز حرفين\"],\"few\":[\"لا يمكن تجاوز \",\"#\",\" حروف\"],\"many\":[\"لا يمكن تجاوز \",\"#\",\" حرفا\"],\"other\":[\"لا يمكن تجاوز \",\"#\",\" حرف\"]}]],\"I1sa5o\":[[\"val\",\"plural\",{\"one\":[\"يجب أن يكون على الأقل واحد حرف\"],\"two\":[\"يجب أن يكون على الأقل حرفين\"],\"few\":[\"يجب أن يكون على الأقل \",\"#\",\" حروف\"],\"many\":[\"يجب أن يكون على الأقل \",\"#\",\" حرفا\"],\"other\":[\"يجب أن يكون على الأقل \",\"#\",\" حرف\"]}]],\"WWcbHw\":[\"غير فعل أو حرف.\"],\"ZQW2PY\":[\"حرف أو عطف.\"],\"0iy5O2\":[\"فعل.\"],\"7L01XJ\":[\"أعمال\"],\"DQqXHw\":[\"اسم فاعل\"],\"AwJc6G\":[\"اسم فاعل\"],\"rJwPkp\":[\"أضف ترحيل SQL جديد.\"],\"t89Ong\":[\"أضف كلمة جديدة\"],\"L18Pbl\":[\"أضف كلمة جديدة إلى معجمك\"],\"TYPFtT\":[\"أضف علامة واضغط Enter\"],\"iJMhp0\":[\"إضافة الكل\"],\"nPm6bB\":[\"أضف ضدا\"],\"jVmrwy\":[\"أضف ضد\"],\"1x4W9u\":[\"أضف مثلا\"],\"nI3A8B\":[\"أضف مثال\"],\"gLlFHX\":[\"أضف حرف\"],\"aLEtgY\":[\"أضف حرف\"],\"Tcbo6a\":[\"أضف مصدر\"],\"vKbErK\":[\"أضف صيغة جمع\"],\"SNF/r2\":[\"أضف جمع\"],\"cR1WUS\":[\"أضف شيئًا لتبدأ!\"],\"Oft+Pb\":[\"أضف بعض الكلمات للبدء!\"],\"Xls3A3\":[\"أضف علامة \",[\"inputValue\"]],\"VMjLu6\":[\"إضافة العلامة \",[\"value\"]],\"uF1GKn\":[\"أضف علامات إلى كلمتك.\"],\"bDXmnN\":[\"أضف كلمة\"],\"p59pEv\":[\"تفاصيل إضافية\"],\"b/7DUT\":[\"مرة أخرى\"],\"KK8UsT\":[\"انتهيت لليوم!\"],\"7Qi3W5\":[\"تعريف عربية للكلمة.\"],\"Y/gBMP\":[\"ترجمة إنجليزية للجملة.\"],\"jalxln\":[\"ترجمة إنجليزية للكلمة.\"],\"hyC+qY\":[\"حدث خطأ غير متوقع. يمكنك محاولة إعادة تحميل الصفحة لإصلاحه.\"],\"Fl8owW\":[\"سنوي — $٧/شهر\"],\"4xBHUg\":[\"الجواب\"],\"vQXp82\":[\"الضد \",[\"0\"]],\"o9dJs3\":[\"كلمة مضادة\"],\"Hvs4LI\":[\"أضداد\"],\"p1Kh9a\":[\"أية تفاصيل إضافية عن هذه الصيغة مثلا تكرار الاستخدام أو السياق.\"],\"9kni2/\":[\"أية صيغ جمع للكلمة.\"],\"2PPE7k\":[\"سيستبدل كل كلمات التي لديها نفس المعرف.\"],\"cnAqww\":[\"لغة التطبيق\"],\"aAIQg2\":[\"المظهر\"],\"8HV3WN\":[\"العربية\"],\"LNIQwr\":[\"التعريف بالعربية\"],\"uKmc5K\":[\"الجملة بالعربية\"],\"wxIhw3\":[\"صيغة الفعل العربي\"],\"071WZA\":[\"الكلمة بالعربية\"],\"pkD36F\":[\"هل أنت متأكد من حذف \\\"\",[\"0\"],\"\\\"؟\"],\"DOiV7q\":[\"هل أنت متأكد أنك تريد حذف هذه الكلمة؟ سيتم إزالتها من معجمك وسيتم حذف البطاقات بها.<0/><1/><2>لا يمكن التراجع عن هذا الإجراء.\"],\"2cZh44\":[\"هل أنت متأكد من حذف هذه الكلمة؟ لا يمكن التراجع عن هذا الإجراء.\"],\"ikBPhc\":[\"هل أنت متأكد من رغبتك في حذف معجمك؟ سيحذف جميع كلماتك بشكل دائم. لا يمكن التراجع عن هذا الإجراء. صدر معجمك قبل حذفه من فضلك.\"],\"IJr17L\":[\"هل أنت متأكد أنك تريد إعادة تعيين تقدم بطاقة هذه؟ لن يتم تعديل إدخال الكلمة في المعجم، ولكن سيتم التعامل مع بطاقات بها على أنها بطاقات جديدة.<0/><1/><2>لا يمكن التراجع عن هذا الإجراء.\"],\"iH8pgl\":[\"رجوع\"],\"0MgdN+\":[\"العودة إلى الأعلى\"],\"KNKCTb\":[\"المتراكمة\"],\"Fg+fNW\":[\"تم مسح المتراكمات!\"],\"vMebS2\":[\"بحر\"],\"EOUool\":[\"تفاصيل أساسية\"],\"cSCbv3\":[\"بيتا\"],\"t/5uBV\":[\"يُدفع $٨٤/سنة\"],\"aIkeAd\":[\"يُدفع شهريًا\"],\"R+w/Va\":[\"الفوترة\"],\"OKWk8n\":[\"بتسجيل الدخول، فإنك توافق على <0>سياسة الخصوصية\"],\"dEgA5A\":[\"ألغ\"],\"oySfhX\":[\"بطاقات مستحقة اليوم أو مؤخرًا\"],\"uV52e1\":[\"بطاقات متأخرة أكثر من ٧ أيام\"],\"zAwyRS\":[\"بطاقات للمراجعة اليوم\"],\"K7tIrx\":[\"الباب\"],\"qWRWG1\":[\"السبب:\"],\"+yPBXI\":[\"اختر ملف\"],\"xCJdfg\":[\"امسح\"],\"ot7qsv\":[\"مسح كل المرشّحات\"],\"saoOio\":[\"امسح المتراكمات\"],\"Oo39Ga\":[\"جارٍ المسح...\"],\"rFmBG3\":[\"سمة الألوان\"],\"mpby9d\":[\"اتصل بالدعم\"],\"M73whl\":[\"السياق\"],\"xGVfLh\":[\"استمر\"],\"RvVi9c\":[\"استمرّ مع بريد الإلكتروني\"],\"NMo6Pj\":[\"تحكم في مكان ظهور الأضداد أثناء المراجعة\"],\"PiH3UR\":[\"تم النسخ!\"],\"he3ygx\":[\"انسخ\"],\"hYgDIe\":[\"إنشاء\"],\"oJc/nD\":[\"أنشئ مجموعة لتنظيم مراجعات بطاقاتك\"],\"wxDqxy\":[\"إنشاء مجموعة جديدة\"],\"oQH8Kl\":[\"أنشئ مجموعة جديدة باختيار الفلاتر. ستكون المجموعة مكونة من البطاقات التي تطابق هذه الفلاتر.\"],\"l7kxcE\":[\"أنشئ مجموعة\"],\"g/Uxjl\":[\"إنشاء مجموعة\"],\"1m75Ii\":[\"أنشئ مجموعتك الأولى\"],\"A+zoTy\":[\"الخطة الحالية\"],\"PQ2zPy\":[\"خصص كيفيّة ظهور البطاقات.\"],\"P+gzBQ\":[\"قم بتخصيص كيف يظهر التطبيق بالنسبة لك.\"],\"ZQKLI1\":[\"منطقة الخطر\"],\"pvnfJD\":[\"غامق\"],\"Wf+eYa\":[\"استكشاف الأخطاء\"],\"LUfCYM\":[\"تم إنشاء المجموعة\"],\"sHVysr\":[\"تم حذف المجموعة\"],\"UzOd8J\":[\"اسم المجموعة\"],\"iJA/GX\":[\"تم إنشاء المجموعة بنجاح!\"],\"M+Nngk\":[\"تم حذف المجموعة بنجاح!\"],\"NVQRbB\":[\"تم تحديث المجموعة بنجاح!\"],\"WWDML8\":[\"تم تحديث المجموعة\"],\"9TyPfF\":[\"المجموعات\"],\"iUt5VS\":[\"تتيح لك المجموعات إنشاء مجموعات فرعية من بطاقاتك التعليمية الموجودة باستخدام الفلاتر على قاموسك، والتي يمكنك دراستها بشكل فردي.\"],\"ovBPCi\":[\"افتراضي\"],\"MbRyzp\":[\"التعريف\"],\"cnGeoo\":[\"احذف\"],\"CYf/wo\":[\"حذف جميع البيانات\"],\"G6sE0d\":[\"حذف المجموعة\"],\"fWNrfJ\":[\"حذف المعجم\"],\"Xpcev7\":[\"حذف كل شيء\"],\"pe67wL\":[\"حذف هذه الكلمة؟\"],\"VEQ9bX\":[\"حذف الكلمة\"],\"/GZNuU\":[\"هل تريد أن تحذف معجمك؟\"],\"Nu4oKW\":[\"الوصف\"],\"URmyfc\":[\"تفاصيل\"],\"wjSthp\":[\"التفاصيل:\"],\"VrH1k+\":[\"معجم\"],\"RPYrAz\":[\"تم حذف المعجم\"],\"460RzB\":[\"ممنوع من الصرف\"],\"bzSI52\":[\"ألغ\"],\"1QfxQT\":[\"اغلق\"],\"Nwbs0q\":[\"لا تعرض\"],\"xifE4+\":[\"المثنى\"],\"jSxAVI\":[\"مثال: ك ت ب\"],\"Pqhtap\":[\"سهل\"],\"ePK91l\":[\"عدَل\"],\"nZQfan\":[\"حرّر \",[\"word\"]],\"4cP5gy\":[\"تعديل المجموعة\"],\"AN/oWt\":[\"تعديل الكلمة\"],\"IQ6Efp\":[\"عدّل مجموعتك\"],\"FEct+T\":[\"عدّل مجموعتك من خلال اختيار الفلاتر. ستتكون المجموعة من البطاقات التي تطابق الفلاتر.\"],\"O3oNi5\":[\"البريد الإلكتروني\"],\"lYGfRP\":[\"الإنجليزية\"],\"7MHe6P\":[\"الترجمة بالإنجليزية\"],\"Ac92c9\":[\"أدخل اسم المجموعة\"],\"ot6UAQ\":[\"أدخل وصفًا لترحيلك\"],\"shwNsK\":[\"أدخل اسم المجموعة\"],\"BTF0Gj\":[\"ادخل رمزك المكون من ٦ أرقام من بريدك الإلكتروني\"],\"ojjQlT\":[\"أدخل نص ترحيل SQL هنا\"],\"CA1DlQ\":[\"العنصر \",[\"arrayIndex\"]],\"Af6M/a\":[\"المثال \",[\"0\"]],\"oea1as\":[\"استخدامات مثالية للكلمة في سياقات مختلفة.\"],\"hFthoo\":[\"أمثلة\"],\"GS+Mus\":[\"صدر\"],\"Mk2MqX\":[\"اكتمل التصدير مع وجود مشاكل\"],\"XydOn5\":[\"فشل التصدير!\"],\"FAMOg+\":[\"تصدير مع البطاقات\"],\"HynDdB\":[\"تصدير معجمك\"],\"cQ+n9e\":[\"تصدير المعجم مع البطاقات سيحفظ تقدم البطاقات بالإضافة إلى كل المحتوى في معجمك. استخدم هذا الخيار إذا كنت ترغب في إنشاء نسخة احتياطية من بياناتك.<0/><1/>تصدير المعجم بدون البطاقات لن يحفظ أي تقدم للبطاقات. استخدم هذا الخيار إذا كنت ترغب في مشاركة معجمك.<2/><3/><4>تحذير: استيراد ملفك بدون البطاقات سيؤدي إلى إعادة تعيين جميع البطاقات.\"],\"1JBTZV\":[\"عبارة\"],\"GiPSsF\":[\"فشل إضافة الكلمة\"],\"zABpXD\":[\"فشل إضافة الكلمة!\"],\"NcBoUU\":[\"فشل تطبيق الترحيل على قاعدة البيانات المحلية.\"],\"eN1Tfn\":[\"فشل مسح المتراكمات\"],\"7hUTxx\":[\"فشل إنشاء المجموعة\"],\"Fr4iT6\":[\"فشل حذف المجموعة\"],\"GCd4Bz\":[\"فشل حذف المعجم\"],\"KLMMnR\":[\"فشل حذف الكلمة\"],\"cncTzY\":[\"فشل الحذف!\"],\"usb0iv\":[\"فشل في إعادة تعيين البيانات المحلية\"],\"dCD/3a\":[\"فشل في استرجاع البيانات من قاعدة البيانات المحلية.\"],\"btG7GG\":[\"فشل استرجاع معلومات قاعدة البيانات.\"],\"CBm+/w\":[\"فشل تحديث المجموعة\"],\"gw2VAF\":[\"فشل في تحديث إعدادات البطاقة.\"],\"tOcErW\":[\"فشل تحديث الإعدادات\"],\"X/iINj\":[\"فشل في تحديث الكلمة!\"],\"cnYJdR\":[\"فشل تحديث الكلمة\"],\"ixyKje\":[\"فشل تحميل الترحيل\"],\"1B52uC\":[\"مؤنّث\"],\"TUSnpz\":[\"فعل\"],\"YCAFdN\":[\"رشّح حسب العلامات...\"],\"cSev+j\":[\"الترشيح\"],\"wG1Flg\":[\"تم تحديث إعدادات البطاقة!\"],\"EiJpdz\":[\"بطاقات\"],\"hpt1Ta\":[\"يتبع لغة جهازك\"],\"tR/FIC\":[\"يتبع إعدادات النظام\"],\"q1hBIe\":[\"مثلا الكلمة\"],\"QRAWTO\":[\"الوزن\"],\"2POOFK\":[\"مجاني\"],\"5iyJje\":[\"جنس\"],\"RkXlPZ\":[\"GitHub\"],\"CKyk7Q\":[\"ارجع\"],\"lUTqcW\":[\"الذهاب إلى القاموس\"],\"OEEQKT\":[\"حسن\"],\"VOwQ6g\":[\"أحسنت في المتراكمات! لا يزال لديك \",[\"0\"],\" مراجعات عادية.\"],\"Xv6Pek\":[\"عمل رائع! عد لاحقًا لمزيد من المراجعات.\"],\"g5Fk5U\":[\"صعب\"],\"h4MDwq\":[\"حرف\"],\"IzmuJh\":[\"الحرف \",[\"0\"]],\"D+zLDD\":[\"مخفي\"],\"VMlRqi\":[\"إخفاء التفاصيل\"],\"QWNZbK\":[\"إخفاء المرشحات\"],\"f+BFfG\":[\"تلميح\"],\"i0qMbr\":[\"منزل\"],\"q0alPy\":[\"كيف ينبغي عرض الأضداد في بطاقات؟\"],\"af2WMF\":[\"طريقة تصنف الكلمة حسب نوعها أو سياقها.\"],\"qGZ1pF\":[\"حروف\"],\"7fIUBE\":[\"المعرف:\"],\"mU4ZuB\":[\"إذا لزم الأمر.\"],\"eQI7A0\":[\"إذا كنت تواجه مشاكل في المزامنة أو عدم تحميل البيانات بشكل صحيح، يمكنك إعادة تعيين بياناتك المحلية وإعادة المزامنة من الخادم.\"],\"wqQIcr\":[\"الأمر\"],\"l3s5ri\":[\"استورد\"],\"5LwmgO\":[\"فشل الاستيراد!\"],\"X85Lgt\":[\"تضمين بطاقات الإنجليزية إلى العربية\"],\"O1SPgK\":[\"نوع الملف غير صحيح\"],\"bjwx3z\":[\"مبنى\"],\"d7G5eB\":[\"إعراب\"],\"IaZUGL\":[\"معلومات مثلا الجذر أو المعنى أو الأمثلة.\"],\"FP8ELf\":[\"الصيغة الزمنية غير صالحة\"],\"LpHyjF\":[\"صيغة النص غير صالحة\"],\"xVH/JG\":[\"نوع غير صالح. المتوقع \",[\"0\"]],\"lBmlgJ\":[\"نوع غير صالح. المتوقع \",[\"0\"],\"، المستلم \",[\"1\"]],\"5R5T/G\":[\"قيمة غير صالحة. يجب أن تكون إحدى القيم التالية: \",[\"0\"]],\"SK5zz1\":[\"اسم\"],\"vXIe7J\":[\"اللغة\"],\"1njn7W\":[\"فاتح\"],\"CZOrLB\":[\"جارٍ تحميل التفاصيل...\"],\"LioGSK\":[\"جارٍ تحميل معجمك...\"],\"Z3FXyt\":[\"جارٍ التحميل...\"],\"1bAISV\":[\"تمت إعادة تعيين البيانات المحلية بنجاح!\"],\"Od5n57\":[\"قم بتسجيل الدخول إلى حسابك الحالي أو قم بالتسجيل للحصول على حساب جديد\"],\"nOhz3x\":[\"تسجيل الخروج\"],\"L9IOec\":[\"إدارة الاشتراك\"],\"c1DM+0\":[\"إدارة مجموعاتك ودراستها.\"],\"QUTgGW\":[\"إدارة معجمك.\"],\"4zd4U3\":[\"إدارة اشتراكك.\"],\"U60v+9\":[\"مصادر\"],\"IPJKNz\":[\"مذكر\"],\"dLgiXX\":[\"مصدر\"],\"SXYWd/\":[\"المصدر \",[\"0\"]],\"6URaYg\":[\"المعنى\"],\"MYTK2T\":[\"المعنى مع هذا الحرف\"],\"zucql+\":[\"القائمة\"],\"qGioCB\":[\"تم تسجيل الترحيل بنجاح.\"],\"O+YlVk\":[\"شهري — $١٠/شهر\"],\"QI9AZD\":[\"أكثر من \",[\"0\"],\" بطاقة للمراجعة\"],\"yf87+x\":[\"الصرف\"],\"60xV9Y\":[\"الصرف ينطبق فقط على الأسماء والأفعال. سيتم إخفاء هذا القسم إذا تم تعيين نوع الكلمة إلى أي شيء آخر.\"],\"qhwV2C\":[\"حسابي\"],\"6YtxFj\":[\"اسم\"],\"TizFpt\":[\"قائمة التنقل\"],\"TQ5Es1\":[\"لا توجد بطاقات متراكمة للمسح.\"],\"WAQMrN\":[\"لا توجد بطاقات مستحقة\"],\"TkUliY\":[\"لا توجد مجموعات بعد\"],\"7+IHTZ\":[\"لم يتم اختيار ملف\"],\"AxPAXW\":[\"لم يتم العثور على نتائج\"],\"vLuosE\":[\"لم يتم العثور على علامات.\"],\"Utp0Ef\":[\"نورد\"],\"tTu2yx\":[\"اسم\"],\"KfoKzr\":[\"صرف الاسم\"],\"zW+FpA\":[\"أو استمر مع\"],\"PMqWHy\":[\"حرف\"],\"UIYada\":[\"اسم مفعول\"],\"9wi5te\":[\"اسم مفعول\"],\"Ff0Dor\":[\"الماضي\"],\"KkgkHx\":[\"الماضي\"],\"uiVVIw\":[\"الماضي\"],\"VHWIM2\":[\"حذف جميع بياناتك نهائيًا بما في ذلك الكلمات والبطاقات والمجموعات.\"],\"1OB0cV\":[\"يرجى الاتصال <0>بالدعم مع التفاصيل التالية:\"],\"HsEwwb\":[\"الرجاء إدخال اسم المجموعة\"],\"nqOcNX\":[\"اختر ملف JSON لمعجمك من فضلك.\"],\"AXJfF/\":[\"حاول مرة أخرى أو أعد تحميل الصفحة.\"],\"fuwKpE\":[\"حاول مرّة أخرى.\"],\"BPig2P\":[\"الجمع\"],\"K5KP2J\":[\"صيغة الجمع \",[\"0\"]],\"zt7UFB\":[\"صيغة الجمع\"],\"u5SHG2\":[\"صيغ جمع\"],\"go9eTo\":[\"حرف\"],\"JuM71B\":[\"حروف الجر\"],\"0Of985\":[\"الحروف التي يمكن استخدامها مع الفعل لتغيير معناه.\"],\"eZb+lw\":[\"المضارع\"],\"24cT5U\":[\"المضارع\"],\"6Kwq+n\":[\"المضارع\"],\"3fPjUY\":[\"برو\"],\"0DYtlD\":[\"المضافة حديثًا\"],\"X5P6yv\":[\"المحدّثة حديثًا\"],\"uabU9X\":[\"المستخدمة مؤخرًا\"],\"7dZnmw\":[\"الصلة\"],\"HpK/8d\":[\"أعد التحميل\"],\"t/YqKh\":[\"احذف\"],\"8dg+Yo\":[\"حقل مطلوب\"],\"+7Cebq\":[\"أعد جدولة جميع البطاقات المتراكمة بتقييمها كـ \\\"صعب\\\".\"],\"ly/6zq\":[\"إعادة التعيين والمزامنة\"],\"vWTWiR\":[\"أعد البطاقة\"],\"7HeQ9b\":[\"إعادة تعيين تقدم البطاقة؟\"],\"2ma9vI\":[\"إعادة تعيين البيانات المحلية\"],\"lLVyir\":[\"إعادة تعيين البيانات المحلية والمزامنة؟\"],\"K/RS6y\":[\"جارٍ إعادة تعيين البيانات المحلية...\"],\"QFtnWs\":[\"بطاقات العكسية\"],\"5k0NLb\":[\"مراجعة\"],\"nqtnG9\":[\"ادرس البطاقات\"],\"HtzuX3\":[\"راجع البطاقات (\",[\"0\"],\" متراكمة)\"],\"TbJrZ9\":[\"راجع البطاقات بالتكرار المتباعد\"],\"05OIsb\":[\"راجع بطاقاتك العربية وقيم فهمك باستخدام خيارات مرة أخرى أو صعب أو جيد أو سهل لتعديل الجدولة.\"],\"cbGyYK\":[\"الجذر\"],\"qMVAMv\":[\"الحروف الأصلية\"],\"tfDRzk\":[\"احفظ\"],\"JAxBTB\":[\"وفّر ٣٠٪\"],\"y3aU20\":[\"حفظ التغييرات\"],\"IUwGEM\":[\"حفظ التغييرات\"],\"bf6lG0\":[\"ترحيلات المخطط\"],\"BnCS55\":[\"ابحث عن علامة...\"],\"VV6Aru\":[\"ابحث عن علامة...\"],\"YIix5Y\":[\"ابحث...\"],\"Du+zn+\":[\"يبحث...\"],\"hid6Sx\":[\"اختر جنسا\"],\"NdMnnc\":[\"اختر إعرابا\"],\"V/vqsf\":[\"حدد أنواع الكلمات التي تريد تضمينها في المجموعة.\"],\"tXQ9KI\":[\"اختر الجنس\"],\"FDpH/H\":[\"جملة\"],\"iw3JO4\":[\"افصل الحروف بمسافات أو فواصل\"],\"Tz0i8g\":[\"الإعدادات\"],\"l8nxCn\":[\"عرض بعد كشف الإجابة\"],\"r0Xcmy\":[\"اعرض الجواب\"],\"vDNaTX\":[\"إظهار الأضداد\"],\"1H95wk\":[\"عرض كتلميح\"],\"BowKyI\":[\"عرض التفاصيل\"],\"C5SZax\":[\"اعرض بطاقات من الإنجليزية إلى العربية.\"],\"+b9Ad2\":[\"عرض المرشحات\"],\"xzH3m9\":[\"إظهار البطاقات العكسية\"],\"maCaRp\":[\"مفرد\"],\"vK/oE0\":[\"تعذر تحميل بعض إدخالات المعجم\"],\"nwtY4N\":[\"حدث خطأ ما\"],\"/HgF9q\":[\"ترتيب حسب\"],\"r20wDW\":[\"نص SQL\"],\"ykSlaQ\":[\"لا يزال لا يعمل؟\"],\"pKr7ta\":[\"أدرس\"],\"+Env0D\":[\"تم إضافة الكلمة بنجاح!\"],\"NJp0hH\":[\"نجح الحذف!\"],\"z6XClS\":[\"تم التصدير بنجاح!\"],\"1uuPpZ\":[\"تم الاستيراد بنجاح!\"],\"/5ZZnV\":[\"تمت إعادة تعيين البطاقة بنجاح.\"],\"oEWC7j\":[\"حدثت الكلمة بنجاح!\"],\"QgnNyZ\":[\"خطأ في المزامنة\"],\"D+NlUC\":[\"نظام\"],\"OYHzN1\":[\"علامات\"],\"iEZ4Fc\":[\"شكرًا لاشتراكك في بهار برو. يمكنك الآن الوصول إلى جميع ميزات برو.\"],\"hz39Yb\":[\"هذا الشفرة غير صالح.\"],\"90dpv/\":[\"هذا البريد الإلكتروني غير صالح.\"],\"7X8sXq\":[\"هذا ليس JSON صالح.\"],\"P7iz9S\":[\"قد يكون التطبيق مفتوحًا في علامة تبويب أخرى. حاول إغلاق علامات التبويب الأخرى وتحديث هذه الصفحة.\"],\"Bm2B8s\":[\"سياق الجملة مثلا رسمي أو عامي.\"],\"MMs+Zk\":[\"تم حذف المجموعة \\\"\",[\"0\"],\"\\\".\"],\"Gpyta0\":[\"صيغة الفعل مثلا I, II, III, IV, هكذا و هكذا...\"],\"OE9TJJ\":[\"صيغة الفعل بالعربية مثلا فعل, أفعل, استفعل, هكذا و هكذا...\"],\"4cDTK/\":[\"قاعدة البيانات المحلية مقفلة بواسطة جلسة أخرى.\"],\"EVX5FZ\":[\"معنى الفعل إذا استعمل مع الحرف.\"],\"bdFFEw\":[\"التصريف.\"],\"nIdeZ6\":[\"الحروف الجذرية للكلمة. يمكن فصل المدخلات بفواصل أو مسافات أو لا تحتوي على محدد مثلا فعل أو ف، ع، ل أو ف ع ل.\"],\"AvErlv\":[\"تمت إضافة الكلمة إلى معجمك.\"],\"LbpyqF\":[\"حدثت الكلمة.\"],\"FEr96N\":[\"المظهر\"],\"uTlsP3\":[\"حدث خطأ أثناء إضافة كلمتك. حاول مرة اخرى.\"],\"boDfXQ\":[\"حدث خطأ أثناء مسح المتراكمات.\"],\"IOwnXs\":[\"حدث خطأ أثناء إنشاء المجموعة\"],\"AObMB6\":[\"حدث خطأ أثناء حذف معجمك. حاول مرة أخرى لاحقا من فضلك.\"],\"QPU+ph\":[\"حدث خطأ أثناء تصدير معجمك. حاول مرة أخرى لاحقا من فضلك.\"],\"+0R2Vl\":[\"حدث خطأ أثناء استيراد لمعجمك. حاول مرة أخرى لاحقا.\"],\"GrwZZY\":[\"حدث خطأ في مزامنة بياناتك. إذا استمرت المشكلة، حاول إعادة تعيين البيانات المحلية من الإعدادات.\"],\"1GLBeM\":[\"حدث خطأ في مزامنة بياناتك. حاول إعادة تعيين البيانات المحلية من الإعدادات.\"],\"Xs1nsK\":[\"حدث خطأ في مزامنة بياناتك. بياناتك المحلية لا تزال متاحة.\"],\"aUu2Qy\":[\"حدث خطأ أثناء تحديث المجموعة\"],\"jObkch\":[\"حدث خطأ أثناء تحديث إعدادات بطاقاتك.\"],\"DvuiAU\":[\"حدث خطأ أثناء تحديث كلمتك. حاول مرة أخرى.\"],\"n//cii\":[\"حدث خطأ أثناء تحميل ترحيل SQL الخاص بك\"],\"p0aTgS\":[\"حدث خطأ أثناء فهرسة بياناتك في محرك البحث.\"],\"7Eqx1H\":[\"حدث خطأ غير متوقع. حاول مرة أخرى من فضلك.\"],\"1hR1ca\":[\"هناك مشكلة مؤقتة في تحميل حسابك. حاول إعادة تحميل الصفحة من فضلك.\"],\"UwqoLj\":[\"هذه الخانة لازم.\"],\"oM4aHs\":[\"هذا حالة غير حساسة.\"],\"GoNjj1\":[\"هذا هو اسم مجموعتك.\"],\"e92j12\":[\"هذا هو إعراب الكلمة.\"],\"fxunD6\":[\"سيؤدي هذا إلى حذف النسخة المحلية من بياناتك المخزنة في هذا المتصفح وتنزيل نسخة جديدة من الخادم. لن تتأثر بياناتك على الخادم. استخدم هذا إذا كنت تواجه أخطاء في المزامنة أو ترى بيانات قديمة.\"],\"lpK0Kp\":[\"سيؤدي هذا إلى حذف جميع كلماتك وبطاقاتك ومجموعاتك نهائيًا. لا يمكن التراجع عن هذا الإجراء.\"],\"NVF43p\":[\"الوقت:\"],\"i1FCIq\":[\"للمراجعة\"],\"1Q2HRv\":[\"تبديل القائمة\"],\"inGj5T\":[\"ليلة طوكيو\"],\"72c5Qo\":[\"الإجمالي\"],\"wFcvZJ\":[\"الترجمة\"],\"/Onh8p\":[\"معرب\"],\"qlwLcm\":[\"استكشاف الأخطاء\"],\"jKoZME\":[\"جرب مصطلح بحث مختلف\"],\"+zy2Nq\":[\"الجنس\"],\"WtTYSX\":[\"أقسام\"],\"xlZRtS\":[\"آه! حدث خطأ ما!\"],\"6njDZ+\":[\"غير قادر على الاتصال بقاعدة البيانات البعيدة.\"],\"WRB75e\":[\"خطأ غير معروف.\"],\"IelE1h\":[\"الترقية إلى برو\"],\"1ZR0xe\":[\"يجب أن تكون القيمة \",[\"0\"],\" أو أكبر\"],\"e5Ml90\":[\"يجب أن تكون القيمة \",[\"0\"],\" أو أقل\"],\"bwa0RV\":[\"فعل\"],\"LnBspw\":[\"صيغة الفعل\"],\"esQ1ry\":[\"صرف الفعل\"],\"WjcFrD\":[\"مصادر للفعل.\"],\"2oIAhB\":[\"المصادر\"],\"s6NYcb\":[\"المصادر\"],\"B4iZJX\":[\"انظر كل الألفاظ في معجمك الشخصي.\"],\"VvvGs4\":[\"لا يمكننا الوصول إلى خوادمنا الآن. تحقق من اتصالك وحاول مرة أخرى.\"],\"dHoQb8\":[\"نواجه مشكلة في إعداد حسابك. حاول مرة أخرى من فضلك.\"],\"eqpeYp\":[\"مرحباً بكم في بحر!\"],\"dZiBrj\":[\"الكلمة\"],\"MJ0gHH\":[\"تمت إضافة الكلمة بنجاح\"],\"wazgbb\":[\"تم حذف الكلمة بنجاح\"],\"2WVQNU\":[\"الكلمة غير موجودة\"],\"Xwf/Kn\":[\"تم تحديث الكلمة بنجاح\"],\"FVyDlC\":[\"الكلمات التي تحتوي على أي من هذه العلامات ستُدرج في المجموعة.\"],\"7niJN/\":[\"الكلمات التي لها معنى عكسي.\"],\"nTIiPJ\":[\"ليس لديك إذن لتحميل ترحيلات المخطط.\"],\"4eom/r\":[\"لديك \",[\"0\"],\" بطاقات متراكمة عندما تكون جاهزًا.\"],\"alITRb\":[\"ليس لديك أي مجموعات بعد.\"],\"XOUb7A\":[\"ليس لديك أي كلمات في قاموسك بعد.\"],\"voqWOr\":[\"أنت جاهز!\"],\"/dColV\":[\"حسابك يحتاج إلى صيانة. تم إخطارنا. حاول مرة أخرى لاحقا من فضلك.\"],\"a8jRIt\":[\"تمت إعادة مزامنة بياناتك من الخادم.\"],\"uRXiIT\":[\"لم يتم إنشاء مجموعتك. يرجى المحاولة مرة أخرى.\"],\"oz/nIQ\":[\"لم يتم تحديث مجموعتك. يرجى المحاولة مرة أخرى.\"],\"L1VLmw\":[\"معجمك\"],\"SB7dXw\":[\"حذف معجمك.\"],\"aQiurv\":[\"تم تحميل معجمك.\"],\"YAeum9\":[\"تم تحديث معجمك!\"],\"C0Fx9N\":[\"معجمك فارغ\"],\"3ma3fF\":[\"معجمك غير صالح. صوب الأخطاء و استورد مرة أخرى من فضلك.\"],\"4bRwmE\":[\"كلمة «محمد» هي معرب.\"],\"kkC1Qd\":[\"كلمة «موسى» هي مبنى.\"],\"jFIhM0\":[\"كلمة «يوسف» هي ممنوع من الصرف.\"]}")as Messages; \ No newline at end of file +/*eslint-disable*/import type{Messages}from"@lingui/core";export const messages=JSON.parse("{\"Wg0uLA\":[[\"0\",\"plural\",{\"one\":[\"علامة واحدة محددة\"],\"two\":[\"علامتان محددتان\"],\"few\":[\"#\",\" علامات محددة\"],\"many\":[\"#\",\" علامة محددة\"],\"other\":[\"#\",\" علامة محددة\"]}]],\"5rgLzy\":[[\"0\",\"plural\",{\"one\":[\"بطاقة متبقية\"],\"other\":[\"بطاقات متبقية\"]}]],\"/hTM9k\":[[\"0\"],\" / \",[\"1\"],\" دفعات\"],\"mHye52\":[[\"0\"],\" / \",[\"1\"],\" بطاقات\"],\"baIPh3\":[[\"0\"],\" بطاقات مستحقة\"],\"beWT44\":[\"تمت إعادة جدولة \",[\"0\"],\" بطاقات.\"],\"JJcBCm\":[[\"0\"],\" إجمالي\"],\"JtTuS0\":[[\"hydrationSkippedCount\",\"plural\",{\"one\":[\"تم تخطي إدخال واحد بسبب مشاكل في البيانات. بياناتك محفوظة، لكن لن تتمكن من البحث عن الإدخال الذي لم يتم تحميله.\"],\"two\":[\"تم تخطي إدخالين بسبب مشاكل في البيانات. بياناتك محفوظة، لكن لن تتمكن من البحث عن الإدخالات التي لم يتم تحميلها.\"],\"few\":[\"تم تخطي \",\"#\",\" إدخالات بسبب مشاكل في البيانات. بياناتك محفوظة، لكن لن تتمكن من البحث عن الإدخالات التي لم يتم تحميلها.\"],\"many\":[\"تم تخطي \",\"#\",\" إدخالًا بسبب مشاكل في البيانات. بياناتك محفوظة، لكن لن تتمكن من البحث عن الإدخالات التي لم يتم تحميلها.\"],\"other\":[\"تم تخطي \",\"#\",\" إدخال بسبب مشاكل في البيانات. بياناتك محفوظة، لكن لن تتمكن من البحث عن الإدخالات التي لم يتم تحميلها.\"]}]],\"UGMDWm\":[\"تم تخطي \",[\"skippedCount\"],\" إدخالات بسبب تلف البيانات.\"],\"gp8eDB\":[[\"totalHits\",\"plural\",{\"one\":[\"نتيجة\"],\"two\":[\"نتيجتان\"],\"few\":[\"نتائج\"],\"many\":[\"نتيجة\"],\"other\":[\"نتيجة\"]}]],\"QSRKsm\":[[\"totalResults\",\"plural\",{\"one\":[[\"totalResults\"],\" نتيجة\"],\"two\":[[\"totalResults\"],\" نتيجتان\"],\"few\":[[\"totalResults\"],\" نتائج\"],\"many\":[[\"totalResults\"],\" نتيجة\"],\"other\":[[\"totalResults\"],\" نتيجة\"]}]],\"gD09hk\":[[\"val\",\"plural\",{\"one\":[\"لا يمكن تجاوز حرف واحد\"],\"two\":[\"لا يمكن تجاوز حرفين\"],\"few\":[\"لا يمكن تجاوز \",\"#\",\" حروف\"],\"many\":[\"لا يمكن تجاوز \",\"#\",\" حرفا\"],\"other\":[\"لا يمكن تجاوز \",\"#\",\" حرف\"]}]],\"I1sa5o\":[[\"val\",\"plural\",{\"one\":[\"يجب أن يكون على الأقل واحد حرف\"],\"two\":[\"يجب أن يكون على الأقل حرفين\"],\"few\":[\"يجب أن يكون على الأقل \",\"#\",\" حروف\"],\"many\":[\"يجب أن يكون على الأقل \",\"#\",\" حرفا\"],\"other\":[\"يجب أن يكون على الأقل \",\"#\",\" حرف\"]}]],\"WWcbHw\":[\"غير فعل أو حرف.\"],\"ZQW2PY\":[\"حرف أو عطف.\"],\"0iy5O2\":[\"فعل.\"],\"7L01XJ\":[\"أعمال\"],\"DQqXHw\":[\"اسم فاعل\"],\"AwJc6G\":[\"اسم فاعل\"],\"rJwPkp\":[\"أضف ترحيل SQL جديد.\"],\"t89Ong\":[\"أضف كلمة جديدة\"],\"L18Pbl\":[\"أضف كلمة جديدة إلى معجمك\"],\"TYPFtT\":[\"أضف علامة واضغط Enter\"],\"iJMhp0\":[\"إضافة الكل\"],\"nPm6bB\":[\"أضف ضدا\"],\"jVmrwy\":[\"أضف ضد\"],\"1x4W9u\":[\"أضف مثلا\"],\"nI3A8B\":[\"أضف مثال\"],\"gLlFHX\":[\"أضف حرف\"],\"aLEtgY\":[\"أضف حرف\"],\"Tcbo6a\":[\"أضف مصدر\"],\"vKbErK\":[\"أضف صيغة جمع\"],\"SNF/r2\":[\"أضف جمع\"],\"cR1WUS\":[\"أضف شيئًا لتبدأ!\"],\"Oft+Pb\":[\"أضف بعض الكلمات للبدء!\"],\"Xls3A3\":[\"أضف علامة \",[\"inputValue\"]],\"VMjLu6\":[\"إضافة العلامة \",[\"value\"]],\"uF1GKn\":[\"أضف علامات إلى كلمتك.\"],\"bDXmnN\":[\"أضف كلمة\"],\"p59pEv\":[\"تفاصيل إضافية\"],\"b/7DUT\":[\"مرة أخرى\"],\"KK8UsT\":[\"انتهيت لليوم!\"],\"7Qi3W5\":[\"تعريف عربية للكلمة.\"],\"Y/gBMP\":[\"ترجمة إنجليزية للجملة.\"],\"jalxln\":[\"ترجمة إنجليزية للكلمة.\"],\"hyC+qY\":[\"حدث خطأ غير متوقع. يمكنك محاولة إعادة تحميل الصفحة لإصلاحه.\"],\"Fl8owW\":[\"سنوي — $٧/شهر\"],\"4xBHUg\":[\"الجواب\"],\"vQXp82\":[\"الضد \",[\"0\"]],\"o9dJs3\":[\"كلمة مضادة\"],\"Hvs4LI\":[\"أضداد\"],\"p1Kh9a\":[\"أية تفاصيل إضافية عن هذه الصيغة مثلا تكرار الاستخدام أو السياق.\"],\"9kni2/\":[\"أية صيغ جمع للكلمة.\"],\"2PPE7k\":[\"سيستبدل كل كلمات التي لديها نفس المعرف.\"],\"cnAqww\":[\"لغة التطبيق\"],\"aAIQg2\":[\"المظهر\"],\"8HV3WN\":[\"العربية\"],\"LNIQwr\":[\"التعريف بالعربية\"],\"uKmc5K\":[\"الجملة بالعربية\"],\"wxIhw3\":[\"صيغة الفعل العربي\"],\"071WZA\":[\"الكلمة بالعربية\"],\"pkD36F\":[\"هل أنت متأكد من حذف \\\"\",[\"0\"],\"\\\"؟\"],\"DOiV7q\":[\"هل أنت متأكد أنك تريد حذف هذه الكلمة؟ سيتم إزالتها من معجمك وسيتم حذف البطاقات بها.<0/><1/><2>لا يمكن التراجع عن هذا الإجراء.\"],\"2cZh44\":[\"هل أنت متأكد من حذف هذه الكلمة؟ لا يمكن التراجع عن هذا الإجراء.\"],\"ikBPhc\":[\"هل أنت متأكد من رغبتك في حذف معجمك؟ سيحذف جميع كلماتك بشكل دائم. لا يمكن التراجع عن هذا الإجراء. صدر معجمك قبل حذفه من فضلك.\"],\"IJr17L\":[\"هل أنت متأكد أنك تريد إعادة تعيين تقدم بطاقة هذه؟ لن يتم تعديل إدخال الكلمة في المعجم، ولكن سيتم التعامل مع بطاقات بها على أنها بطاقات جديدة.<0/><1/><2>لا يمكن التراجع عن هذا الإجراء.\"],\"OsXw/g\":[\"تعبئة تلقائية\"],\"ujMTU0\":[\"فشلت التعبئة التلقائية\"],\"iH8pgl\":[\"رجوع\"],\"0MgdN+\":[\"العودة إلى الأعلى\"],\"KNKCTb\":[\"المتراكمة\"],\"Fg+fNW\":[\"تم مسح المتراكمات!\"],\"vMebS2\":[\"بحر\"],\"EOUool\":[\"تفاصيل أساسية\"],\"cSCbv3\":[\"بيتا\"],\"t/5uBV\":[\"يُدفع $٨٤/سنة\"],\"aIkeAd\":[\"يُدفع شهريًا\"],\"R+w/Va\":[\"الفوترة\"],\"OKWk8n\":[\"بتسجيل الدخول، فإنك توافق على <0>سياسة الخصوصية\"],\"dEgA5A\":[\"ألغ\"],\"oySfhX\":[\"بطاقات مستحقة اليوم أو مؤخرًا\"],\"uV52e1\":[\"بطاقات متأخرة أكثر من ٧ أيام\"],\"zAwyRS\":[\"بطاقات للمراجعة اليوم\"],\"K7tIrx\":[\"الباب\"],\"qWRWG1\":[\"السبب:\"],\"+yPBXI\":[\"اختر ملف\"],\"xCJdfg\":[\"امسح\"],\"ot7qsv\":[\"مسح كل المرشّحات\"],\"saoOio\":[\"امسح المتراكمات\"],\"Oo39Ga\":[\"جارٍ المسح...\"],\"rFmBG3\":[\"سمة الألوان\"],\"mpby9d\":[\"اتصل بالدعم\"],\"M73whl\":[\"السياق\"],\"xGVfLh\":[\"استمر\"],\"RvVi9c\":[\"استمرّ مع بريد الإلكتروني\"],\"NMo6Pj\":[\"تحكم في مكان ظهور الأضداد أثناء المراجعة\"],\"PiH3UR\":[\"تم النسخ!\"],\"he3ygx\":[\"انسخ\"],\"hYgDIe\":[\"إنشاء\"],\"oJc/nD\":[\"أنشئ مجموعة لتنظيم مراجعات بطاقاتك\"],\"wxDqxy\":[\"إنشاء مجموعة جديدة\"],\"oQH8Kl\":[\"أنشئ مجموعة جديدة باختيار الفلاتر. ستكون المجموعة مكونة من البطاقات التي تطابق هذه الفلاتر.\"],\"l7kxcE\":[\"أنشئ مجموعة\"],\"g/Uxjl\":[\"إنشاء مجموعة\"],\"1m75Ii\":[\"أنشئ مجموعتك الأولى\"],\"A+zoTy\":[\"الخطة الحالية\"],\"PQ2zPy\":[\"خصص كيفيّة ظهور البطاقات.\"],\"P+gzBQ\":[\"قم بتخصيص كيف يظهر التطبيق بالنسبة لك.\"],\"ZQKLI1\":[\"منطقة الخطر\"],\"pvnfJD\":[\"غامق\"],\"Wf+eYa\":[\"استكشاف الأخطاء\"],\"LUfCYM\":[\"تم إنشاء المجموعة\"],\"sHVysr\":[\"تم حذف المجموعة\"],\"UzOd8J\":[\"اسم المجموعة\"],\"iJA/GX\":[\"تم إنشاء المجموعة بنجاح!\"],\"M+Nngk\":[\"تم حذف المجموعة بنجاح!\"],\"NVQRbB\":[\"تم تحديث المجموعة بنجاح!\"],\"WWDML8\":[\"تم تحديث المجموعة\"],\"9TyPfF\":[\"المجموعات\"],\"iUt5VS\":[\"تتيح لك المجموعات إنشاء مجموعات فرعية من بطاقاتك التعليمية الموجودة باستخدام الفلاتر على قاموسك، والتي يمكنك دراستها بشكل فردي.\"],\"ovBPCi\":[\"افتراضي\"],\"MbRyzp\":[\"التعريف\"],\"cnGeoo\":[\"احذف\"],\"CYf/wo\":[\"حذف جميع البيانات\"],\"G6sE0d\":[\"حذف المجموعة\"],\"fWNrfJ\":[\"حذف المعجم\"],\"Xpcev7\":[\"حذف كل شيء\"],\"pe67wL\":[\"حذف هذه الكلمة؟\"],\"VEQ9bX\":[\"حذف الكلمة\"],\"/GZNuU\":[\"هل تريد أن تحذف معجمك؟\"],\"Nu4oKW\":[\"الوصف\"],\"URmyfc\":[\"تفاصيل\"],\"wjSthp\":[\"التفاصيل:\"],\"VrH1k+\":[\"معجم\"],\"RPYrAz\":[\"تم حذف المعجم\"],\"460RzB\":[\"ممنوع من الصرف\"],\"bzSI52\":[\"ألغ\"],\"1QfxQT\":[\"اغلق\"],\"Nwbs0q\":[\"لا تعرض\"],\"xifE4+\":[\"المثنى\"],\"jSxAVI\":[\"مثال: ك ت ب\"],\"Pqhtap\":[\"سهل\"],\"ePK91l\":[\"عدَل\"],\"nZQfan\":[\"حرّر \",[\"word\"]],\"4cP5gy\":[\"تعديل المجموعة\"],\"AN/oWt\":[\"تعديل الكلمة\"],\"IQ6Efp\":[\"عدّل مجموعتك\"],\"FEct+T\":[\"عدّل مجموعتك من خلال اختيار الفلاتر. ستتكون المجموعة من البطاقات التي تطابق الفلاتر.\"],\"O3oNi5\":[\"البريد الإلكتروني\"],\"lYGfRP\":[\"الإنجليزية\"],\"7MHe6P\":[\"الترجمة بالإنجليزية\"],\"Ac92c9\":[\"أدخل اسم المجموعة\"],\"ot6UAQ\":[\"أدخل وصفًا لترحيلك\"],\"shwNsK\":[\"أدخل اسم المجموعة\"],\"BTF0Gj\":[\"ادخل رمزك المكون من ٦ أرقام من بريدك الإلكتروني\"],\"ojjQlT\":[\"أدخل نص ترحيل SQL هنا\"],\"CA1DlQ\":[\"العنصر \",[\"arrayIndex\"]],\"Af6M/a\":[\"المثال \",[\"0\"]],\"oea1as\":[\"استخدامات مثالية للكلمة في سياقات مختلفة.\"],\"hFthoo\":[\"أمثلة\"],\"GS+Mus\":[\"صدر\"],\"Mk2MqX\":[\"اكتمل التصدير مع وجود مشاكل\"],\"XydOn5\":[\"فشل التصدير!\"],\"FAMOg+\":[\"تصدير مع البطاقات\"],\"HynDdB\":[\"تصدير معجمك\"],\"cQ+n9e\":[\"تصدير المعجم مع البطاقات سيحفظ تقدم البطاقات بالإضافة إلى كل المحتوى في معجمك. استخدم هذا الخيار إذا كنت ترغب في إنشاء نسخة احتياطية من بياناتك.<0/><1/>تصدير المعجم بدون البطاقات لن يحفظ أي تقدم للبطاقات. استخدم هذا الخيار إذا كنت ترغب في مشاركة معجمك.<2/><3/><4>تحذير: استيراد ملفك بدون البطاقات سيؤدي إلى إعادة تعيين جميع البطاقات.\"],\"1JBTZV\":[\"عبارة\"],\"GiPSsF\":[\"فشل إضافة الكلمة\"],\"zABpXD\":[\"فشل إضافة الكلمة!\"],\"NcBoUU\":[\"فشل تطبيق الترحيل على قاعدة البيانات المحلية.\"],\"eN1Tfn\":[\"فشل مسح المتراكمات\"],\"7hUTxx\":[\"فشل إنشاء المجموعة\"],\"Fr4iT6\":[\"فشل حذف المجموعة\"],\"GCd4Bz\":[\"فشل حذف المعجم\"],\"KLMMnR\":[\"فشل حذف الكلمة\"],\"cncTzY\":[\"فشل الحذف!\"],\"RztBUK\":[\"فشل توليد المثال\"],\"usb0iv\":[\"فشل في إعادة تعيين البيانات المحلية\"],\"dCD/3a\":[\"فشل في استرجاع البيانات من قاعدة البيانات المحلية.\"],\"btG7GG\":[\"فشل استرجاع معلومات قاعدة البيانات.\"],\"CBm+/w\":[\"فشل تحديث المجموعة\"],\"gw2VAF\":[\"فشل في تحديث إعدادات البطاقة.\"],\"tOcErW\":[\"فشل تحديث الإعدادات\"],\"X/iINj\":[\"فشل في تحديث الكلمة!\"],\"cnYJdR\":[\"فشل تحديث الكلمة\"],\"ixyKje\":[\"فشل تحميل الترحيل\"],\"1B52uC\":[\"مؤنّث\"],\"TUSnpz\":[\"فعل\"],\"+6O2ek\":[\"أدخل الكلمة والترجمة والنوع أولاً.\"],\"YCAFdN\":[\"رشّح حسب العلامات...\"],\"cSev+j\":[\"الترشيح\"],\"wG1Flg\":[\"تم تحديث إعدادات البطاقة!\"],\"EiJpdz\":[\"بطاقات\"],\"hpt1Ta\":[\"يتبع لغة جهازك\"],\"tR/FIC\":[\"يتبع إعدادات النظام\"],\"q1hBIe\":[\"مثلا الكلمة\"],\"QRAWTO\":[\"الوزن\"],\"2POOFK\":[\"مجاني\"],\"5iyJje\":[\"جنس\"],\"2Pl4DZ\":[\"توليد مثال\"],\"NOdFZR\":[\"جارٍ التوليد...\"],\"RkXlPZ\":[\"GitHub\"],\"CKyk7Q\":[\"ارجع\"],\"lUTqcW\":[\"الذهاب إلى القاموس\"],\"OEEQKT\":[\"حسن\"],\"VOwQ6g\":[\"أحسنت في المتراكمات! لا يزال لديك \",[\"0\"],\" مراجعات عادية.\"],\"Xv6Pek\":[\"عمل رائع! عد لاحقًا لمزيد من المراجعات.\"],\"g5Fk5U\":[\"صعب\"],\"h4MDwq\":[\"حرف\"],\"IzmuJh\":[\"الحرف \",[\"0\"]],\"D+zLDD\":[\"مخفي\"],\"VMlRqi\":[\"إخفاء التفاصيل\"],\"QWNZbK\":[\"إخفاء المرشحات\"],\"f+BFfG\":[\"تلميح\"],\"i0qMbr\":[\"منزل\"],\"q0alPy\":[\"كيف ينبغي عرض الأضداد في بطاقات؟\"],\"af2WMF\":[\"طريقة تصنف الكلمة حسب نوعها أو سياقها.\"],\"qGZ1pF\":[\"حروف\"],\"7fIUBE\":[\"المعرف:\"],\"mU4ZuB\":[\"إذا لزم الأمر.\"],\"eQI7A0\":[\"إذا كنت تواجه مشاكل في المزامنة أو عدم تحميل البيانات بشكل صحيح، يمكنك إعادة تعيين بياناتك المحلية وإعادة المزامنة من الخادم.\"],\"wqQIcr\":[\"الأمر\"],\"l3s5ri\":[\"استورد\"],\"5LwmgO\":[\"فشل الاستيراد!\"],\"X85Lgt\":[\"تضمين بطاقات الإنجليزية إلى العربية\"],\"O1SPgK\":[\"نوع الملف غير صحيح\"],\"bjwx3z\":[\"مبنى\"],\"d7G5eB\":[\"إعراب\"],\"IaZUGL\":[\"معلومات مثلا الجذر أو المعنى أو الأمثلة.\"],\"FP8ELf\":[\"الصيغة الزمنية غير صالحة\"],\"LpHyjF\":[\"صيغة النص غير صالحة\"],\"xVH/JG\":[\"نوع غير صالح. المتوقع \",[\"0\"]],\"lBmlgJ\":[\"نوع غير صالح. المتوقع \",[\"0\"],\"، المستلم \",[\"1\"]],\"5R5T/G\":[\"قيمة غير صالحة. يجب أن تكون إحدى القيم التالية: \",[\"0\"]],\"SK5zz1\":[\"اسم\"],\"vXIe7J\":[\"اللغة\"],\"1njn7W\":[\"فاتح\"],\"CZOrLB\":[\"جارٍ تحميل التفاصيل...\"],\"LioGSK\":[\"جارٍ تحميل معجمك...\"],\"Z3FXyt\":[\"جارٍ التحميل...\"],\"1bAISV\":[\"تمت إعادة تعيين البيانات المحلية بنجاح!\"],\"Od5n57\":[\"قم بتسجيل الدخول إلى حسابك الحالي أو قم بالتسجيل للحصول على حساب جديد\"],\"nOhz3x\":[\"تسجيل الخروج\"],\"L9IOec\":[\"إدارة الاشتراك\"],\"c1DM+0\":[\"إدارة مجموعاتك ودراستها.\"],\"QUTgGW\":[\"إدارة معجمك.\"],\"4zd4U3\":[\"إدارة اشتراكك.\"],\"U60v+9\":[\"مصادر\"],\"IPJKNz\":[\"مذكر\"],\"dLgiXX\":[\"مصدر\"],\"SXYWd/\":[\"المصدر \",[\"0\"]],\"6URaYg\":[\"المعنى\"],\"MYTK2T\":[\"المعنى مع هذا الحرف\"],\"zucql+\":[\"القائمة\"],\"qGioCB\":[\"تم تسجيل الترحيل بنجاح.\"],\"O+YlVk\":[\"شهري — $١٠/شهر\"],\"QI9AZD\":[\"أكثر من \",[\"0\"],\" بطاقة للمراجعة\"],\"yf87+x\":[\"الصرف\"],\"60xV9Y\":[\"الصرف ينطبق فقط على الأسماء والأفعال. سيتم إخفاء هذا القسم إذا تم تعيين نوع الكلمة إلى أي شيء آخر.\"],\"qhwV2C\":[\"حسابي\"],\"6YtxFj\":[\"اسم\"],\"TizFpt\":[\"قائمة التنقل\"],\"TQ5Es1\":[\"لا توجد بطاقات متراكمة للمسح.\"],\"WAQMrN\":[\"لا توجد بطاقات مستحقة\"],\"TkUliY\":[\"لا توجد مجموعات بعد\"],\"7+IHTZ\":[\"لم يتم اختيار ملف\"],\"AxPAXW\":[\"لم يتم العثور على نتائج\"],\"vLuosE\":[\"لم يتم العثور على علامات.\"],\"Utp0Ef\":[\"نورد\"],\"tTu2yx\":[\"اسم\"],\"KfoKzr\":[\"صرف الاسم\"],\"zW+FpA\":[\"أو استمر مع\"],\"PMqWHy\":[\"حرف\"],\"UIYada\":[\"اسم مفعول\"],\"9wi5te\":[\"اسم مفعول\"],\"Ff0Dor\":[\"الماضي\"],\"KkgkHx\":[\"الماضي\"],\"uiVVIw\":[\"الماضي\"],\"VHWIM2\":[\"حذف جميع بياناتك نهائيًا بما في ذلك الكلمات والبطاقات والمجموعات.\"],\"1OB0cV\":[\"يرجى الاتصال <0>بالدعم مع التفاصيل التالية:\"],\"HsEwwb\":[\"الرجاء إدخال اسم المجموعة\"],\"nqOcNX\":[\"اختر ملف JSON لمعجمك من فضلك.\"],\"AXJfF/\":[\"حاول مرة أخرى أو أعد تحميل الصفحة.\"],\"fuwKpE\":[\"حاول مرّة أخرى.\"],\"6hUL0D\":[\"يرجى الانتظار قبل المحاولة مرة أخرى.\"],\"BPig2P\":[\"الجمع\"],\"K5KP2J\":[\"صيغة الجمع \",[\"0\"]],\"zt7UFB\":[\"صيغة الجمع\"],\"u5SHG2\":[\"صيغ جمع\"],\"go9eTo\":[\"حرف\"],\"JuM71B\":[\"حروف الجر\"],\"0Of985\":[\"الحروف التي يمكن استخدامها مع الفعل لتغيير معناه.\"],\"eZb+lw\":[\"المضارع\"],\"24cT5U\":[\"المضارع\"],\"6Kwq+n\":[\"المضارع\"],\"3fPjUY\":[\"برو\"],\"zbzsUz\":[\"تم الوصول إلى الحد الأقصى\"],\"0DYtlD\":[\"المضافة حديثًا\"],\"X5P6yv\":[\"المحدّثة حديثًا\"],\"uabU9X\":[\"المستخدمة مؤخرًا\"],\"7dZnmw\":[\"الصلة\"],\"HpK/8d\":[\"أعد التحميل\"],\"t/YqKh\":[\"احذف\"],\"8dg+Yo\":[\"حقل مطلوب\"],\"+7Cebq\":[\"أعد جدولة جميع البطاقات المتراكمة بتقييمها كـ \\\"صعب\\\".\"],\"ly/6zq\":[\"إعادة التعيين والمزامنة\"],\"vWTWiR\":[\"أعد البطاقة\"],\"7HeQ9b\":[\"إعادة تعيين تقدم البطاقة؟\"],\"2ma9vI\":[\"إعادة تعيين البيانات المحلية\"],\"lLVyir\":[\"إعادة تعيين البيانات المحلية والمزامنة؟\"],\"K/RS6y\":[\"جارٍ إعادة تعيين البيانات المحلية...\"],\"QFtnWs\":[\"بطاقات العكسية\"],\"5k0NLb\":[\"مراجعة\"],\"nqtnG9\":[\"ادرس البطاقات\"],\"HtzuX3\":[\"راجع البطاقات (\",[\"0\"],\" متراكمة)\"],\"TbJrZ9\":[\"راجع البطاقات بالتكرار المتباعد\"],\"05OIsb\":[\"راجع بطاقاتك العربية وقيم فهمك باستخدام خيارات مرة أخرى أو صعب أو جيد أو سهل لتعديل الجدولة.\"],\"cbGyYK\":[\"الجذر\"],\"qMVAMv\":[\"الحروف الأصلية\"],\"tfDRzk\":[\"احفظ\"],\"JAxBTB\":[\"وفّر ٣٠٪\"],\"y3aU20\":[\"حفظ التغييرات\"],\"IUwGEM\":[\"حفظ التغييرات\"],\"bf6lG0\":[\"ترحيلات المخطط\"],\"BnCS55\":[\"ابحث عن علامة...\"],\"VV6Aru\":[\"ابحث عن علامة...\"],\"YIix5Y\":[\"ابحث...\"],\"Du+zn+\":[\"يبحث...\"],\"hid6Sx\":[\"اختر جنسا\"],\"NdMnnc\":[\"اختر إعرابا\"],\"V/vqsf\":[\"حدد أنواع الكلمات التي تريد تضمينها في المجموعة.\"],\"tXQ9KI\":[\"اختر الجنس\"],\"FDpH/H\":[\"جملة\"],\"iw3JO4\":[\"افصل الحروف بمسافات أو فواصل\"],\"Tz0i8g\":[\"الإعدادات\"],\"l8nxCn\":[\"عرض بعد كشف الإجابة\"],\"r0Xcmy\":[\"اعرض الجواب\"],\"vDNaTX\":[\"إظهار الأضداد\"],\"1H95wk\":[\"عرض كتلميح\"],\"BowKyI\":[\"عرض التفاصيل\"],\"C5SZax\":[\"اعرض بطاقات من الإنجليزية إلى العربية.\"],\"+b9Ad2\":[\"عرض المرشحات\"],\"xzH3m9\":[\"إظهار البطاقات العكسية\"],\"maCaRp\":[\"مفرد\"],\"vK/oE0\":[\"تعذر تحميل بعض إدخالات المعجم\"],\"nwtY4N\":[\"حدث خطأ ما\"],\"fWsBTs\":[\"حدث خطأ ما. يرجى المحاولة مرة أخرى.\"],\"/HgF9q\":[\"ترتيب حسب\"],\"r20wDW\":[\"نص SQL\"],\"ykSlaQ\":[\"لا يزال لا يعمل؟\"],\"pKr7ta\":[\"أدرس\"],\"+Env0D\":[\"تم إضافة الكلمة بنجاح!\"],\"NJp0hH\":[\"نجح الحذف!\"],\"z6XClS\":[\"تم التصدير بنجاح!\"],\"1uuPpZ\":[\"تم الاستيراد بنجاح!\"],\"/5ZZnV\":[\"تمت إعادة تعيين البطاقة بنجاح.\"],\"oEWC7j\":[\"حدثت الكلمة بنجاح!\"],\"QgnNyZ\":[\"خطأ في المزامنة\"],\"D+NlUC\":[\"نظام\"],\"OYHzN1\":[\"علامات\"],\"iEZ4Fc\":[\"شكرًا لاشتراكك في بهار برو. يمكنك الآن الوصول إلى جميع ميزات برو.\"],\"hz39Yb\":[\"هذا الشفرة غير صالح.\"],\"90dpv/\":[\"هذا البريد الإلكتروني غير صالح.\"],\"7X8sXq\":[\"هذا ليس JSON صالح.\"],\"P7iz9S\":[\"قد يكون التطبيق مفتوحًا في علامة تبويب أخرى. حاول إغلاق علامات التبويب الأخرى وتحديث هذه الصفحة.\"],\"Bm2B8s\":[\"سياق الجملة مثلا رسمي أو عامي.\"],\"MMs+Zk\":[\"تم حذف المجموعة \\\"\",[\"0\"],\"\\\".\"],\"Gpyta0\":[\"صيغة الفعل مثلا I, II, III, IV, هكذا و هكذا...\"],\"OE9TJJ\":[\"صيغة الفعل بالعربية مثلا فعل, أفعل, استفعل, هكذا و هكذا...\"],\"4cDTK/\":[\"قاعدة البيانات المحلية مقفلة بواسطة جلسة أخرى.\"],\"EVX5FZ\":[\"معنى الفعل إذا استعمل مع الحرف.\"],\"bdFFEw\":[\"التصريف.\"],\"nIdeZ6\":[\"الحروف الجذرية للكلمة. يمكن فصل المدخلات بفواصل أو مسافات أو لا تحتوي على محدد مثلا فعل أو ف، ع، ل أو ف ع ل.\"],\"AvErlv\":[\"تمت إضافة الكلمة إلى معجمك.\"],\"LbpyqF\":[\"حدثت الكلمة.\"],\"FEr96N\":[\"المظهر\"],\"uTlsP3\":[\"حدث خطأ أثناء إضافة كلمتك. حاول مرة اخرى.\"],\"boDfXQ\":[\"حدث خطأ أثناء مسح المتراكمات.\"],\"IOwnXs\":[\"حدث خطأ أثناء إنشاء المجموعة\"],\"AObMB6\":[\"حدث خطأ أثناء حذف معجمك. حاول مرة أخرى لاحقا من فضلك.\"],\"QPU+ph\":[\"حدث خطأ أثناء تصدير معجمك. حاول مرة أخرى لاحقا من فضلك.\"],\"+0R2Vl\":[\"حدث خطأ أثناء استيراد لمعجمك. حاول مرة أخرى لاحقا.\"],\"GrwZZY\":[\"حدث خطأ في مزامنة بياناتك. إذا استمرت المشكلة، حاول إعادة تعيين البيانات المحلية من الإعدادات.\"],\"1GLBeM\":[\"حدث خطأ في مزامنة بياناتك. حاول إعادة تعيين البيانات المحلية من الإعدادات.\"],\"Xs1nsK\":[\"حدث خطأ في مزامنة بياناتك. بياناتك المحلية لا تزال متاحة.\"],\"aUu2Qy\":[\"حدث خطأ أثناء تحديث المجموعة\"],\"jObkch\":[\"حدث خطأ أثناء تحديث إعدادات بطاقاتك.\"],\"DvuiAU\":[\"حدث خطأ أثناء تحديث كلمتك. حاول مرة أخرى.\"],\"n//cii\":[\"حدث خطأ أثناء تحميل ترحيل SQL الخاص بك\"],\"p0aTgS\":[\"حدث خطأ أثناء فهرسة بياناتك في محرك البحث.\"],\"7Eqx1H\":[\"حدث خطأ غير متوقع. حاول مرة أخرى من فضلك.\"],\"1hR1ca\":[\"هناك مشكلة مؤقتة في تحميل حسابك. حاول إعادة تحميل الصفحة من فضلك.\"],\"UwqoLj\":[\"هذه الخانة لازم.\"],\"oM4aHs\":[\"هذا حالة غير حساسة.\"],\"GoNjj1\":[\"هذا هو اسم مجموعتك.\"],\"e92j12\":[\"هذا هو إعراب الكلمة.\"],\"fxunD6\":[\"سيؤدي هذا إلى حذف النسخة المحلية من بياناتك المخزنة في هذا المتصفح وتنزيل نسخة جديدة من الخادم. لن تتأثر بياناتك على الخادم. استخدم هذا إذا كنت تواجه أخطاء في المزامنة أو ترى بيانات قديمة.\"],\"lpK0Kp\":[\"سيؤدي هذا إلى حذف جميع كلماتك وبطاقاتك ومجموعاتك نهائيًا. لا يمكن التراجع عن هذا الإجراء.\"],\"NVF43p\":[\"الوقت:\"],\"i1FCIq\":[\"للمراجعة\"],\"1Q2HRv\":[\"تبديل القائمة\"],\"inGj5T\":[\"ليلة طوكيو\"],\"72c5Qo\":[\"الإجمالي\"],\"wFcvZJ\":[\"الترجمة\"],\"/Onh8p\":[\"معرب\"],\"qlwLcm\":[\"استكشاف الأخطاء\"],\"jKoZME\":[\"جرب مصطلح بحث مختلف\"],\"+zy2Nq\":[\"الجنس\"],\"WtTYSX\":[\"أقسام\"],\"xlZRtS\":[\"آه! حدث خطأ ما!\"],\"6njDZ+\":[\"غير قادر على الاتصال بقاعدة البيانات البعيدة.\"],\"WRB75e\":[\"خطأ غير معروف.\"],\"IelE1h\":[\"الترقية إلى برو\"],\"1z3VP6\":[\"قم بالترقية إلى برو لتوليد الأمثلة.\"],\"pIqsHO\":[\"قم بالترقية إلى برو لاستخدام التعبئة التلقائية.\"],\"1ZR0xe\":[\"يجب أن تكون القيمة \",[\"0\"],\" أو أكبر\"],\"e5Ml90\":[\"يجب أن تكون القيمة \",[\"0\"],\" أو أقل\"],\"bwa0RV\":[\"فعل\"],\"LnBspw\":[\"صيغة الفعل\"],\"esQ1ry\":[\"صرف الفعل\"],\"WjcFrD\":[\"مصادر للفعل.\"],\"2oIAhB\":[\"المصادر\"],\"s6NYcb\":[\"المصادر\"],\"B4iZJX\":[\"انظر كل الألفاظ في معجمك الشخصي.\"],\"VvvGs4\":[\"لا يمكننا الوصول إلى خوادمنا الآن. تحقق من اتصالك وحاول مرة أخرى.\"],\"dHoQb8\":[\"نواجه مشكلة في إعداد حسابك. حاول مرة أخرى من فضلك.\"],\"eqpeYp\":[\"مرحباً بكم في بحر!\"],\"dZiBrj\":[\"الكلمة\"],\"MJ0gHH\":[\"تمت إضافة الكلمة بنجاح\"],\"wazgbb\":[\"تم حذف الكلمة بنجاح\"],\"2WVQNU\":[\"الكلمة غير موجودة\"],\"Xwf/Kn\":[\"تم تحديث الكلمة بنجاح\"],\"FVyDlC\":[\"الكلمات التي تحتوي على أي من هذه العلامات ستُدرج في المجموعة.\"],\"7niJN/\":[\"الكلمات التي لها معنى عكسي.\"],\"nTIiPJ\":[\"ليس لديك إذن لتحميل ترحيلات المخطط.\"],\"4eom/r\":[\"لديك \",[\"0\"],\" بطاقات متراكمة عندما تكون جاهزًا.\"],\"alITRb\":[\"ليس لديك أي مجموعات بعد.\"],\"XOUb7A\":[\"ليس لديك أي كلمات في قاموسك بعد.\"],\"voqWOr\":[\"أنت جاهز!\"],\"/dColV\":[\"حسابك يحتاج إلى صيانة. تم إخطارنا. حاول مرة أخرى لاحقا من فضلك.\"],\"a8jRIt\":[\"تمت إعادة مزامنة بياناتك من الخادم.\"],\"uRXiIT\":[\"لم يتم إنشاء مجموعتك. يرجى المحاولة مرة أخرى.\"],\"oz/nIQ\":[\"لم يتم تحديث مجموعتك. يرجى المحاولة مرة أخرى.\"],\"L1VLmw\":[\"معجمك\"],\"SB7dXw\":[\"حذف معجمك.\"],\"aQiurv\":[\"تم تحميل معجمك.\"],\"YAeum9\":[\"تم تحديث معجمك!\"],\"C0Fx9N\":[\"معجمك فارغ\"],\"3ma3fF\":[\"معجمك غير صالح. صوب الأخطاء و استورد مرة أخرى من فضلك.\"],\"4bRwmE\":[\"كلمة «محمد» هي معرب.\"],\"kkC1Qd\":[\"كلمة «موسى» هي مبنى.\"],\"jFIhM0\":[\"كلمة «يوسف» هي ممنوع من الصرف.\"]}")as Messages; \ No newline at end of file diff --git a/packages/i18n/locales/en.po b/packages/i18n/locales/en.po index 1eaafd5..3ba3a02 100644 --- a/packages/i18n/locales/en.po +++ b/packages/i18n/locales/en.po @@ -52,7 +52,7 @@ msgstr "{0} total" msgid "{hydrationSkippedCount, plural, one {# entry was skipped due to data issues. Your data is preserved, but you won't be able to search for the entry that wasn't loaded.} other {# entries were skipped due to data issues. Your data is preserved, but you won't be able to search for any entries that weren't loaded.}}" msgstr "{hydrationSkippedCount, plural, one {# entry was skipped due to data issues. Your data is preserved, but you won't be able to search for the entry that wasn't loaded.} other {# entries were skipped due to data issues. Your data is preserved, but you won't be able to search for any entries that weren't loaded.}}" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:123 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:130 msgid "{skippedCount} entries were skipped due to data corruption." msgstr "{skippedCount} entries were skipped due to data corruption." @@ -108,7 +108,7 @@ msgstr "Add a new SQL migration." msgid "Add a new word" msgstr "Add a new word" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:188 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:297 msgid "Add a new word to your dictionary" msgstr "Add a new word to your dictionary" @@ -121,7 +121,7 @@ msgstr "Add a tag and press enter" msgid "Add all" msgstr "Add all" -#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:355 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:440 msgid "Add antonym" msgstr "Add antonym" @@ -130,7 +130,7 @@ msgstr "Add antonym" msgid "Add Antonym" msgstr "Add Antonym" -#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:281 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:324 msgid "Add example" msgstr "Add example" @@ -184,13 +184,13 @@ msgid "Add tags to your word." msgstr "Add tags to your word." #: ../../apps/web/src/routes/_authorized-layout/_search-layout/index.lazy.tsx:113 -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:48 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:56 #: ../../apps/mobile/src/app/(search)/(home)/index.tsx:156 #: ../../apps/mobile/src/app/(search)/(home)/add-word.tsx:71 msgid "Add word" msgstr "Add word" -#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:63 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:105 #: ../../apps/mobile/src/app/(search)/(home)/add-word.tsx:437 #: ../../apps/mobile/src/app/(search)/(home)/edit-word/[id].tsx:547 msgid "Additional Details" @@ -204,11 +204,11 @@ msgstr "Again" msgid "All done for today!" msgstr "All done for today!" -#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:95 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:137 msgid "An Arabic definition of the word." msgstr "An Arabic definition of the word." -#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:216 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:258 msgid "An English translation of the sentence." msgstr "An English translation of the sentence." @@ -220,7 +220,7 @@ msgstr "An English translation of the word." msgid "An unexpected error occurred. You can try reloading the page to fix it." msgstr "An unexpected error occurred. You can try reloading the page to fix it." -#: ../../apps/web/src/components/features/settings/BillingSettingsCard.tsx:99 +#: ../../apps/web/src/components/features/settings/BillingSettingsCard.tsx:101 msgid "Annual — $7/mo" msgstr "Annual — $7/mo" @@ -231,7 +231,7 @@ msgid "Answer" msgstr "Answer" #. placeholder {0}: index + 1 -#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:300 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:385 msgid "Antonym {0}" msgstr "Antonym {0}" @@ -240,7 +240,7 @@ msgstr "Antonym {0}" msgid "Antonym word" msgstr "Antonym word" -#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:288 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:373 #: ../../apps/mobile/src/app/(search)/(home)/add-word.tsx:555 #: ../../apps/mobile/src/app/(search)/(home)/edit-word/[id].tsx:665 msgid "Antonyms" @@ -255,7 +255,7 @@ msgstr "Any additional details about this form such as frequency of usage or con msgid "Any plural forms of the word." msgstr "Any plural forms of the word." -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:419 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:426 msgid "Any words that have the same ID will be overwritten." msgstr "Any words that have the same ID will be overwritten." @@ -263,7 +263,7 @@ msgstr "Any words that have the same ID will be overwritten." msgid "App language" msgstr "App language" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:199 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:206 #: ../../apps/mobile/src/app/(search)/settings.tsx:236 msgid "Appearance" msgstr "Appearance" @@ -296,7 +296,7 @@ msgstr "Arabic word" msgid "Are you sure you want to delete \"{0}\"?" msgstr "Are you sure you want to delete \"{0}\"?" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:140 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:147 msgid "Are you sure you want to delete this word? It will be removed from your dictionary and its flashcards will be deleted.<0/><1/><2>This action cannot be undone." msgstr "Are you sure you want to delete this word? It will be removed from your dictionary and its flashcards will be deleted.<0/><1/><2>This action cannot be undone." @@ -304,16 +304,28 @@ msgstr "Are you sure you want to delete this word? It will be removed from your msgid "Are you sure you want to delete this word? This action cannot be undone." msgstr "Are you sure you want to delete this word? This action cannot be undone." -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:496 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:503 msgid "Are you sure you want to delete your dictionary? All your words will be deleted permanently. This action cannot be undone. Please make sure to export your dictionary before deleting it." msgstr "Are you sure you want to delete your dictionary? All your words will be deleted permanently. This action cannot be undone. Please make sure to export your dictionary before deleting it." -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:88 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:95 msgid "Are you sure you want to reset this flashcard's progress? The word entry in the dictionary will not be modified, but its corresponding flashcards will be treated as new ones.<0/><1/><2>This action cannot be undone." msgstr "Are you sure you want to reset this flashcard's progress? The word entry in the dictionary will not be modified, but its corresponding flashcards will be treated as new ones.<0/><1/><2>This action cannot be undone." -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:216 -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:74 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:485 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:538 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:325 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:382 +msgid "Autofill" +msgstr "Autofill" + +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:367 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:209 +msgid "Autofill failed" +msgstr "Autofill failed" + +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:223 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:82 msgid "Back" msgstr "Back" @@ -347,24 +359,24 @@ msgstr "Basic Details" msgid "BETA" msgstr "BETA" -#: ../../apps/web/src/components/features/settings/BillingSettingsCard.tsx:111 +#: ../../apps/web/src/components/features/settings/BillingSettingsCard.tsx:113 msgid "Billed $84/year" msgstr "Billed $84/year" -#: ../../apps/web/src/components/features/settings/BillingSettingsCard.tsx:86 +#: ../../apps/web/src/components/features/settings/BillingSettingsCard.tsx:88 msgid "Billed monthly" msgstr "Billed monthly" -#: ../../apps/web/src/components/features/settings/BillingSettingsCard.tsx:39 +#: ../../apps/web/src/components/features/settings/BillingSettingsCard.tsx:41 msgid "Billing" msgstr "Billing" -#: ../../apps/web/src/routes/_unauthorized-layout/login/route.lazy.tsx:159 +#: ../../apps/web/src/routes/_unauthorized-layout/login/route.lazy.tsx:164 msgid "By signing in, you agree to our <0>Privacy Policy" msgstr "By signing in, you agree to our <0>Privacy Policy" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:514 -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:594 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:521 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:601 #: ../../apps/mobile/src/app/(search)/settings.tsx:128 #: ../../apps/mobile/src/app/(search)/decks.tsx:283 #: ../../apps/mobile/src/app/(search)/(home)/add-word.tsx:995 @@ -415,7 +427,7 @@ msgstr "Clear backlog" #~ msgid "Clearing..." #~ msgstr "Clearing..." -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:217 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:224 msgid "Color theme" msgstr "Color theme" @@ -423,7 +435,7 @@ msgstr "Color theme" msgid "Contact support" msgstr "Contact support" -#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:231 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:273 msgid "Context" msgstr "Context" @@ -432,7 +444,7 @@ msgstr "Context" msgid "Continue" msgstr "Continue" -#: ../../apps/web/src/routes/_unauthorized-layout/login/route.lazy.tsx:137 +#: ../../apps/web/src/routes/_unauthorized-layout/login/route.lazy.tsx:142 #: ../../apps/mobile/src/app/(auth)/login.tsx:105 msgid "Continue with Email" msgstr "Continue with Email" @@ -478,7 +490,7 @@ msgstr "Create Deck" msgid "Create your first deck" msgstr "Create your first deck" -#: ../../apps/web/src/components/features/settings/BillingSettingsCard.tsx:51 +#: ../../apps/web/src/components/features/settings/BillingSettingsCard.tsx:53 msgid "Current plan" msgstr "Current plan" @@ -486,7 +498,7 @@ msgstr "Current plan" msgid "Customize how flashcards appear." msgstr "Customize how flashcards appear." -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:203 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:210 msgid "Customize how the application looks for you." msgstr "Customize how the application looks for you." @@ -499,7 +511,7 @@ msgstr "Danger Zone" msgid "Dark" msgstr "Dark" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:530 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:537 msgid "Debugging" msgstr "Debugging" @@ -549,17 +561,17 @@ msgid "Default" msgstr "Default" #: ../../apps/web/src/components/search/InfiniteScroll.tsx:138 -#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:81 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:123 #: ../../apps/mobile/src/components/dictionary/DictionaryEntryCard.tsx:117 #: ../../apps/mobile/src/app/(search)/(home)/add-word.tsx:444 #: ../../apps/mobile/src/app/(search)/(home)/edit-word/[id].tsx:554 msgid "Definition" msgstr "Definition" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:485 -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:508 -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:129 -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:161 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:492 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:515 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:136 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:168 #: ../../apps/web/src/routes/_authorized-layout/_app-layout/decks/route.lazy.tsx:207 #: ../../apps/mobile/src/app/(search)/decks.tsx:285 #: ../../apps/mobile/src/app/(search)/(home)/edit-word/[id].tsx:393 @@ -582,7 +594,7 @@ msgstr "Delete Dictionary" msgid "Delete Everything" msgstr "Delete Everything" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:136 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:143 msgid "Delete this word?" msgstr "Delete this word?" @@ -590,7 +602,7 @@ msgstr "Delete this word?" msgid "Delete word" msgstr "Delete word" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:492 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:499 msgid "Delete your dictionary?" msgstr "Delete your dictionary?" @@ -607,7 +619,7 @@ msgstr "Details" msgid "Details:" msgstr "Details:" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:234 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:241 msgid "Dictionary" msgstr "Dictionary" @@ -619,8 +631,8 @@ msgstr "Dictionary deleted" msgid "Diptote" msgstr "Diptote" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:194 -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:221 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:348 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:420 msgid "Discard" msgstr "Discard" @@ -653,7 +665,7 @@ msgstr "Easy" msgid "Edit" msgstr "Edit" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:188 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:195 msgid "Edit {word}" msgstr "Edit {word}" @@ -674,7 +686,7 @@ msgstr "Edit your deck" msgid "Edit your deck by choosing filters. The deck will be composed of the cards that match the filters." msgstr "Edit your deck by choosing filters. The deck will be composed of the cards that match the filters." -#: ../../apps/web/src/routes/_unauthorized-layout/login/route.lazy.tsx:111 +#: ../../apps/web/src/routes/_unauthorized-layout/login/route.lazy.tsx:116 #: ../../apps/mobile/src/app/(auth)/login.tsx:68 msgid "Email" msgstr "Email" @@ -716,46 +728,46 @@ msgid "Entry {arrayIndex}" msgstr "Entry {arrayIndex}" #. placeholder {0}: index + 1 -#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:166 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:208 #: ../../apps/mobile/src/app/(search)/(home)/add-word.tsx:499 #: ../../apps/mobile/src/app/(search)/(home)/edit-word/[id].tsx:609 msgid "Example {0}" msgstr "Example {0}" -#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:158 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:200 msgid "Example usages of the word in different contexts." msgstr "Example usages of the word in different contexts." #: ../../apps/web/src/components/search/InfiniteScroll.tsx:292 -#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:154 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:196 #: ../../apps/mobile/src/components/dictionary/DictionaryEntryCard.tsx:262 #: ../../apps/mobile/src/app/(search)/(home)/add-word.tsx:490 #: ../../apps/mobile/src/app/(search)/(home)/edit-word/[id].tsx:600 msgid "Examples" msgstr "Examples" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:429 -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:465 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:436 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:472 msgid "Export" msgstr "Export" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:122 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:129 msgid "Export completed with issues" msgstr "Export completed with issues" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:132 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:139 msgid "Export failed!" msgstr "Export failed!" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:473 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:480 msgid "Export with flashcards" msgstr "Export with flashcards" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:436 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:443 msgid "Export your dictionary" msgstr "Export your dictionary" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:440 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:447 msgid "Exporting dictionary with flaschards will save your flashcard progress along with all the content in your dictionary. Use this option if you want to make a backup of your data.<0/><1/>Exporting your dictionary without flashcards will not save any flashcard progress. Use this option if you want to share your dictionary.<2/><3/><4>Warning: Importing your file without flashcards will reset all of your flashcards." msgstr "Exporting dictionary with flaschards will save your flashcard progress along with all the content in your dictionary. Use this option if you want to make a backup of your data.<0/><1/>Exporting your dictionary without flashcards will not save any flashcard progress. Use this option if you want to share your dictionary.<2/><3/><4>Warning: Importing your file without flashcards will reset all of your flashcards." @@ -771,7 +783,7 @@ msgstr "Expression" msgid "Failed to add word" msgstr "Failed to add word" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:165 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:177 msgid "Failed to add word!" msgstr "Failed to add word!" @@ -799,11 +811,15 @@ msgstr "Failed to delete dictionary" msgid "Failed to delete word" msgstr "Failed to delete word" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:172 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:179 msgid "Failed to delete!" msgstr "Failed to delete!" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:581 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:90 +msgid "Failed to generate example" +msgstr "Failed to generate example" + +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:588 msgid "Failed to reset local data" msgstr "Failed to reset local data" @@ -827,7 +843,7 @@ msgstr "Failed to update flashcard settings." msgid "Failed to update settings" msgstr "Failed to update settings" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:330 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:341 msgid "Failed to update the word!" msgstr "Failed to update the word!" @@ -852,6 +868,13 @@ msgstr "Feminine" msgid "Fi'l" msgstr "Fi'l" +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:498 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:551 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:338 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:395 +msgid "Fill in the word, translation, and type first." +msgstr "Fill in the word, translation, and type first." + #: ../../apps/web/src/components/features/dictionary/filters/TagsFilter.tsx:51 msgid "Filter by tags..." msgstr "Filter by tags..." @@ -888,7 +911,7 @@ msgstr "For example, the word" msgid "Form" msgstr "Form" -#: ../../apps/web/src/components/features/settings/BillingSettingsCard.tsx:25 +#: ../../apps/web/src/components/features/settings/BillingSettingsCard.tsx:30 msgid "Free" msgstr "Free" @@ -900,7 +923,19 @@ msgstr "Free" msgid "Gender" msgstr "Gender" -#: ../../apps/web/src/routes/_unauthorized-layout/login/route.lazy.tsx:155 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:355 +msgid "Generate example" +msgstr "Generate example" + +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:483 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:536 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:323 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:380 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:353 +msgid "Generating..." +msgstr "Generating..." + +#: ../../apps/web/src/routes/_unauthorized-layout/login/route.lazy.tsx:160 #: ../../apps/mobile/src/components/GithubLoginButton.tsx:24 msgid "GitHub" msgstr "GitHub" @@ -910,7 +945,7 @@ msgstr "GitHub" msgid "Go back" msgstr "Go back" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/checkout-success/route.lazy.tsx:36 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/checkout-success/route.lazy.tsx:44 msgid "Go to dictionary" msgstr "Go to dictionary" @@ -961,8 +996,8 @@ msgstr "Hide filters" msgid "Hint" msgstr "Hint" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:179 -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:39 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:186 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:47 #: ../../apps/web/src/components/MobileHeader.tsx:154 #: ../../apps/web/src/components/DesktopNavigation.tsx:53 #: ../../apps/web/src/components/DesktopNavigation.tsx:59 @@ -992,7 +1027,7 @@ msgstr "ID:" msgid "if needed." msgstr "if needed." -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:534 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:541 msgid "If you're experiencing sync issues or data not loading correctly, you can reset your local data and re-sync from the server." msgstr "If you're experiencing sync issues or data not loading correctly, you can reset your local data and re-sync from the server." @@ -1004,12 +1039,12 @@ msgstr "If you're experiencing sync issues or data not loading correctly, you ca msgid "Imperative" msgstr "Imperative" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:393 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:400 msgid "Import" msgstr "Import" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:365 -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:371 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:372 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:378 msgid "Import failed!" msgstr "Import failed!" @@ -1017,7 +1052,7 @@ msgstr "Import failed!" msgid "Include English to Arabic flashcards" msgstr "Include English to Arabic flashcards" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:253 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:260 msgid "Incorrect file type" msgstr "Incorrect file type" @@ -1031,7 +1066,7 @@ msgstr "Indeclinable" msgid "Inflection" msgstr "Inflection" -#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:67 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:109 msgid "Information such as the word's root, meaning, and examples." msgstr "Information such as the word's root, meaning, and examples." @@ -1063,7 +1098,7 @@ msgstr "Invalid value. Expected one of: {0}" msgid "Ism" msgstr "Ism" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:224 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:231 #: ../../apps/mobile/src/app/(search)/settings.tsx:258 msgid "Language" msgstr "Language" @@ -1090,7 +1125,7 @@ msgstr "Loading..." #~ msgid "Local data reset successfully!" #~ msgstr "Local data reset successfully!" -#: ../../apps/web/src/routes/_unauthorized-layout/login/route.lazy.tsx:93 +#: ../../apps/web/src/routes/_unauthorized-layout/login/route.lazy.tsx:98 #: ../../apps/mobile/src/app/(auth)/login.tsx:63 msgid "Log in to your existing account or sign up for a new one" msgstr "Log in to your existing account or sign up for a new one" @@ -1101,7 +1136,7 @@ msgstr "Log in to your existing account or sign up for a new one" msgid "Logout" msgstr "Logout" -#: ../../apps/web/src/components/features/settings/BillingSettingsCard.tsx:61 +#: ../../apps/web/src/components/features/settings/BillingSettingsCard.tsx:63 msgid "Manage Subscription" msgstr "Manage Subscription" @@ -1109,11 +1144,11 @@ msgstr "Manage Subscription" msgid "Manage your decks and study them." msgstr "Manage your decks and study them." -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:238 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:245 msgid "Manage your dictionary." msgstr "Manage your dictionary." -#: ../../apps/web/src/components/features/settings/BillingSettingsCard.tsx:43 +#: ../../apps/web/src/components/features/settings/BillingSettingsCard.tsx:45 msgid "Manage your subscription." msgstr "Manage your subscription." @@ -1154,7 +1189,7 @@ msgstr "Menu" msgid "Migration successfully registered." msgstr "Migration successfully registered." -#: ../../apps/web/src/components/features/settings/BillingSettingsCard.tsx:82 +#: ../../apps/web/src/components/features/settings/BillingSettingsCard.tsx:84 msgid "Monthly — $10/mo" msgstr "Monthly — $10/mo" @@ -1227,7 +1262,7 @@ msgstr "Noun" msgid "Noun Morphology" msgstr "Noun Morphology" -#: ../../apps/web/src/routes/_unauthorized-layout/login/route.lazy.tsx:149 +#: ../../apps/web/src/routes/_unauthorized-layout/login/route.lazy.tsx:154 #: ../../apps/mobile/src/app/(auth)/login.tsx:111 msgid "Or continue with" msgstr "Or continue with" @@ -1272,11 +1307,11 @@ msgstr "Please contact <0>support with the following details:" msgid "Please enter a deck name" msgstr "Please enter a deck name" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:254 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:261 msgid "Please select a JSON file with your dictionary." msgstr "Please select a JSON file with your dictionary." -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:582 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:589 msgid "Please try again or reload the page." msgstr "Please try again or reload the page." @@ -1287,6 +1322,12 @@ msgstr "Please try again or reload the page." msgid "Please try again." msgstr "Please try again." +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:364 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:206 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:87 +msgid "Please wait before trying again." +msgstr "Please wait before trying again." + #: ../../apps/web/src/components/search/InfiniteScroll.tsx:188 #: ../../apps/mobile/src/components/dictionary/DictionaryEntryCard.tsx:159 msgid "Plural" @@ -1337,10 +1378,16 @@ msgstr "Present tense" msgid "Present Tense" msgstr "Present Tense" -#: ../../apps/web/src/components/features/settings/BillingSettingsCard.tsx:23 +#: ../../apps/web/src/components/features/settings/BillingSettingsCard.tsx:27 msgid "Pro" msgstr "Pro" +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:363 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:205 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:86 +msgid "Rate limit reached" +msgstr "Rate limit reached" + #: ../../apps/web/src/components/features/dictionary/filters/DictionaryFilters.tsx:36 msgid "Recently added" msgstr "Recently added" @@ -1364,8 +1411,8 @@ msgstr "Reload" #: ../../apps/web/src/components/features/dictionary/add/VerbMorphologyCardSection.tsx:251 #: ../../apps/web/src/components/features/dictionary/add/VerbMorphologyCardSection.tsx:408 #: ../../apps/web/src/components/features/dictionary/add/IsmMorphologyCardSection.tsx:183 -#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:263 -#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:337 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:305 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:422 msgid "Remove" msgstr "Remove" @@ -1377,28 +1424,28 @@ msgstr "Required field" msgid "Reschedule all backlog cards by grading them as \"Hard\"." msgstr "Reschedule all backlog cards by grading them as \"Hard\"." -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:588 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:595 msgid "Reset and re-sync" msgstr "Reset and re-sync" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:77 -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:111 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:84 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:118 msgid "Reset flashcard" msgstr "Reset flashcard" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:84 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:91 msgid "Reset flashcard progress?" msgstr "Reset flashcard progress?" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:546 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:553 msgid "Reset local data" msgstr "Reset local data" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:553 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:560 msgid "Reset local data and re-sync?" msgstr "Reset local data and re-sync?" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:186 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:193 msgid "Resetting local data..." msgstr "Resetting local data..." @@ -1429,7 +1476,7 @@ msgstr "Review flashcards with spaced repetition" msgid "Review your Arabic flashcards and grade your understanding with Again, Hard, Good, or Easy options to adjust scheduling." msgstr "Review your Arabic flashcards and grade your understanding with Again, Hard, Good, or Easy options to adjust scheduling." -#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:120 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:162 msgid "Root letters" msgstr "Root letters" @@ -1438,17 +1485,17 @@ msgstr "Root letters" msgid "Root Letters" msgstr "Root Letters" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:356 -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:385 -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:199 -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:226 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:509 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:583 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:353 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:425 #: ../../apps/web/src/components/features/settings/FlashcardSettingsCardSection.tsx:232 #: ../../apps/web/src/components/features/settings/AdminSettingsCardSection.tsx:146 #: ../../apps/mobile/src/app/(search)/(home)/add-word.tsx:1005 msgid "Save" msgstr "Save" -#: ../../apps/web/src/components/features/settings/BillingSettingsCard.tsx:105 +#: ../../apps/web/src/components/features/settings/BillingSettingsCard.tsx:107 msgid "Save 30%" msgstr "Save 30%" @@ -1504,7 +1551,7 @@ msgstr "Select the types of words that you want to include in the deck." msgid "Select type" msgstr "Select type" -#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:176 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:218 msgid "Sentence" msgstr "Sentence" @@ -1513,7 +1560,7 @@ msgstr "Sentence" msgid "Separate letters with spaces or commas" msgstr "Separate letters with spaces or commas" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:193 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:200 #: ../../apps/web/src/components/MobileHeader.tsx:178 #: ../../apps/web/src/components/DesktopNavigation.tsx:107 #: ../../apps/mobile/src/app/(search)/settings.tsx:175 @@ -1569,6 +1616,12 @@ msgstr "Some dictionary entries couldn't be loaded" msgid "Something went wrong" msgstr "Something went wrong" +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:368 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:210 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:91 +msgid "Something went wrong. Please try again." +msgstr "Something went wrong. Please try again." + #: ../../apps/web/src/components/features/dictionary/filters/DictionaryFilters.tsx:161 msgid "Sort by" msgstr "Sort by" @@ -1585,27 +1638,27 @@ msgstr "Still not working?" msgid "Study" msgstr "Study" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:157 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:169 msgid "Successfully added word!" msgstr "Successfully added word!" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:166 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:173 msgid "Successfully deleted!" msgstr "Successfully deleted!" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:126 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:133 msgid "Successfully exported!" msgstr "Successfully exported!" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:342 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:349 msgid "Successfully imported!" msgstr "Successfully imported!" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:106 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:113 msgid "Successfully reset the flashcard." msgstr "Successfully reset the flashcard." -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:322 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:333 msgid "Successfully updated the word!" msgstr "Successfully updated the word!" @@ -1629,7 +1682,7 @@ msgstr "System" msgid "Tags" msgstr "Tags" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/checkout-success/route.lazy.tsx:26 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/checkout-success/route.lazy.tsx:34 msgid "Thank you for subscribing to Bahar Pro. You now have access to all Pro features." msgstr "Thank you for subscribing to Bahar Pro. You now have access to all Pro features." @@ -1652,7 +1705,7 @@ msgstr "That is not valid JSON." msgid "The app may be open in another tab. Try closing other tabs and refreshing this page." msgstr "The app may be open in another tab. Try closing other tabs and refreshing this page." -#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:245 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:287 msgid "The context of the sentence, ex. formal or colloquial." msgstr "The context of the sentence, ex. formal or colloquial." @@ -1681,24 +1734,24 @@ msgstr "The meaning of the verb when used with the harf." msgid "The morphological breakdown of the word." msgstr "The morphological breakdown of the word." -#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:135 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:177 msgid "The root letters of the word. The input can be separated by commas, spaces or have no delimeter ex. فعل or ف, ع, ل or ف ع ل." msgstr "The root letters of the word. The input can be separated by commas, spaces or have no delimeter ex. فعل or ف, ع, ل or ف ع ل." -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:158 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:170 msgid "The word has been added to your dictionary." msgstr "The word has been added to your dictionary." -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:323 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:334 msgid "The word has been updated." msgstr "The word has been updated." -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:210 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:217 #: ../../apps/mobile/src/app/(search)/settings.tsx:243 msgid "Theme" msgstr "Theme" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:166 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:178 msgid "There was an error adding your word. Please try again." msgstr "There was an error adding your word. Please try again." @@ -1710,15 +1763,15 @@ msgstr "There was an error clearing your backlog." msgid "There was an error creating the deck" msgstr "There was an error creating the deck" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:173 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:180 msgid "There was an error deleting your dictionary. Please try again later." msgstr "There was an error deleting your dictionary. Please try again later." -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:133 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:140 msgid "There was an error exporting your dictionary. Please try again later." msgstr "There was an error exporting your dictionary. Please try again later." -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:372 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:379 msgid "There was an error importing your dictionary. Please try again later." msgstr "There was an error importing your dictionary. Please try again later." @@ -1742,7 +1795,7 @@ msgstr "There was an error updating the deck" msgid "There was an error updating your flashcard settings." msgstr "There was an error updating your flashcard settings." -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:331 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:342 msgid "There was an error updating your word. Please try again." msgstr "There was an error updating your word. Please try again." @@ -1773,7 +1826,7 @@ msgstr "There's a temporary issue loading your account. Please try reloading the msgid "This field is required." msgstr "This field is required." -#: ../../apps/web/src/routes/_unauthorized-layout/login/route.lazy.tsx:119 +#: ../../apps/web/src/routes/_unauthorized-layout/login/route.lazy.tsx:124 #: ../../apps/mobile/src/app/(auth)/login.tsx:94 msgid "This is case insensitive." msgstr "This is case insensitive." @@ -1786,7 +1839,7 @@ msgstr "This is the name of your deck." msgid "This refers to how many case endings the word can take." msgstr "This refers to how many case endings the word can take." -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:557 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:564 msgid "This will delete the local copy of your data stored in this browser and download a fresh copy from the server. Your data on the server will not be affected. Use this if you're experiencing sync errors or seeing outdated data." msgstr "This will delete the local copy of your data stored in this browser and download a fresh copy from the server. Your data on the server will not be affected. Use this if you're experiencing sync errors or seeing outdated data." @@ -1815,7 +1868,7 @@ msgid "Total" msgstr "Total" #: ../../apps/web/src/components/features/dictionary/add/BasicDetailsFormSection.tsx:64 -#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:202 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:244 #: ../../apps/mobile/src/app/(search)/(home)/add-word.tsx:381 #: ../../apps/mobile/src/app/(search)/(home)/edit-word/[id].tsx:491 msgid "Translation" @@ -1857,10 +1910,21 @@ msgstr "Unable to connect to remote database." msgid "Unknown error." msgstr "Unknown error." -#: ../../apps/web/src/components/features/settings/BillingSettingsCard.tsx:69 +#: ../../apps/web/src/components/features/settings/BillingSettingsCard.tsx:71 msgid "Upgrade to Pro" msgstr "Upgrade to Pro" +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:363 +msgid "Upgrade to Pro to generate examples." +msgstr "Upgrade to Pro to generate examples." + +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:493 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/edit/$wordId.tsx:546 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:333 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx:390 +msgid "Upgrade to Pro to use AI autofill." +msgstr "Upgrade to Pro to use AI autofill." + #. placeholder {0}: String(err.minimum) #: ../../apps/web/src/lib/error.ts:128 msgid "Value must be {0} or greater" @@ -1913,7 +1977,7 @@ msgstr "We can't reach our servers right now. Check your connection and try agai msgid "We're having trouble with your account setup. Please try again." msgstr "We're having trouble with your account setup. Please try again." -#: ../../apps/web/src/routes/_unauthorized-layout/login/route.lazy.tsx:89 +#: ../../apps/web/src/routes/_unauthorized-layout/login/route.lazy.tsx:94 #: ../../apps/mobile/src/app/(auth)/login.tsx:59 msgid "Welcome to Bahar!" msgstr "Welcome to Bahar!" @@ -1921,7 +1985,7 @@ msgstr "Welcome to Bahar!" #: ../../apps/web/src/components/features/dictionary/add/VerbMorphologyCardSection.tsx:192 #: ../../apps/web/src/components/features/dictionary/add/IsmMorphologyCardSection.tsx:125 #: ../../apps/web/src/components/features/dictionary/add/BasicDetailsFormSection.tsx:40 -#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:310 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:395 #: ../../apps/mobile/src/app/(search)/(home)/add-word.tsx:357 #: ../../apps/mobile/src/app/(search)/(home)/edit-word/[id].tsx:467 msgid "Word" @@ -1947,7 +2011,7 @@ msgstr "Word updated successfully" msgid "Words that have any of these tags will be included in the deck." msgstr "Words that have any of these tags will be included in the deck." -#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:292 +#: ../../apps/web/src/components/features/dictionary/add/AdditionalDetailsFormSection.tsx:377 msgid "Words that have the opposite meaning." msgstr "Words that have the opposite meaning." @@ -1968,7 +2032,7 @@ msgstr "You have no decks yet." msgid "You have no words in your dictionary yet." msgstr "You have no words in your dictionary yet." -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/checkout-success/route.lazy.tsx:22 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/checkout-success/route.lazy.tsx:30 msgid "You're all set!" msgstr "You're all set!" @@ -1993,15 +2057,15 @@ msgstr "Your deck was not updated. Please try again." msgid "Your Dictionary" msgstr "Your Dictionary" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:167 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:174 msgid "Your dictionary has been deleted." msgstr "Your dictionary has been deleted." -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:127 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:134 msgid "Your dictionary has been downloaded." msgstr "Your dictionary has been downloaded." -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:343 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:350 msgid "Your dictionary has been updated!" msgstr "Your dictionary has been updated!" @@ -2009,7 +2073,7 @@ msgstr "Your dictionary has been updated!" msgid "Your dictionary is empty" msgstr "Your dictionary is empty" -#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:366 +#: ../../apps/web/src/routes/_authorized-layout/_app-layout/settings/route.lazy.tsx:373 msgid "Your dictionary is not valid. Please fix the errors and upload it again." msgstr "Your dictionary is not valid. Please fix the errors and upload it again." diff --git a/packages/i18n/locales/en.ts b/packages/i18n/locales/en.ts index 6233374..c4b0855 100644 --- a/packages/i18n/locales/en.ts +++ b/packages/i18n/locales/en.ts @@ -1 +1 @@ -/*eslint-disable*/import type{Messages}from"@lingui/core";export const messages=JSON.parse("{\"Wg0uLA\":[[\"0\",\"plural\",{\"one\":[\"#\",\" tag selected\"],\"other\":[\"#\",\" tags selected\"]}]],\"5rgLzy\":[[\"0\",\"plural\",{\"one\":[\"card left\"],\"other\":[\"cards left\"]}]],\"/hTM9k\":[[\"0\"],\" / \",[\"1\"],\" batches\"],\"mHye52\":[[\"0\"],\" / \",[\"1\"],\" cards\"],\"baIPh3\":[[\"0\"],\" cards due\"],\"beWT44\":[[\"0\"],\" cards have been rescheduled.\"],\"JJcBCm\":[[\"0\"],\" total\"],\"JtTuS0\":[[\"hydrationSkippedCount\",\"plural\",{\"one\":[\"#\",\" entry was skipped due to data issues. Your data is preserved, but you won't be able to search for the entry that wasn't loaded.\"],\"other\":[\"#\",\" entries were skipped due to data issues. Your data is preserved, but you won't be able to search for any entries that weren't loaded.\"]}]],\"UGMDWm\":[[\"skippedCount\"],\" entries were skipped due to data corruption.\"],\"gp8eDB\":[[\"totalHits\",\"plural\",{\"one\":[\"result\"],\"other\":[\"results\"]}]],\"QSRKsm\":[[\"totalResults\",\"plural\",{\"one\":[[\"totalResults\"],\" result\"],\"other\":[[\"totalResults\"],\" results\"]}]],\"gD09hk\":[[\"val\",\"plural\",{\"one\":[\"Cannot exceed \",\"#\",\" character\"],\"other\":[\"Cannot exceed \",\"#\",\" characters\"]}]],\"I1sa5o\":[[\"val\",\"plural\",{\"one\":[\"Must be at least \",\"#\",\" character\"],\"other\":[\"Must be at least \",\"#\",\" characters\"]}]],\"WWcbHw\":[\"A noun, adjective, adverb or pronoun, and anything that is not a verb or preposition.\"],\"ZQW2PY\":[\"A preposition or conjunction.\"],\"0iy5O2\":[\"A verb.\"],\"7L01XJ\":[\"Actions\"],\"DQqXHw\":[\"Active participle\"],\"AwJc6G\":[\"Active Participle\"],\"rJwPkp\":[\"Add a new SQL migration.\"],\"t89Ong\":[\"Add a new word\"],\"L18Pbl\":[\"Add a new word to your dictionary\"],\"TYPFtT\":[\"Add a tag and press enter\"],\"iJMhp0\":[\"Add all\"],\"nPm6bB\":[\"Add antonym\"],\"jVmrwy\":[\"Add Antonym\"],\"1x4W9u\":[\"Add example\"],\"nI3A8B\":[\"Add Example\"],\"gLlFHX\":[\"Add harf\"],\"aLEtgY\":[\"Add Harf\"],\"Tcbo6a\":[\"Add Masdar\"],\"vKbErK\":[\"Add plural\"],\"SNF/r2\":[\"Add Plural\"],\"cR1WUS\":[\"Add some to get started!\"],\"Oft+Pb\":[\"Add some words to get started!\"],\"Xls3A3\":[\"Add tag \",[\"inputValue\"]],\"VMjLu6\":[\"Add tag \",[\"value\"]],\"uF1GKn\":[\"Add tags to your word.\"],\"bDXmnN\":[\"Add word\"],\"p59pEv\":[\"Additional Details\"],\"b/7DUT\":[\"Again\"],\"KK8UsT\":[\"All done for today!\"],\"7Qi3W5\":[\"An Arabic definition of the word.\"],\"Y/gBMP\":[\"An English translation of the sentence.\"],\"jalxln\":[\"An English translation of the word.\"],\"hyC+qY\":[\"An unexpected error occurred. You can try reloading the page to fix it.\"],\"Fl8owW\":[\"Annual — $7/mo\"],\"4xBHUg\":[\"Answer\"],\"vQXp82\":[\"Antonym \",[\"0\"]],\"o9dJs3\":[\"Antonym word\"],\"Hvs4LI\":[\"Antonyms\"],\"p1Kh9a\":[\"Any additional details about this form such as frequency of usage or context.\"],\"9kni2/\":[\"Any plural forms of the word.\"],\"2PPE7k\":[\"Any words that have the same ID will be overwritten.\"],\"cnAqww\":[\"App language\"],\"aAIQg2\":[\"Appearance\"],\"8HV3WN\":[\"Arabic\"],\"LNIQwr\":[\"Arabic definition\"],\"uKmc5K\":[\"Arabic sentence\"],\"wxIhw3\":[\"Arabic verb form\"],\"071WZA\":[\"Arabic word\"],\"pkD36F\":[\"Are you sure you want to delete \\\"\",[\"0\"],\"\\\"?\"],\"DOiV7q\":[\"Are you sure you want to delete this word? It will be removed from your dictionary and its flashcards will be deleted.<0/><1/><2>This action cannot be undone.\"],\"2cZh44\":[\"Are you sure you want to delete this word? This action cannot be undone.\"],\"ikBPhc\":[\"Are you sure you want to delete your dictionary? All your words will be deleted permanently. This action cannot be undone. Please make sure to export your dictionary before deleting it.\"],\"IJr17L\":[\"Are you sure you want to reset this flashcard's progress? The word entry in the dictionary will not be modified, but its corresponding flashcards will be treated as new ones.<0/><1/><2>This action cannot be undone.\"],\"iH8pgl\":[\"Back\"],\"0MgdN+\":[\"Back to top\"],\"KNKCTb\":[\"Backlog\"],\"Fg+fNW\":[\"Backlog cleared!\"],\"vMebS2\":[\"Bahar\"],\"EOUool\":[\"Basic Details\"],\"cSCbv3\":[\"BETA\"],\"t/5uBV\":[\"Billed $84/year\"],\"aIkeAd\":[\"Billed monthly\"],\"R+w/Va\":[\"Billing\"],\"OKWk8n\":[\"By signing in, you agree to our <0>Privacy Policy\"],\"dEgA5A\":[\"Cancel\"],\"oySfhX\":[\"Cards due today or recently\"],\"uV52e1\":[\"Cards overdue by more than 7 days\"],\"zAwyRS\":[\"Cards to review today\"],\"K7tIrx\":[\"Category\"],\"qWRWG1\":[\"Cause:\"],\"+yPBXI\":[\"Choose file\"],\"xCJdfg\":[\"Clear\"],\"ot7qsv\":[\"Clear all filters\"],\"saoOio\":[\"Clear backlog\"],\"Oo39Ga\":[\"Clearing...\"],\"rFmBG3\":[\"Color theme\"],\"mpby9d\":[\"Contact support\"],\"M73whl\":[\"Context\"],\"xGVfLh\":[\"Continue\"],\"RvVi9c\":[\"Continue with Email\"],\"NMo6Pj\":[\"Control where antonyms appear during review\"],\"PiH3UR\":[\"Copied!\"],\"he3ygx\":[\"Copy\"],\"hYgDIe\":[\"Create\"],\"oJc/nD\":[\"Create a deck to organize your flashcard reviews\"],\"wxDqxy\":[\"Create a new deck\"],\"oQH8Kl\":[\"Create a new deck by choosing filters. The deck will be composed of the cards that match the filters.\"],\"l7kxcE\":[\"Create deck\"],\"g/Uxjl\":[\"Create Deck\"],\"1m75Ii\":[\"Create your first deck\"],\"A+zoTy\":[\"Current plan\"],\"PQ2zPy\":[\"Customize how flashcards appear.\"],\"P+gzBQ\":[\"Customize how the application looks for you.\"],\"ZQKLI1\":[\"Danger Zone\"],\"pvnfJD\":[\"Dark\"],\"Wf+eYa\":[\"Debugging\"],\"LUfCYM\":[\"Deck created\"],\"sHVysr\":[\"Deck deleted\"],\"UzOd8J\":[\"Deck Name\"],\"iJA/GX\":[\"Deck successfully created!\"],\"M+Nngk\":[\"Deck successfully deleted!\"],\"NVQRbB\":[\"Deck successfully updated!\"],\"WWDML8\":[\"Deck updated\"],\"9TyPfF\":[\"Decks\"],\"iUt5VS\":[\"Decks allow you to create subsets of your existing flashcards by using filters on your dictionary which you can then study individually.\"],\"ovBPCi\":[\"Default\"],\"MbRyzp\":[\"Definition\"],\"cnGeoo\":[\"Delete\"],\"CYf/wo\":[\"Delete All Data\"],\"G6sE0d\":[\"Delete Deck\"],\"fWNrfJ\":[\"Delete Dictionary\"],\"Xpcev7\":[\"Delete Everything\"],\"pe67wL\":[\"Delete this word?\"],\"VEQ9bX\":[\"Delete word\"],\"/GZNuU\":[\"Delete your dictionary?\"],\"Nu4oKW\":[\"Description\"],\"URmyfc\":[\"Details\"],\"wjSthp\":[\"Details:\"],\"VrH1k+\":[\"Dictionary\"],\"RPYrAz\":[\"Dictionary deleted\"],\"460RzB\":[\"Diptote\"],\"bzSI52\":[\"Discard\"],\"1QfxQT\":[\"Dismiss\"],\"Nwbs0q\":[\"Don't show\"],\"xifE4+\":[\"Dual\"],\"jSxAVI\":[\"e.g. ك ت ب\"],\"Pqhtap\":[\"Easy\"],\"ePK91l\":[\"Edit\"],\"nZQfan\":[\"Edit \",[\"word\"]],\"4cP5gy\":[\"Edit Deck\"],\"AN/oWt\":[\"Edit word\"],\"IQ6Efp\":[\"Edit your deck\"],\"FEct+T\":[\"Edit your deck by choosing filters. The deck will be composed of the cards that match the filters.\"],\"O3oNi5\":[\"Email\"],\"lYGfRP\":[\"English\"],\"7MHe6P\":[\"English translation\"],\"Ac92c9\":[\"Enter a deck name\"],\"ot6UAQ\":[\"Enter a description for your migration\"],\"shwNsK\":[\"Enter deck name\"],\"BTF0Gj\":[\"Enter your 6-digit code from your email\"],\"ojjQlT\":[\"Enter your SQL migration script here\"],\"CA1DlQ\":[\"Entry \",[\"arrayIndex\"]],\"Af6M/a\":[\"Example \",[\"0\"]],\"oea1as\":[\"Example usages of the word in different contexts.\"],\"hFthoo\":[\"Examples\"],\"GS+Mus\":[\"Export\"],\"Mk2MqX\":[\"Export completed with issues\"],\"XydOn5\":[\"Export failed!\"],\"FAMOg+\":[\"Export with flashcards\"],\"HynDdB\":[\"Export your dictionary\"],\"cQ+n9e\":[\"Exporting dictionary with flaschards will save your flashcard progress along with all the content in your dictionary. Use this option if you want to make a backup of your data.<0/><1/>Exporting your dictionary without flashcards will not save any flashcard progress. Use this option if you want to share your dictionary.<2/><3/><4>Warning: Importing your file without flashcards will reset all of your flashcards.\"],\"1JBTZV\":[\"Expression\"],\"GiPSsF\":[\"Failed to add word\"],\"zABpXD\":[\"Failed to add word!\"],\"NcBoUU\":[\"Failed to apply migration to local database.\"],\"eN1Tfn\":[\"Failed to clear backlog\"],\"7hUTxx\":[\"Failed to create deck\"],\"Fr4iT6\":[\"Failed to delete deck\"],\"GCd4Bz\":[\"Failed to delete dictionary\"],\"KLMMnR\":[\"Failed to delete word\"],\"cncTzY\":[\"Failed to delete!\"],\"usb0iv\":[\"Failed to reset local data\"],\"dCD/3a\":[\"Failed to retrieve data from local database.\"],\"btG7GG\":[\"Failed to retrieve database information.\"],\"CBm+/w\":[\"Failed to update deck\"],\"gw2VAF\":[\"Failed to update flashcard settings.\"],\"tOcErW\":[\"Failed to update settings\"],\"X/iINj\":[\"Failed to update the word!\"],\"cnYJdR\":[\"Failed to update word\"],\"ixyKje\":[\"Failed to upload migration\"],\"1B52uC\":[\"Feminine\"],\"TUSnpz\":[\"Fi'l\"],\"YCAFdN\":[\"Filter by tags...\"],\"cSev+j\":[\"Filters\"],\"wG1Flg\":[\"Flashcard settings updated!\"],\"EiJpdz\":[\"Flashcards\"],\"hpt1Ta\":[\"Follows your device language\"],\"tR/FIC\":[\"Follows your system settings\"],\"q1hBIe\":[\"For example, the word\"],\"QRAWTO\":[\"Form\"],\"2POOFK\":[\"Free\"],\"5iyJje\":[\"Gender\"],\"RkXlPZ\":[\"GitHub\"],\"CKyk7Q\":[\"Go back\"],\"lUTqcW\":[\"Go to dictionary\"],\"OEEQKT\":[\"Good\"],\"VOwQ6g\":[\"Great work on the backlog! You still have \",[\"0\"],\" regular reviews.\"],\"Xv6Pek\":[\"Great work! Come back later for more reviews.\"],\"g5Fk5U\":[\"Hard\"],\"h4MDwq\":[\"Harf\"],\"IzmuJh\":[\"Harf \",[\"0\"]],\"D+zLDD\":[\"Hidden\"],\"VMlRqi\":[\"Hide details\"],\"QWNZbK\":[\"Hide filters\"],\"f+BFfG\":[\"Hint\"],\"i0qMbr\":[\"Home\"],\"q0alPy\":[\"How should antonyms be shown in flashcards?\"],\"af2WMF\":[\"How the word is categorized based on its type or context.\"],\"qGZ1pF\":[\"Huroof\"],\"7fIUBE\":[\"ID:\"],\"mU4ZuB\":[\"if needed.\"],\"eQI7A0\":[\"If you're experiencing sync issues or data not loading correctly, you can reset your local data and re-sync from the server.\"],\"wqQIcr\":[\"Imperative\"],\"l3s5ri\":[\"Import\"],\"5LwmgO\":[\"Import failed!\"],\"X85Lgt\":[\"Include English to Arabic flashcards\"],\"O1SPgK\":[\"Incorrect file type\"],\"bjwx3z\":[\"Indeclinable\"],\"d7G5eB\":[\"Inflection\"],\"IaZUGL\":[\"Information such as the word's root, meaning, and examples.\"],\"FP8ELf\":[\"Invalid datetime format\"],\"LpHyjF\":[\"Invalid string format\"],\"xVH/JG\":[\"Invalid type. Expected \",[\"0\"]],\"lBmlgJ\":[\"Invalid type. Expected \",[\"0\"],\", received \",[\"1\"]],\"5R5T/G\":[\"Invalid value. Expected one of: \",[\"0\"]],\"SK5zz1\":[\"Ism\"],\"vXIe7J\":[\"Language\"],\"1njn7W\":[\"Light\"],\"CZOrLB\":[\"Loading details...\"],\"LioGSK\":[\"Loading your dictionary...\"],\"Z3FXyt\":[\"Loading...\"],\"1bAISV\":[\"Local data reset successfully!\"],\"Od5n57\":[\"Log in to your existing account or sign up for a new one\"],\"nOhz3x\":[\"Logout\"],\"L9IOec\":[\"Manage Subscription\"],\"c1DM+0\":[\"Manage your decks and study them.\"],\"QUTgGW\":[\"Manage your dictionary.\"],\"4zd4U3\":[\"Manage your subscription.\"],\"U60v+9\":[\"Masadir\"],\"IPJKNz\":[\"Masculine\"],\"dLgiXX\":[\"Masdar\"],\"SXYWd/\":[\"Masdar \",[\"0\"]],\"6URaYg\":[\"Meaning\"],\"MYTK2T\":[\"Meaning with this preposition\"],\"zucql+\":[\"Menu\"],\"qGioCB\":[\"Migration successfully registered.\"],\"O+YlVk\":[\"Monthly — $10/mo\"],\"QI9AZD\":[\"More than \",[\"0\"],\" cards to review\"],\"yf87+x\":[\"Morphology\"],\"60xV9Y\":[\"Morphology only applies to isms and fi'ls. This section will be hidden if the type of the word is set to anything else.\"],\"qhwV2C\":[\"My Account\"],\"6YtxFj\":[\"Name\"],\"TizFpt\":[\"Navigation menu\"],\"TQ5Es1\":[\"No backlog cards to clear.\"],\"WAQMrN\":[\"No cards due\"],\"TkUliY\":[\"No decks yet\"],\"7+IHTZ\":[\"No file chosen\"],\"AxPAXW\":[\"No results found\"],\"vLuosE\":[\"No tags found.\"],\"Utp0Ef\":[\"Nord\"],\"tTu2yx\":[\"Noun\"],\"KfoKzr\":[\"Noun Morphology\"],\"zW+FpA\":[\"Or continue with\"],\"PMqWHy\":[\"Particle\"],\"UIYada\":[\"Passive participle\"],\"9wi5te\":[\"Passive Participle\"],\"Ff0Dor\":[\"Past\"],\"KkgkHx\":[\"Past tense\"],\"uiVVIw\":[\"Past Tense\"],\"VHWIM2\":[\"Permanently delete all your data including words, flashcards, and decks.\"],\"1OB0cV\":[\"Please contact <0>support with the following details:\"],\"HsEwwb\":[\"Please enter a deck name\"],\"nqOcNX\":[\"Please select a JSON file with your dictionary.\"],\"AXJfF/\":[\"Please try again or reload the page.\"],\"fuwKpE\":[\"Please try again.\"],\"BPig2P\":[\"Plural\"],\"K5KP2J\":[\"Plural \",[\"0\"]],\"zt7UFB\":[\"Plural form\"],\"u5SHG2\":[\"Plurals\"],\"go9eTo\":[\"Preposition\"],\"JuM71B\":[\"Prepositions (Huroof)\"],\"0Of985\":[\"Prepositions (huroof) that can be used with the verb to change its meaning.\"],\"eZb+lw\":[\"Present\"],\"24cT5U\":[\"Present tense\"],\"6Kwq+n\":[\"Present Tense\"],\"3fPjUY\":[\"Pro\"],\"0DYtlD\":[\"Recently added\"],\"X5P6yv\":[\"Recently updated\"],\"uabU9X\":[\"Recently used\"],\"7dZnmw\":[\"Relevance\"],\"HpK/8d\":[\"Reload\"],\"t/YqKh\":[\"Remove\"],\"8dg+Yo\":[\"Required field\"],\"+7Cebq\":[\"Reschedule all backlog cards by grading them as \\\"Hard\\\".\"],\"ly/6zq\":[\"Reset and re-sync\"],\"vWTWiR\":[\"Reset flashcard\"],\"7HeQ9b\":[\"Reset flashcard progress?\"],\"2ma9vI\":[\"Reset local data\"],\"lLVyir\":[\"Reset local data and re-sync?\"],\"K/RS6y\":[\"Resetting local data...\"],\"QFtnWs\":[\"Reverse flashcards\"],\"5k0NLb\":[\"Review\"],\"nqtnG9\":[\"Review flashcards\"],\"HtzuX3\":[\"Review flashcards (\",[\"0\"],\" in backlog)\"],\"TbJrZ9\":[\"Review flashcards with spaced repetition\"],\"05OIsb\":[\"Review your Arabic flashcards and grade your understanding with Again, Hard, Good, or Easy options to adjust scheduling.\"],\"cbGyYK\":[\"Root letters\"],\"qMVAMv\":[\"Root Letters\"],\"tfDRzk\":[\"Save\"],\"JAxBTB\":[\"Save 30%\"],\"y3aU20\":[\"Save changes\"],\"IUwGEM\":[\"Save Changes\"],\"bf6lG0\":[\"Schema Migrations\"],\"BnCS55\":[\"Search for a tag...\"],\"VV6Aru\":[\"Search tag...\"],\"YIix5Y\":[\"Search...\"],\"Du+zn+\":[\"Searching...\"],\"hid6Sx\":[\"Select gender\"],\"NdMnnc\":[\"Select inflection\"],\"V/vqsf\":[\"Select the types of words that you want to include in the deck.\"],\"tXQ9KI\":[\"Select type\"],\"FDpH/H\":[\"Sentence\"],\"iw3JO4\":[\"Separate letters with spaces or commas\"],\"Tz0i8g\":[\"Settings\"],\"l8nxCn\":[\"Show after revealing the answer\"],\"r0Xcmy\":[\"Show answer\"],\"vDNaTX\":[\"Show antonyms\"],\"1H95wk\":[\"Show as a hint\"],\"BowKyI\":[\"Show details\"],\"C5SZax\":[\"Show English to Arabic flashcards.\"],\"+b9Ad2\":[\"Show filters\"],\"xzH3m9\":[\"Show reverse flashcards\"],\"maCaRp\":[\"Singular\"],\"vK/oE0\":[\"Some dictionary entries couldn't be loaded\"],\"nwtY4N\":[\"Something went wrong\"],\"/HgF9q\":[\"Sort by\"],\"r20wDW\":[\"SQL Script\"],\"ykSlaQ\":[\"Still not working?\"],\"pKr7ta\":[\"Study\"],\"+Env0D\":[\"Successfully added word!\"],\"NJp0hH\":[\"Successfully deleted!\"],\"z6XClS\":[\"Successfully exported!\"],\"1uuPpZ\":[\"Successfully imported!\"],\"/5ZZnV\":[\"Successfully reset the flashcard.\"],\"oEWC7j\":[\"Successfully updated the word!\"],\"QgnNyZ\":[\"Sync error\"],\"D+NlUC\":[\"System\"],\"OYHzN1\":[\"Tags\"],\"iEZ4Fc\":[\"Thank you for subscribing to Bahar Pro. You now have access to all Pro features.\"],\"hz39Yb\":[\"That code is invalid.\"],\"90dpv/\":[\"That email is invalid.\"],\"7X8sXq\":[\"That is not valid JSON.\"],\"P7iz9S\":[\"The app may be open in another tab. Try closing other tabs and refreshing this page.\"],\"Bm2B8s\":[\"The context of the sentence, ex. formal or colloquial.\"],\"MMs+Zk\":[\"The deck \\\"\",[\"0\"],\"\\\" has been deleted.\"],\"Gpyta0\":[\"The form of the verb ex. I, II, III, IV, etc...\"],\"OE9TJJ\":[\"The form of the verb in Arabic ex. فعل, أفعل, استفعل, etc...\"],\"4cDTK/\":[\"The local database is locked by another session.\"],\"EVX5FZ\":[\"The meaning of the verb when used with the harf.\"],\"bdFFEw\":[\"The morphological breakdown of the word.\"],\"nIdeZ6\":[\"The root letters of the word. The input can be separated by commas, spaces or have no delimeter ex. فعل or ف, ع, ل or ف ع ل.\"],\"AvErlv\":[\"The word has been added to your dictionary.\"],\"LbpyqF\":[\"The word has been updated.\"],\"FEr96N\":[\"Theme\"],\"uTlsP3\":[\"There was an error adding your word. Please try again.\"],\"boDfXQ\":[\"There was an error clearing your backlog.\"],\"IOwnXs\":[\"There was an error creating the deck\"],\"AObMB6\":[\"There was an error deleting your dictionary. Please try again later.\"],\"QPU+ph\":[\"There was an error exporting your dictionary. Please try again later.\"],\"+0R2Vl\":[\"There was an error importing your dictionary. Please try again later.\"],\"GrwZZY\":[\"There was an error syncing your data. If this persists, try resetting local data in Settings.\"],\"1GLBeM\":[\"There was an error syncing your data. Please try resetting local data in Settings.\"],\"Xs1nsK\":[\"There was an error syncing your data. Your local data is still available.\"],\"aUu2Qy\":[\"There was an error updating the deck\"],\"jObkch\":[\"There was an error updating your flashcard settings.\"],\"DvuiAU\":[\"There was an error updating your word. Please try again.\"],\"n//cii\":[\"There was an error uploading your SQL migration\"],\"p0aTgS\":[\"There was an error when indexing your data in the search engine.\"],\"7Eqx1H\":[\"There was an unexpected error. Please try again.\"],\"1hR1ca\":[\"There's a temporary issue loading your account. Please try reloading the page.\"],\"UwqoLj\":[\"This field is required.\"],\"oM4aHs\":[\"This is case insensitive.\"],\"GoNjj1\":[\"This is the name of your deck.\"],\"e92j12\":[\"This refers to how many case endings the word can take.\"],\"fxunD6\":[\"This will delete the local copy of your data stored in this browser and download a fresh copy from the server. Your data on the server will not be affected. Use this if you're experiencing sync errors or seeing outdated data.\"],\"lpK0Kp\":[\"This will permanently delete all your words, flashcards, and decks. This action cannot be undone.\"],\"NVF43p\":[\"Time:\"],\"i1FCIq\":[\"To review\"],\"1Q2HRv\":[\"Toggle Menu\"],\"inGj5T\":[\"Tokyo Night\"],\"72c5Qo\":[\"Total\"],\"wFcvZJ\":[\"Translation\"],\"/Onh8p\":[\"Triptote\"],\"qlwLcm\":[\"Troubleshooting\"],\"jKoZME\":[\"Try a different search term\"],\"+zy2Nq\":[\"Type\"],\"WtTYSX\":[\"Types\"],\"xlZRtS\":[\"Uh oh! Something went wrong :/\"],\"6njDZ+\":[\"Unable to connect to remote database.\"],\"WRB75e\":[\"Unknown error.\"],\"IelE1h\":[\"Upgrade to Pro\"],\"1ZR0xe\":[\"Value must be \",[\"0\"],\" or greater\"],\"e5Ml90\":[\"Value must be \",[\"0\"],\" or less\"],\"bwa0RV\":[\"Verb\"],\"LnBspw\":[\"Verb form\"],\"esQ1ry\":[\"Verb Morphology\"],\"WjcFrD\":[\"Verbal noun forms (masadir) of the verb.\"],\"2oIAhB\":[\"Verbal nouns\"],\"s6NYcb\":[\"Verbal Nouns (Masadir)\"],\"B4iZJX\":[\"View all the words in your personal dictionary.\"],\"VvvGs4\":[\"We can't reach our servers right now. Check your connection and try again.\"],\"dHoQb8\":[\"We're having trouble with your account setup. Please try again.\"],\"eqpeYp\":[\"Welcome to Bahar!\"],\"dZiBrj\":[\"Word\"],\"MJ0gHH\":[\"Word added successfully\"],\"wazgbb\":[\"Word deleted successfully\"],\"2WVQNU\":[\"Word not found\"],\"Xwf/Kn\":[\"Word updated successfully\"],\"FVyDlC\":[\"Words that have any of these tags will be included in the deck.\"],\"7niJN/\":[\"Words that have the opposite meaning.\"],\"nTIiPJ\":[\"You do not have access to upload schema migrations.\"],\"4eom/r\":[\"You have \",[\"0\"],\" cards in your backlog when you're ready.\"],\"alITRb\":[\"You have no decks yet.\"],\"XOUb7A\":[\"You have no words in your dictionary yet.\"],\"voqWOr\":[\"You're all set!\"],\"/dColV\":[\"Your account needs maintenance. We've been notified. Please try again later.\"],\"a8jRIt\":[\"Your data has been re-synced from the server.\"],\"uRXiIT\":[\"Your deck was not created. Please try again.\"],\"oz/nIQ\":[\"Your deck was not updated. Please try again.\"],\"L1VLmw\":[\"Your Dictionary\"],\"SB7dXw\":[\"Your dictionary has been deleted.\"],\"aQiurv\":[\"Your dictionary has been downloaded.\"],\"YAeum9\":[\"Your dictionary has been updated!\"],\"C0Fx9N\":[\"Your dictionary is empty\"],\"3ma3fF\":[\"Your dictionary is not valid. Please fix the errors and upload it again.\"],\"4bRwmE\":[\"محمد is a triptote;\"],\"kkC1Qd\":[\"موسى is indeclinable.\"],\"jFIhM0\":[\"يوسف is a diptote;\"]}")as Messages; \ No newline at end of file +/*eslint-disable*/import type{Messages}from"@lingui/core";export const messages=JSON.parse("{\"Wg0uLA\":[[\"0\",\"plural\",{\"one\":[\"#\",\" tag selected\"],\"other\":[\"#\",\" tags selected\"]}]],\"5rgLzy\":[[\"0\",\"plural\",{\"one\":[\"card left\"],\"other\":[\"cards left\"]}]],\"/hTM9k\":[[\"0\"],\" / \",[\"1\"],\" batches\"],\"mHye52\":[[\"0\"],\" / \",[\"1\"],\" cards\"],\"baIPh3\":[[\"0\"],\" cards due\"],\"beWT44\":[[\"0\"],\" cards have been rescheduled.\"],\"JJcBCm\":[[\"0\"],\" total\"],\"JtTuS0\":[[\"hydrationSkippedCount\",\"plural\",{\"one\":[\"#\",\" entry was skipped due to data issues. Your data is preserved, but you won't be able to search for the entry that wasn't loaded.\"],\"other\":[\"#\",\" entries were skipped due to data issues. Your data is preserved, but you won't be able to search for any entries that weren't loaded.\"]}]],\"UGMDWm\":[[\"skippedCount\"],\" entries were skipped due to data corruption.\"],\"gp8eDB\":[[\"totalHits\",\"plural\",{\"one\":[\"result\"],\"other\":[\"results\"]}]],\"QSRKsm\":[[\"totalResults\",\"plural\",{\"one\":[[\"totalResults\"],\" result\"],\"other\":[[\"totalResults\"],\" results\"]}]],\"gD09hk\":[[\"val\",\"plural\",{\"one\":[\"Cannot exceed \",\"#\",\" character\"],\"other\":[\"Cannot exceed \",\"#\",\" characters\"]}]],\"I1sa5o\":[[\"val\",\"plural\",{\"one\":[\"Must be at least \",\"#\",\" character\"],\"other\":[\"Must be at least \",\"#\",\" characters\"]}]],\"WWcbHw\":[\"A noun, adjective, adverb or pronoun, and anything that is not a verb or preposition.\"],\"ZQW2PY\":[\"A preposition or conjunction.\"],\"0iy5O2\":[\"A verb.\"],\"7L01XJ\":[\"Actions\"],\"DQqXHw\":[\"Active participle\"],\"AwJc6G\":[\"Active Participle\"],\"rJwPkp\":[\"Add a new SQL migration.\"],\"t89Ong\":[\"Add a new word\"],\"L18Pbl\":[\"Add a new word to your dictionary\"],\"TYPFtT\":[\"Add a tag and press enter\"],\"iJMhp0\":[\"Add all\"],\"nPm6bB\":[\"Add antonym\"],\"jVmrwy\":[\"Add Antonym\"],\"1x4W9u\":[\"Add example\"],\"nI3A8B\":[\"Add Example\"],\"gLlFHX\":[\"Add harf\"],\"aLEtgY\":[\"Add Harf\"],\"Tcbo6a\":[\"Add Masdar\"],\"vKbErK\":[\"Add plural\"],\"SNF/r2\":[\"Add Plural\"],\"cR1WUS\":[\"Add some to get started!\"],\"Oft+Pb\":[\"Add some words to get started!\"],\"Xls3A3\":[\"Add tag \",[\"inputValue\"]],\"VMjLu6\":[\"Add tag \",[\"value\"]],\"uF1GKn\":[\"Add tags to your word.\"],\"bDXmnN\":[\"Add word\"],\"p59pEv\":[\"Additional Details\"],\"b/7DUT\":[\"Again\"],\"KK8UsT\":[\"All done for today!\"],\"7Qi3W5\":[\"An Arabic definition of the word.\"],\"Y/gBMP\":[\"An English translation of the sentence.\"],\"jalxln\":[\"An English translation of the word.\"],\"hyC+qY\":[\"An unexpected error occurred. You can try reloading the page to fix it.\"],\"Fl8owW\":[\"Annual — $7/mo\"],\"4xBHUg\":[\"Answer\"],\"vQXp82\":[\"Antonym \",[\"0\"]],\"o9dJs3\":[\"Antonym word\"],\"Hvs4LI\":[\"Antonyms\"],\"p1Kh9a\":[\"Any additional details about this form such as frequency of usage or context.\"],\"9kni2/\":[\"Any plural forms of the word.\"],\"2PPE7k\":[\"Any words that have the same ID will be overwritten.\"],\"cnAqww\":[\"App language\"],\"aAIQg2\":[\"Appearance\"],\"8HV3WN\":[\"Arabic\"],\"LNIQwr\":[\"Arabic definition\"],\"uKmc5K\":[\"Arabic sentence\"],\"wxIhw3\":[\"Arabic verb form\"],\"071WZA\":[\"Arabic word\"],\"pkD36F\":[\"Are you sure you want to delete \\\"\",[\"0\"],\"\\\"?\"],\"DOiV7q\":[\"Are you sure you want to delete this word? It will be removed from your dictionary and its flashcards will be deleted.<0/><1/><2>This action cannot be undone.\"],\"2cZh44\":[\"Are you sure you want to delete this word? This action cannot be undone.\"],\"ikBPhc\":[\"Are you sure you want to delete your dictionary? All your words will be deleted permanently. This action cannot be undone. Please make sure to export your dictionary before deleting it.\"],\"IJr17L\":[\"Are you sure you want to reset this flashcard's progress? The word entry in the dictionary will not be modified, but its corresponding flashcards will be treated as new ones.<0/><1/><2>This action cannot be undone.\"],\"OsXw/g\":[\"Autofill\"],\"ujMTU0\":[\"Autofill failed\"],\"iH8pgl\":[\"Back\"],\"0MgdN+\":[\"Back to top\"],\"KNKCTb\":[\"Backlog\"],\"Fg+fNW\":[\"Backlog cleared!\"],\"vMebS2\":[\"Bahar\"],\"EOUool\":[\"Basic Details\"],\"cSCbv3\":[\"BETA\"],\"t/5uBV\":[\"Billed $84/year\"],\"aIkeAd\":[\"Billed monthly\"],\"R+w/Va\":[\"Billing\"],\"OKWk8n\":[\"By signing in, you agree to our <0>Privacy Policy\"],\"dEgA5A\":[\"Cancel\"],\"oySfhX\":[\"Cards due today or recently\"],\"uV52e1\":[\"Cards overdue by more than 7 days\"],\"zAwyRS\":[\"Cards to review today\"],\"K7tIrx\":[\"Category\"],\"qWRWG1\":[\"Cause:\"],\"+yPBXI\":[\"Choose file\"],\"xCJdfg\":[\"Clear\"],\"ot7qsv\":[\"Clear all filters\"],\"saoOio\":[\"Clear backlog\"],\"Oo39Ga\":[\"Clearing...\"],\"rFmBG3\":[\"Color theme\"],\"mpby9d\":[\"Contact support\"],\"M73whl\":[\"Context\"],\"xGVfLh\":[\"Continue\"],\"RvVi9c\":[\"Continue with Email\"],\"NMo6Pj\":[\"Control where antonyms appear during review\"],\"PiH3UR\":[\"Copied!\"],\"he3ygx\":[\"Copy\"],\"hYgDIe\":[\"Create\"],\"oJc/nD\":[\"Create a deck to organize your flashcard reviews\"],\"wxDqxy\":[\"Create a new deck\"],\"oQH8Kl\":[\"Create a new deck by choosing filters. The deck will be composed of the cards that match the filters.\"],\"l7kxcE\":[\"Create deck\"],\"g/Uxjl\":[\"Create Deck\"],\"1m75Ii\":[\"Create your first deck\"],\"A+zoTy\":[\"Current plan\"],\"PQ2zPy\":[\"Customize how flashcards appear.\"],\"P+gzBQ\":[\"Customize how the application looks for you.\"],\"ZQKLI1\":[\"Danger Zone\"],\"pvnfJD\":[\"Dark\"],\"Wf+eYa\":[\"Debugging\"],\"LUfCYM\":[\"Deck created\"],\"sHVysr\":[\"Deck deleted\"],\"UzOd8J\":[\"Deck Name\"],\"iJA/GX\":[\"Deck successfully created!\"],\"M+Nngk\":[\"Deck successfully deleted!\"],\"NVQRbB\":[\"Deck successfully updated!\"],\"WWDML8\":[\"Deck updated\"],\"9TyPfF\":[\"Decks\"],\"iUt5VS\":[\"Decks allow you to create subsets of your existing flashcards by using filters on your dictionary which you can then study individually.\"],\"ovBPCi\":[\"Default\"],\"MbRyzp\":[\"Definition\"],\"cnGeoo\":[\"Delete\"],\"CYf/wo\":[\"Delete All Data\"],\"G6sE0d\":[\"Delete Deck\"],\"fWNrfJ\":[\"Delete Dictionary\"],\"Xpcev7\":[\"Delete Everything\"],\"pe67wL\":[\"Delete this word?\"],\"VEQ9bX\":[\"Delete word\"],\"/GZNuU\":[\"Delete your dictionary?\"],\"Nu4oKW\":[\"Description\"],\"URmyfc\":[\"Details\"],\"wjSthp\":[\"Details:\"],\"VrH1k+\":[\"Dictionary\"],\"RPYrAz\":[\"Dictionary deleted\"],\"460RzB\":[\"Diptote\"],\"bzSI52\":[\"Discard\"],\"1QfxQT\":[\"Dismiss\"],\"Nwbs0q\":[\"Don't show\"],\"xifE4+\":[\"Dual\"],\"jSxAVI\":[\"e.g. ك ت ب\"],\"Pqhtap\":[\"Easy\"],\"ePK91l\":[\"Edit\"],\"nZQfan\":[\"Edit \",[\"word\"]],\"4cP5gy\":[\"Edit Deck\"],\"AN/oWt\":[\"Edit word\"],\"IQ6Efp\":[\"Edit your deck\"],\"FEct+T\":[\"Edit your deck by choosing filters. The deck will be composed of the cards that match the filters.\"],\"O3oNi5\":[\"Email\"],\"lYGfRP\":[\"English\"],\"7MHe6P\":[\"English translation\"],\"Ac92c9\":[\"Enter a deck name\"],\"ot6UAQ\":[\"Enter a description for your migration\"],\"shwNsK\":[\"Enter deck name\"],\"BTF0Gj\":[\"Enter your 6-digit code from your email\"],\"ojjQlT\":[\"Enter your SQL migration script here\"],\"CA1DlQ\":[\"Entry \",[\"arrayIndex\"]],\"Af6M/a\":[\"Example \",[\"0\"]],\"oea1as\":[\"Example usages of the word in different contexts.\"],\"hFthoo\":[\"Examples\"],\"GS+Mus\":[\"Export\"],\"Mk2MqX\":[\"Export completed with issues\"],\"XydOn5\":[\"Export failed!\"],\"FAMOg+\":[\"Export with flashcards\"],\"HynDdB\":[\"Export your dictionary\"],\"cQ+n9e\":[\"Exporting dictionary with flaschards will save your flashcard progress along with all the content in your dictionary. Use this option if you want to make a backup of your data.<0/><1/>Exporting your dictionary without flashcards will not save any flashcard progress. Use this option if you want to share your dictionary.<2/><3/><4>Warning: Importing your file without flashcards will reset all of your flashcards.\"],\"1JBTZV\":[\"Expression\"],\"GiPSsF\":[\"Failed to add word\"],\"zABpXD\":[\"Failed to add word!\"],\"NcBoUU\":[\"Failed to apply migration to local database.\"],\"eN1Tfn\":[\"Failed to clear backlog\"],\"7hUTxx\":[\"Failed to create deck\"],\"Fr4iT6\":[\"Failed to delete deck\"],\"GCd4Bz\":[\"Failed to delete dictionary\"],\"KLMMnR\":[\"Failed to delete word\"],\"cncTzY\":[\"Failed to delete!\"],\"RztBUK\":[\"Failed to generate example\"],\"usb0iv\":[\"Failed to reset local data\"],\"dCD/3a\":[\"Failed to retrieve data from local database.\"],\"btG7GG\":[\"Failed to retrieve database information.\"],\"CBm+/w\":[\"Failed to update deck\"],\"gw2VAF\":[\"Failed to update flashcard settings.\"],\"tOcErW\":[\"Failed to update settings\"],\"X/iINj\":[\"Failed to update the word!\"],\"cnYJdR\":[\"Failed to update word\"],\"ixyKje\":[\"Failed to upload migration\"],\"1B52uC\":[\"Feminine\"],\"TUSnpz\":[\"Fi'l\"],\"+6O2ek\":[\"Fill in the word, translation, and type first.\"],\"YCAFdN\":[\"Filter by tags...\"],\"cSev+j\":[\"Filters\"],\"wG1Flg\":[\"Flashcard settings updated!\"],\"EiJpdz\":[\"Flashcards\"],\"hpt1Ta\":[\"Follows your device language\"],\"tR/FIC\":[\"Follows your system settings\"],\"q1hBIe\":[\"For example, the word\"],\"QRAWTO\":[\"Form\"],\"2POOFK\":[\"Free\"],\"5iyJje\":[\"Gender\"],\"2Pl4DZ\":[\"Generate example\"],\"NOdFZR\":[\"Generating...\"],\"RkXlPZ\":[\"GitHub\"],\"CKyk7Q\":[\"Go back\"],\"lUTqcW\":[\"Go to dictionary\"],\"OEEQKT\":[\"Good\"],\"VOwQ6g\":[\"Great work on the backlog! You still have \",[\"0\"],\" regular reviews.\"],\"Xv6Pek\":[\"Great work! Come back later for more reviews.\"],\"g5Fk5U\":[\"Hard\"],\"h4MDwq\":[\"Harf\"],\"IzmuJh\":[\"Harf \",[\"0\"]],\"D+zLDD\":[\"Hidden\"],\"VMlRqi\":[\"Hide details\"],\"QWNZbK\":[\"Hide filters\"],\"f+BFfG\":[\"Hint\"],\"i0qMbr\":[\"Home\"],\"q0alPy\":[\"How should antonyms be shown in flashcards?\"],\"af2WMF\":[\"How the word is categorized based on its type or context.\"],\"qGZ1pF\":[\"Huroof\"],\"7fIUBE\":[\"ID:\"],\"mU4ZuB\":[\"if needed.\"],\"eQI7A0\":[\"If you're experiencing sync issues or data not loading correctly, you can reset your local data and re-sync from the server.\"],\"wqQIcr\":[\"Imperative\"],\"l3s5ri\":[\"Import\"],\"5LwmgO\":[\"Import failed!\"],\"X85Lgt\":[\"Include English to Arabic flashcards\"],\"O1SPgK\":[\"Incorrect file type\"],\"bjwx3z\":[\"Indeclinable\"],\"d7G5eB\":[\"Inflection\"],\"IaZUGL\":[\"Information such as the word's root, meaning, and examples.\"],\"FP8ELf\":[\"Invalid datetime format\"],\"LpHyjF\":[\"Invalid string format\"],\"xVH/JG\":[\"Invalid type. Expected \",[\"0\"]],\"lBmlgJ\":[\"Invalid type. Expected \",[\"0\"],\", received \",[\"1\"]],\"5R5T/G\":[\"Invalid value. Expected one of: \",[\"0\"]],\"SK5zz1\":[\"Ism\"],\"vXIe7J\":[\"Language\"],\"1njn7W\":[\"Light\"],\"CZOrLB\":[\"Loading details...\"],\"LioGSK\":[\"Loading your dictionary...\"],\"Z3FXyt\":[\"Loading...\"],\"1bAISV\":[\"Local data reset successfully!\"],\"Od5n57\":[\"Log in to your existing account or sign up for a new one\"],\"nOhz3x\":[\"Logout\"],\"L9IOec\":[\"Manage Subscription\"],\"c1DM+0\":[\"Manage your decks and study them.\"],\"QUTgGW\":[\"Manage your dictionary.\"],\"4zd4U3\":[\"Manage your subscription.\"],\"U60v+9\":[\"Masadir\"],\"IPJKNz\":[\"Masculine\"],\"dLgiXX\":[\"Masdar\"],\"SXYWd/\":[\"Masdar \",[\"0\"]],\"6URaYg\":[\"Meaning\"],\"MYTK2T\":[\"Meaning with this preposition\"],\"zucql+\":[\"Menu\"],\"qGioCB\":[\"Migration successfully registered.\"],\"O+YlVk\":[\"Monthly — $10/mo\"],\"QI9AZD\":[\"More than \",[\"0\"],\" cards to review\"],\"yf87+x\":[\"Morphology\"],\"60xV9Y\":[\"Morphology only applies to isms and fi'ls. This section will be hidden if the type of the word is set to anything else.\"],\"qhwV2C\":[\"My Account\"],\"6YtxFj\":[\"Name\"],\"TizFpt\":[\"Navigation menu\"],\"TQ5Es1\":[\"No backlog cards to clear.\"],\"WAQMrN\":[\"No cards due\"],\"TkUliY\":[\"No decks yet\"],\"7+IHTZ\":[\"No file chosen\"],\"AxPAXW\":[\"No results found\"],\"vLuosE\":[\"No tags found.\"],\"Utp0Ef\":[\"Nord\"],\"tTu2yx\":[\"Noun\"],\"KfoKzr\":[\"Noun Morphology\"],\"zW+FpA\":[\"Or continue with\"],\"PMqWHy\":[\"Particle\"],\"UIYada\":[\"Passive participle\"],\"9wi5te\":[\"Passive Participle\"],\"Ff0Dor\":[\"Past\"],\"KkgkHx\":[\"Past tense\"],\"uiVVIw\":[\"Past Tense\"],\"VHWIM2\":[\"Permanently delete all your data including words, flashcards, and decks.\"],\"1OB0cV\":[\"Please contact <0>support with the following details:\"],\"HsEwwb\":[\"Please enter a deck name\"],\"nqOcNX\":[\"Please select a JSON file with your dictionary.\"],\"AXJfF/\":[\"Please try again or reload the page.\"],\"fuwKpE\":[\"Please try again.\"],\"6hUL0D\":[\"Please wait before trying again.\"],\"BPig2P\":[\"Plural\"],\"K5KP2J\":[\"Plural \",[\"0\"]],\"zt7UFB\":[\"Plural form\"],\"u5SHG2\":[\"Plurals\"],\"go9eTo\":[\"Preposition\"],\"JuM71B\":[\"Prepositions (Huroof)\"],\"0Of985\":[\"Prepositions (huroof) that can be used with the verb to change its meaning.\"],\"eZb+lw\":[\"Present\"],\"24cT5U\":[\"Present tense\"],\"6Kwq+n\":[\"Present Tense\"],\"3fPjUY\":[\"Pro\"],\"zbzsUz\":[\"Rate limit reached\"],\"0DYtlD\":[\"Recently added\"],\"X5P6yv\":[\"Recently updated\"],\"uabU9X\":[\"Recently used\"],\"7dZnmw\":[\"Relevance\"],\"HpK/8d\":[\"Reload\"],\"t/YqKh\":[\"Remove\"],\"8dg+Yo\":[\"Required field\"],\"+7Cebq\":[\"Reschedule all backlog cards by grading them as \\\"Hard\\\".\"],\"ly/6zq\":[\"Reset and re-sync\"],\"vWTWiR\":[\"Reset flashcard\"],\"7HeQ9b\":[\"Reset flashcard progress?\"],\"2ma9vI\":[\"Reset local data\"],\"lLVyir\":[\"Reset local data and re-sync?\"],\"K/RS6y\":[\"Resetting local data...\"],\"QFtnWs\":[\"Reverse flashcards\"],\"5k0NLb\":[\"Review\"],\"nqtnG9\":[\"Review flashcards\"],\"HtzuX3\":[\"Review flashcards (\",[\"0\"],\" in backlog)\"],\"TbJrZ9\":[\"Review flashcards with spaced repetition\"],\"05OIsb\":[\"Review your Arabic flashcards and grade your understanding with Again, Hard, Good, or Easy options to adjust scheduling.\"],\"cbGyYK\":[\"Root letters\"],\"qMVAMv\":[\"Root Letters\"],\"tfDRzk\":[\"Save\"],\"JAxBTB\":[\"Save 30%\"],\"y3aU20\":[\"Save changes\"],\"IUwGEM\":[\"Save Changes\"],\"bf6lG0\":[\"Schema Migrations\"],\"BnCS55\":[\"Search for a tag...\"],\"VV6Aru\":[\"Search tag...\"],\"YIix5Y\":[\"Search...\"],\"Du+zn+\":[\"Searching...\"],\"hid6Sx\":[\"Select gender\"],\"NdMnnc\":[\"Select inflection\"],\"V/vqsf\":[\"Select the types of words that you want to include in the deck.\"],\"tXQ9KI\":[\"Select type\"],\"FDpH/H\":[\"Sentence\"],\"iw3JO4\":[\"Separate letters with spaces or commas\"],\"Tz0i8g\":[\"Settings\"],\"l8nxCn\":[\"Show after revealing the answer\"],\"r0Xcmy\":[\"Show answer\"],\"vDNaTX\":[\"Show antonyms\"],\"1H95wk\":[\"Show as a hint\"],\"BowKyI\":[\"Show details\"],\"C5SZax\":[\"Show English to Arabic flashcards.\"],\"+b9Ad2\":[\"Show filters\"],\"xzH3m9\":[\"Show reverse flashcards\"],\"maCaRp\":[\"Singular\"],\"vK/oE0\":[\"Some dictionary entries couldn't be loaded\"],\"nwtY4N\":[\"Something went wrong\"],\"fWsBTs\":[\"Something went wrong. Please try again.\"],\"/HgF9q\":[\"Sort by\"],\"r20wDW\":[\"SQL Script\"],\"ykSlaQ\":[\"Still not working?\"],\"pKr7ta\":[\"Study\"],\"+Env0D\":[\"Successfully added word!\"],\"NJp0hH\":[\"Successfully deleted!\"],\"z6XClS\":[\"Successfully exported!\"],\"1uuPpZ\":[\"Successfully imported!\"],\"/5ZZnV\":[\"Successfully reset the flashcard.\"],\"oEWC7j\":[\"Successfully updated the word!\"],\"QgnNyZ\":[\"Sync error\"],\"D+NlUC\":[\"System\"],\"OYHzN1\":[\"Tags\"],\"iEZ4Fc\":[\"Thank you for subscribing to Bahar Pro. You now have access to all Pro features.\"],\"hz39Yb\":[\"That code is invalid.\"],\"90dpv/\":[\"That email is invalid.\"],\"7X8sXq\":[\"That is not valid JSON.\"],\"P7iz9S\":[\"The app may be open in another tab. Try closing other tabs and refreshing this page.\"],\"Bm2B8s\":[\"The context of the sentence, ex. formal or colloquial.\"],\"MMs+Zk\":[\"The deck \\\"\",[\"0\"],\"\\\" has been deleted.\"],\"Gpyta0\":[\"The form of the verb ex. I, II, III, IV, etc...\"],\"OE9TJJ\":[\"The form of the verb in Arabic ex. فعل, أفعل, استفعل, etc...\"],\"4cDTK/\":[\"The local database is locked by another session.\"],\"EVX5FZ\":[\"The meaning of the verb when used with the harf.\"],\"bdFFEw\":[\"The morphological breakdown of the word.\"],\"nIdeZ6\":[\"The root letters of the word. The input can be separated by commas, spaces or have no delimeter ex. فعل or ف, ع, ل or ف ع ل.\"],\"AvErlv\":[\"The word has been added to your dictionary.\"],\"LbpyqF\":[\"The word has been updated.\"],\"FEr96N\":[\"Theme\"],\"uTlsP3\":[\"There was an error adding your word. Please try again.\"],\"boDfXQ\":[\"There was an error clearing your backlog.\"],\"IOwnXs\":[\"There was an error creating the deck\"],\"AObMB6\":[\"There was an error deleting your dictionary. Please try again later.\"],\"QPU+ph\":[\"There was an error exporting your dictionary. Please try again later.\"],\"+0R2Vl\":[\"There was an error importing your dictionary. Please try again later.\"],\"GrwZZY\":[\"There was an error syncing your data. If this persists, try resetting local data in Settings.\"],\"1GLBeM\":[\"There was an error syncing your data. Please try resetting local data in Settings.\"],\"Xs1nsK\":[\"There was an error syncing your data. Your local data is still available.\"],\"aUu2Qy\":[\"There was an error updating the deck\"],\"jObkch\":[\"There was an error updating your flashcard settings.\"],\"DvuiAU\":[\"There was an error updating your word. Please try again.\"],\"n//cii\":[\"There was an error uploading your SQL migration\"],\"p0aTgS\":[\"There was an error when indexing your data in the search engine.\"],\"7Eqx1H\":[\"There was an unexpected error. Please try again.\"],\"1hR1ca\":[\"There's a temporary issue loading your account. Please try reloading the page.\"],\"UwqoLj\":[\"This field is required.\"],\"oM4aHs\":[\"This is case insensitive.\"],\"GoNjj1\":[\"This is the name of your deck.\"],\"e92j12\":[\"This refers to how many case endings the word can take.\"],\"fxunD6\":[\"This will delete the local copy of your data stored in this browser and download a fresh copy from the server. Your data on the server will not be affected. Use this if you're experiencing sync errors or seeing outdated data.\"],\"lpK0Kp\":[\"This will permanently delete all your words, flashcards, and decks. This action cannot be undone.\"],\"NVF43p\":[\"Time:\"],\"i1FCIq\":[\"To review\"],\"1Q2HRv\":[\"Toggle Menu\"],\"inGj5T\":[\"Tokyo Night\"],\"72c5Qo\":[\"Total\"],\"wFcvZJ\":[\"Translation\"],\"/Onh8p\":[\"Triptote\"],\"qlwLcm\":[\"Troubleshooting\"],\"jKoZME\":[\"Try a different search term\"],\"+zy2Nq\":[\"Type\"],\"WtTYSX\":[\"Types\"],\"xlZRtS\":[\"Uh oh! Something went wrong :/\"],\"6njDZ+\":[\"Unable to connect to remote database.\"],\"WRB75e\":[\"Unknown error.\"],\"IelE1h\":[\"Upgrade to Pro\"],\"1z3VP6\":[\"Upgrade to Pro to generate examples.\"],\"pIqsHO\":[\"Upgrade to Pro to use AI autofill.\"],\"1ZR0xe\":[\"Value must be \",[\"0\"],\" or greater\"],\"e5Ml90\":[\"Value must be \",[\"0\"],\" or less\"],\"bwa0RV\":[\"Verb\"],\"LnBspw\":[\"Verb form\"],\"esQ1ry\":[\"Verb Morphology\"],\"WjcFrD\":[\"Verbal noun forms (masadir) of the verb.\"],\"2oIAhB\":[\"Verbal nouns\"],\"s6NYcb\":[\"Verbal Nouns (Masadir)\"],\"B4iZJX\":[\"View all the words in your personal dictionary.\"],\"VvvGs4\":[\"We can't reach our servers right now. Check your connection and try again.\"],\"dHoQb8\":[\"We're having trouble with your account setup. Please try again.\"],\"eqpeYp\":[\"Welcome to Bahar!\"],\"dZiBrj\":[\"Word\"],\"MJ0gHH\":[\"Word added successfully\"],\"wazgbb\":[\"Word deleted successfully\"],\"2WVQNU\":[\"Word not found\"],\"Xwf/Kn\":[\"Word updated successfully\"],\"FVyDlC\":[\"Words that have any of these tags will be included in the deck.\"],\"7niJN/\":[\"Words that have the opposite meaning.\"],\"nTIiPJ\":[\"You do not have access to upload schema migrations.\"],\"4eom/r\":[\"You have \",[\"0\"],\" cards in your backlog when you're ready.\"],\"alITRb\":[\"You have no decks yet.\"],\"XOUb7A\":[\"You have no words in your dictionary yet.\"],\"voqWOr\":[\"You're all set!\"],\"/dColV\":[\"Your account needs maintenance. We've been notified. Please try again later.\"],\"a8jRIt\":[\"Your data has been re-synced from the server.\"],\"uRXiIT\":[\"Your deck was not created. Please try again.\"],\"oz/nIQ\":[\"Your deck was not updated. Please try again.\"],\"L1VLmw\":[\"Your Dictionary\"],\"SB7dXw\":[\"Your dictionary has been deleted.\"],\"aQiurv\":[\"Your dictionary has been downloaded.\"],\"YAeum9\":[\"Your dictionary has been updated!\"],\"C0Fx9N\":[\"Your dictionary is empty\"],\"3ma3fF\":[\"Your dictionary is not valid. Please fix the errors and upload it again.\"],\"4bRwmE\":[\"محمد is a triptote;\"],\"kkC1Qd\":[\"موسى is indeclinable.\"],\"jFIhM0\":[\"يوسف is a diptote;\"]}")as Messages; \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1683cbd..f759113 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -29,6 +29,9 @@ importers: '@better-auth/expo': specifier: 1.4.19 version: 1.4.19(@better-auth/core@1.4.19)(better-auth@1.4.19) + '@cloudflare/tanstack-ai': + specifier: ^0.1.5 + version: 0.1.5(@tanstack/ai@0.6.1)(zod@4.3.6) '@elysiajs/cors': specifier: ^1.4.0 version: 1.4.0(elysia@1.4.19) @@ -47,9 +50,6 @@ importers: '@tanstack/ai': specifier: ^0.6.1 version: 0.6.1 - '@tanstack/ai-openai': - specifier: ^0.6.0 - version: 0.6.0(@tanstack/ai@0.6.1)(zod@4.3.6) '@tursodatabase/api': specifier: ^1.9.0 version: 1.9.0 @@ -645,9 +645,9 @@ importers: version: 0.45.1(@libsql/client@0.10.0)(@opentelemetry/api@1.9.0)(@upstash/redis@1.36.0)(bun-types@1.3.5)(kysely@0.28.5) drizzle-zod: specifier: ^0.8.3 - version: 0.8.3(drizzle-orm@0.45.1)(zod@4.0.17) + version: 0.8.3(drizzle-orm@0.45.1)(zod@4.3.6) zod: - specifier: 4.0.17 + specifier: '>=4.0.0' version: 4.3.6 devDependencies: '@bahar/typescript-config': @@ -817,6 +817,36 @@ packages: '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.30 + /@anthropic-ai/sdk@0.71.2(zod@4.3.6): + resolution: {integrity: sha512-TGNDEUuEstk/DKu0/TflXAEt+p+p/WhTlFzEnoosvbaDU2LTjm42igSdlL0VijrKpWejtOKxX0b8A7uc+XiSAQ==} + hasBin: true + requiresBuild: true + peerDependencies: + zod: ^3.25.0 || ^4.0.0 + peerDependenciesMeta: + zod: + optional: true + dependencies: + json-schema-to-ts: 3.1.1 + zod: 4.3.6 + dev: false + optional: true + + /@anthropic-ai/sdk@0.78.0(zod@4.3.6): + resolution: {integrity: sha512-PzQhR715td/m1UaaN5hHXjYB8Gl2lF9UVhrrGrZeysiF6Rb74Wc9GCB8hzLdzmQtBd1qe89F9OptgB9Za1Ib5w==} + hasBin: true + requiresBuild: true + peerDependencies: + zod: ^3.25.0 || ^4.0.0 + peerDependenciesMeta: + zod: + optional: true + dependencies: + json-schema-to-ts: 3.1.1 + zod: 4.3.6 + dev: false + optional: true + /@apideck/better-ajv-errors@0.3.6(ajv@8.18.0): resolution: {integrity: sha512-P+ZygBLZtkp0qqOAJJVX4oX/sFo5JR3eBWwwuqHHhK0GIgQOKWrAfiAaWX0aArHkRWHMuggFEgAZNxVPwPZYaA==} engines: {node: '>=10'} @@ -3727,6 +3757,31 @@ packages: mime: 3.0.0 dev: true + /@cloudflare/tanstack-ai@0.1.5(@tanstack/ai@0.6.1)(zod@4.3.6): + resolution: {integrity: sha512-/HOsjZyXd7BZ5IGagaOWSB5kT/Shuc3dyLezIXkiiiL0sgP5ags6IAh0HAILmguIpPC7KyK0o6A1SjDQPrIv6g==} + peerDependencies: + '@tanstack/ai': ^0.5.0 + dependencies: + '@tanstack/ai': 0.6.1 + openai: 6.25.0(zod@4.3.6) + optionalDependencies: + '@anthropic-ai/sdk': 0.78.0(zod@4.3.6) + '@google/genai': 1.43.0 + '@openrouter/sdk': 0.8.0 + '@tanstack/ai-anthropic': 0.5.0(@tanstack/ai@0.6.1)(zod@4.3.6) + '@tanstack/ai-gemini': 0.5.0(@tanstack/ai@0.6.1) + '@tanstack/ai-grok': 0.5.0(@tanstack/ai@0.6.1)(zod@4.3.6) + '@tanstack/ai-openai': 0.5.0(@tanstack/ai@0.6.1)(zod@4.3.6) + '@tanstack/ai-openrouter': 0.5.1(@tanstack/ai@0.6.1) + transitivePeerDependencies: + - '@modelcontextprotocol/sdk' + - bufferutil + - supports-color + - utf-8-validate + - ws + - zod + dev: false + /@cloudflare/unenv-preset@2.0.2(unenv@2.0.0-rc.14)(workerd@1.20250718.0): resolution: {integrity: sha512-nyzYnlZjjV5xT3LizahG1Iu6mnrCaxglJ04rZLpDwlDVDZ7v46lNsfxhV3A/xtfgQuSHmLnc6SVI+KwBpc3Lwg==} peerDependencies: @@ -5899,6 +5954,27 @@ packages: tslib: 2.8.1 dev: false + /@google/genai@1.43.0: + resolution: {integrity: sha512-hklCsJNdMlDM1IwcCVcGQFBg2izY0+t5BIGbRsxi2UnKi6AGKL7pqJqmBDNRbw0bYCs4y3NA7TB+fkKfP/Nrdw==} + engines: {node: '>=20.0.0'} + requiresBuild: true + peerDependencies: + '@modelcontextprotocol/sdk': ^1.25.2 + peerDependenciesMeta: + '@modelcontextprotocol/sdk': + optional: true + dependencies: + google-auth-library: 10.6.1 + p-retry: 4.6.2 + protobufjs: 7.5.4 + ws: 8.18.3 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: false + optional: true + /@hookform/resolvers@5.2.2(react-hook-form@7.56.4): resolution: {integrity: sha512-A/IxlMLShx3KjV/HeTcTfaMxdwy690+L/ZADoeaTltLx+CVuzkeVIPuybK3jrRfw7YZnmdKsVVHAlEPIAEUNlA==} peerDependencies: @@ -7350,6 +7426,22 @@ packages: fastq: 1.16.0 dev: true + /@openrouter/sdk@0.3.15: + resolution: {integrity: sha512-tmiMQGu6L1fHD9NpIABN9LALEZitqM27CFebSVyJTQDcxCcR3m1F6v1O1MnOlLmedCFU+/BojniRGFAXo1F3Bw==} + requiresBuild: true + dependencies: + zod: 4.3.6 + dev: false + optional: true + + /@openrouter/sdk@0.8.0: + resolution: {integrity: sha512-hmCY5CE/adBmwZmrwuSx7Pw5UngcyuA9FvgpouyWEX8m283omLD1BqJlYYkLdVoUdI8iGNFHKezH2CeJqsVymw==} + requiresBuild: true + dependencies: + zod: 4.3.6 + dev: false + optional: true + /@opentelemetry/api-logs@0.208.0: resolution: {integrity: sha512-CjruKY9V6NMssL/T1kAFgzosF1v9o6oeN+aX5JB/C/xPNtmgIJqcXHG7fA82Ou1zCpWGl4lROQUKwUNE1pMCyg==} engines: {node: '>=8.0.0'} @@ -7985,6 +8077,69 @@ packages: - supports-color dev: false + /@protobufjs/aspromise@1.1.2: + resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} + requiresBuild: true + dev: false + optional: true + + /@protobufjs/base64@1.1.2: + resolution: {integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==} + requiresBuild: true + dev: false + optional: true + + /@protobufjs/codegen@2.0.4: + resolution: {integrity: sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==} + requiresBuild: true + dev: false + optional: true + + /@protobufjs/eventemitter@1.1.0: + resolution: {integrity: sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==} + requiresBuild: true + dev: false + optional: true + + /@protobufjs/fetch@1.1.0: + resolution: {integrity: sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==} + requiresBuild: true + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/inquire': 1.1.0 + dev: false + optional: true + + /@protobufjs/float@1.0.2: + resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==} + requiresBuild: true + dev: false + optional: true + + /@protobufjs/inquire@1.1.0: + resolution: {integrity: sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==} + requiresBuild: true + dev: false + optional: true + + /@protobufjs/path@1.1.2: + resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==} + requiresBuild: true + dev: false + optional: true + + /@protobufjs/pool@1.1.0: + resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==} + requiresBuild: true + dev: false + optional: true + + /@protobufjs/utf8@1.1.0: + resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==} + requiresBuild: true + dev: false + optional: true + /@radix-ui/number@1.1.1: resolution: {integrity: sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==} dev: false @@ -12633,16 +12788,46 @@ packages: vite: 6.4.1(@types/node@20.10.6) dev: false + /@tanstack/ai-anthropic@0.5.0(@tanstack/ai@0.6.1)(zod@4.3.6): + resolution: {integrity: sha512-PiQx4Kpw+NNjXvVhes29LoO/IvD8M9GGQsNvtLCd+dDhZt3FzdNwHWMZBCpaQWPW142iuhowagh79X//onNjDw==} + requiresBuild: true + peerDependencies: + '@tanstack/ai': ^0.5.0 + zod: ^4.0.0 + dependencies: + '@anthropic-ai/sdk': 0.71.2(zod@4.3.6) + '@tanstack/ai': 0.6.1 + zod: 4.3.6 + dev: false + optional: true + /@tanstack/ai-client@0.5.1: resolution: {integrity: sha512-96Qm8sQYBgfLIUR3f09aaLERsNtg+lpZ1J2jiqFTc8YiL+21Ya2Q1JDU3Opd8nNDIhvjwv1tdNxXAsZnwGKKKQ==} dependencies: '@tanstack/ai': 0.6.1 dev: false - /@tanstack/ai-openai@0.6.0(@tanstack/ai@0.6.1)(zod@4.3.6): - resolution: {integrity: sha512-CSDgYr63ftw+nGb1IpB+3qIOngLE1pZjasiaeOdDQ6CbSEJDNcR7VNmyTx3RsoTh9fChKbLhJzYpem1Mpag2og==} + /@tanstack/ai-gemini@0.5.0(@tanstack/ai@0.6.1): + resolution: {integrity: sha512-gunJgwRG+38fbYSE83/XJMHFy/7hDN4Fb91vAAZLK3nh4DoN0ReVbRB4BK9cY9iVYQqGq2PA8d5ruDgfcKO2hQ==} + requiresBuild: true peerDependencies: - '@tanstack/ai': ^0.6.1 + '@tanstack/ai': ^0.5.0 + dependencies: + '@google/genai': 1.43.0 + '@tanstack/ai': 0.6.1 + transitivePeerDependencies: + - '@modelcontextprotocol/sdk' + - bufferutil + - supports-color + - utf-8-validate + dev: false + optional: true + + /@tanstack/ai-grok@0.5.0(@tanstack/ai@0.6.1)(zod@4.3.6): + resolution: {integrity: sha512-X2ix/NmAXC1EyE3UIDSdX+T9A3VwWvQrnAomMyxqGDbDHHm+yQbjioloGOcwQ6Z3yzONeVcO36T6apoX2UPLsw==} + requiresBuild: true + peerDependencies: + '@tanstack/ai': ^0.5.0 zod: ^4.0.0 dependencies: '@tanstack/ai': 0.6.1 @@ -12651,6 +12836,33 @@ packages: transitivePeerDependencies: - ws dev: false + optional: true + + /@tanstack/ai-openai@0.5.0(@tanstack/ai@0.6.1)(zod@4.3.6): + resolution: {integrity: sha512-0xJg+BkqVgIRbl4LyiPQWCLOapfGpK4lSzqjaWRkz2Hf1C3m4exg76rBuv1mvr4G3XAR5SnMRSj3XxlWMuRImA==} + requiresBuild: true + peerDependencies: + '@tanstack/ai': ^0.5.0 + zod: ^4.0.0 + dependencies: + '@tanstack/ai': 0.6.1 + openai: 6.25.0(zod@4.3.6) + zod: 4.3.6 + transitivePeerDependencies: + - ws + dev: false + optional: true + + /@tanstack/ai-openrouter@0.5.1(@tanstack/ai@0.6.1): + resolution: {integrity: sha512-kdv091+tDafNc1V+B4FG0n7sDa49Y2Uqxg3CrXGMR5sdpu5sT4zhg98UJMqK0asdq80ZNwSL8IgyhbStPLcCMQ==} + requiresBuild: true + peerDependencies: + '@tanstack/ai': 0.5.1 + dependencies: + '@openrouter/sdk': 0.3.15 + '@tanstack/ai': 0.6.1 + dev: false + optional: true /@tanstack/ai-react@0.6.1(@tanstack/ai@0.6.1)(@types/react@19.1.17)(react@19.0.0): resolution: {integrity: sha512-9cGHe1z5NSV5QpFRV5CX2CBXco393JfVxEl4DbGkO9bHsc4cHOUm3sglYZ01Ebcq/pDVoUFDrkHaBxn511GrxA==} @@ -13201,6 +13413,12 @@ packages: resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} dev: true + /@types/retry@0.12.0: + resolution: {integrity: sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==} + requiresBuild: true + dev: false + optional: true + /@types/sax@1.2.7: resolution: {integrity: sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==} dependencies: @@ -14497,6 +14715,12 @@ packages: resolution: {integrity: sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==} engines: {node: '>=0.6'} + /bignumber.js@9.3.1: + resolution: {integrity: sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==} + requiresBuild: true + dev: false + optional: true + /binary-extensions@2.2.0: resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} engines: {node: '>=8'} @@ -14624,6 +14848,12 @@ packages: dependencies: node-int64: 0.4.0 + /buffer-equal-constant-time@1.0.1: + resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} + requiresBuild: true + dev: false + optional: true + /buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} @@ -15810,16 +16040,6 @@ packages: kysely: 0.28.5 dev: false - /drizzle-zod@0.8.3(drizzle-orm@0.45.1)(zod@4.0.17): - resolution: {integrity: sha512-66yVOuvGhKJnTdiqj1/Xaaz9/qzOdRJADpDa68enqS6g3t0kpNkwNYjUuaeXgZfO/UWuIM9HIhSlJ6C5ZraMww==} - peerDependencies: - drizzle-orm: '>=0.36.0' - zod: ^3.25.0 || ^4.0.0 - dependencies: - drizzle-orm: 0.45.1(@libsql/client@0.10.0)(@opentelemetry/api@1.9.0)(@upstash/redis@1.36.0)(bun-types@1.3.5)(kysely@0.28.5) - zod: 4.0.17 - dev: false - /drizzle-zod@0.8.3(drizzle-orm@0.45.1)(zod@4.3.6): resolution: {integrity: sha512-66yVOuvGhKJnTdiqj1/Xaaz9/qzOdRJADpDa68enqS6g3t0kpNkwNYjUuaeXgZfO/UWuIM9HIhSlJ6C5ZraMww==} peerDependencies: @@ -15847,6 +16067,14 @@ packages: /eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + /ecdsa-sig-formatter@1.0.11: + resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} + requiresBuild: true + dependencies: + safe-buffer: 5.2.1 + dev: false + optional: true + /ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} @@ -17291,6 +17519,33 @@ packages: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} dev: true + /gaxios@7.1.3: + resolution: {integrity: sha512-YGGyuEdVIjqxkxVH1pUTMY/XtmmsApXrCVv5EU25iX6inEPbV+VakJfLealkBtJN69AQmh1eGOdCl9Sm1UP6XQ==} + engines: {node: '>=18'} + requiresBuild: true + dependencies: + extend: 3.0.2 + https-proxy-agent: 7.0.6 + node-fetch: 3.3.2 + rimraf: 5.0.10 + transitivePeerDependencies: + - supports-color + dev: false + optional: true + + /gcp-metadata@8.1.2: + resolution: {integrity: sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==} + engines: {node: '>=18'} + requiresBuild: true + dependencies: + gaxios: 7.1.3 + google-logging-utils: 1.1.3 + json-bigint: 1.0.0 + transitivePeerDependencies: + - supports-color + dev: false + optional: true + /generator-function@2.0.1: resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==} engines: {node: '>= 0.4'} @@ -17498,6 +17753,29 @@ packages: csstype: 3.2.3 dev: true + /google-auth-library@10.6.1: + resolution: {integrity: sha512-5awwuLrzNol+pFDmKJd0dKtZ0fPLAtoA5p7YO4ODsDu6ONJUVqbYwvv8y2ZBO5MBNp9TJXigB19710kYpBPdtA==} + engines: {node: '>=18'} + requiresBuild: true + dependencies: + base64-js: 1.5.1 + ecdsa-sig-formatter: 1.0.11 + gaxios: 7.1.3 + gcp-metadata: 8.1.2 + google-logging-utils: 1.1.3 + jws: 4.0.1 + transitivePeerDependencies: + - supports-color + dev: false + optional: true + + /google-logging-utils@1.1.3: + resolution: {integrity: sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==} + engines: {node: '>=14'} + requiresBuild: true + dev: false + optional: true + /gopd@1.2.0: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} @@ -19025,9 +19303,27 @@ packages: engines: {node: '>=6'} hasBin: true + /json-bigint@1.0.0: + resolution: {integrity: sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==} + requiresBuild: true + dependencies: + bignumber.js: 9.3.1 + dev: false + optional: true + /json-parse-even-better-errors@2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + /json-schema-to-ts@3.1.1: + resolution: {integrity: sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==} + engines: {node: '>=16'} + requiresBuild: true + dependencies: + '@babel/runtime': 7.28.6 + ts-algebra: 2.0.0 + dev: false + optional: true + /json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} dev: true @@ -19062,6 +19358,25 @@ packages: engines: {node: '>=0.10.0'} dev: true + /jwa@2.0.1: + resolution: {integrity: sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==} + requiresBuild: true + dependencies: + buffer-equal-constant-time: 1.0.1 + ecdsa-sig-formatter: 1.0.11 + safe-buffer: 5.2.1 + dev: false + optional: true + + /jws@4.0.1: + resolution: {integrity: sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==} + requiresBuild: true + dependencies: + jwa: 2.0.1 + safe-buffer: 5.2.1 + dev: false + optional: true + /kleur@3.0.3: resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} engines: {node: '>=6'} @@ -19401,6 +19716,12 @@ packages: chalk: 4.1.2 is-unicode-supported: 0.1.0 + /long@5.3.2: + resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} + requiresBuild: true + dev: false + optional: true + /longest-streak@3.1.0: resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} dev: false @@ -21162,6 +21483,16 @@ packages: p-timeout: 6.1.4 dev: false + /p-retry@4.6.2: + resolution: {integrity: sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==} + engines: {node: '>=8'} + requiresBuild: true + dependencies: + '@types/retry': 0.12.0 + retry: 0.13.1 + dev: false + optional: true + /p-timeout@6.1.4: resolution: {integrity: sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg==} engines: {node: '>=14.16'} @@ -21580,6 +21911,26 @@ packages: resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==} dev: false + /protobufjs@7.5.4: + resolution: {integrity: sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==} + engines: {node: '>=12.0.0'} + requiresBuild: true + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/base64': 1.1.2 + '@protobufjs/codegen': 2.0.4 + '@protobufjs/eventemitter': 1.1.0 + '@protobufjs/fetch': 1.1.0 + '@protobufjs/float': 1.0.2 + '@protobufjs/inquire': 1.1.0 + '@protobufjs/path': 1.1.2 + '@protobufjs/pool': 1.1.0 + '@protobufjs/utf8': 1.1.0 + '@types/node': 20.10.6 + long: 5.3.2 + dev: false + optional: true + /proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} dev: false @@ -22743,6 +23094,13 @@ packages: unified: 11.0.5 dev: false + /retry@0.13.1: + resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==} + engines: {node: '>= 4'} + requiresBuild: true + dev: false + optional: true + /reusify@1.0.4: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} @@ -22753,6 +23111,15 @@ packages: dependencies: glob: 7.2.3 + /rimraf@5.0.10: + resolution: {integrity: sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==} + hasBin: true + requiresBuild: true + dependencies: + glob: 10.4.5 + dev: false + optional: true + /rollup-plugin-inject@3.0.2: resolution: {integrity: sha512-ptg9PQwzs3orn4jkgXJ74bfs5vYz1NCZlSQMBUA0wKcGp5i5pA1AO3fOUEte8enhGUC+iapTCzEWw2jEFFUO/w==} deprecated: This package has been deprecated and is no longer maintained. Please use @rollup/plugin-inject. @@ -23929,6 +24296,12 @@ packages: zod: 4.3.6 dev: true + /ts-algebra@2.0.0: + resolution: {integrity: sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==} + requiresBuild: true + dev: false + optional: true + /ts-fsrs@5.2.3: resolution: {integrity: sha512-R3IjceC9WfnvUin6Nx+DwqEzh3Qil6Gg2yEHqvocUcC7Nbi+xDrFg/1fKaYBT0tJedDnDAguXMSX0hijhi859w==} engines: {node: '>=18.0.0'} @@ -25675,10 +26048,6 @@ packages: /zod@3.25.76: resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} - /zod@4.0.17: - resolution: {integrity: sha512-1PHjlYRevNxxdy2JZ8JcNAw7rX8V9P1AKkP+x/xZfxB0K5FYfuV+Ug6P/6NVSR2jHQ+FzDDoDHS04nYUsOIyLQ==} - dev: false - /zod@4.3.6: resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==} From 254198183a02be751a737b893d3d37fafeaa41c4 Mon Sep 17 00:00:00 2001 From: sufyan Date: Tue, 24 Mar 2026 08:32:22 -0400 Subject: [PATCH 06/15] chore: apply formatter fixes Co-Authored-By: Claude Opus 4.6 (1M context) --- apps/api/src/middleware.ts | 4 +--- .../_app-layout/dictionary/add/route.lazy.tsx | 4 +--- .../_app-layout/dictionary/edit/$wordId.tsx | 4 +--- bahar.pen | 14 ++++++++++++++ 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/apps/api/src/middleware.ts b/apps/api/src/middleware.ts index acd3abf..43ccba3 100644 --- a/apps/api/src/middleware.ts +++ b/apps/api/src/middleware.ts @@ -76,9 +76,7 @@ export const betterAuthGuard = new Elysia({ name: "better-auth" }) }); }, }), - userRateLimit: ( - limits: RateLimiterOpts | RateLimiterOpts[] - ) => ({ + userRateLimit: (limits: RateLimiterOpts | RateLimiterOpts[]) => ({ async resolve(opts) { const { status, user } = opts as typeof opts & { user: User }; const limitsArray = Array.isArray(limits) ? limits : [limits]; diff --git a/apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx b/apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx index a415799..9eb66f6 100644 --- a/apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx +++ b/apps/web/src/routes/_authorized-layout/_app-layout/dictionary/add/route.lazy.tsx @@ -360,9 +360,7 @@ const Add = () => {