Files
Cibello-app/apps/worker/scripts/translation-status.ts
T
Claude 0ecd78f7e3 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>
2026-08-21 16:09:22 +00:00

84 lines
2.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 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);
},
);