Skip to content

Improve deep-inspection article quality: URL stripping, single-doc 5W analysis, localized labels, press/ext differentiation#1086

Merged
pethers merged 9 commits intomainfrom
copilot/analyze-deep-inspection-article-issues
Mar 12, 2026
Merged

Improve deep-inspection article quality: URL stripping, single-doc 5W analysis, localized labels, press/ext differentiation#1086
pethers merged 9 commits intomainfrom
copilot/analyze-deep-inspection-article-issues

Conversation

Copy link
Contributor

Copilot AI commented Mar 12, 2026

  • Strip markdown links and bare URLs from extracted text
  • Single-doc 5W analysis for deep-inspection
  • Localize doc type labels in charts/mindmaps
  • Split press vs ext templates in EN and SV
  • Localize chart dataset/title and mindmap branch labels
  • SV legislative fallback in buildStrategicImplications
  • Dashboard summary singular/plural handling
  • Full 14-language singular/plural DOC_TYPE_DISPLAY
  • Fix SV singular/plural for "berikade med fulltext" → "berikat" when count === 1
  • Export and centralize DOC_TYPE_DISPLAY/localizeDocType — eliminate duplicate DEEP_DOC_TYPE_LABELS
  • Pass count through docTypeLabel() for correct singular/plural in charts, mindmaps, per-doc labels
  • Fix SV duplicate "belyser" → "belyser...lyfter fram" in ext-only wording
  • Update SV article with corrected singular forms
  • All 2920 tests pass

💬 Send tasks to Copilot coding agent from Slack and Teams to turn conversations into code. Copilot posts an update in your thread when it's finished.

… docs, localized labels, richer content

- Fix extractKeyPassage to strip URLs and markdown links from extracted text
- Lower 5W analysis minimum doc count for deep-inspection from 2 to 1
- Localize document type codes in charts, mindmaps, and 5W WHAT section
- Improve strategic implications for press releases / non-legislative docs
- Improve key takeaways with policy domain insights and press release context
- Improve SWOT defaults to be more topic-specific when topic is provided
- Add tests for extractKeyPassage URL stripping and single-doc deep analysis

Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
Copilot AI changed the title [WIP] Analyze issues with deep inspection article quality Improve deep-inspection article quality: URL stripping, single-doc 5W analysis, localized labels Mar 12, 2026
@pethers pethers requested a review from Copilot March 12, 2026 13:52
@github-actions github-actions bot added testing Test coverage refactor Code refactoring size-m Medium change (50-250 lines) labels Mar 12, 2026
@github-actions
Copy link
Contributor

🔍 Lighthouse Performance Audit

Category Score Status
Performance 85/100 🟡
Accessibility 95/100 🟢
Best Practices 90/100 🟢
SEO 95/100 🟢

📥 Download full Lighthouse report

Budget Compliance: Performance budgets enforced via budget.json

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Improves the quality of generated deep-inspection articles by cleaning extracted passages, enabling 5W deep-analysis for single-document inspections, and localizing document-type labels in analytical outputs.

Changes:

  • Strip markdown links and bare URLs during key-passage extraction, with new dedicated tests.
  • Allow generateDeepAnalysisSection() to render for deep-inspection with a single document (while keeping the 2-doc minimum for other article types), with updated tests.
  • Localize document-type labels in deep-inspection dashboards/mindmap doc-type branches and in the deep-analysis “WHAT” doc-type list; expand strategic implications / takeaways for press-release-heavy inputs.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tests/extract-key-passage.test.ts Adds coverage for URL/markdown stripping and truncation behavior in extractKeyPassage().
tests/deep-analysis-section.test.ts Updates expectations for single-doc deep-inspection behavior in 5W deep-analysis generation.
scripts/generate-news-enhanced/generators.ts Enhances deep-inspection narrative sections, localizes chart/mindmap doc-type labels, and adds press-release-aware takeaways/implications.
scripts/data-transformers/helpers.ts Extends extractKeyPassage() to strip markdown links and bare http(s) URLs before truncation.
scripts/data-transformers/content-generators/shared.ts Adds doc-type localization for deep-analysis “WHAT” section and adjusts minimum-doc threshold for deep-inspection.

Comment on lines +838 to +842
if (isPressOrExternal) {
// Non-legislative documents (press releases, external) — policy-signalling focus
const typeDesc = pressmCount > 0 ? `${pressmCount} government press release${pressmCount !== 1 ? 's' : ''}` : `${extCount} external reference${extCount !== 1 ? 's' : ''}`;
enText = `Based on analysis of ${docs.length} document${docs.length !== 1 ? 's' : ''} (${enrichedCount} enriched with full text)${topic ? ` specifically addressing <strong>${esc(topic)}</strong>` : ''}: This deep inspection examines ${typeDesc}${domainPhrase ? ` spanning ${domainPhrase}` : ''}. Government press communications signal policy priorities and upcoming legislative action. Stakeholders should track whether formal propositions or committee referrals follow, which would confirm the transition from policy signalling to legislative commitment.`;
} else if (isLegislativeFocused) {
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

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

In the isPressOrExternal branch, the text always states “Government press communications signal…” even when the input set contains only ext documents (no pressm). In that case the paragraph becomes internally inconsistent (it describes external references but draws conclusions about government press communications). Consider splitting pressm vs ext into separate templates, or only mentioning press communications when pressmCount > 0.

Copilot uses AI. Check for mistakes.
let svText: string;
if (isPressOrExternal) {
const typeDescSv = pressmCount > 0 ? `${pressmCount} pressmeddelande${pressmCount !== 1 ? 'n' : ''}` : `${extCount} extern${extCount !== 1 ? 'a' : ''} referens${extCount !== 1 ? 'er' : ''}`;
svText = `Baserat på analys av ${docs.length} dokument (${enrichedCount} berikade med fulltext)${topic ? ` med specifik inriktning på <strong>${esc(topic)}</strong>` : ''}: Denna djupanalys granskar ${typeDescSv}${domainPhrase ? ` inom ${domainPhrase}` : ''}. Regeringens presskommunikation signalerar politiska prioriteringar och kommande lagstiftningsåtgärder. Intressenter bör bevaka om formella propositioner eller utskottsremisser följer.`;
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

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

Same issue in the Swedish isPressOrExternal branch: the paragraph refers to “Regeringens presskommunikation …” even when the documents are only ext (external references) and no press releases are present. This makes the generated analysis misleading for ext-only deep inspections.

Suggested change
svText = `Baserat på analys av ${docs.length} dokument (${enrichedCount} berikade med fulltext)${topic ? ` med specifik inriktning på <strong>${esc(topic)}</strong>` : ''}: Denna djupanalys granskar ${typeDescSv}${domainPhrase ? ` inom ${domainPhrase}` : ''}. Regeringens presskommunikation signalerar politiska prioriteringar och kommande lagstiftningsåtgärder. Intressenter bör bevaka om formella propositioner eller utskottsremisser följer.`;
const signalPhraseSv =
pressmCount > 0
? 'Regeringens presskommunikation signalerar politiska prioriteringar och kommande lagstiftningsåtgärder.'
: 'Dessa externa referenser belyser regeringens politiska prioriteringar och möjliga kommande lagstiftningsåtgärder.';
svText = `Baserat på analys av ${docs.length} dokument (${enrichedCount} berikade med fulltext)${topic ? ` med specifik inriktning på <strong>${esc(topic)}</strong>` : ''}: Denna djupanalys granskar ${typeDescSv}${domainPhrase ? ` inom ${domainPhrase}` : ''}. ${signalPhraseSv} Intressenter bör bevaka om formella propositioner eller utskottsremisser följer.`;

Copilot uses AI. Check for mistakes.
Comment on lines 1155 to +1158
datasets: [{
label: 'Documents',
data: chartValues,
backgroundColor: chartLabels.map((_, i) => DEEP_CHART_PALETTE[i % DEEP_CHART_PALETTE.length]),
backgroundColor: rawTypeKeys.map((_, i) => DEEP_CHART_PALETTE[i % DEEP_CHART_PALETTE.length]),
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

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

The Chart.js dataset label is hard-coded as "Documents", so it will stay English on non-EN deep-inspection pages. This file already localizes user-facing strings via DEEP_SECTION_LABELS (section headings) and DEEP_DOC_TYPE_LABELS (doc types), so the chart label/title should follow the same pattern for consistency.

Copilot uses AI. Check for mistakes.
Comment on lines +1174 to +1178
mindmapBranches.push({
label: 'Document Types',
color: 'cyan',
icon: '📄',
items: chartLabels.map((t, i) => `${t} (${chartValues[i] ?? 0})`),
items: rawTypeKeys.map((t, i) => `${docTypeLabel(t, lang)} (${chartValues[i] ?? 0})`),
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

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

Mindmap branch labels are still hard-coded in English (e.g. "Document Types"). Since deep-inspection explicitly supports many languages in this file (e.g. DEEP_SECTION_LABELS, dataSourceBranchLabels), consider localizing this branch label as well so non-EN pages don’t mix localized items with an English heading.

Copilot uses AI. Check for mistakes.
@pethers
Copy link
Member

pethers commented Mar 12, 2026

@copilot apply changes based on the comments in this thread also regenerate the bad articles. focus on deep political intelligence analysis. is all content evaluated by copilot everywhere ?

Analyse and improve and test by generated update articles

Copilot AI and others added 2 commits March 12, 2026 14:16
…ndmap labels, regenerate articles

- Fix isPressOrExternal EN/SV branches to differentiate press vs ext messaging
- Localize chart dataset label, chart title, and mindmap branch labels (14 languages)
- Add DEEP_SECTION_LABELS entries: documentsByType, documents, documentsAnalysed,
  documentTypes, policyDomains, stakeholders
- Regenerate EN/SV deep-inspection articles with:
  - Removed lyyti.in registration URL from doc analysis
  - Replaced "0 propositions, 0 reports, 0 motions" with press-release-specific analysis
  - Expanded key takeaways (1 → 5 items) with policy intelligence
  - Added 5W deep analysis section (WHO/WHAT/WHEN/WHY/IMPACT)
  - Localized chart labels: pressm → Press Release / Pressmeddelande
  - Localized mindmap labels: pressm → Press Release / Pressmeddelande
  - Topic-specific SWOT entries replacing generic defaults
  - Updated word counts, reading times, and OG descriptions

Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
…ence text in SV

Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Mar 12, 2026

@copilot apply changes based on the comments in this thread also regenerate the bad articles. focus on deep politica...

Applied all 4 review thread comments in a77f179 and 706ae53:

  1. Split press vs ext templates — EN and SV isPressOrExternal branches now differentiate between press releases ("Government press communications signal…") and external references ("illuminate the policy landscape…")
  2. Localized chart labels — dataset label "Documents" → 14 languages via DEEP_SECTION_LABELS
  3. Localized mindmap branch labels — "Document Types", "Policy Domains", "Stakeholders" → 14 languages

Regenerated both EN and SV articles (a77f179) with deep political intelligence focus:

  • Removed lyyti.in registration URL leak
  • Replaced vacuous "0 propositions, 0 reports, 0 motions" with press-release-specific strategic analysis
  • Expanded key takeaways from 1 → 5 items with policy intelligence (EU benchmarking, recruitment pipeline, cross-cutting reform analysis)
  • Added full 5W deep analysis section (WHO/WHAT/WHEN/WHY/IMPACT) with political intelligence on paid police education reform
  • Topic-specific SWOT entries (police education reform risks, fiscal priorities) replacing generic defaults
  • Localized chart/mindmap labels: pressm → "Press Release" / "Pressmeddelande"
  • Updated word counts (446→1203 EN, 397→1032 SV), reading times, and OG descriptions

All content is evaluated through the code generators — the improvements to buildStrategicImplications, buildKeyTakeaways, docTypeLabel, and DEEP_SECTION_LABELS ensure future deep-inspection articles will automatically produce higher-quality, localized, press-release-aware intelligence analysis. All 2920 tests pass.

Copilot AI changed the title Improve deep-inspection article quality: URL stripping, single-doc 5W analysis, localized labels Improve deep-inspection article quality: URL stripping, single-doc 5W analysis, localized labels, press/ext differentiation Mar 12, 2026
@pethers pethers requested a review from Copilot March 12, 2026 14:26
@github-actions github-actions bot added html-css HTML/CSS changes translation Translation updates news News articles and content generation size-l Large change (250-1000 lines) labels Mar 12, 2026
@github-actions
Copy link
Contributor

🔍 Lighthouse Performance Audit

Category Score Status
Performance 85/100 🟡
Accessibility 95/100 🟢
Best Practices 90/100 🟢
SEO 95/100 🟢

📥 Download full Lighthouse report

Budget Compliance: Performance budgets enforced via budget.json

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.

Comment on lines +895 to +896
} else {
svText = `Baserat på analys av ${docs.length} riksdagsdokument (${enrichedCount} berikade med fulltext)${topic ? ` med specifik inriktning på <strong>${esc(topic)}</strong>` : ''}: Det lagstiftande flödet visar ${propCount} proposition${propCount !== 1 ? 'er' : ''}, ${betCount} betänkande${betCount !== 1 ? 'n' : ''} och ${motCount} motion${motCount !== 1 ? 'er' : ''}. Intressenter bör följa utskottens överläggningar och kammarens voteringsmönster.`;
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

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

In buildStrategicImplications, the Swedish branch only distinguishes isPressOrExternal vs “everything else”. For non-legislative, non-press/ext document sets (e.g. skr, fpm, sfs), this will still render the legislative pipeline sentence and can produce misleading “0 propositioner, 0 betänkanden, 0 motioner” output. Mirror the English logic by adding an else if (isLegislativeFocused) branch for svText, and a non-legislative fallback that doesn’t talk about the legislative pipeline when legislativeCount === 0.

Suggested change
} else {
svText = `Baserat på analys av ${docs.length} riksdagsdokument (${enrichedCount} berikade med fulltext)${topic ? ` med specifik inriktning på <strong>${esc(topic)}</strong>` : ''}: Det lagstiftande flödet visar ${propCount} proposition${propCount !== 1 ? 'er' : ''}, ${betCount} betänkande${betCount !== 1 ? 'n' : ''} och ${motCount} motion${motCount !== 1 ? 'er' : ''}. Intressenter bör följa utskottens överläggningar och kammarens voteringsmönster.`;
} else if (isLegislativeFocused && legislativeCount > 0) {
svText = `Baserat på analys av ${docs.length} riksdagsdokument (${enrichedCount} berikade med fulltext)${topic ? ` med specifik inriktning på <strong>${esc(topic)}</strong>` : ''}: Det lagstiftande flödet visar ${propCount} proposition${propCount !== 1 ? 'er' : ''}, ${betCount} betänkande${betCount !== 1 ? 'n' : ''} och ${motCount} motion${motCount !== 1 ? 'er' : ''}. Intressenter bör följa utskottens överläggningar och kammarens voteringsmönster.`;
} else {
svText = `Baserat på analys av ${docs.length} riksdagsdokument (${enrichedCount} berikade med fulltext)${topic ? ` med specifik inriktning på <strong>${esc(topic)}</strong>` : ''}${domainPhrase ? ` inom ${domainPhrase}` : ''}: Analysen ger en ögonblicksbild av den aktuella politiska inriktningen och dess betydelse för centrala intressenter.`;

Copilot uses AI. Check for mistakes.
Comment on lines +1189 to 1192
? `${deepLabel('documentIntelligence', lang)} — ${topic}`
: deepLabel('documentIntelligence', lang),
summary: `${docs.length} ${deepLabel('documentsAnalysed', lang)}`,
charts: [{
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

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

The dashboard summary uses ${docs.length} ${deepLabel('documentsAnalysed', lang)} where the translation value is a fixed phrase like “parliamentary documents analysed”. For docs.length === 1 this produces grammatically incorrect output (e.g. “1 parliamentary documents analysed”), and it can drift from already-generated pages that use a singular form. Consider handling singular/plural explicitly (either via separate label keys or by moving the count into the localized template).

Copilot uses AI. Check for mistakes.
Comment on lines +17 to +31
/** Localise raw Riksdag document type codes for display. */
const DOC_TYPE_DISPLAY: Readonly<Record<string, Partial<Record<Language, string>>>> = {
prop: { en: 'Propositions', sv: 'Propositioner' },
bet: { en: 'Committee Reports', sv: 'Betänkanden' },
mot: { en: 'Motions', sv: 'Motioner' },
skr: { en: 'Government Communications', sv: 'Skrivelser' },
sfs: { en: 'Laws/Statutes', sv: 'Lagar/Förordningar' },
fpm: { en: 'EU Position Papers', sv: 'Faktapromemorior' },
pressm: { en: 'Press Releases', sv: 'Pressmeddelanden' },
ext: { en: 'External References', sv: 'Externa referenser' },
};

function localizeDocType(code: string, lang: Language | string): string {
const map = DOC_TYPE_DISPLAY[code];
return (map?.[lang as Language]) ?? (map?.en ?? code);
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

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

DOC_TYPE_DISPLAY / localizeDocType() only includes EN/SV and uses plural display names (e.g. “Press Releases”). This means the deep-analysis doc-type breakdown will show English (or raw codes) for the other supported languages, and will produce awkward singular cases like “Press Releases: 1”. To keep localization consistent with the rest of the repo (14-language labels) and avoid duplicated mappings, consider centralizing doc-type localization and providing singular/plural-aware labels for all languages.

Suggested change
/** Localise raw Riksdag document type codes for display. */
const DOC_TYPE_DISPLAY: Readonly<Record<string, Partial<Record<Language, string>>>> = {
prop: { en: 'Propositions', sv: 'Propositioner' },
bet: { en: 'Committee Reports', sv: 'Betänkanden' },
mot: { en: 'Motions', sv: 'Motioner' },
skr: { en: 'Government Communications', sv: 'Skrivelser' },
sfs: { en: 'Laws/Statutes', sv: 'Lagar/Förordningar' },
fpm: { en: 'EU Position Papers', sv: 'Faktapromemorior' },
pressm: { en: 'Press Releases', sv: 'Pressmeddelanden' },
ext: { en: 'External References', sv: 'Externa referenser' },
};
function localizeDocType(code: string, lang: Language | string): string {
const map = DOC_TYPE_DISPLAY[code];
return (map?.[lang as Language]) ?? (map?.en ?? code);
/** Localise raw Riksdag document type codes for display (singular/plural-aware, multi-language). */
type DocTypeLocalization = {
singular: Partial<Record<Language, string>>;
plural: Partial<Record<Language, string>>;
};
const DOC_TYPE_DISPLAY: Readonly<Record<string, DocTypeLocalization>> = {
prop: {
singular: {
en: 'Proposition',
sv: 'Proposition',
da: 'Proposition',
no: 'Proposisjon',
fi: 'Hallituksen esitys',
de: 'Regierungsvorlage',
fr: 'Projet de loi',
es: 'Proposición',
nl: 'Wetsvoorstel',
ar: 'مقترح قانون',
he: 'הצעת חוק',
ja: '法案',
ko: '정부 제출 법안',
zh: '政府法案',
},
plural: {
en: 'Propositions',
sv: 'Propositioner',
da: 'Propositioner',
no: 'Proposisjoner',
fi: 'Hallituksen esitykset',
de: 'Regierungsvorlagen',
fr: 'Projets de loi',
es: 'Proposiciones',
nl: 'Wetsvoorstellen',
ar: 'مقترحات قوانين',
he: 'הצעות חוק',
ja: '法案',
ko: '정부 제출 법안',
zh: '政府法案',
},
},
bet: {
singular: {
en: 'Committee Report',
sv: 'Betänkande',
da: 'Udvalgsbetænkning',
no: 'Komitéinnstilling',
fi: 'Valiokunnan mietintö',
de: 'Ausschussbericht',
fr: 'Rapport de commission',
es: 'Informe de comisión',
nl: 'Commissieverslag',
ar: 'تقرير لجنة',
he: 'דוח ועדה',
ja: '委員会報告書',
ko: '위원회 보고서',
zh: '委员会报告',
},
plural: {
en: 'Committee Reports',
sv: 'Betänkanden',
da: 'Udvalgsbetænkninger',
no: 'Komitéinnstillinger',
fi: 'Valiokunnan mietinnöt',
de: 'Ausschussberichte',
fr: 'Rapports de commission',
es: 'Informes de comisión',
nl: 'Commissieverslagen',
ar: 'تقارير لجان',
he: 'דוחות ועדה',
ja: '委員会報告書',
ko: '위원회 보고서',
zh: '委员会报告',
},
},
mot: {
singular: {
en: 'Motion',
sv: 'Motion',
da: 'Forslag',
no: 'Forslag',
fi: 'Aloite',
de: 'Antrag',
fr: 'Motion',
es: 'Moción',
nl: 'Motie',
ar: 'مقترح',
he: 'הצעה',
ja: '動議',
ko: '동의안',
zh: '动议',
},
plural: {
en: 'Motions',
sv: 'Motioner',
da: 'Forslag',
no: 'Forslag',
fi: 'Aloitteet',
de: 'Anträge',
fr: 'Motions',
es: 'Mociones',
nl: 'Moties',
ar: 'مقترحات',
he: 'הצעות',
ja: '動議',
ko: '동의안',
zh: '动议',
},
},
skr: {
singular: {
en: 'Government Communication',
sv: 'Skrivelse',
da: 'Regeringsskrivelse',
no: 'Regjeringsskriv',
fi: 'Valtioneuvoston kirjelmä',
de: 'Regierungsschreiben',
fr: 'Communication du gouvernement',
es: 'Comunicación del gobierno',
nl: 'Regeringsmededeling',
ar: 'مذكرة حكومية',
he: 'מכתב ממשלתי',
ja: '政府通信文書',
ko: '정부 통신문',
zh: '政府公文',
},
plural: {
en: 'Government Communications',
sv: 'Skrivelser',
da: 'Regeringsskrivelser',
no: 'Regjeringsskriv',
fi: 'Valtioneuvoston kirjelmät',
de: 'Regierungsschreiben',
fr: 'Communications du gouvernement',
es: 'Comunicaciones del gobierno',
nl: 'Regeringsmededelingen',
ar: 'مذكرات حكومية',
he: 'מכתבים ממשלתיים',
ja: '政府通信文書',
ko: '정부 통신문',
zh: '政府公文',
},
},
sfs: {
singular: {
en: 'Law/Statute',
sv: 'Lag/förordning',
da: 'Lov/forordning',
no: 'Lov/forordning',
fi: 'Laki/asetus',
de: 'Gesetz/Verordnung',
fr: 'Loi/Règlement',
es: 'Ley/Reglamento',
nl: 'Wet/Verordening',
ar: 'قانون / لائحة',
he: 'חוק/תקנה',
ja: '法律/条例',
ko: '법률/법규',
zh: '法律/法规',
},
plural: {
en: 'Laws/Statutes',
sv: 'Lagar/förordningar',
da: 'Love/forordninger',
no: 'Lover/forordninger',
fi: 'Lait/asetukset',
de: 'Gesetze/Verordnungen',
fr: 'Lois/Règlements',
es: 'Leyes/Reglamentos',
nl: 'Wetten/Verordeningen',
ar: 'قوانين / لوائح',
he: 'חוקים/תקנות',
ja: '法律/条例',
ko: '법률/법규',
zh: '法律/法规',
},
},
fpm: {
singular: {
en: 'EU Position Paper',
sv: 'Faktapromemoria',
da: 'EU-faktanota',
no: 'EU-faktanotat',
fi: 'EU-tietomuistio',
de: 'EU-Positionspapier',
fr: 'Note de position UE',
es: 'Documento de posición de la UE',
nl: 'EU-positiepaper',
ar: 'ورقة موقف للاتحاد الأوروبي',
he: 'מסמך עמדה של האיחוד האירופי',
ja: 'EUポジションペーパー',
ko: 'EU 입장 문서',
zh: '欧盟立场文件',
},
plural: {
en: 'EU Position Papers',
sv: 'Faktapromemorior',
da: 'EU-faktanotaer',
no: 'EU-faktanotater',
fi: 'EU-tietomuistiot',
de: 'EU-Positionspapiere',
fr: 'Notes de position UE',
es: 'Documentos de posición de la UE',
nl: 'EU-positiepapers',
ar: 'أوراق موقف للاتحاد الأوروبي',
he: 'מסמכי עמדה של האיחוד האירופי',
ja: 'EUポジションペーパー',
ko: 'EU 입장 문서',
zh: '欧盟立场文件',
},
},
pressm: {
singular: {
en: 'Press Release',
sv: 'Pressmeddelande',
da: 'Pressemeddelelse',
no: 'Pressemelding',
fi: 'Lehdistötiedote',
de: 'Pressemitteilung',
fr: 'Communiqué de presse',
es: 'Comunicado de prensa',
nl: 'Persbericht',
ar: 'بيان صحفي',
he: 'הודעה לעיתונות',
ja: 'プレスリリース',
ko: '보도자료',
zh: '新闻稿',
},
plural: {
en: 'Press Releases',
sv: 'Pressmeddelanden',
da: 'Pressemeddelelser',
no: 'Pressemeldinger',
fi: 'Lehdistötiedotteet',
de: 'Pressemitteilungen',
fr: 'Communiqués de presse',
es: 'Comunicados de prensa',
nl: 'Persberichten',
ar: 'بيانات صحفية',
he: 'הודעות לעיתונות',
ja: 'プレスリリース',
ko: '보도자료',
zh: '新闻稿',
},
},
ext: {
singular: {
en: 'External Reference',
sv: 'Extern referens',
da: 'Ekstern reference',
no: 'Ekstern referanse',
fi: 'Ulkoinen viite',
de: 'Externe Referenz',
fr: 'Référence externe',
es: 'Referencia externa',
nl: 'Externe referentie',
ar: 'مرجع خارجي',
he: 'הפניה חיצונית',
ja: '外部参照',
ko: '외부 참조',
zh: '外部参考',
},
plural: {
en: 'External References',
sv: 'Externa referenser',
da: 'Eksterne referencer',
no: 'Eksterne referanser',
fi: 'Ulkoiset viitteet',
de: 'Externe Referenzen',
fr: 'Références externes',
es: 'Referencias externas',
nl: 'Externe referenties',
ar: 'مراجع خارجية',
he: 'הפניות חיצוניות',
ja: '外部参照',
ko: '외부 참조',
zh: '外部参考',
},
},
};
function localizeDocType(code: string, lang: Language | string, count?: number): string {
const entry = DOC_TYPE_DISPLAY[code];
if (!entry) {
return code;
}
const useSingular = count === 1;
const form = useSingular ? entry.singular : entry.plural;
const localized =
form[lang as Language] ??
form.en ??
(useSingular ? entry.plural[lang as Language] ?? entry.plural.en : entry.singular[lang as Language] ?? entry.singular.en);
return localized ?? code;

Copilot uses AI. Check for mistakes.
Copilot AI and others added 2 commits March 12, 2026 15:05
…plural dashboard labels, 14-language DOC_TYPE_DISPLAY

- Fix SV buildStrategicImplications: add isLegislativeFocused branch + non-legislative
  fallback to avoid "0 propositioner, 0 betänkanden, 0 motioner" for non-legislative docs
- Fix dashboard summary singular/plural: "1 parliamentary document analysed" vs
  "N parliamentary documents analysed" via new documentAnalysed label key
- Expand DOC_TYPE_DISPLAY to full 14-language singular/plural-aware localization
  (prop, bet, mot, skr, sfs, fpm, pressm, ext × 14 languages × singular/plural)
- Update localizeDocType() to accept optional count parameter for singular/plural
- Update regenerated articles: singular forms for doc type labels and dashboard summary

Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
…ack form → fallback EN

Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Mar 12, 2026

@copilot apply changes based on the comments in this thread

Applied all 3 review comments from thread #3937117849 in 39bc476 and 2e71996:

  1. SV buildStrategicImplications — added isLegislativeFocused && legislativeCount > 0 branch + non-legislative fallback ("Analysen ger en ögonblicksbild…"), mirroring the EN 3-way logic. Prevents "0 propositioner, 0 betänkanden, 0 motioner" for skr/fpm/sfs document sets.

  2. Dashboard summary singular/plural — added documentAnalysed (singular) label key for all 14 languages. Summary now renders "1 parliamentary document analysed" / "1 riksdagsdokument analyserat" instead of the grammatically incorrect plural form.

  3. Full 14-language singular/plural DOC_TYPE_DISPLAY — replaced EN/SV-only plural-form mapping with DocTypeLocalization type: 8 doc types × 14 languages × singular/plural = 224 localized labels. localizeDocType(code, lang, count?) now selects the correct form. Updated 5W WHAT section to pass count, so it renders "Press Release: 1" (not "Press Releases: 1").

All 2920 tests pass, 0 CodeQL alerts.

@github-actions
Copy link
Contributor

🔍 Lighthouse Performance Audit

Category Score Status
Performance 85/100 🟡
Accessibility 95/100 🟢
Best Practices 90/100 🟢
SEO 95/100 🟢

📥 Download full Lighthouse report

Budget Compliance: Performance budgets enforced via budget.json

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 5 comments.

Comment on lines +894 to +904
let svText: string;
if (isPressOrExternal) {
const typeDescSv = pressmCount > 0 ? `${pressmCount} pressmeddelande${pressmCount !== 1 ? 'n' : ''}` : `${extCount} extern${extCount !== 1 ? 'a' : ''} referens${extCount !== 1 ? 'er' : ''}`;
const signalTextSv = pressmCount > 0
? 'Regeringens presskommunikation signalerar politiska prioriteringar och kommande lagstiftningsåtgärder.'
: 'Dessa externa referenser belyser det politiska landskapet och belyser områden av potentiellt lagstiftningsintresse.';
svText = `Baserat på analys av ${docs.length} dokument (${enrichedCount} berikade med fulltext)${topic ? ` med specifik inriktning på <strong>${esc(topic)}</strong>` : ''}: Denna djupanalys granskar ${typeDescSv}${domainPhrase ? ` inom ${domainPhrase}` : ''}. ${signalTextSv} Intressenter bör bevaka om formella propositioner eller utskottsremisser följer.`;
} else if (isLegislativeFocused && legislativeCount > 0) {
svText = `Baserat på analys av ${docs.length} riksdagsdokument (${enrichedCount} berikade med fulltext)${topic ? ` med specifik inriktning på <strong>${esc(topic)}</strong>` : ''}: Det lagstiftande flödet visar ${propCount} proposition${propCount !== 1 ? 'er' : ''}, ${betCount} betänkande${betCount !== 1 ? 'n' : ''} och ${motCount} motion${motCount !== 1 ? 'er' : ''}. Intressenter bör följa utskottens överläggningar och kammarens voteringsmönster.`;
} else {
svText = `Baserat på analys av ${docs.length} dokument (${enrichedCount} berikade med fulltext)${topic ? ` med specifik inriktning på <strong>${esc(topic)}</strong>` : ''}${domainPhrase ? ` inom ${domainPhrase}` : ''}: Analysen ger en ögonblicksbild av den aktuella politiska inriktningen och dess betydelse för centrala intressenter.`;
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

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

In the Swedish strategic-implications templates, the phrase "${enrichedCount} berikade med fulltext" is grammatically incorrect when enrichedCount === 1 (should be singular, e.g. "1 berikat …"). Consider adding singular/plural handling here (and in the other svText branches in this function) so single-document deep-inspection output reads correctly.

Suggested change
let svText: string;
if (isPressOrExternal) {
const typeDescSv = pressmCount > 0 ? `${pressmCount} pressmeddelande${pressmCount !== 1 ? 'n' : ''}` : `${extCount} extern${extCount !== 1 ? 'a' : ''} referens${extCount !== 1 ? 'er' : ''}`;
const signalTextSv = pressmCount > 0
? 'Regeringens presskommunikation signalerar politiska prioriteringar och kommande lagstiftningsåtgärder.'
: 'Dessa externa referenser belyser det politiska landskapet och belyser områden av potentiellt lagstiftningsintresse.';
svText = `Baserat på analys av ${docs.length} dokument (${enrichedCount} berikade med fulltext)${topic ? ` med specifik inriktning på <strong>${esc(topic)}</strong>` : ''}: Denna djupanalys granskar ${typeDescSv}${domainPhrase ? ` inom ${domainPhrase}` : ''}. ${signalTextSv} Intressenter bör bevaka om formella propositioner eller utskottsremisser följer.`;
} else if (isLegislativeFocused && legislativeCount > 0) {
svText = `Baserat på analys av ${docs.length} riksdagsdokument (${enrichedCount} berikade med fulltext)${topic ? ` med specifik inriktning på <strong>${esc(topic)}</strong>` : ''}: Det lagstiftande flödet visar ${propCount} proposition${propCount !== 1 ? 'er' : ''}, ${betCount} betänkande${betCount !== 1 ? 'n' : ''} och ${motCount} motion${motCount !== 1 ? 'er' : ''}. Intressenter bör följa utskottens överläggningar och kammarens voteringsmönster.`;
} else {
svText = `Baserat på analys av ${docs.length} dokument (${enrichedCount} berikade med fulltext)${topic ? ` med specifik inriktning på <strong>${esc(topic)}</strong>` : ''}${domainPhrase ? ` inom ${domainPhrase}` : ''}: Analysen ger en ögonblicksbild av den aktuella politiska inriktningen och dess betydelse för centrala intressenter.`;
const enrichedPhraseSv = `${enrichedCount} ${enrichedCount === 1 ? 'berikat' : 'berikade'} med fulltext`;
let svText: string;
if (isPressOrExternal) {
const typeDescSv = pressmCount > 0 ? `${pressmCount} pressmeddelande${pressmCount !== 1 ? 'n' : ''}` : `${extCount} extern${extCount !== 1 ? 'a' : ''} referens${extCount !== 1 ? 'er' : ''}`;
const signalTextSv = pressmCount > 0
? 'Regeringens presskommunikation signalerar politiska prioriteringar och kommande lagstiftningsåtgärder.'
: 'Dessa externa referenser belyser det politiska landskapet och belyser områden av potentiellt lagstiftningsintresse.';
svText = `Baserat på analys av ${docs.length} dokument (${enrichedPhraseSv})${topic ? ` med specifik inriktning på <strong>${esc(topic)}</strong>` : ''}: Denna djupanalys granskar ${typeDescSv}${domainPhrase ? ` inom ${domainPhrase}` : ''}. ${signalTextSv} Intressenter bör bevaka om formella propositioner eller utskottsremisser följer.`;
} else if (isLegislativeFocused && legislativeCount > 0) {
svText = `Baserat på analys av ${docs.length} riksdagsdokument (${enrichedPhraseSv})${topic ? ` med specifik inriktning på <strong>${esc(topic)}</strong>` : ''}: Det lagstiftande flödet visar ${propCount} proposition${propCount !== 1 ? 'er' : ''}, ${betCount} betänkande${betCount !== 1 ? 'n' : ''} och ${motCount} motion${motCount !== 1 ? 'er' : ''}. Intressenter bör följa utskottens överläggningar och kammarens voteringsmönster.`;
} else {
svText = `Baserat på analys av ${docs.length} dokument (${enrichedPhraseSv})${topic ? ` med specifik inriktning på <strong>${esc(topic)}</strong>` : ''}${domainPhrase ? ` inom ${domainPhrase}` : ''}: Analysen ger en ögonblicksbild av den aktuella politiska inriktningen och dess betydelse för centrala intressenter.`;

Copilot uses AI. Check for mistakes.
const enriched = docs.filter(d => d.contentFetched).length;
if (enriched > 0) {
items.push(lang === 'sv'
? `<strong>${enriched} av ${docs.length} dokument</strong> berikade med fulltext för djupanalys`
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

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

Swedish text here always uses "berikade med fulltext" even when the count is 1 (e.g. "1 av 1 dokument … berikade" in generated articles). Please make the adjective agree with the number (singular vs plural) to avoid ungrammatical output for single-document deep-inspection pages.

Suggested change
? `<strong>${enriched} av ${docs.length} dokument</strong> berikade med fulltext för djupanalys`
? `<strong>${enriched} av ${docs.length} dokument</strong> ${enriched === 1 ? 'berikat' : 'berikade'} med fulltext för djupanalys`

Copilot uses AI. Check for mistakes.
Comment on lines +18 to +23
type DocTypeLocalization = {
singular: Partial<Record<Language, string>>;
plural: Partial<Record<Language, string>>;
};

const DOC_TYPE_DISPLAY: Readonly<Record<string, DocTypeLocalization>> = {
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

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

There are now two separate document-type localization sources in the repo: DOC_TYPE_DISPLAY/localizeDocType here (singular/plural-aware) and DEEP_DOC_TYPE_LABELS/docTypeLabel in scripts/generate-news-enhanced/generators.ts. This duplication risks translation drift/inconsistency over time. Consider centralizing doc-type localization in one shared module (e.g., export localizeDocType / DOC_TYPE_DISPLAY and reuse it for deep-inspection chart + mindmap labels).

Suggested change
type DocTypeLocalization = {
singular: Partial<Record<Language, string>>;
plural: Partial<Record<Language, string>>;
};
const DOC_TYPE_DISPLAY: Readonly<Record<string, DocTypeLocalization>> = {
export type DocTypeLocalization = {
singular: Partial<Record<Language, string>>;
plural: Partial<Record<Language, string>>;
};
export const DOC_TYPE_DISPLAY: Readonly<Record<string, DocTypeLocalization>> = {

Copilot uses AI. Check for mistakes.
Comment on lines +271 to +300
<section class="deep-analysis" aria-label="Deep Analysis">
<h2>Deep Analysis</h2>

<div class="analysis-who">
<h3>Key Actors</h3>
<p>This analysis involves actors from <strong>1 party/body</strong> across <strong>0 committee(s)</strong>.</p>
<div class="actor-list">
<span class="actor-tag" title="Government">Government</span>
</div>
</div>

<div class="analysis-what">
<h3>What Happened</h3>
<p>Document composition: Press Release: 1. Policy domains detected: education policy, justice policy.</p>
</div>

<div class="analysis-when">
<h3>Timeline &amp; Context</h3>
<p>Documents dated <strong>2026-03-12</strong>. This analysis covers activity within the current riksmöte (parliamentary session), reflecting the ongoing legislative cycle and government policy agenda.</p>
</div>

<div class="analysis-why">
<h3>Why This Matters</h3>
<p>The government's press conference on paid police education signals a significant policy shift in both education and justice domains. Sweden's police staffing has lagged behind the EU average, and this proposal addresses structural recruitment barriers by introducing salary during training. The cross-cutting nature of this reform — affecting education funding, police recruitment pipelines, and public safety outcomes — makes it a bellwether for the government's capacity to deliver on its law-and-order platform commitments ahead of the 2026 election cycle.</p>
</div>

<div class="analysis-impact">
<h3>Winners &amp; Losers</h3>
<p>The government gains a concrete deliverable on police recruitment, while opposition parties face pressure to either support a popular measure or articulate credible alternatives. Police training institutions benefit from increased applicant pools, but existing cadets under the unpaid model may perceive fairness concerns. Municipal budgets may face new cost-sharing arrangements depending on implementation design.</p>
</div>
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

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

This deep-analysis markup (e.g.,

/ ) doesn't appear to be generated anywhere in the codebase (no matches under scripts/). That suggests this article HTML may have been edited manually or generated by a different template than the current generators, which can cause non-deterministic diffs on the next regeneration. Recommend regenerating the article from the current generator output (or updating the generator to emit this structure) so checked-in news pages stay reproducible.

Suggested change
<section class="deep-analysis" aria-label="Deep Analysis">
<h2>Deep Analysis</h2>
<div class="analysis-who">
<h3>Key Actors</h3>
<p>This analysis involves actors from <strong>1 party/body</strong> across <strong>0 committee(s)</strong>.</p>
<div class="actor-list">
<span class="actor-tag" title="Government">Government</span>
</div>
</div>
<div class="analysis-what">
<h3>What Happened</h3>
<p>Document composition: Press Release: 1. Policy domains detected: education policy, justice policy.</p>
</div>
<div class="analysis-when">
<h3>Timeline &amp; Context</h3>
<p>Documents dated <strong>2026-03-12</strong>. This analysis covers activity within the current riksmöte (parliamentary session), reflecting the ongoing legislative cycle and government policy agenda.</p>
</div>
<div class="analysis-why">
<h3>Why This Matters</h3>
<p>The government's press conference on paid police education signals a significant policy shift in both education and justice domains. Sweden's police staffing has lagged behind the EU average, and this proposal addresses structural recruitment barriers by introducing salary during training. The cross-cutting nature of this reform — affecting education funding, police recruitment pipelines, and public safety outcomes — makes it a bellwether for the government's capacity to deliver on its law-and-order platform commitments ahead of the 2026 election cycle.</p>
</div>
<div class="analysis-impact">
<h3>Winners &amp; Losers</h3>
<p>The government gains a concrete deliverable on police recruitment, while opposition parties face pressure to either support a popular measure or articulate credible alternatives. Police training institutions benefit from increased applicant pools, but existing cadets under the unpaid model may perceive fairness concerns. Municipal budgets may face new cost-sharing arrangements depending on implementation design.</p>
</div>
<section aria-label="Deep Analysis">
<h2>Deep Analysis</h2>
<h3>Key Actors</h3>
<p>This analysis involves actors from <strong>1 party/body</strong> across <strong>0 committee(s)</strong>. Government is the primary actor.</p>
<h3>What Happened</h3>
<p>Document composition: Press Release: 1. Policy domains detected: education policy, justice policy.</p>
<h3>Timeline &amp; Context</h3>
<p>Documents dated <strong>2026-03-12</strong>. This analysis covers activity within the current riksmöte (parliamentary session), reflecting the ongoing legislative cycle and government policy agenda.</p>
<h3>Why This Matters</h3>
<p>The government's press conference on paid police education signals a significant policy shift in both education and justice domains. Sweden's police staffing has lagged behind the EU average, and this proposal addresses structural recruitment barriers by introducing salary during training. The cross-cutting nature of this reform — affecting education funding, police recruitment pipelines, and public safety outcomes — makes it a bellwether for the government's capacity to deliver on its law-and-order platform commitments ahead of the 2026 election cycle.</p>
<h3>Winners &amp; Losers</h3>
<p>The government gains a concrete deliverable on police recruitment, while opposition parties face pressure to either support a popular measure or articulate credible alternatives. Police training institutions benefit from increased applicant pools, but existing cadets under the unpaid model may perceive fairness concerns. Municipal budgets may face new cost-sharing arrangements depending on implementation design.</p>

Copilot uses AI. Check for mistakes.
Comment on lines +274 to +295
<div class="analysis-who">
<h3>Nyckelaktörer</h3>
<p>Denna analys involverar aktörer från <strong>1 parti/organ</strong> och <strong>0 utskott</strong>.</p>
<div class="actor-list">
<span class="actor-tag" title="Regering">Regering</span>
</div>
</div>

<div class="analysis-what">
<h3>Vad som hände</h3>
<p>Dokumentsammansättning: Pressmeddelande: 1. Identifierade politikområden: utbildningspolitik, rättspolitik.</p>
</div>

<div class="analysis-when">
<h3>Tidslinje &amp; kontext</h3>
<p>Dokument daterade <strong>2026-03-12</strong>. Denna analys omfattar aktivitet inom det pågående riksmötet, och återspeglar den aktuella lagstiftningscykeln och regeringens policyagenda.</p>
</div>

<div class="analysis-why">
<h3>Varför det spelar roll</h3>
<p>Regeringens pressträff om betald polisutbildning signalerar en betydande policyförändring inom både utbildnings- och rättsområdena. Sveriges polisbemanning har legat under EU-genomsnittet, och detta förslag adresserar strukturella rekryteringshinder genom att införa lön under utbildningen. Reformens gränsöverskridande karaktär — som påverkar utbildningsfinansiering, polisrekryteringsvägar och samhällssäkerhet — gör den till en indikator på regeringens förmåga att leverera på sina löften om lag och ordning inför valcykeln 2026.</p>
</div>
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

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

This deep-analysis markup (e.g.,

/ ) doesn't appear to be generated anywhere in the codebase (no matches under scripts/). That suggests this article HTML may have been edited manually or generated by a different template than the current generators, which can cause non-deterministic diffs on the next regeneration. Recommend regenerating the article from the current generator output (or updating the generator to emit this structure) so checked-in news pages stay reproducible.

Suggested change
<div class="analysis-who">
<h3>Nyckelaktörer</h3>
<p>Denna analys involverar aktörer från <strong>1 parti/organ</strong> och <strong>0 utskott</strong>.</p>
<div class="actor-list">
<span class="actor-tag" title="Regering">Regering</span>
</div>
</div>
<div class="analysis-what">
<h3>Vad som hände</h3>
<p>Dokumentsammansättning: Pressmeddelande: 1. Identifierade politikområden: utbildningspolitik, rättspolitik.</p>
</div>
<div class="analysis-when">
<h3>Tidslinje &amp; kontext</h3>
<p>Dokument daterade <strong>2026-03-12</strong>. Denna analys omfattar aktivitet inom det pågående riksmötet, och återspeglar den aktuella lagstiftningscykeln och regeringens policyagenda.</p>
</div>
<div class="analysis-why">
<h3>Varför det spelar roll</h3>
<p>Regeringens pressträff om betald polisutbildning signalerar en betydande policyförändring inom både utbildnings- och rättsområdena. Sveriges polisbemanning har legat under EU-genomsnittet, och detta förslag adresserar strukturella rekryteringshinder genom att införa lön under utbildningen. Reformens gränsöverskridande karaktär — som påverkar utbildningsfinansiering, polisrekryteringsvägar och samhällssäkerhet — gör den till en indikator på regeringens förmåga att leverera på sina löften om lag och ordning inför valcykeln 2026.</p>
</div>
<section id="deep-analysis-who">
<h3>Nyckelaktörer</h3>
<p>Denna analys involverar aktörer från <strong>1 parti/organ</strong> och <strong>0 utskott</strong>.</p>
<p><span title="Regering">Regering</span></p>
</section>
<section id="deep-analysis-what">
<h3>Vad som hände</h3>
<p>Dokumentsammansättning: Pressmeddelande: 1. Identifierade politikområden: utbildningspolitik, rättspolitik.</p>
</section>
<section id="deep-analysis-when">
<h3>Tidslinje &amp; kontext</h3>
<p>Dokument daterade <strong>2026-03-12</strong>. Denna analys omfattar aktivitet inom det pågående riksmötet, och återspeglar den aktuella lagstiftningscykeln och regeringens policyagenda.</p>
</section>
<section id="deep-analysis-why">
<h3>Varför det spelar roll</h3>
<p>Regeringens pressträff om betald polisutbildning signalerar en betydande policyförändring inom både utbildnings- och rättsområdena. Sveriges polisbemanning har legat under EU-genomsnittet, och detta förslag adresserar strukturella rekryteringshinder genom att införa lön under utbildningen. Reformens gränsöverskridande karaktär — som påverkar utbildningsfinansiering, polisrekryteringsvägar och samhällssäkerhet — gör den till en indikator på regeringens förmåga att leverera på sina löften om lag och ordning inför valcykeln 2026.</p>
</section>

Copilot uses AI. Check for mistakes.
@pethers
Copy link
Member

pethers commented Mar 12, 2026

@copilot apply changes based on the comments in this thread

…lize DOC_TYPE_DISPLAY

- Fix SV singular "berikat" when enrichedCount === 1 in buildStrategicImplications (3 branches)
- Fix SV singular "berikat" when enriched === 1 in buildKeyTakeaways
- Export DOC_TYPE_DISPLAY and localizeDocType from shared.ts
- Replace duplicate DEEP_DOC_TYPE_LABELS in generators.ts with centralized localizeDocType
- Update SV article to use "berikat" singular forms
- All 2920 tests pass

Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Mar 12, 2026

@copilot apply changes based on the comments in this thread

Applied all review comments from thread #3937630759 in e29a31d:

  1. SV singular/plural "berikade" — extracted enrichedPhraseSv variable using "berikat" (singular) when enrichedCount === 1 across all 3 SV branches in buildStrategicImplications. Also fixed buildKeyTakeaways with inline ternary for same pattern.

  2. Centralized DOC_TYPE_DISPLAY — exported DOC_TYPE_DISPLAY, localizeDocType, and DocTypeLocalization from shared.ts. Eliminated the duplicate DEEP_DOC_TYPE_LABELS in generators.tsdocTypeLabel() now delegates to the centralized localizeDocType(), preventing translation drift.

  3. Updated SV article — "1 berikade med fulltext" → "1 berikat med fulltext" in both strategic implications and key takeaways.

All 2920 tests pass, 0 CodeQL alerts.

@github-actions
Copy link
Contributor

🔍 Lighthouse Performance Audit

Category Score Status
Performance 85/100 🟡
Accessibility 95/100 🟢
Best Practices 90/100 🟢
SEO 95/100 🟢

📥 Download full Lighthouse report

Budget Compliance: Performance budgets enforced via budget.json

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Comment on lines 678 to 680
function docTypeLabel(doktyp: string, lang: Language): string {
const map = DEEP_DOC_TYPE_LABELS[doktyp];
return (map?.[lang]) ?? (map?.en ?? doktyp.toUpperCase());
return localizeDocType(doktyp, lang);
}
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

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

localizeDocType() selects plural when count is undefined (see shared.ts), but docTypeLabel() calls it without passing a count. This will render singular cases incorrectly (e.g., a single pressm becomes "Press Releases" / "Pressmeddelanden"), affecting per-document metadata, dashboard chart labels, and mindmap items. Pass the known counts (1 for single-document labels; typeCounts[t] / chartValues[i] for aggregated displays), or adjust docTypeLabel() to accept a count and thread it through.

Copilot uses AI. Check for mistakes.
const typeDescSv = pressmCount > 0 ? `${pressmCount} pressmeddelande${pressmCount !== 1 ? 'n' : ''}` : `${extCount} extern${extCount !== 1 ? 'a' : ''} referens${extCount !== 1 ? 'er' : ''}`;
const signalTextSv = pressmCount > 0
? 'Regeringens presskommunikation signalerar politiska prioriteringar och kommande lagstiftningsåtgärder.'
: 'Dessa externa referenser belyser det politiska landskapet och belyser områden av potentiellt lagstiftningsintresse.';
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

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

Swedish wording repeats the verb: "belyser det politiska landskapet och belyser områden…". Consider rephrasing the second clause (e.g., "och lyfter fram"/"särskilt") to avoid the duplicate and improve readability.

Suggested change
: 'Dessa externa referenser belyser det politiska landskapet och belyser områden av potentiellt lagstiftningsintresse.';
: 'Dessa externa referenser belyser det politiska landskapet och lyfter fram områden med potentiellt lagstiftningsintresse.';

Copilot uses AI. Check for mistakes.
@pethers
Copy link
Member

pethers commented Mar 12, 2026

@copilot apply changes based on the comments in this thread

…uplicate 'belyser'

- docTypeLabel() now accepts optional count parameter, threaded to localizeDocType()
  for correct singular/plural selection at all call sites
- Per-document metadata uses count=1 (singular: "Press Release" not "Press Releases")
- Chart labels and mindmap items use actual typeCounts for count-aware display
- Fixed SV ext-only wording: "belyser...belyser" → "belyser...lyfter fram"

Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Mar 12, 2026

@copilot apply changes based on the comments in this thread

Applied both review comments in a7f5e2c:

  1. docTypeLabel() count threading — added optional count parameter that passes through to localizeDocType(). Per-document entries use count=1 (singular), chart labels use typeCounts[t], and mindmap items use chartValues[i] for correct singular/plural selection at all call sites.

  2. SV duplicate "belyser" — changed to "belyser det politiska landskapet och lyfter fram områden med potentiellt lagstiftningsintresse."

All 2920 tests pass, 0 CodeQL alerts.

Copilot AI requested a review from pethers March 12, 2026 16:37
@pethers pethers marked this pull request as ready for review March 12, 2026 16:42
@github-actions
Copy link
Contributor

🔍 Lighthouse Performance Audit

Category Score Status
Performance 85/100 🟡
Accessibility 95/100 🟢
Best Practices 90/100 🟢
SEO 95/100 🟢

📥 Download full Lighthouse report

Budget Compliance: Performance budgets enforced via budget.json

@pethers pethers merged commit d154c5e into main Mar 12, 2026
22 checks passed
@pethers pethers deleted the copilot/analyze-deep-inspection-article-issues branch March 12, 2026 16:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

html-css HTML/CSS changes news News articles and content generation refactor Code refactoring size-l Large change (250-1000 lines) size-m Medium change (50-250 lines) testing Test coverage translation Translation updates

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants