feat(worker): translation-status.ts – snabb översikt över översättningsläget

- 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 <noreply@anthropic.com>
This commit is contained in:
Claude
2026-08-21 16:09:22 +00:00
parent b5bfb7cb8b
commit 0ecd78f7e3
+83
View File
@@ -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<number>`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<number>`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);
},
);