Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions .github/workflows/news-translate.md
Original file line number Diff line number Diff line change
Expand Up @@ -654,6 +654,39 @@ The TypeScript script generates **structural baselines only** — it translates
3. **Raw Swedish API text** — Interpellation excerpts, proposition summaries that come from the Riksdag API are often pasted as-is. You MUST translate these to the target language or summarize them.
4. **English boilerplate phrases** — Remove or translate phrases like "Read the full proposition", "Live intelligence platform for Swedish Parliament monitoring"
5. **Section headings** that were not covered by CONTENT_LABELS (e.g., specific policy domain names used as h3/h4 headings)
6. **🚨 AI_MUST_REPLACE HTML comments** — SCAN every HTML comment in the **translated** article. If any contains `AI_MUST_REPLACE`, you MUST generate replacement content in the target language. See critical section below.

#### 🚨 CRITICAL: AI_MUST_REPLACE Comment Handling

The content generator embeds placeholder HTML comments in the form:
```html
<!-- AI_MUST_REPLACE: marker_name — DATA: hint text. Write specific analysis here. Output MUST be in the article's language. -->
```

**These comments MUST be replaced with real content before publication.** Leaving them in the article is a hard CI failure (exit 1). The translation workflow MUST:

1. **SCAN every HTML comment** in the translated article for `AI_MUST_REPLACE`
2. **For each marker found**, read the `DATA:` hint inside the comment to understand what content to generate
3. **Replace the entire `<!-- AI_MUST_REPLACE ... -->` comment** with genuine, specific analysis written in the **target language** (not English)
Comment on lines 654 to +670
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new checklist item says to scan every HTML comment in the source article for AI_MUST_REPLACE, but the critical section below says to scan the translated article. Please make this consistent (ideally require scanning the translated output, since that’s what CI validates) to avoid operator confusion.

Copilot uses AI. Check for mistakes.
4. **Use actual document data** (party names, vote counts, document titles) — NOT generic templates
5. **Verify zero markers remain** before creating a PR

**Detection command (run before PR creation):**
```bash
grep -r 'AI_MUST_REPLACE' news/${ARTICLE_DATE}-*-${lang}.html && echo "❌ MARKERS FOUND — must replace before PR" || echo "✅ No markers found"
```

**Common marker types and required output:**
- `timeline_context` → Analysis of scheduling significance and political timing
- `why_matters` → Specific explanation of why these documents matter politically
- `political_impact` → Named-party analysis of political impact with vote arithmetic
- `consequences` → Specific implementation consequences and next steps
- `coalition_instability` → Current coalition stability indicators with evidence
- `critical_assessment` → Critical evaluation of intent vs. likely outcomes
- `single_party_dominance` → Analysis of why one party dominates
- `debate_analysis` → Insights from debate data
- `majority_impact` → Effect of thin majority on specific legislation
- `winners_losers_analysis` → Political winners and losers analysis

#### Translation Completeness Check Process:

Expand Down
11 changes: 11 additions & 0 deletions scripts/check-banned-patterns.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*
* Sources banned patterns from the canonical BANNED_PATTERNS list in shared.ts
* so the bash script does not maintain a duplicate pattern set.
* Also detects unresolved AI_MUST_REPLACE markers in HTML comments.
*
* Usage: npx tsx scripts/check-banned-patterns.ts news/*.html
* Exit code: number of articles containing banned patterns (0 = clean)
Expand All @@ -12,13 +13,23 @@
import { readFileSync } from 'fs';
import { detectBannedPatterns } from './data-transformers/content-generators/shared.js';

/** Regex for unresolved AI_MUST_REPLACE placeholders in HTML comments. */
const AI_MUST_REPLACE_RE = /<!--[\s\S]*?AI_MUST_REPLACE[\s\S]*?-->/;

const files = process.argv.slice(2);
let count = 0;

for (const file of files) {
try {
const html = readFileSync(file, 'utf-8');
const labels = detectBannedPatterns(html);

// Detect AI_MUST_REPLACE markers inside HTML comments — these are
// unresolved template placeholders that must never reach production.
if (AI_MUST_REPLACE_RE.test(html)) {
labels.push('aiMustReplaceComment: Unresolved AI_MUST_REPLACE placeholder in HTML comment');
}

if (labels.length > 0) {
count++;
// Machine-readable output for the bash wrapper
Expand Down
199 changes: 199 additions & 0 deletions scripts/translation-dictionary-committee-names.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
/**
* @module Translation Dictionary — Committee Names
* @description Committee names and Swedish parliamentary institution names
* for all 14 supported languages.
*
* Split from translation-dictionary.ts for maintainability.
* Imported and combined in translation-dictionary.ts.
*/

import type { Language } from './types/language.js';

/**
* Swedish parliamentary institution names and committee names.
* Each entry: [Swedish term, per-language translations].
*/
export const COMMITTEE_NAME_TERMS: ReadonlyArray<readonly [string, Record<Language, string>]> = [
// ---- Swedish parliamentary institution names ----
[
'riksdagen',
{
sv: 'riksdagen', en: 'the Riksdag', da: 'Riksdag', no: 'Riksdag',
fi: 'Riksdag', de: 'Riksdag', fr: 'le Riksdag', es: 'el Riksdag',
nl: 'de Riksdag', ar: 'البرلمان السويدي', he: 'הריקסדאג',
ja: 'スウェーデン国会', ko: '스웨덴 의회', zh: '瑞典议会',
},
],
[
'regeringen',
{
sv: 'regeringen', en: 'the Government', da: 'regeringen', no: 'regjeringen',
fi: 'hallitus', de: 'die Regierung', fr: 'le gouvernement', es: 'el gobierno',
nl: 'de regering', ar: 'الحكومة', he: 'הממשלה',
ja: '政府', ko: '정부', zh: '政府',
},
],
// ---- Committee names ----
[
'arbetsmarknadsutskottet',
{
sv: 'arbetsmarknadsutskottet', en: 'Committee on Labour Market Affairs',
da: 'Arbejdsmarkedsudvalget', no: 'Arbeidsmarkedskomiteen',
fi: 'Työvaliokunta', de: 'Ausschuss für Arbeitsmarktangelegenheiten',
fr: 'Comité du marché du travail', es: 'Comité de Mercado Laboral',
nl: 'Commissie voor Arbeidsmarktzaken', ar: 'لجنة سوق العمل',
he: 'ועדת שוק העבודה', ja: '労働市場委員会', ko: '노동시장위원회', zh: '劳动市场委员会',
},
],
[
'civilutskottet',
{
sv: 'civilutskottet', en: 'Committee on Civil Affairs',
da: 'Civiludvalget', no: 'Sivilkomiteen', fi: 'Siviiliasioiden valiokunta',
de: 'Ausschuss für Zivilrecht', fr: 'Comité des affaires civiles',
es: 'Comité de Asuntos Civiles', nl: 'Commissie voor Burgerlijke Zaken',
ar: 'لجنة الشؤون المدنية', he: 'ועדת ענייני אזרחות',
ja: '市民問題委員会', ko: '민사문제위원회', zh: '民事委员会',
},
],
[
'finansutskottet',
{
sv: 'finansutskottet', en: 'Committee on Finance',
da: 'Finansudvalget', no: 'Finanskomiteen', fi: 'Valtiovarainvaliokunta',
de: 'Finanzausschuss', fr: 'Comité des finances',
es: 'Comité de Finanzas', nl: 'Financiëncommissie',
ar: 'لجنة المالية', he: 'ועדת האוצר',
ja: '財政委員会', ko: '재정위원회', zh: '财政委员会',
},
],
[
'försvarsutskottet',
{
sv: 'försvarsutskottet', en: 'Committee on Defence',
da: 'Forsvarsudvalget', no: 'Forsvarskomiteen', fi: 'Puolustusvaliokunta',
de: 'Verteidigungsausschuss', fr: 'Comité de la défense',
es: 'Comité de Defensa', nl: 'Defensiecommissie',
ar: 'لجنة الدفاع', he: 'ועדת הביטחון', ja: '防衛委員会', ko: '방위위원회', zh: '国防委员会',
},
],
[
'justitieutskottet',
{
sv: 'justitieutskottet', en: 'Committee on Justice',
da: 'Retsudvalget', no: 'Justiskomiteen', fi: 'Lakivaliokunta',
de: 'Rechtsausschuss', fr: 'Comité de justice',
es: 'Comité de Justicia', nl: 'Justitiecommissie',
ar: 'لجنة العدل', he: 'ועדת המשפטים', ja: '司法委員会', ko: '법무위원회', zh: '司法委员会',
},
],
[
'konstitutionsutskottet',
{
sv: 'konstitutionsutskottet', en: 'Committee on the Constitution',
da: 'Forfatningsudvalget', no: 'Konstitusjonskomiteen', fi: 'Perustuslakivaliokunta',
de: 'Verfassungsausschuss', fr: 'Comité de la Constitution',
es: 'Comité Constitucional', nl: 'Grondwetcommissie',
ar: 'لجنة الدستور', he: 'ועדת החוקה', ja: '憲法委員会', ko: '헌법위원회', zh: '宪法委员会',
},
],
[
'kulturutskottet',
{
sv: 'kulturutskottet', en: 'Committee on Cultural Affairs',
da: 'Kulturudvalget', no: 'Kulturkomiteen', fi: 'Kulttuurivaliokunta',
de: 'Kulturausschuss', fr: 'Comité de la culture',
es: 'Comité de Cultura', nl: 'Cultuurcommissie',
ar: 'لجنة الثقافة', he: 'ועדת התרבות', ja: '文化委員会', ko: '문화위원회', zh: '文化委员会',
},
],
[
'miljö- och jordbruksutskottet',
{
sv: 'miljö- och jordbruksutskottet', en: 'Committee on Environment and Agriculture',
da: 'Miljø- og Landbrugsudvalget', no: 'Miljø- og Landbrukskomiteen',
fi: 'Ympäristö- ja maatalousvaliokunta',
de: 'Ausschuss für Umwelt und Landwirtschaft',
fr: 'Comité de l\'environnement et de l\'agriculture',
es: 'Comité de Medio Ambiente y Agricultura',
nl: 'Commissie voor Milieu en Landbouw',
ar: 'لجنة البيئة والزراعة', he: 'ועדת הסביבה והחקלאות',
ja: '環境農業委員会', ko: '환경농업위원회', zh: '环境农业委员会',
},
],
[
'näringsutskottet',
{
sv: 'näringsutskottet', en: 'Committee on Industry and Trade',
da: 'Erhvervsudvalget', no: 'Næringskomiteen', fi: 'Talousvaliokunta',
de: 'Ausschuss für Wirtschaft und Handel', fr: 'Comité de l\'industrie et du commerce',
es: 'Comité de Industria y Comercio', nl: 'Commissie voor Industrie en Handel',
ar: 'لجنة الصناعة والتجارة', he: 'ועדת התעשייה והמסחר',
ja: '産業貿易委員会', ko: '산업통상위원회', zh: '工业贸易委员会',
},
],
[
'skatteutskottet',
{
sv: 'skatteutskottet', en: 'Committee on Taxation',
da: 'Skatteudvalget', no: 'Skattekomiteen', fi: 'Verovaliokunta',
de: 'Steuerausschuss', fr: 'Comité de la fiscalité',
es: 'Comité Fiscal', nl: 'Belastingcommissie',
ar: 'لجنة الضرائب', he: 'ועדת המיסים', ja: '税制委員会', ko: '세금위원회', zh: '税务委员会',
},
],
[
'socialförsäkringsutskottet',
{
sv: 'socialförsäkringsutskottet', en: 'Committee on Social Insurance',
da: 'Socialforsikringsudvalget', no: 'Sosialforsikringskomiteen',
fi: 'Sosiaalivakuutusvaliokunta',
de: 'Ausschuss für Sozialversicherung', fr: 'Comité de l\'assurance sociale',
es: 'Comité de Seguro Social', nl: 'Commissie voor Sociale Verzekering',
ar: 'لجنة التأمين الاجتماعي', he: 'ועדת הביטוח הסוציאלי',
ja: '社会保険委員会', ko: '사회보험위원회', zh: '社会保险委员会',
},
],
[
'socialutskottet',
{
sv: 'socialutskottet', en: 'Committee on Social Affairs',
da: 'Socialudvalget', no: 'Sosialkomiteen', fi: 'Sosiaaliasioiden valiokunta',
de: 'Sozialausschuss', fr: 'Comité des affaires sociales',
es: 'Comité de Asuntos Sociales', nl: 'Sociale Commissie',
ar: 'لجنة الشؤون الاجتماعية', he: 'ועדת הרווחה',
ja: '社会問題委員会', ko: '사회문제위원회', zh: '社会事务委员会',
},
],
[
'trafikutskottet',
{
sv: 'trafikutskottet', en: 'Committee on Transport',
da: 'Trafikudvalget', no: 'Transportkomiteen', fi: 'Liikennevaliokunta',
de: 'Verkehrsausschuss', fr: 'Comité des transports',
es: 'Comité de Transporte', nl: 'Transportcommissie',
ar: 'لجنة المواصلات', he: 'ועדת התחבורה', ja: '交通委員会', ko: '교통위원회', zh: '交通委员会',
},
],
[
'utbildningsutskottet',
{
sv: 'utbildningsutskottet', en: 'Committee on Education',
da: 'Uddannelsesudvalget', no: 'Utdanningskomiteen', fi: 'Koulutusvaliokunta',
de: 'Bildungsausschuss', fr: 'Comité de l\'éducation',
es: 'Comité de Educación', nl: 'Onderwijscommissie',
ar: 'لجنة التعليم', he: 'ועדת החינוך', ja: '教育委員会', ko: '교육위원회', zh: '教育委员会',
},
],
[
'utrikesutskottet',
{
sv: 'utrikesutskottet', en: 'Committee on Foreign Affairs',
da: 'Udenrigsudvalget', no: 'Utenrikskomiteen', fi: 'Ulkoasiainvaliokunta',
de: 'Außenpolitischer Ausschuss', fr: 'Comité des affaires étrangères',
es: 'Comité de Asuntos Exteriores', nl: 'Commissie voor Buitenlandse Zaken',
ar: 'لجنة الشؤون الخارجية', he: 'ועדת החוץ',
ja: '外務委員会', ko: '외무위원회', zh: '外交委员会',
},
],
];
Loading
Loading