euparliamentmonitor 0.9.19 → 0.9.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/package.json +4 -3
- package/scripts/aggregator/editorial-brief-resolver.d.ts +38 -0
- package/scripts/aggregator/editorial-brief-resolver.js +32 -0
- package/scripts/aggregator/generator/render-one.js +35 -0
- package/scripts/aggregator/html/localize-body.d.ts +32 -0
- package/scripts/aggregator/html/localize-body.js +69 -0
- package/scripts/aggregator/html/shell.d.ts +10 -0
- package/scripts/aggregator/html/shell.js +11 -1
- package/scripts/aggregator/markdown-renderer.d.ts +23 -24
- package/scripts/aggregator/markdown-renderer.js +39 -25
- package/scripts/aggregator/metadata/artifact-highlight.d.ts +15 -22
- package/scripts/aggregator/metadata/artifact-highlight.js +14 -230
- package/scripts/aggregator/metadata/artifact-walker.d.ts +34 -0
- package/scripts/aggregator/metadata/artifact-walker.js +177 -0
- package/scripts/aggregator/metadata/editorial-highlight.d.ts +15 -0
- package/scripts/aggregator/metadata/editorial-highlight.js +53 -0
- package/scripts/aggregator/metadata/priority-finding-highlight.js +7 -2
- package/scripts/aggregator/metadata/resolve-helpers.js +9 -3
- package/scripts/aggregator/metadata/text-utils.js +7 -0
- package/scripts/aggregator/metadata/translated-sibling.d.ts +23 -0
- package/scripts/aggregator/metadata/translated-sibling.js +39 -0
- package/scripts/aggregator/reader-guide/builder.js +3 -1
- package/scripts/aggregator/reader-guide/labels.d.ts +7 -0
- package/scripts/aggregator/reader-guide/labels.js +22 -0
- package/scripts/aggregator/reader-intelligence-guide.d.ts +1 -1
- package/scripts/aggregator/reader-intelligence-guide.js +1 -1
- package/scripts/aggregator/seo-entity-extractor.d.ts +45 -0
- package/scripts/aggregator/seo-entity-extractor.js +211 -0
- package/scripts/constants/articles/breaking-strings-central.d.ts +8 -0
- package/scripts/constants/articles/breaking-strings-central.js +105 -0
- package/scripts/constants/articles/breaking-strings-east.d.ts +8 -0
- package/scripts/constants/articles/breaking-strings-east.js +203 -0
- package/scripts/constants/articles/breaking-strings-nordic.d.ts +8 -0
- package/scripts/constants/articles/breaking-strings-nordic.js +252 -0
- package/scripts/constants/articles/breaking-strings-west.d.ts +8 -0
- package/scripts/constants/articles/breaking-strings-west.js +154 -0
- package/scripts/constants/articles/breaking.d.ts +0 -1
- package/scripts/constants/articles/breaking.js +9 -6
- package/scripts/constants/articles/dashboard/ar.d.ts +8 -0
- package/scripts/constants/articles/dashboard/ar.js +71 -0
- package/scripts/constants/articles/dashboard/da.d.ts +8 -0
- package/scripts/constants/articles/dashboard/da.js +71 -0
- package/scripts/constants/articles/dashboard/de.d.ts +8 -0
- package/scripts/constants/articles/dashboard/de.js +71 -0
- package/scripts/constants/articles/dashboard/en.d.ts +8 -0
- package/scripts/constants/articles/dashboard/en.js +71 -0
- package/scripts/constants/articles/dashboard/es.d.ts +8 -0
- package/scripts/constants/articles/dashboard/es.js +71 -0
- package/scripts/constants/articles/dashboard/fi.d.ts +8 -0
- package/scripts/constants/articles/dashboard/fi.js +71 -0
- package/scripts/constants/articles/dashboard/fr.d.ts +8 -0
- package/scripts/constants/articles/dashboard/fr.js +71 -0
- package/scripts/constants/articles/dashboard/he.d.ts +8 -0
- package/scripts/constants/articles/dashboard/he.js +71 -0
- package/scripts/constants/articles/dashboard/index.d.ts +7 -0
- package/scripts/constants/articles/dashboard/index.js +33 -0
- package/scripts/constants/articles/dashboard/ja.d.ts +8 -0
- package/scripts/constants/articles/dashboard/ja.js +71 -0
- package/scripts/constants/articles/dashboard/ko.d.ts +8 -0
- package/scripts/constants/articles/dashboard/ko.js +71 -0
- package/scripts/constants/articles/dashboard/nl.d.ts +8 -0
- package/scripts/constants/articles/dashboard/nl.js +71 -0
- package/scripts/constants/articles/dashboard/no.d.ts +8 -0
- package/scripts/constants/articles/dashboard/no.js +71 -0
- package/scripts/constants/articles/dashboard/sv.d.ts +8 -0
- package/scripts/constants/articles/dashboard/sv.js +71 -0
- package/scripts/constants/articles/dashboard/zh.d.ts +8 -0
- package/scripts/constants/articles/dashboard/zh.js +71 -0
- package/scripts/constants/articles/dashboard.d.ts +7 -2
- package/scripts/constants/articles/dashboard.js +4 -8
- package/scripts/constants/articles/deep-analysis/ar.d.ts +8 -0
- package/scripts/constants/articles/deep-analysis/ar.js +75 -0
- package/scripts/constants/articles/deep-analysis/da.d.ts +8 -0
- package/scripts/constants/articles/deep-analysis/da.js +75 -0
- package/scripts/constants/articles/deep-analysis/de.d.ts +8 -0
- package/scripts/constants/articles/deep-analysis/de.js +75 -0
- package/scripts/constants/articles/deep-analysis/en.d.ts +8 -0
- package/scripts/constants/articles/deep-analysis/en.js +75 -0
- package/scripts/constants/articles/deep-analysis/es.d.ts +8 -0
- package/scripts/constants/articles/deep-analysis/es.js +75 -0
- package/scripts/constants/articles/deep-analysis/fi.d.ts +8 -0
- package/scripts/constants/articles/deep-analysis/fi.js +75 -0
- package/scripts/constants/articles/deep-analysis/fr.d.ts +8 -0
- package/scripts/constants/articles/deep-analysis/fr.js +75 -0
- package/scripts/constants/articles/deep-analysis/he.d.ts +8 -0
- package/scripts/constants/articles/deep-analysis/he.js +75 -0
- package/scripts/constants/articles/deep-analysis/index.d.ts +7 -0
- package/scripts/constants/articles/deep-analysis/index.js +33 -0
- package/scripts/constants/articles/deep-analysis/ja.d.ts +8 -0
- package/scripts/constants/articles/deep-analysis/ja.js +75 -0
- package/scripts/constants/articles/deep-analysis/ko.d.ts +8 -0
- package/scripts/constants/articles/deep-analysis/ko.js +75 -0
- package/scripts/constants/articles/deep-analysis/nl.d.ts +8 -0
- package/scripts/constants/articles/deep-analysis/nl.js +75 -0
- package/scripts/constants/articles/deep-analysis/no.d.ts +8 -0
- package/scripts/constants/articles/deep-analysis/no.js +75 -0
- package/scripts/constants/articles/deep-analysis/sv.d.ts +8 -0
- package/scripts/constants/articles/deep-analysis/sv.js +75 -0
- package/scripts/constants/articles/deep-analysis/zh.d.ts +8 -0
- package/scripts/constants/articles/deep-analysis/zh.js +75 -0
- package/scripts/constants/articles/deep-analysis.d.ts +4 -3
- package/scripts/constants/articles/deep-analysis.js +3 -7
- package/scripts/constants/articles/localized-keywords-central.d.ts +8 -0
- package/scripts/constants/articles/localized-keywords-central.js +118 -0
- package/scripts/constants/articles/localized-keywords-nordic.d.ts +8 -0
- package/scripts/constants/articles/localized-keywords-nordic.js +303 -0
- package/scripts/constants/articles/localized-keywords.js +4 -2
- package/scripts/constants/articles/swot-builder-central.d.ts +8 -0
- package/scripts/constants/articles/swot-builder-central.js +90 -0
- package/scripts/constants/articles/swot-builder-nordic.d.ts +8 -0
- package/scripts/constants/articles/swot-builder-nordic.js +216 -0
- package/scripts/constants/articles/swot.js +4 -2
- package/scripts/constants/articles/week-ahead-eu.d.ts +12 -0
- package/scripts/constants/articles/week-ahead-eu.js +278 -0
- package/scripts/constants/articles/week-ahead-global.d.ts +12 -0
- package/scripts/constants/articles/week-ahead-global.js +278 -0
- package/scripts/constants/articles/week-ahead.d.ts +4 -7
- package/scripts/constants/articles/week-ahead.js +11 -535
- package/scripts/constants/world-bank/category-map-analysis.d.ts +9 -0
- package/scripts/constants/world-bank/category-map-analysis.js +204 -0
- package/scripts/constants/world-bank/category-map-legislative.d.ts +9 -0
- package/scripts/constants/world-bank/category-map-legislative.js +130 -0
- package/scripts/constants/world-bank/category-map-periodic.d.ts +9 -0
- package/scripts/constants/world-bank/category-map-periodic.js +176 -0
- package/scripts/constants/world-bank/category-map.d.ts +3 -26
- package/scripts/constants/world-bank/category-map.js +8 -501
- package/scripts/discover-untranslated-briefs.js +123 -4
- package/scripts/generators/news-indexes/per-language.js +21 -7
- package/scripts/generators/political-intelligence/html.js +39 -8
- package/scripts/generators/sitemap/html.js +25 -7
- package/scripts/mcp/ep/client.d.ts +0 -1
- package/scripts/mcp/ep/client.js +0 -65
- package/scripts/mcp/ep/error-classifier.d.ts +2 -2
- package/scripts/mcp/ep/error-classifier.js +2 -2
- package/scripts/mcp/ep/tools-list.d.ts +13 -0
- package/scripts/mcp/ep/tools-list.js +79 -0
- package/scripts/mcp/ep-mcp-client.d.ts +1 -0
- package/scripts/mcp/ep-mcp-client.js +1 -0
- package/scripts/mcp/imf/client.d.ts +3 -64
- package/scripts/mcp/imf/client.js +18 -207
- package/scripts/mcp/imf/http-transport.d.ts +92 -0
- package/scripts/mcp/imf/http-transport.js +232 -0
- package/scripts/mcp/transport/connection.d.ts +25 -53
- package/scripts/mcp/transport/connection.js +90 -250
- package/scripts/mcp/transport/process.d.ts +62 -0
- package/scripts/mcp/transport/process.js +147 -0
- package/scripts/mcp/transport/reconnect.d.ts +73 -0
- package/scripts/mcp/transport/reconnect.js +96 -0
- package/scripts/validate-brief-translations.js +122 -6
- package/scripts/constants/articles/breaking-strings-eu.d.ts +0 -7
- package/scripts/constants/articles/breaking-strings-global.d.ts +0 -7
- package/scripts/constants/articles/dashboard-builder-eu.d.ts +0 -7
- package/scripts/constants/articles/dashboard-builder-global.d.ts +0 -7
- package/scripts/constants/articles/deep-analysis-strings-eu.d.ts +0 -7
- package/scripts/constants/articles/deep-analysis-strings-global.d.ts +0 -7
- package/scripts/constants/articles/localized-keywords-eu.d.ts +0 -7
- package/scripts/constants/articles/swot-builder-eu.d.ts +0 -7
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { getLocalizedString, getTextDirection } from '../../constants/language-core.js';
|
|
4
4
|
import { escapeHTML } from '../../utils/file-utils.js';
|
|
5
5
|
import { READER_GUIDE_SECTION_ID } from '../reader-guide-constants.js';
|
|
6
|
-
import { READER_GUIDE_TITLE_LABELS, READER_GUIDE_INTRO_LABELS, READER_GUIDE_COL_NEED_LABELS, READER_GUIDE_COL_VALUE_LABELS, } from './labels.js';
|
|
6
|
+
import { READER_GUIDE_TITLE_LABELS, READER_GUIDE_INTRO_LABELS, READER_GUIDE_TIP_LABELS, READER_GUIDE_COL_NEED_LABELS, READER_GUIDE_COL_VALUE_LABELS, } from './labels.js';
|
|
7
7
|
import { READER_GUIDE_ROWS } from './rows.js';
|
|
8
8
|
import { getReaderGuideSectionIcon } from './icons.js';
|
|
9
9
|
/**
|
|
@@ -40,11 +40,13 @@ export function buildReaderIntelligenceGuideHtml(lang, sections, _included = [])
|
|
|
40
40
|
return '';
|
|
41
41
|
const title = getLocalizedString(READER_GUIDE_TITLE_LABELS, lang);
|
|
42
42
|
const intro = getLocalizedString(READER_GUIDE_INTRO_LABELS, lang);
|
|
43
|
+
const tip = getLocalizedString(READER_GUIDE_TIP_LABELS, lang);
|
|
43
44
|
const colNeed = getLocalizedString(READER_GUIDE_COL_NEED_LABELS, lang);
|
|
44
45
|
const colValue = getLocalizedString(READER_GUIDE_COL_VALUE_LABELS, lang);
|
|
45
46
|
return `<section id="${READER_GUIDE_SECTION_ID}" data-component="reader-intelligence-guide" aria-label="${escapeHTML(title)}"${dir === 'rtl' ? ' dir="rtl"' : ''}>
|
|
46
47
|
<h2 id="${READER_GUIDE_SECTION_ID}-heading"><span class="guide-icon" aria-hidden="true">🧭</span> ${escapeHTML(title)}</h2>
|
|
47
48
|
<p class="reader-guide-intro">${escapeHTML(intro)}</p>
|
|
49
|
+
<p class="reader-guide-tip"><span class="guide-icon" aria-hidden="true">💡</span> ${escapeHTML(tip)}</p>
|
|
48
50
|
<div class="table-scroll" role="region" tabindex="0" aria-labelledby="${READER_GUIDE_SECTION_ID}-heading">
|
|
49
51
|
<table class="reader-guide-table">
|
|
50
52
|
<caption class="sr-only">${escapeHTML(title)}</caption>
|
|
@@ -10,6 +10,13 @@ import type { LanguageMap } from '../../types/index.js';
|
|
|
10
10
|
export declare const READER_GUIDE_TITLE_LABELS: LanguageMap;
|
|
11
11
|
/** Introduction text for the Reader Intelligence Guide */
|
|
12
12
|
export declare const READER_GUIDE_INTRO_LABELS: LanguageMap;
|
|
13
|
+
/**
|
|
14
|
+
* Practical "how to read this article" tip rendered immediately under the
|
|
15
|
+
* intro. Distinct from the intro so existing snapshot tests continue to
|
|
16
|
+
* match the intro string verbatim, and so styles can target the two
|
|
17
|
+
* paragraphs independently.
|
|
18
|
+
*/
|
|
19
|
+
export declare const READER_GUIDE_TIP_LABELS: LanguageMap;
|
|
13
20
|
/** Table header: "Reader need" */
|
|
14
21
|
export declare const READER_GUIDE_COL_NEED_LABELS: LanguageMap;
|
|
15
22
|
/** Table header: "What you'll get" */
|
|
@@ -34,6 +34,28 @@ export const READER_GUIDE_INTRO_LABELS = {
|
|
|
34
34
|
ko: '이 가이드를 사용하여 기사를 원시 산출물 모음이 아닌 정치 인텔리전스 제품으로 읽으십시오. 고가치 독자 관점이 먼저 나타납니다. 기술적 출처는 감사 부록에서 확인할 수 있습니다.',
|
|
35
35
|
zh: '使用本指南将文章作为政治情报产品而非原始工件集合来阅读。高价值读者视角优先呈现;技术出处可在审计附录中查阅。',
|
|
36
36
|
};
|
|
37
|
+
/**
|
|
38
|
+
* Practical "how to read this article" tip rendered immediately under the
|
|
39
|
+
* intro. Distinct from the intro so existing snapshot tests continue to
|
|
40
|
+
* match the intro string verbatim, and so styles can target the two
|
|
41
|
+
* paragraphs independently.
|
|
42
|
+
*/
|
|
43
|
+
export const READER_GUIDE_TIP_LABELS = {
|
|
44
|
+
en: 'Tip: skim the Executive Brief first, then jump to the lens that matches your role — analyst, journalist, advocate, or policymaker — using the links below.',
|
|
45
|
+
sv: 'Tips: börja med att skumma sammanfattningen, gå sedan till det perspektiv som matchar din roll — analytiker, journalist, intressent eller beslutsfattare — via länkarna nedan.',
|
|
46
|
+
da: 'Tip: skim først resuméet, og hop derefter til det perspektiv, der passer til din rolle — analytiker, journalist, fortaler eller beslutningstager — via linkene nedenfor.',
|
|
47
|
+
no: 'Tips: skum gjennom sammendraget først, og hopp deretter til perspektivet som passer din rolle — analytiker, journalist, talsperson eller beslutningstaker — via lenkene under.',
|
|
48
|
+
fi: 'Vinkki: silmäile ensin tiivistelmä ja siirry sitten roolisi mukaiseen näkökulmaan — analyytikko, toimittaja, vaikuttaja tai päättäjä — alla olevien linkkien kautta.',
|
|
49
|
+
de: 'Tipp: Überfliegen Sie zuerst die Zusammenfassung und springen Sie dann über die Links unten zur Perspektive, die zu Ihrer Rolle passt — Analystin, Journalist, Interessenvertreterin oder Entscheidungsträger.',
|
|
50
|
+
fr: "Astuce : parcourez d'abord le résumé exécutif, puis accédez à la perspective correspondant à votre rôle — analyste, journaliste, défenseur ou décideur — via les liens ci-dessous.",
|
|
51
|
+
es: 'Consejo: hojee primero el resumen ejecutivo y luego salte a la perspectiva que coincida con su rol — analista, periodista, defensor o responsable de políticas — usando los enlaces a continuación.',
|
|
52
|
+
nl: 'Tip: lees eerst de samenvatting door en spring vervolgens naar het perspectief dat bij uw rol past — analist, journalist, belangenbehartiger of beleidsmaker — via de onderstaande links.',
|
|
53
|
+
ar: 'نصيحة: ابدأ بتصفح الملخص التنفيذي، ثم انتقل إلى المنظور الذي يطابق دورك — محلل أو صحفي أو مدافع أو صانع سياسات — عبر الروابط أدناه.',
|
|
54
|
+
he: 'טיפ: סקור תחילה את התקציר ולאחר מכן עבור אל הזווית המתאימה לתפקידך — אנליסט, עיתונאי, מקדם או קובע מדיניות — באמצעות הקישורים שלהלן.',
|
|
55
|
+
ja: 'ヒント:まずエグゼクティブブリーフを概観し、その後、下のリンクからアナリスト、ジャーナリスト、アドボケイト、政策立案者など、あなたの役割に合った視点へ移動してください。',
|
|
56
|
+
ko: '팁: 먼저 경영진 브리프를 훑어본 다음 아래 링크를 사용해 분석가, 기자, 옹호자, 정책 입안자 등 본인의 역할에 맞는 관점으로 이동하십시오.',
|
|
57
|
+
zh: '提示:先快速浏览执行摘要,然后通过下方链接跳转到与您的角色相匹配的视角——分析师、记者、倡导者或政策制定者。',
|
|
58
|
+
};
|
|
37
59
|
/** Table header: "Reader need" */
|
|
38
60
|
export const READER_GUIDE_COL_NEED_LABELS = {
|
|
39
61
|
en: 'Reader need',
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
*/
|
|
18
18
|
export type { TocSection, IncludedArtifact } from './reader-guide-constants.js';
|
|
19
19
|
export { READER_GUIDE_SECTION_ID, READER_GUIDE_SECTION_IDS, READER_GUIDE_SECTION_TITLE, } from './reader-guide-constants.js';
|
|
20
|
-
export { READER_GUIDE_TITLE_LABELS, READER_GUIDE_INTRO_LABELS, READER_GUIDE_COL_NEED_LABELS, READER_GUIDE_COL_VALUE_LABELS, READER_GUIDE_COL_SOURCE_LABELS, } from './reader-guide/labels.js';
|
|
20
|
+
export { READER_GUIDE_TITLE_LABELS, READER_GUIDE_INTRO_LABELS, READER_GUIDE_TIP_LABELS, READER_GUIDE_COL_NEED_LABELS, READER_GUIDE_COL_VALUE_LABELS, READER_GUIDE_COL_SOURCE_LABELS, } from './reader-guide/labels.js';
|
|
21
21
|
export { getReaderGuideSectionIcon } from './reader-guide/icons.js';
|
|
22
22
|
export { buildReaderIntelligenceGuideHtml } from './reader-guide/builder.js';
|
|
23
23
|
export { stripInlineReaderGuide } from './reader-guide/strip.js';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// SPDX-FileCopyrightText: 2024-2026 Hack23 AB
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
export { READER_GUIDE_SECTION_ID, READER_GUIDE_SECTION_IDS, READER_GUIDE_SECTION_TITLE, } from './reader-guide-constants.js';
|
|
4
|
-
export { READER_GUIDE_TITLE_LABELS, READER_GUIDE_INTRO_LABELS, READER_GUIDE_COL_NEED_LABELS, READER_GUIDE_COL_VALUE_LABELS, READER_GUIDE_COL_SOURCE_LABELS, } from './reader-guide/labels.js';
|
|
4
|
+
export { READER_GUIDE_TITLE_LABELS, READER_GUIDE_INTRO_LABELS, READER_GUIDE_TIP_LABELS, READER_GUIDE_COL_NEED_LABELS, READER_GUIDE_COL_VALUE_LABELS, READER_GUIDE_COL_SOURCE_LABELS, } from './reader-guide/labels.js';
|
|
5
5
|
export { getReaderGuideSectionIcon } from './reader-guide/icons.js';
|
|
6
6
|
export { buildReaderIntelligenceGuideHtml } from './reader-guide/builder.js';
|
|
7
7
|
export { stripInlineReaderGuide } from './reader-guide/strip.js';
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extract organization names from `intelligence/stakeholder-map.md`'s H3
|
|
3
|
+
* headings. Each tier-1/tier-2 stakeholder appears as a heading shaped like:
|
|
4
|
+
* `### EPP — Manfred Weber / 185 MEPs (25.73%)`
|
|
5
|
+
* `### European Commission — Ursula von der Leyen (EPP)`
|
|
6
|
+
* `### Tech Industry (Big Tech Gatekeepers)`
|
|
7
|
+
*
|
|
8
|
+
* The entity name is everything before the first em-dash, en-dash, slash,
|
|
9
|
+
* parenthesis, or colon — whichever comes first — trimmed and de-duplicated
|
|
10
|
+
* with case-insensitive equality. "Risk N: …" headings are filtered out
|
|
11
|
+
* because they describe risk scenarios rather than organizations.
|
|
12
|
+
*
|
|
13
|
+
* @param markdown - Raw stakeholder-map.md contents
|
|
14
|
+
* @returns Ordered, de-duplicated stakeholder names
|
|
15
|
+
*/
|
|
16
|
+
export declare function extractStakeholderNames(markdown: string): readonly string[];
|
|
17
|
+
/**
|
|
18
|
+
* Extract media-outlet names from `extended/media-framing-analysis.md`.
|
|
19
|
+
* Editorial convention is a series of bold "framing buckets":
|
|
20
|
+
* `**Centre-Left Media (Le Monde, Der Spiegel, Guardian EU section):**`
|
|
21
|
+
* `**Tech-Beat Media (TechCrunch EU, The Verge, Politico Tech):**`
|
|
22
|
+
*
|
|
23
|
+
* This function pulls every comma-separated outlet from each parenthetical
|
|
24
|
+
* list, trims trailing colons / asterisks, and de-duplicates with
|
|
25
|
+
* case-insensitive equality.
|
|
26
|
+
*
|
|
27
|
+
* @param markdown - Raw media-framing-analysis.md contents
|
|
28
|
+
* @returns Ordered, de-duplicated media-outlet names
|
|
29
|
+
*/
|
|
30
|
+
export declare function extractMediaOutletNames(markdown: string): readonly string[];
|
|
31
|
+
/**
|
|
32
|
+
* Collect SEO `mentions` entities for an analysis run by combining
|
|
33
|
+
* stakeholder names and media-outlet names from the run's intelligence
|
|
34
|
+
* and extended folders. Returns a single deduplicated, length-capped
|
|
35
|
+
* list ready to feed into JSON-LD `mentions`.
|
|
36
|
+
*
|
|
37
|
+
* Stakeholders are listed first (high-signal political-group / institution
|
|
38
|
+
* entities), media outlets second. The combined list is truncated to
|
|
39
|
+
* {@link MAX_MENTIONS} entries.
|
|
40
|
+
*
|
|
41
|
+
* @param runDir - Absolute analysis run directory path
|
|
42
|
+
* @returns Ordered, de-duplicated mentions list (may be empty)
|
|
43
|
+
*/
|
|
44
|
+
export declare function extractRunMentions(runDir: string): readonly string[];
|
|
45
|
+
//# sourceMappingURL=seo-entity-extractor.d.ts.map
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2024-2026 Hack23 AB
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
/**
|
|
4
|
+
* @module Aggregator/SeoEntityExtractor
|
|
5
|
+
* @description Extract real-world organizations named in an analysis run's
|
|
6
|
+
* `intelligence/stakeholder-map.md` and `extended/media-framing-analysis.md`
|
|
7
|
+
* artifacts for emission as JSON-LD `mentions` entries on every language
|
|
8
|
+
* variant of the rendered article.
|
|
9
|
+
*
|
|
10
|
+
* The same English-extracted list is reused across all 14 language variants
|
|
11
|
+
* because the entities are language-independent proper nouns (political
|
|
12
|
+
* groups, EU institutions, media outlets) — search engines and AI overviews
|
|
13
|
+
* benefit from consistent entity grounding regardless of which language
|
|
14
|
+
* the surrounding prose is in.
|
|
15
|
+
*/
|
|
16
|
+
import fs from 'fs';
|
|
17
|
+
import path from 'path';
|
|
18
|
+
/**
|
|
19
|
+
* Maximum number of mentions emitted into the JSON-LD `mentions` array.
|
|
20
|
+
* Schema.org accepts arbitrarily many entries, but indexers commonly cap
|
|
21
|
+
* structured-data entity lists at ~30 — staying under this avoids
|
|
22
|
+
* truncation and keeps the rendered JSON-LD blob compact.
|
|
23
|
+
*/
|
|
24
|
+
const MAX_MENTIONS = 30;
|
|
25
|
+
/**
|
|
26
|
+
* Minimum length for an extracted entity name. Below this, the candidate
|
|
27
|
+
* is almost certainly a fragment (single capital letter, lone particle)
|
|
28
|
+
* rather than a real organization.
|
|
29
|
+
*/
|
|
30
|
+
const MIN_ENTITY_LENGTH = 2;
|
|
31
|
+
/**
|
|
32
|
+
* Maximum length for an extracted entity name. Anything longer is almost
|
|
33
|
+
* certainly a misparsed sentence fragment.
|
|
34
|
+
*/
|
|
35
|
+
const MAX_ENTITY_LENGTH = 80;
|
|
36
|
+
/**
|
|
37
|
+
* Read a UTF-8 file relative to `runDir`. Returns `null` when the path is
|
|
38
|
+
* missing or unreadable — the extractor treats absent intelligence
|
|
39
|
+
* artifacts as a soft signal (no mentions to emit) rather than an error.
|
|
40
|
+
*
|
|
41
|
+
* @param runDir - Absolute path to the analysis run directory
|
|
42
|
+
* @param relPath - Forward-slash path under `runDir`
|
|
43
|
+
* @returns File contents or `null`
|
|
44
|
+
*/
|
|
45
|
+
function readRunFile(runDir, relPath) {
|
|
46
|
+
const abs = path.join(runDir, relPath);
|
|
47
|
+
try {
|
|
48
|
+
if (!fs.existsSync(abs))
|
|
49
|
+
return null;
|
|
50
|
+
return fs.readFileSync(abs, 'utf8');
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Extract organization names from `intelligence/stakeholder-map.md`'s H3
|
|
58
|
+
* headings. Each tier-1/tier-2 stakeholder appears as a heading shaped like:
|
|
59
|
+
* `### EPP — Manfred Weber / 185 MEPs (25.73%)`
|
|
60
|
+
* `### European Commission — Ursula von der Leyen (EPP)`
|
|
61
|
+
* `### Tech Industry (Big Tech Gatekeepers)`
|
|
62
|
+
*
|
|
63
|
+
* The entity name is everything before the first em-dash, en-dash, slash,
|
|
64
|
+
* parenthesis, or colon — whichever comes first — trimmed and de-duplicated
|
|
65
|
+
* with case-insensitive equality. "Risk N: …" headings are filtered out
|
|
66
|
+
* because they describe risk scenarios rather than organizations.
|
|
67
|
+
*
|
|
68
|
+
* @param markdown - Raw stakeholder-map.md contents
|
|
69
|
+
* @returns Ordered, de-duplicated stakeholder names
|
|
70
|
+
*/
|
|
71
|
+
export function extractStakeholderNames(markdown) {
|
|
72
|
+
const lines = markdown.split('\n');
|
|
73
|
+
const names = [];
|
|
74
|
+
const seen = new Set();
|
|
75
|
+
for (const rawLine of lines) {
|
|
76
|
+
if (!rawLine.startsWith('### '))
|
|
77
|
+
continue;
|
|
78
|
+
const headingText = rawLine.slice(4).trim();
|
|
79
|
+
if (!headingText)
|
|
80
|
+
continue;
|
|
81
|
+
// Skip risk-scenario headings: `### Risk N: …` / `### Risk 1: PfE Internal Split…`
|
|
82
|
+
if (/^risk\s+\d+\s*:/i.test(headingText))
|
|
83
|
+
continue;
|
|
84
|
+
// Split on the first em-dash, en-dash, slash, opening paren, or colon.
|
|
85
|
+
const splitIdx = findFirstSplitChar(headingText);
|
|
86
|
+
const candidate = splitIdx >= 0 ? headingText.slice(0, splitIdx) : headingText;
|
|
87
|
+
const name = candidate.trim().replace(/\*+$/, '').trim();
|
|
88
|
+
if (!isValidEntityName(name))
|
|
89
|
+
continue;
|
|
90
|
+
const key = name.toLowerCase();
|
|
91
|
+
if (seen.has(key))
|
|
92
|
+
continue;
|
|
93
|
+
seen.add(key);
|
|
94
|
+
names.push(name);
|
|
95
|
+
}
|
|
96
|
+
return names;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Find the index of the first stakeholder-heading separator character.
|
|
100
|
+
* Uses indexOf in a loop instead of a regex to satisfy CodeQL's
|
|
101
|
+
* regex-injection / catastrophic-backtracking lints (cf.
|
|
102
|
+
* `replaceFirstStringIn` in `html/localize-body.ts`).
|
|
103
|
+
*
|
|
104
|
+
* @param text - Heading text (without the leading `### `)
|
|
105
|
+
* @returns Index of the first separator, or `-1` if none found
|
|
106
|
+
*/
|
|
107
|
+
function findFirstSplitChar(text) {
|
|
108
|
+
const separators = ['—', '–', '/', '(', ':'];
|
|
109
|
+
let best = -1;
|
|
110
|
+
for (const sep of separators) {
|
|
111
|
+
const idx = text.indexOf(sep);
|
|
112
|
+
if (idx >= 0 && (best < 0 || idx < best))
|
|
113
|
+
best = idx;
|
|
114
|
+
}
|
|
115
|
+
return best;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Extract media-outlet names from `extended/media-framing-analysis.md`.
|
|
119
|
+
* Editorial convention is a series of bold "framing buckets":
|
|
120
|
+
* `**Centre-Left Media (Le Monde, Der Spiegel, Guardian EU section):**`
|
|
121
|
+
* `**Tech-Beat Media (TechCrunch EU, The Verge, Politico Tech):**`
|
|
122
|
+
*
|
|
123
|
+
* This function pulls every comma-separated outlet from each parenthetical
|
|
124
|
+
* list, trims trailing colons / asterisks, and de-duplicates with
|
|
125
|
+
* case-insensitive equality.
|
|
126
|
+
*
|
|
127
|
+
* @param markdown - Raw media-framing-analysis.md contents
|
|
128
|
+
* @returns Ordered, de-duplicated media-outlet names
|
|
129
|
+
*/
|
|
130
|
+
export function extractMediaOutletNames(markdown) {
|
|
131
|
+
const lines = markdown.split('\n');
|
|
132
|
+
const names = [];
|
|
133
|
+
const seen = new Set();
|
|
134
|
+
for (const rawLine of lines) {
|
|
135
|
+
// Look for bold prefix followed by parenthesised outlet list.
|
|
136
|
+
// Pattern: `**…Media (X, Y, Z):**` — anchor on `Media (` to avoid
|
|
137
|
+
// matching unrelated parentheticals in surrounding prose.
|
|
138
|
+
const mediaIdx = rawLine.indexOf('Media (');
|
|
139
|
+
if (mediaIdx < 0)
|
|
140
|
+
continue;
|
|
141
|
+
const openParen = rawLine.indexOf('(', mediaIdx);
|
|
142
|
+
if (openParen < 0)
|
|
143
|
+
continue;
|
|
144
|
+
const closeParen = rawLine.indexOf(')', openParen);
|
|
145
|
+
if (closeParen < 0)
|
|
146
|
+
continue;
|
|
147
|
+
const inner = rawLine.slice(openParen + 1, closeParen);
|
|
148
|
+
for (const piece of inner.split(',')) {
|
|
149
|
+
const candidate = piece.trim().replace(/\*+$/, '').trim();
|
|
150
|
+
if (!isValidEntityName(candidate))
|
|
151
|
+
continue;
|
|
152
|
+
const key = candidate.toLowerCase();
|
|
153
|
+
if (seen.has(key))
|
|
154
|
+
continue;
|
|
155
|
+
seen.add(key);
|
|
156
|
+
names.push(candidate);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return names;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Guard for extracted-entity sanity: rejects empty strings, single
|
|
163
|
+
* characters, and pathological multi-sentence captures.
|
|
164
|
+
*
|
|
165
|
+
* @param name - Candidate entity name
|
|
166
|
+
* @returns `true` when the name is a plausible organization label
|
|
167
|
+
*/
|
|
168
|
+
function isValidEntityName(name) {
|
|
169
|
+
if (!name)
|
|
170
|
+
return false;
|
|
171
|
+
if (name.length < MIN_ENTITY_LENGTH)
|
|
172
|
+
return false;
|
|
173
|
+
if (name.length > MAX_ENTITY_LENGTH)
|
|
174
|
+
return false;
|
|
175
|
+
// Reject candidates that are just punctuation / decoration.
|
|
176
|
+
if (!/[A-Za-z]/.test(name))
|
|
177
|
+
return false;
|
|
178
|
+
return true;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Collect SEO `mentions` entities for an analysis run by combining
|
|
182
|
+
* stakeholder names and media-outlet names from the run's intelligence
|
|
183
|
+
* and extended folders. Returns a single deduplicated, length-capped
|
|
184
|
+
* list ready to feed into JSON-LD `mentions`.
|
|
185
|
+
*
|
|
186
|
+
* Stakeholders are listed first (high-signal political-group / institution
|
|
187
|
+
* entities), media outlets second. The combined list is truncated to
|
|
188
|
+
* {@link MAX_MENTIONS} entries.
|
|
189
|
+
*
|
|
190
|
+
* @param runDir - Absolute analysis run directory path
|
|
191
|
+
* @returns Ordered, de-duplicated mentions list (may be empty)
|
|
192
|
+
*/
|
|
193
|
+
export function extractRunMentions(runDir) {
|
|
194
|
+
const stakeholderMd = readRunFile(runDir, 'intelligence/stakeholder-map.md');
|
|
195
|
+
const mediaMd = readRunFile(runDir, 'extended/media-framing-analysis.md');
|
|
196
|
+
const stakeholders = stakeholderMd ? extractStakeholderNames(stakeholderMd) : [];
|
|
197
|
+
const mediaOutlets = mediaMd ? extractMediaOutletNames(mediaMd) : [];
|
|
198
|
+
const merged = [];
|
|
199
|
+
const seen = new Set();
|
|
200
|
+
for (const name of [...stakeholders, ...mediaOutlets]) {
|
|
201
|
+
const key = name.toLowerCase();
|
|
202
|
+
if (seen.has(key))
|
|
203
|
+
continue;
|
|
204
|
+
seen.add(key);
|
|
205
|
+
merged.push(name);
|
|
206
|
+
if (merged.length >= MAX_MENTIONS)
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
return merged;
|
|
210
|
+
}
|
|
211
|
+
//# sourceMappingURL=seo-entity-extractor.js.map
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module Constants/Articles/BreakingStringsCentral
|
|
3
|
+
* @description Central breaking-news strings.
|
|
4
|
+
*/
|
|
5
|
+
import type { LanguageMap, BreakingStrings } from '../../types/index.js';
|
|
6
|
+
/** Central breaking-news strings */
|
|
7
|
+
export declare const BREAKING_STRINGS_CENTRAL: Pick<LanguageMap<BreakingStrings>, 'de' | 'fr'>;
|
|
8
|
+
//# sourceMappingURL=breaking-strings-central.d.ts.map
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2024-2026 Hack23 AB
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import { BRK_WHY_ANOMALIES, BRK_WHY_NORMAL, BRK_NEUTRAL_REASON, BRK_LEGAL_CONSEQUENCE, BRK_PROC_CONSEQUENCE, BRK_IMPACT_ECONOMIC, BRK_IMPACT_SOCIAL, BRK_IMPACT_GEO_COALITION, BRK_IMPACT_GEO_NORMAL, BRK_MISTAKE_DESC, BRK_MISTAKE_ALT, } from './_shared.js';
|
|
4
|
+
/** Central breaking-news strings */
|
|
5
|
+
export const BREAKING_STRINGS_CENTRAL = {
|
|
6
|
+
de: {
|
|
7
|
+
breakingBanner: '⚡ EILMELDUNG',
|
|
8
|
+
votingAnomalyIntel: 'Abstimmungsanomalien — Nachrichtendienstanalyse',
|
|
9
|
+
coalitionDynamics: 'Bewertung der Koalitionsdynamik',
|
|
10
|
+
analyticalReport: 'Analytischer Bericht',
|
|
11
|
+
keyMEPInfluence: 'Analyse des Einflusses wichtiger MdEPs',
|
|
12
|
+
intelligenceBriefing: 'Nachrichtendienstbriefing',
|
|
13
|
+
votingAnomalyAlert: 'Warnung vor Abstimmungsanomalien',
|
|
14
|
+
coalitionDynamicsSection: 'Koalitionsdynamik',
|
|
15
|
+
keyPlayers: 'Parlamentarische Schlüsselfiguren',
|
|
16
|
+
placeholderNotice: 'Dies ist Platzhalterinhalt, der generiert wurde, während der MCP-Server des EU-Parlaments nicht verfügbar ist.',
|
|
17
|
+
placeholderLede: 'Bedeutende parlamentarische Entwicklungen werden überwacht. Verbinden Sie den MCP-Server des EU-Parlaments für Echtzeit-Informationen.',
|
|
18
|
+
lede: 'Die Nachrichtendienstanalyse des MCP-Servers des EU-Parlaments hat bedeutende parlamentarische Entwicklungen identifiziert, die sofortige Aufmerksamkeit erfordern',
|
|
19
|
+
feedLede: 'Die neuesten Feeds des Europäischen Parlaments beleuchten aktuelle parlamentarische Aktivitäten',
|
|
20
|
+
adoptedTextsHeading: 'Kürzlich Angenommene Texte',
|
|
21
|
+
recentEventsHeading: 'Aktuelle Parlamentarische Ereignisse',
|
|
22
|
+
procedureUpdatesHeading: 'Aktualisierungen der Gesetzgebungsverfahren',
|
|
23
|
+
mepUpdatesHeading: 'MdEP-Aktualisierungen',
|
|
24
|
+
noFeedDataNotice: 'Keine neuen Feeddaten vom Europäischen Parlament verfügbar.',
|
|
25
|
+
asOf: 'zum',
|
|
26
|
+
breakingWhatFn: (date, adopted, events, procedures, meps) => `Neueste Entwicklungen am ${date}: ${adopted} neu angenommene Texte, ${events} Ereignisse, ${procedures} Verfahrensupdates, ${meps} MdEP-Änderungen.`,
|
|
27
|
+
breakingWhyAnomalies: BRK_WHY_ANOMALIES,
|
|
28
|
+
breakingWhyNormal: BRK_WHY_NORMAL,
|
|
29
|
+
breakingWinnerActor: 'Gesetzgebende Mehrheit',
|
|
30
|
+
breakingWinnerReasonFn: (count) => `${count} Gesetzestexte wurden im parlamentarischen Verfahren vorangebracht.`,
|
|
31
|
+
breakingNeutralActor: 'Oppositionsgruppen',
|
|
32
|
+
breakingNeutralReason: BRK_NEUTRAL_REASON,
|
|
33
|
+
breakingOutlookActiveFn: (date) => `session_date=${date}`,
|
|
34
|
+
breakingOutlookTransitionalFn: (date) => `session_date=${date} transitional=true`,
|
|
35
|
+
breakingLegalObligationsConsequence: BRK_LEGAL_CONSEQUENCE,
|
|
36
|
+
breakingProcedureConsequence: BRK_PROC_CONSEQUENCE,
|
|
37
|
+
breakingImpactPoliticalAnomalies: BRK_WHY_ANOMALIES,
|
|
38
|
+
breakingImpactPoliticalNormalFn: (count) => `legislative_texts=${count}`,
|
|
39
|
+
breakingImpactEconomic: BRK_IMPACT_ECONOMIC,
|
|
40
|
+
breakingImpactSocial: BRK_IMPACT_SOCIAL,
|
|
41
|
+
breakingImpactLegalFn: (count) => `legal_instruments=${count}`,
|
|
42
|
+
breakingImpactGeopoliticalCoalition: BRK_IMPACT_GEO_COALITION,
|
|
43
|
+
breakingImpactGeopoliticalNormal: BRK_IMPACT_GEO_NORMAL,
|
|
44
|
+
breakingMistakeActor: 'Fraktionsgeschäftsführer',
|
|
45
|
+
breakingMistakeDescription: BRK_MISTAKE_DESC,
|
|
46
|
+
breakingMistakeAlternative: BRK_MISTAKE_ALT,
|
|
47
|
+
breakingAdoptedPrefix: 'Angenommen:',
|
|
48
|
+
breakingMEPPrefix: 'MdEP:',
|
|
49
|
+
anomalyUnavailable: 'Detaillierte Analyse von Abstimmungsanomalien ist aufgrund technischer Einschränkungen der Quelldaten derzeit nicht verfügbar.',
|
|
50
|
+
coalitionUnavailable: 'Eine detaillierte Bewertung der Koalitionsdynamik kann derzeit nicht angezeigt werden, da die erforderlichen Grundlagendaten vorübergehend fehlen.',
|
|
51
|
+
adoptedTextTypeLabel: 'Angenommener Text',
|
|
52
|
+
adoptedTextItemLabelFn: (label) => label,
|
|
53
|
+
showingXofNFn: (shown, total) => `${shown} von ${total} angezeigt`,
|
|
54
|
+
},
|
|
55
|
+
fr: {
|
|
56
|
+
breakingBanner: '⚡ DERNIÈRES NOUVELLES',
|
|
57
|
+
votingAnomalyIntel: 'Anomalies de Vote — Analyse de Renseignement',
|
|
58
|
+
coalitionDynamics: 'Évaluation des Dynamiques de Coalition',
|
|
59
|
+
analyticalReport: 'Rapport Analytique',
|
|
60
|
+
keyMEPInfluence: "Analyse de l'Influence des Eurodéputés Clés",
|
|
61
|
+
intelligenceBriefing: 'Briefing de Renseignement',
|
|
62
|
+
votingAnomalyAlert: 'Alerte Anomalie de Vote',
|
|
63
|
+
coalitionDynamicsSection: 'Dynamiques de Coalition',
|
|
64
|
+
keyPlayers: 'Acteurs Parlementaires Clés',
|
|
65
|
+
placeholderNotice: 'Ceci est un contenu indicatif généré pendant que le serveur MCP du Parlement européen est indisponible.',
|
|
66
|
+
placeholderLede: 'Des développements parlementaires importants sont surveillés. Connectez le serveur MCP du Parlement européen pour recevoir des renseignements en temps réel.',
|
|
67
|
+
lede: "L'analyse de renseignement du serveur MCP du Parlement européen a identifié des développements parlementaires significatifs nécessitant une attention immédiate",
|
|
68
|
+
feedLede: 'Les dernières données du Parlement européen mettent en lumière les activités parlementaires récentes',
|
|
69
|
+
adoptedTextsHeading: 'Textes Récemment Adoptés',
|
|
70
|
+
recentEventsHeading: 'Événements Parlementaires Récents',
|
|
71
|
+
procedureUpdatesHeading: 'Mises à Jour des Procédures Législatives',
|
|
72
|
+
mepUpdatesHeading: 'Mises à Jour des Eurodéputés',
|
|
73
|
+
noFeedDataNotice: 'Aucune donnée de flux récente disponible du Parlement européen.',
|
|
74
|
+
asOf: 'au',
|
|
75
|
+
breakingWhatFn: (date, adopted, events, procedures, meps) => `Dernières évolutions au ${date}\u00a0: ${adopted} textes nouvellement adoptés, ${events} événements, ${procedures} mises à jour procédurales, ${meps} changements de députés.`,
|
|
76
|
+
breakingWhyAnomalies: BRK_WHY_ANOMALIES,
|
|
77
|
+
breakingWhyNormal: BRK_WHY_NORMAL,
|
|
78
|
+
breakingWinnerActor: 'Majorité législative',
|
|
79
|
+
breakingWinnerReasonFn: (count) => `${count} textes législatifs ont été avancés dans le cadre du processus parlementaire.`,
|
|
80
|
+
breakingNeutralActor: "Groupes d'opposition",
|
|
81
|
+
breakingNeutralReason: BRK_NEUTRAL_REASON,
|
|
82
|
+
breakingOutlookActiveFn: (date) => `session_date=${date}`,
|
|
83
|
+
breakingOutlookTransitionalFn: (date) => `session_date=${date} transitional=true`,
|
|
84
|
+
breakingLegalObligationsConsequence: BRK_LEGAL_CONSEQUENCE,
|
|
85
|
+
breakingProcedureConsequence: BRK_PROC_CONSEQUENCE,
|
|
86
|
+
breakingImpactPoliticalAnomalies: BRK_WHY_ANOMALIES,
|
|
87
|
+
breakingImpactPoliticalNormalFn: (count) => `legislative_texts=${count}`,
|
|
88
|
+
breakingImpactEconomic: BRK_IMPACT_ECONOMIC,
|
|
89
|
+
breakingImpactSocial: BRK_IMPACT_SOCIAL,
|
|
90
|
+
breakingImpactLegalFn: (count) => `legal_instruments=${count}`,
|
|
91
|
+
breakingImpactGeopoliticalCoalition: BRK_IMPACT_GEO_COALITION,
|
|
92
|
+
breakingImpactGeopoliticalNormal: BRK_IMPACT_GEO_NORMAL,
|
|
93
|
+
breakingMistakeActor: 'Chefs de file des groupes politiques',
|
|
94
|
+
breakingMistakeDescription: BRK_MISTAKE_DESC,
|
|
95
|
+
breakingMistakeAlternative: BRK_MISTAKE_ALT,
|
|
96
|
+
breakingAdoptedPrefix: 'Adopté\u00a0:',
|
|
97
|
+
breakingMEPPrefix: 'Député\u00a0:',
|
|
98
|
+
anomalyUnavailable: "L'analyse détaillée des anomalies de vote n'est pas disponible pour le moment en raison de limitations techniques des données sources.",
|
|
99
|
+
coalitionUnavailable: "L'évaluation détaillée de la dynamique de coalition ne peut pas être affichée pour le moment, car les données sous-jacentes nécessaires sont temporairement indisponibles.",
|
|
100
|
+
adoptedTextTypeLabel: 'Texte adopté',
|
|
101
|
+
adoptedTextItemLabelFn: (label) => label,
|
|
102
|
+
showingXofNFn: (shown, total) => `Affichage de ${shown} sur ${total}`,
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
//# sourceMappingURL=breaking-strings-central.js.map
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module Constants/Articles/BreakingStringsEast
|
|
3
|
+
* @description East breaking-news strings.
|
|
4
|
+
*/
|
|
5
|
+
import type { LanguageMap, BreakingStrings } from '../../types/index.js';
|
|
6
|
+
/** East breaking-news strings */
|
|
7
|
+
export declare const BREAKING_STRINGS_EAST: Pick<LanguageMap<BreakingStrings>, 'he' | 'ja' | 'ko' | 'zh'>;
|
|
8
|
+
//# sourceMappingURL=breaking-strings-east.d.ts.map
|