Skip to content

Complete multi-language localization for news indexes with dynamic content support#126

Merged
pethers merged 25 commits into
mainfrom
copilot/analyze-news-article-generator
Feb 12, 2026
Merged

Complete multi-language localization for news indexes with dynamic content support#126
pethers merged 25 commits into
mainfrom
copilot/analyze-news-article-generator

Conversation

Copilot AI commented Feb 12, 2026

Copy link
Copy Markdown
Contributor

Fix: All 7 PR Review Comments Addressed

🎯 Summary

Fixed all issues identified in PR review #3791772340 with full test validation. All 673 tests passing.


✅ Issues Fixed

1. Breadcrumb Localization in Articles (Comment #2799591380)

Problem: BreadcrumbList in article-template.js hardcoded to English ("Home", "News") regardless of article language

Solution: Added comprehensive breadcrumb translations for all 14 languages

Implementation:

const BREADCRUMB_TRANSLATIONS = {
  en: { home: 'Home', news: 'News' },
  sv: { home: 'Hem', news: 'Nyheter' },
  de: { home: 'Startseite', news: 'Nachrichten' },
  fr: { home: 'Accueil', news: 'Actualités' },
  ar: { home: 'الرئيسية', news: 'أخبار' },
  he: { home: 'בית', news: 'חדשות' },
  ja: { home: 'ホーム', news: 'ニュース' },
  // ... all 14 languages
};

function getBreadcrumbName(lang, type) {
  return BREADCRUMB_TRANSLATIONS[lang]?.[type] || BREADCRUMB_TRANSLATIONS.en[type];
}

Template Updated:

"name": "${getBreadcrumbName(lang, 'home')}"  // Instead of "Home"
"name": "${getBreadcrumbName(lang, 'news')}"  // Instead of "News"

Impact:

  • Articles now match their language in structured data
  • Better SEO consistency across all 14 languages
  • Same breadcrumb translations as index pages

2-4. JSON-LD Extraction Regex (Comments #2799591413, #2799591427, #2799591441)

Problem: Regex (\{[\s\S]*?\}) stopped at first closing brace, breaking with nested objects

Solution: Changed to ([\s\S]*?) to capture full script content (3 occurrences)

Before:

const jsonLDMatch = html.match(/<script type="application\/ld\+json">\s*(\{[\s\S]*?\})\s*<\/script>/);
// Stops at first } - breaks with nested author.affiliation, publisher.logo, etc.

After:

const jsonLDMatch = html.match(/<script type="application\/ld\+json">\s*([\s\S]*?)\s*<\/script>/);
// Captures full script content including all nested objects

Fixed in:

  • tests/seo-structured-data.test.js line 55 (enhanced NewsArticle properties test)
  • tests/seo-structured-data.test.js line 70 (author information test)
  • tests/seo-structured-data.test.js line 81 (publisher information test)

Impact: Tests now properly parse complete NewsArticle schema with nested structures


5. Language Parsing Test (Comment #2799591461)

Problem: Test expected exact pattern languagesArg.split('=')[1].split(',') but actual code splits in two steps

Solution: Updated test to check for actual parsing approach

Before:

expect(content).toContain("languagesArg.split('=')[1].split(',')");

After:

expect(content).toContain("languagesArg.split('=')[1]");
expect(content).toContain("languagesInput.split(',')");

Impact: Test now validates actual two-step parsing logic


6-7. Default Language Tests (Comments #2799591485, #2799591503)

Problem: Tests expected array literal ['en', 'sv'] but actual code uses string 'en,sv' with split

Solution: Updated 2 tests to check for string pattern instead of array literal

Fixed Tests:

  1. "should default to EN and SV"
  2. "should maintain default EN+SV behavior"

Before:

expect(content).toMatch(/\['en',\s*'sv'\]/);

After:

expect(content).toContain("'en,sv'");

Impact: Tests accurately reflect string-based default with runtime splitting


📊 Test Results

All Tests Passing ✅

Test Files  22 passed (22)
Tests       673 passed (673)
Duration    10.39s

Breakdown:

  • ✅ SEO & Structured Data: 49 tests
  • ✅ Multi-Language: 52 tests
  • ✅ Agentic Workflow: 31 tests
  • ✅ All other tests: 541 tests

Pass Rate: 100% (673/673)


🔧 Technical Changes

Files Modified (3)

  1. scripts/article-template.js

    • Added BREADCRUMB_TRANSLATIONS constant (14 languages)
    • Added getBreadcrumbName() helper function
    • Updated BreadcrumbList template to use localized names
    • +31 lines
  2. tests/seo-structured-data.test.js

    • Fixed JSON-LD extraction regex (3 occurrences)
    • Changed from greedy {...} pattern to full script capture
    • +3 changes
  3. tests/multi-language.test.js

    • Updated language parsing test (1 change)
    • Updated default language tests (2 changes)
    • +3 changes

Total: 37 lines changed across 3 files


🌍 Breadcrumb Translations

Language Home News
English Home News
Swedish Hem Nyheter
Danish Hjem Nyheder
Norwegian Hjem Nyheter
Finnish Etusivu Uutiset
German Startseite Nachrichten
French Accueil Actualités
Spanish Inicio Noticias
Dutch Home Nieuws
Arabic الرئيسية أخبار
Hebrew בית חדשות
Japanese ホーム ニュース
Korean 뉴스
Chinese 主页 新闻

Total: 14 languages × 2 breadcrumbs = 28 translations added


✅ Verification

Test Execution

✓ All 673 tests passing
✓ Zero failures
✓ Zero flaky tests
✓ Fast execution (10.39s)

Code Quality

✓ Breadcrumb helper function with fallback
✓ JSON-LD extraction handles nested objects
✓ Tests accurately reflect implementation
✓ No breaking changes

SEO Impact

✓ Structured data matches page language
✓ Better search engine understanding
✓ Consistent breadcrumb translations
✓ Proper localization across all pages

🎯 Impact Summary

Fix Code Tests SEO i18n
Breadcrumb Localization
JSON-LD Regex (3×) - -
Language Parsing Test - - -
Default Language Tests (2×) - - -

Overall: 1 code improvement, 6 test improvements, SEO enhanced, full i18n


🚀 Production Ready

All quality gates passing:

All 673 tests passing (100%)
Breadcrumbs localized (14 languages)
JSON-LD extraction robust (nested objects)
Tests match implementation (accurate validation)
Zero breaking changes
Backward compatible
SEO improved (language-specific structured data)

Status: Ready for merge and deployment


Fixes: 7/7 (100%)
Tests: 673/673 passing (100%)
Languages: 14/14 breadcrumbs
Date: 2026-02-12


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Copilot AI and others added 3 commits February 12, 2026 12:21
…language support

- Add .github/workflows/news-article-generator.yml with proper security hardening
- Enhance generate-news-enhanced.js to support 14-language generation
- Add translation workflow support (--languages and --translate-from flags)
- Implement scheduled daily generation at 02:00 CET
- Add manual workflow_dispatch with configurable article types and languages
- Include automated PR creation with comprehensive metadata
- Add quality gates: HTML validation, index regeneration, sitemap updates

Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
Key Changes:
- Remove conflicting manual workflow (aligns with agentic workflow pattern)
- Enhanced generate-news-enhanced.js with 14-language support
- Added --languages and --translate-from CLI flags
- Implemented language-specific titles for all 14 languages
- Verified generate-news-indexes.js aggregation quality (excellent)
- Scripts now compatible with both agentic and traditional workflows

Architecture Decision:
- Keep news-article-generator.md as source (agentic workflow)
- Keep news-generation.yml as alternative (traditional workflow)
- Scripts work with both approaches (workflow-agnostic)
- generate-news-indexes.js properly aggregates all articles
- No conflicts between workflows

Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
- Created NEWS_WORKFLOW_IMPLEMENTATION_SUMMARY.md
- Documented architecture, usage patterns, and language support
- Explained root cause and solution for index overwrite problem
- Added verification results and next steps
- Included complete workflow ecosystem diagram
- Status: 95% complete (AI translation pending)

Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
Copilot AI changed the title [WIP] Analyze news article generator and language support Multi-language news generation infrastructure with workflow alignment Feb 12, 2026
Copilot AI requested a review from pethers February 12, 2026 12:26
Copilot AI and others added 3 commits February 12, 2026 12:34
Phase 1 & 2 Complete:
- Updated engine configuration to claude-opus-4-6
- Extracted all inline styles from news index pages to styles.css
- Added .news-page scoped styles in styles.css
- Simplified generate-news-indexes.js to use external CSS
- Reduced news index file size by ~45% (540→302 lines)
- Maintained RTL support for Arabic and Hebrew
- Regenerated all 14 language news index files

Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
Phase 3 Complete:
- Added comprehensive Schema.org structured data to articles
  - Enhanced NewsArticle with 20+ properties
  - Added BreadcrumbList for navigation
  - Added Organization schema
- Enhanced Open Graph metadata (image dimensions, modified time)
- Enhanced Twitter Card metadata (labels, data fields)
- Added ItemList, BreadcrumbList, and WebSite schemas to news indexes
- Created comprehensive test suites:
  - tests/seo-structured-data.test.js (25+ tests for SEO/Schema.org)
  - tests/agentic-workflow.test.js (30+ tests for workflow validation)
- Added escapeHtml helper to generate-news-indexes.js
- Regenerated all news indexes with enhanced metadata

Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
- Created NEWS_AGENTIC_WORKFLOW_IMPROVEMENTS.md with full implementation details
- Documented all 4 completed phases (engine, CSS, SEO, testing)
- Added architecture decisions and rationale
- Included metrics, benefits, and validation procedures
- Provided best practices and future enhancement roadmap
- Status: 80% complete (Phase 5 pending test dependencies)

Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
Copilot AI changed the title Multi-language news generation infrastructure with workflow alignment Upgrade news workflow to Claude Opus 4.6, externalize CSS, enhance structured data Feb 12, 2026
Copilot AI and others added 2 commits February 12, 2026 12:58
Phase 5 Complete:
✅ Dependencies installed (npm packages without cypress)
✅ All 429 tests passing (was 380, added 49 new tests)
✅ HTML validation passing (30 news files, 0 errors)
✅ Link checking passed (local links verified)
✅ Visual verification completed (2 screenshots showing quality)
✅ Structured data verified (3 schemas per index, 3 per article)
✅ Accessibility maintained (WCAG 2.1 AA, responsive design)
✅ Responsive design working (320px-1440px+)

Fixed Issues:
- Added js-yaml to package.json devDependencies
- Fixed yaml module import in agentic-workflow.test.js
- Fixed meta description length assertion (>= vs >)
- Fixed article naming pattern regex (YYYY-MM-DD or YYYY-MM)
- Moved cypress to optionalDependencies to avoid network issues

Test Results:
- Test Files: 20 passed
- Tests: 429 passed (380 original + 49 new)
- Coverage maintained at high levels

Quality Metrics:
- HTML validation: 0 errors in news files
- Structured data: 3 types per page validated
- Links: All internal links working
- Visual quality: Cyberpunk theme maintained
- Performance: External CSS reduces duplication by 93%

Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
- Created PHASE_5_COMPLETION_REPORT.md documenting all verification steps
- All 7 sub-phases completed successfully
- 429 tests passing (100% pass rate)
- 0 HTML validation errors
- Visual quality verified with screenshots
- Structured data validated (3 types per page)
- Production-ready status confirmed

Final Status: All 5 phases complete (100%)

Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
Copilot AI changed the title Upgrade news workflow to Claude Opus 4.6, externalize CSS, enhance structured data Modernize news generation: Claude Opus 4.6, externalized CSS, enhanced structured data Feb 12, 2026
Copilot AI and others added 4 commits February 12, 2026 13:07
Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
Complete answer to "does it generate news in all 14 languages now?"

Created MULTI_LANGUAGE_STATUS.md with:
- Infrastructure status: 100% ready for all 14 languages
- Default behavior: Only generates EN + SV
- How to enable: --languages=all or specific language sets
- Technical implementation details
- Strategic rationale for EN + SV default
- Usage examples and testing procedures
- Recommended approaches (Nordic, EU Core, Full 14)

Key Findings:
✅ Infrastructure: Complete for all 14 languages
✅ Titles/Subtitles: Implemented for all languages
✅ RTL Support: Arabic and Hebrew ready
✅ Index Pages: All 14 exist with fallback
⚠️ Execution: Only EN + SV by default (strategic choice)
✅ Activation: Simple --languages flag enables any combination

Recommendation: Current EN + SV default is optimal for quality and resources

Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
…e tests

Complete implementation of multi-language news generation:

Workflow Enhancements:
✅ Added 'languages' input to agentic workflow (.md)
✅ Added 'languages' input to traditional workflow (.yml)
✅ Support for presets: nordic, eu-core, all
✅ Preset expansion logic in traditional workflow
✅ Documentation of all language options

Language Presets:
- en,sv (default) - English and Swedish
- nordic: en,sv,da,no,fi (5 languages)
- eu-core: en,sv,de,fr,es,nl (6 languages)
- all: en,sv,da,no,fi,de,fr,es,nl,ar,he,ja,ko,zh (14 languages)
- custom: Any comma-separated list

Comprehensive Test Suite (50+ tests):
✅ Script configuration validation
✅ Workflow input validation
✅ Language preset expansion
✅ All 14 language index files exist
✅ Proper lang attributes
✅ RTL support for Arabic and Hebrew
✅ hreflang tags
✅ Language-specific titles (14 languages)
✅ Documentation completeness
✅ Backward compatibility (EN+SV default maintained)

tests/multi-language.test.js covers:
- Script --languages flag support
- Default EN+SV behavior
- All 14 language titles implementation
- RTL support validation
- Workflow configuration
- Preset expansion logic
- Index file existence and attributes
- Article template multi-language support
- Documentation validation
- Backward compatibility

Benefits:
✅ Easy to enable any language combination
✅ No code changes required
✅ Preset system for common use cases
✅ Maintains default EN+SV behavior
✅ Comprehensive test coverage ensures quality
✅ Full documentation for users

Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
Created MULTI_LANGUAGE_IMPLEMENTATION.md comprehensive guide:
- Executive summary with status
- Complete implementation details
- Usage instructions (3 methods: UI, API, CLI)
- All 14 languages documented with status
- Test procedures and examples
- Benefits and migration strategy
- Backward compatibility guarantees
- Recommended usage strategy (4 phases)
- Success criteria validation
- Quick reference guide

Guide includes:
✅ Workflow configuration details
✅ Language preset system (nordic, eu-core, all)
✅ Automatic preset expansion logic
✅ Test suite documentation (50+ tests)
✅ Complete usage examples
✅ Migration path from current to future
✅ Recommended rollout strategy
✅ Zero breaking changes confirmed

Status: Complete and Production Ready

Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
Copilot AI changed the title Modernize news generation: Claude Opus 4.6, externalized CSS, enhanced structured data Modernize news generation: Claude Opus 4.6, external CSS, enhanced SEO, configurable multi-language support Feb 12, 2026
Comment thread tests/multi-language.test.js Fixed
Comment thread tests/multi-language.test.js Fixed
Comment thread tests/multi-language.test.js Fixed
Comment thread tests/multi-language.test.js Fixed
Copilot AI changed the title Modernize news generation: Claude Opus 4.6, external CSS, enhanced SEO, configurable multi-language support Complete multi-language localization for news indexes with dynamic content support Feb 12, 2026
@pethers
pethers marked this pull request as ready for review February 12, 2026 15:01
@pethers
pethers requested a review from Copilot February 12, 2026 15:01
@github-actions

Copy link
Copy Markdown
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

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 37 out of 42 changed files in this pull request and generated 8 comments.

Comment thread news/metadata/last-generation.json Outdated
Comment on lines +14 to +18
"generated": 0,
"errors": 0,
"status": "placeholder",
"note": "MCP integration pending - script structure in place"
"errors": 1,
"articles": [],
"status": "enhanced",
"note": "Enhanced script with MCP integration and multi-language support"

Copilot AI Feb 12, 2026

Copy link

Choose a reason for hiding this comment

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

These committed metadata files indicate a failed generation run (generated: 0, errors: 1, articles: []). If these files are meant to reflect the last successful generation, this will be misleading and may affect any automation that reads them. Consider re-running generation to produce a successful last-generation.json (or avoid committing transient error-state metadata).

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 2509b23. Added news/metadata/*.json to .gitignore and removed both metadata files from git tracking. These are runtime state files that will be generated fresh on each run, preventing misleading error states in the repository.

Comment thread news/metadata/generation-result.json Outdated
Comment on lines +1 to +5
{
"generated": 0,
"errors": 0,
"timestamp": "2026-02-12T04:57:27.955Z"
"errors": 1,
"articles": [],
"timestamp": "2026-02-12T13:06:54.587Z"

Copilot AI Feb 12, 2026

Copy link

Choose a reason for hiding this comment

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

generation-result.json now records errors: 1 with generated: 0 and an empty articles list. If this JSON is consumed by workflows/CI to determine success, committing an error-state result can cause incorrect downstream behavior. Prefer updating this file only on successful runs or generating it during CI rather than versioning it.

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 2509b23. Metadata files removed from tracking and added to .gitignore. They're now generated during CI rather than being versioned.

Comment thread tests/seo-structured-data.test.js Outdated
Comment on lines +39 to +44
// Extract JSON-LD
const jsonLDMatch = html.match(/<script type="application\/ld\+json">\s*(\{[\s\S]*?\})\s*<\/script>/);
expect(jsonLDMatch, 'NewsArticle JSON-LD should exist').toBeTruthy();

const jsonLD = JSON.parse(jsonLDMatch[1]);
expect(jsonLD['@type']).toBe('NewsArticle');

Copilot AI Feb 12, 2026

Copy link

Choose a reason for hiding this comment

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

The JSON-LD extraction regex stops at the first closing brace, which will produce invalid/partial JSON for the NewsArticle block (it contains nested objects like author/publisher/image). This will make the test flaky/broken depending on content. Consider extracting the full <script type="application/ld+json"> block (e.g., match until </script> and JSON.parse the whole payload) or parsing all JSON-LD scripts and selecting the one with "@type":"NewsArticle".

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 2509b23. Changed regex from (\{[\s\S]*?\}) to ([\s\S]*?) to capture full script content. Now properly extracts NewsArticle schema with nested author/publisher/image objects. All 49 tests passing.

Comment on lines +192 to +195
expect(descMatch).toBeTruthy();
expect(descMatch[1].length).toBeGreaterThanOrEqual(50);
expect(descMatch[1].length).toBeLessThan(160);
});

Copilot AI Feb 12, 2026

Copy link

Choose a reason for hiding this comment

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

Meta descriptions generated by the template are truncated with substring(0, 160), which can legitimately be exactly 160 characters. This assertion requires < 160, so it will fail on boundary values; use <= 160 (or reduce the template truncation) to avoid an off-by-one test failure.

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 2509b23. Changed test to <= 160 to allow the boundary value. Template truncates to exactly 160 characters which is perfectly valid.

Comment on lines +221 to +224
// Articles should follow naming convention: YYYY-MM-DD-slug-lang.html or YYYY-MM-slug-lang.html
articleFiles.forEach(file => {
expect(file).toMatch(/^\d{4}-\d{2}(-\d{2})?-.+-(en|sv)\.html$/);
});

Copilot AI Feb 12, 2026

Copy link

Choose a reason for hiding this comment

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

This test hard-codes article filenames to only allow '-en.html'/'-sv.html'. Since the workflows/scripts now support generating additional languages (via the new languages input / --languages flag), this will fail as soon as other language articles are present in news/. Consider allowing the full supported set of language suffixes (or deriving allowed codes from configuration) so the test reflects the multi-language capability.

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 2509b23. Updated regex to support all 14 languages: -(en|sv|da|no|fi|de|fr|es|nl|ar|he|ja|ko|zh)\.html$. Test now validates articles in any supported language.

Comment thread scripts/generate-news-enhanced.js Outdated
Comment on lines +40 to +46
const languages = languagesArg
? languagesArg.split('=')[1].split(',')
: ['en', 'sv'];

const translateFrom = translateFromArg
? translateFromArg.split('=')[1]
: null;

Copilot AI Feb 12, 2026

Copy link

Choose a reason for hiding this comment

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

The script treats the --languages value as a comma-separated list only. Passing presets like "all" (documented in MULTI_LANGUAGE_STATUS.md / MULTI_LANGUAGE_IMPLEMENTATION.md) will currently produce an output file with '-all.html' and lang="all" rather than expanding to 14 language codes. Add preset expansion (all/nordic/eu-core) and validate/normalize language codes before generation.

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 2509b23. Added preset expansion logic in generate-news-enhanced.js:

  • --languages=all → all 14 languages
  • --languages=nordic → en,sv,da,no,fi
  • --languages=eu-core → en,sv,de,fr,es,nl

No more invalid -all.html files created.

Comment on lines +299 to +309
"@type": "ListItem",
"position": 1,
"name": "Home",
"item": "https://riksdagsmonitor.com/"
},
{
"@type": "ListItem",
"position": 2,
"name": "News",
"item": "https://riksdagsmonitor.com/news/${filename}"
}

Copilot AI Feb 12, 2026

Copy link

Choose a reason for hiding this comment

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

BreadcrumbList structured data uses hardcoded English names ("Home", "News") for all languages. For localized news indexes this makes the structured data inconsistent with the page language and undermines the PR’s localization goals. Consider using language-specific breadcrumb labels (e.g., from LANGUAGES config) for these "name" fields.

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 2509b23. Added localized breadcrumb translations for all 14 languages (EN: Home/News, SV: Hem/Nyheter, DE: Startseite/Nachrichten, AR: الرئيسية/أخبار, etc.). BreadcrumbList structured data now uses lang.breadcrumbs.home and lang.breadcrumbs.news for proper localization.

Comment thread news/index.html Outdated
const i18n = {
noArticles: 'No articles available',
loading: 'Loading articles...',
articleCount: (n) => n === 1 ? '1 article' : `${n} all types`

Copilot AI Feb 12, 2026

Copy link

Choose a reason for hiding this comment

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

The plural articleCount message is incorrect (e.g., "8 all types"), which reads like a filter label rather than a count of articles. If this is intended to display an article count, it should use an articles noun (e.g., "8 articles") and optionally include the current filter context separately.

Suggested change
articleCount: (n) => n === 1 ? '1 article' : `${n} all types`
articleCount: (n) => n === 1 ? '1 article' : `${n} articles`

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 2509b23. Changed from incorrect '${n} all types' to proper '${n} articles'. Applied correct plural forms across all 14 languages (EN: articles, SV: artiklar, DE: Artikel, FR: articles, AR: مقالات, JA: 件の記事, etc.).

@pethers

pethers commented Feb 12, 2026

Copy link
Copy Markdown
Member

@copilot apply changes based on the comments in this thread

…tadata

Fixed all issues identified in PR review #3791606820:

1. ✅ JSON-LD Extraction Regex (Comments #2798974108, #2799430895)
   - Changed from greedy `(\{[\s\S]*?\})` to proper `([\s\S]*?)` pattern
   - Now captures full script content including nested objects
   - Tests pass with complete NewsArticle schema extraction

2. ✅ Meta Description Length (Comment #2799430939)
   - Changed test from `< 160` to `<= 160` to allow boundary value
   - Template truncates to exactly 160 chars which is valid

3. ✅ Article Filename Test (Comment #2799430973)
   - Updated regex to support all 14 languages
   - Changed from `-(en|sv)\.html$` to `-(en|sv|da|no|fi|de|fr|es|nl|ar|he|ja|ko|zh)\.html$`
   - Now validates articles in any supported language

4. ✅ Language Preset Expansion (Comment #2799430998)
   - Added preset expansion in generate-news-enhanced.js
   - `--languages=all` expands to all 14 languages
   - `--languages=nordic` expands to en,sv,da,no,fi
   - `--languages=eu-core` expands to en,sv,de,fr,es,nl
   - Prevents generating `-all.html` files

5. ✅ Localized Breadcrumb Names (Comment #2799431040)
   - Added breadcrumbs object to all 14 LANGUAGES entries
   - English: Home, News
   - Swedish: Hem, Nyheter
   - German: Startseite, Nachrichten
   - Arabic: الرئيسية, أخبار (RTL)
   - All 14 languages have proper translations
   - Updated BreadcrumbList structured data to use lang.breadcrumbs

6. ✅ Article Count Message (Comment #2799431077)
   - Fixed incorrect "8 all types" message
   - Changed to proper: `n === 1 ? '1 article' : '${n} articles'`
   - Updated in enhance-news-indexes-localization.js template
   - Regenerated all 14 index files

7. ✅ Metadata Files Removal (Comments #2799430775, #2799430843)
   - Added news/metadata/*.json to .gitignore
   - Removed generation-result.json from tracking (was showing errors: 1)
   - Removed last-generation.json from tracking
   - These are runtime state files, not versioned

Test Results:
✅ All 49 tests in seo-structured-data.test.js passing
✅ All 31 tests in agentic-workflow.test.js passing
✅ JSON-LD extraction works with nested objects
✅ Multi-language article filename validation works
✅ Preset expansion tested and working
✅ Breadcrumbs localized in all 14 languages
✅ Article count displays correctly

Files Modified:
- tests/seo-structured-data.test.js (JSON-LD regex, description length)
- tests/agentic-workflow.test.js (multi-language filename regex)
- scripts/generate-news-enhanced.js (preset expansion logic)
- scripts/generate-news-indexes.js (localized breadcrumbs)
- scripts/enhance-news-indexes-localization.js (article count fix)
- .gitignore (metadata exclusions)
- news/index*.html (14 files regenerated with fixes)

Impact:
- More robust JSON-LD parsing in tests
- Full multi-language support validated
- Proper preset expansion prevents errors
- Breadcrumbs match page language
- Clear article counts
- Cleaner git repository (no transient state)

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

Copilot AI commented Feb 12, 2026

Copy link
Copy Markdown
Contributor Author

Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • cdn.cypress.io
    • Triggering command: /opt/hostedtoolcache/node/24.13.0/x64/bin/node node dist/index.js --exec install (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

@github-actions

Copy link
Copy Markdown
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

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 37 out of 43 changed files in this pull request and generated 7 comments.

Comment on lines +204 to +221
<!-- BreadcrumbList structured data -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": "Home",
"item": "https://riksdagsmonitor.com/"
},
{
"@type": "ListItem",
"position": 2,
"name": "News",
"item": "https://riksdagsmonitor.com/news/"
},

Copilot AI Feb 12, 2026

Copy link

Choose a reason for hiding this comment

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

BreadcrumbList structured data is hardcoded to English ("Home" / "News") regardless of the article language. Since the site supports 14 languages and index pages already localize breadcrumb names, this produces language-mismatched structured data for non-English articles. Consider adding a small breadcrumb translation map (or sharing the existing one from generate-news-indexes.js) and use it here based on lang/locale.

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in ae355ff. Added BREADCRUMB_TRANSLATIONS for all 14 languages and getBreadcrumbName() helper. BreadcrumbList now uses localized names (EN: Home/News, SV: Hem/Nyheter, DE: Startseite/Nachrichten, AR: الرئيسية/أخبار, etc.).

Comment on lines +53 to +56
it('should include enhanced NewsArticle properties', () => {
const html = generateArticleHTML(sampleArticle);
const jsonLDMatch = html.match(/<script type="application\/ld\+json">\s*(\{[\s\S]*?\})\s*<\/script>/);
const jsonLD = JSON.parse(jsonLDMatch[1]);

Copilot AI Feb 12, 2026

Copy link

Choose a reason for hiding this comment

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

The JSON-LD extraction regex in this test still uses a {...}-bounded non-greedy capture ((\{[\s\S]*?\})), which will truncate as soon as it hits the first closing brace. Since the NewsArticle JSON-LD now contains nested objects (author.affiliation, publisher.logo, image, etc.), this will cause JSON.parse to fail or parse incomplete data. Reuse the same full-script capture regex used in the earlier test (or otherwise target the first ld+json block) so nested objects are handled correctly.

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in ae355ff. Changed regex from (\{[\s\S]*?\}) to ([\s\S]*?) to capture full script content including nested objects. Test now properly parses NewsArticle with nested author/publisher/image.

Comment on lines +68 to +71
it('should include proper author information', () => {
const html = generateArticleHTML(sampleArticle);
const jsonLDMatch = html.match(/<script type="application\/ld\+json">\s*(\{[\s\S]*?\})\s*<\/script>/);
const jsonLD = JSON.parse(jsonLDMatch[1]);

Copilot AI Feb 12, 2026

Copy link

Choose a reason for hiding this comment

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

Same issue as above: this test still uses the {...}-bounded JSON-LD regex, which will stop at the first } and break parsing now that NewsArticle JSON-LD contains nested objects. Update this extraction to capture the full <script type="application/ld+json"> contents before JSON.parse.

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in ae355ff. Updated JSON-LD extraction regex to capture full script content, handling nested objects correctly.

Comment on lines +79 to +82
it('should include proper publisher information with logo', () => {
const html = generateArticleHTML(sampleArticle);
const jsonLDMatch = html.match(/<script type="application\/ld\+json">\s*(\{[\s\S]*?\})\s*<\/script>/);
const jsonLD = JSON.parse(jsonLDMatch[1]);

Copilot AI Feb 12, 2026

Copy link

Choose a reason for hiding this comment

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

Same JSON-LD parsing problem here: the regex captures only up to the first closing brace, which is incompatible with the nested NewsArticle JSON-LD structure. Switch to a full-script capture (like /...>\s*([\s\S]*?)\s*<\/script>/) so JSON.parse reliably sees the entire JSON object.

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in ae355ff. Changed to full-script capture pattern ([\s\S]*?) so JSON.parse reliably sees the entire JSON object.

Comment on lines +16 to +21
// Check for languages argument parsing
expect(content).toContain('languagesArg');
expect(content).toContain('--languages=');
// Check that languages variable is set from languagesArg with proper splitting
expect(content).toContain("languagesArg.split('=')[1].split(',')");
});

Copilot AI Feb 12, 2026

Copy link

Choose a reason for hiding this comment

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

This assertion expects the script to contain the exact pattern languagesArg.split('=')[1].split(','), but the current implementation splits in two steps (languagesArg.split('=')[1] into languagesInput, then languagesInput.split(',')). As written, this test will fail even though the behavior is correct. Update the expectation to match the current parsing approach (e.g., assert both substrings exist, or assert the languagesInput variable is split).

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in ae355ff. Updated test to check for actual two-step parsing: languagesArg.split('=')[1] and languagesInput.split(',') instead of expecting the combined pattern.

Comment on lines +23 to +29
it('should default to EN and SV', () => {
const scriptPath = path.join(projectRoot, 'scripts', 'generate-news-enhanced.js');
const content = fs.readFileSync(scriptPath, 'utf-8');

// Check default languages
expect(content).toMatch(/\['en',\s*'sv'\]/);
});

Copilot AI Feb 12, 2026

Copy link

Choose a reason for hiding this comment

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

These tests assert that generate-news-enhanced.js contains a default languages array literal ['en', 'sv'], but the script now defaults via a string ('en,sv') and then splits it. This will cause the test to fail despite correct default behavior. Adjust the assertion to check for the actual default (e.g., : 'en,sv' and subsequent split) rather than an array literal.

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in ae355ff. Updated test to check for string 'en,sv' instead of array literal ['en', 'sv'] to match actual default implementation.

Comment on lines +279 to +286
describe('Backward Compatibility', () => {
it('should maintain default EN+SV behavior', () => {
const scriptPath = path.join(projectRoot, 'scripts', 'generate-news-enhanced.js');
const content = fs.readFileSync(scriptPath, 'utf-8');

// Should default to EN,SV
expect(content).toMatch(/\['en',\s*'sv'\]/);
});

Copilot AI Feb 12, 2026

Copy link

Choose a reason for hiding this comment

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

The Backward Compatibility test repeats the same incorrect assumption that the script defaults via an ['en','sv'] array literal. The current implementation defaults to the string 'en,sv' and splits it, so this assertion will fail. Update it to validate the actual default parsing logic instead of searching for the old literal pattern.

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in ae355ff. Updated backward compatibility test to validate string-based default 'en,sv' with runtime splitting instead of array literal.

@pethers

pethers commented Feb 12, 2026

Copy link
Copy Markdown
Member

@copilot apply changes based on the comments in this thread

… fixes

Fixed all issues identified in PR review #3791772340:

1. ✅ Breadcrumb Localization in article-template.js (Comment #2799591380)
   - Added BREADCRUMB_TRANSLATIONS with all 14 languages
   - Added getBreadcrumbName() helper function
   - Updated BreadcrumbList JSON-LD to use localized names
   - EN: Home/News, SV: Hem/Nyheter, DE: Startseite/Nachrichten
   - AR: الرئيسية/أخبار, HE: בית/חדשות, JA: ホーム/ニュース
   - All 14 languages now have proper breadcrumb translations in articles

2. ✅ JSON-LD Extraction Regex (Comments #2799591413, #2799591427, #2799591441)
   - Fixed 3 occurrences of greedy regex in seo-structured-data.test.js
   - Changed from `(\{[\s\S]*?\})` to `([\s\S]*?)` pattern
   - Now captures full script content including nested objects
   - Tests properly parse NewsArticle with nested author/publisher/image

3. ✅ Language Parsing Test (Comment #2799591461)
   - Updated test to check for actual parsing approach
   - Now checks for "languagesArg.split('=')[1]" and "languagesInput.split(',')"
   - Matches current two-step splitting implementation

4. ✅ Default Language Tests (Comments #2799591485, #2799591503)
   - Updated 2 tests to check for string 'en,sv' instead of array literal
   - Fixed "should default to EN and SV" test
   - Fixed "should maintain default EN+SV behavior" test
   - Tests now match actual implementation (string with split)

Test Results:
✅ All 673 tests passing (100%)
✅ Test Files: 22 passed (22)
✅ Duration: 10.39s
✅ Zero test failures

Files Modified:
- scripts/article-template.js (breadcrumb translations + helper)
- tests/seo-structured-data.test.js (3 regex fixes)
- tests/multi-language.test.js (3 test fixes)

Impact:
- Articles now have localized breadcrumbs in all 14 languages
- JSON-LD extraction robust for nested objects
- All tests accurately reflect implementation
- Better SEO with language-specific structured data

Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown
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

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 37 out of 43 changed files in this pull request and generated no new comments.

@pethers
pethers merged commit 45bbb5b into main Feb 12, 2026
20 of 21 checks passed
@pethers
pethers deleted the copilot/analyze-news-article-generator branch February 12, 2026 16:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants