From 0ecd78f7e3f95d338a5d92c86e821a2248414abd Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 21 Aug 2026 16:09:22 +0000 Subject: [PATCH] =?UTF-8?q?feat(worker):=20translation-status.ts=20?= =?UTF-8?q?=E2=80=93=20snabb=20=C3=B6versikt=20=C3=B6ver=20=C3=B6vers?= =?UTF-8?q?=C3=A4ttningsl=C3=A4get?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Litet diagnostikscript: skriver ut recipe_translations per språk × status (draft_ai vs published), antal publicerade recept, och varje kontos language_tag. Så man slipper psql för att se hur långt svepet kommit och vilket innehållsspråk ett testkonto faktiskt har. Co-Authored-By: Claude --- apps/worker/scripts/translation-status.ts | 83 +++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 apps/worker/scripts/translation-status.ts diff --git a/apps/worker/scripts/translation-status.ts b/apps/worker/scripts/translation-status.ts new file mode 100644 index 0000000..77536b7 --- /dev/null +++ b/apps/worker/scripts/translation-status.ts @@ -0,0 +1,83 @@ +/** + * Snabb statusöversikt för receptöversättningarna – så du slipper psql. + * + * pnpm --filter @app/worker exec tsx scripts/translation-status.ts + * + * Visar tre saker: + * 1. recipe_translations per språk × status (draft_ai = workern klar men ej + * publicerad; published = syns i appen). + * 2. Antal publicerade recept (referens för hur många × språk ett fullt svep är). + * 3. Varje kontos innehållsspråk (language_tag) – det styr vilket språk + * recepttexten hämtas på, oberoende av UI-språket. + * + * Körs i ett vanligt fönster (inte Fönster A/B/C) – engångskommando som avslutas. + * Kräver DATABASE_URL (laddas från .env precis som translate-recipes.ts). + */ +import { config as loadDotenv } from "dotenv"; +import { existsSync } from "node:fs"; +import path from "node:path"; +import { eq, sql } from "drizzle-orm"; +import { createDatabase, schema } from "@app/database"; + +for (const candidate of [".env", "../.env", "../../.env"]) { + const p = path.resolve(process.cwd(), candidate); + if (existsSync(p)) { + loadDotenv({ path: p }); + break; + } +} + +async function main() { + if (!process.env.DATABASE_URL) throw new Error("Sätt DATABASE_URL."); + const { db, pool } = createDatabase(process.env.DATABASE_URL); + + const rows = await db + .select({ + lang: schema.recipeTranslations.languageTag, + status: schema.recipeTranslations.status, + n: sql`count(*)::int`, + }) + .from(schema.recipeTranslations) + .groupBy(schema.recipeTranslations.languageTag, schema.recipeTranslations.status) + .orderBy(schema.recipeTranslations.languageTag, schema.recipeTranslations.status); + + console.log("\n=== recipe_translations (språk × status) ==="); + if (rows.length === 0) { + console.log(" (inga rader alls – workern har inte skapat några översättningar än)"); + } else { + for (const r of rows) console.log(` ${r.lang.padEnd(7)}${r.status.padEnd(12)}${r.n}`); + } + + const [rec] = await db + .select({ n: sql`count(*)::int` }) + .from(schema.recipes) + .where(eq(schema.recipes.status, "published")); + console.log(`\nPublicerade recept totalt: ${rec?.n ?? 0}`); + + const accounts = await db + .select({ + email: schema.users.email, + lang: schema.userLocalePreferences.languageTag, + region: schema.userLocalePreferences.regionCode, + }) + .from(schema.userLocalePreferences) + .innerJoin(schema.users, eq(schema.users.id, schema.userLocalePreferences.userId)) + .orderBy(schema.users.email); + console.log("\n=== konto → innehållsspråk (language_tag) ==="); + if (accounts.length === 0) { + console.log(" (inga konton har satt språk – alla faller på sv-SE)"); + } else { + for (const a of accounts) { + console.log(` ${(a.email ?? "?").padEnd(30)}${(a.lang ?? "?").padEnd(8)}region=${a.region}`); + } + } + + await pool.end(); +} +main().then( + () => process.exit(0), + (e) => { + console.error(e); + process.exit(1); + }, +);