Skip to content

Comments

fix(i18n): localize SEO keywords and structured data for all 14 languages#493

Merged
pethers merged 5 commits intomainfrom
copilot/fix-twitter-card-localization
Feb 24, 2026
Merged

fix(i18n): localize SEO keywords and structured data for all 14 languages#493
pethers merged 5 commits intomainfrom
copilot/fix-twitter-card-localization

Conversation

Copy link
Contributor

Copilot AI commented Feb 24, 2026

generateMetadata() produced hardcoded English keywords ('parliament', 'week ahead', 'legislation', etc.) for all language variants. The Schema.org JSON-LD jobTitle and organization description fields were also English-only.

Changes

scripts/data-transformers.ts

  • Added SEO_KEYWORD_TRANSLATIONS — lookup table mapping 27 English keyword terms to all 13 non-English languages
  • Added localizeKeyword(keyword, lang) helper with English fallback
  • Updated generateMetadata() — all keywords.push() calls now go through kw() alias; Riksdag stays as-is (proper noun)
  • Added jobTitle and siteDescription translations to all 14 CONTENT_LABELS language blocks

scripts/types/content.ts

  • Extended ContentLabelSet with jobTitle: string and siteDescription: string

scripts/article-template.ts

  • Schema.org "jobTitle" and Organization "description" now resolve via CONTENT_LABELS[lang]

tests/data-transformers.test.ts

  • Added unit tests verifying non-English keyword localization: German committee-reports, Japanese propositions, Arabic motions
  • Added test confirming Riksdag remains a proper noun across all non-Latin-script languages
  • Added test confirming English fallback (e.g. breaking newsEilmeldung in German)

Before (German article):

<meta name="keywords" content="committee, reports, betänkanden, parliament, ...">

After:

<meta name="keywords" content="ausschuss, berichte, parlamentsberichte, parlament, ...">

topics slugs (internal categorization) and Riksdag remain in English intentionally.

Original prompt

This section details on the original issue you should resolve

<issue_title>fix(i18n): Twitter Card labels (twitter:label1, twitter:label2) not localized for non-English articles</issue_title>
<issue_description>## 📋 Issue Type
Bug Fix / i18n Quality

🎯 Objective

Fix Twitter Card twitter:label1 ("Reading time") and twitter:label2 ("Article type") to be localized per language. Currently these labels remain in English for all non-English language variants while only the twitter:data1 and twitter:data2 values are translated.

📊 Current State — Evidence from Recent PRs

Affected PRs: All news article PRs — #480, #482, #483, #485

Example — Government Propositions articles:

<!-- In 2026-02-24-government-propositions-de.html (German) -->
<meta name="twitter:label1" content="Reading time">     <!-- ❌ Should be "Lesezeit" -->
<meta name="twitter:data1" content="5 Min. Lesezeit">   <!-- ✅ Correctly localized -->
<meta name="twitter:label2" content="Article type">      <!-- ❌ Should be "Artikeltyp" -->
<meta name="twitter:data2" content="Analyse">            <!-- ✅ Correctly localized -->

<!-- Same pattern in Japanese, Arabic, Chinese, Korean, French, etc. -->
<meta name="twitter:label1" content="Reading time">      <!-- ❌ English in all languages -->
<meta name="twitter:label2" content="Article type">      <!-- ❌ English in all languages -->

Root cause: scripts/article-template.ts lines 347-349:

<meta name="twitter:label1" content="Reading time">
<meta name="twitter:label2" content="Article type">

These are hardcoded English strings. The template already receives a lang parameter but doesn't use it for label localization.

🚀 Desired State

Twitter Card labels localized per language:

Language twitter:label1 twitter:label2
en Reading time Article type
sv Lästid Artikeltyp
de Lesezeit Artikeltyp
fr Temps de lecture Type d'article
es Tiempo de lectura Tipo de artículo
ja 読了時間 記事タイプ
ar وقت القراءة نوع المقال
zh 阅读时间 文章类型
ko 읽기 시간 기사 유형
da Læsetid Artikeltype
no Lesetid Artikkeltype
fi Lukuaika Artikkelityyppi
nl Leestijd Artikeltype
he זמן קריאה סוג כתבה

🔧 Implementation Approach

  1. Add twitterLabel1 and twitterLabel2 translations to the LABELS object in scripts/data-transformers.ts
  2. Update scripts/article-template.ts to accept lang and look up localized Twitter labels
  3. Run npx vitest run to verify

🤖 Recommended Agent

code-quality-engineer — systematic fix in article template with translation table

✅ Acceptance Criteria

  • twitter:label1 is localized for all 14 languages
  • twitter:label2 is localized for all 14 languages
  • Existing twitter:data1 and twitter:data2 localization still works
  • Existing tests pass (npx vitest run)

📚 References

<agent_instructions>Fix Twitter Card label localization in article template.

Key tasks:

  1. Add twitterLabel1 (Reading time) and twitterLabel2 (Article type) translations to the LABELS object in scripts/data-transformers.ts for all 14 languages.
  2. Update scripts/article-template.ts to use the lang parameter to look up localized Twitter labels at lines 347-349.
  3. The twitter:data1 and twitter:data2 values are already correctly localized — only the label keys need fixing.
  4. Run npx vitest run to verify all tests pass.

This is a small, focused change: add 2 translation keys × 14 languages = 28 new entries, then update 2 lines in the template.</agent_instructions>

Comments on the Issue (you are @copilot in this section)


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI changed the title [WIP] Fix Twitter Card labels localization for non-English articles fix(i18n): localize Twitter Card labels for all 14 languages Feb 24, 2026
Copilot AI changed the title fix(i18n): localize Twitter Card labels for all 14 languages fix(i18n): localize SEO keywords and structured data for all 14 languages Feb 24, 2026
@pethers pethers requested a review from Copilot February 24, 2026 11:49
@github-actions github-actions bot added deployment Deployment configuration refactor Code refactoring size-xl Extra large change (> 1000 lines) labels Feb 24, 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

Updates the article generation pipeline to produce fully localized SEO metadata and structured data across all 14 supported languages, instead of emitting English-only keywords and JSON-LD fields in non-English variants.

Changes:

  • Extended ContentLabelSet and CONTENT_LABELS with localized Twitter Card labels plus localized Schema.org jobTitle and Organization description strings.
  • Added an SEO keyword translation table + helper to localize generateMetadata() keyword output per language (with English fallback).
  • Updated the HTML article template to read Twitter/JSON-LD fields from CONTENT_LABELS[lang] instead of hardcoded English literals.

Reviewed changes

Copilot reviewed 3 out of 4 changed files in this pull request and generated 1 comment.

File Description
scripts/types/content.ts Adds new required label fields (twitterLabel1/2, jobTitle, siteDescription) to the shared label type.
scripts/data-transformers.ts Populates new labels for all languages; adds SEO keyword localization table + wires localized keywords into generateMetadata().
scripts/article-template.ts Uses localized labels for Twitter Card labels and JSON-LD jobTitle / Organization description.
Comments suppressed due to low confidence (1)

scripts/data-transformers.ts:3189

  • In the 'month-ahead' case, tags are still generated using L(lang, 'weekAhead'), which will label month-ahead articles as “Week Ahead” (and local equivalents). If month-ahead is a distinct article type (as implied by the new localized 'month ahead' keyword), add a dedicated label key (e.g. monthAhead) to ContentLabelSet/CONTENT_LABELS and use it here so the tag matches the article type.
      keywords.push(kw('parliament'), kw('month ahead'), kw('calendar'), kw('outlook'));
      topics.push('parliament', 'outlook');
      {
        const tagVal = L(lang, 'weekAhead');
        tags.push(typeof tagVal === 'string' ? tagVal : '');

Comment on lines +3148 to +3153
const kw = (k: string): string => localizeKeyword(k, lang);

// Add type-specific keywords
switch (type) {
case 'week-ahead':
keywords.push('parliament', 'week ahead', 'calendar', 'events');
keywords.push(kw('parliament'), kw('week ahead'), kw('calendar'), kw('events'));
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

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

Keyword localization is newly introduced via SEO_KEYWORD_TRANSLATIONS/localizeKeyword() and the kw() helper, but the existing generateMetadata tests don’t assert any non-English keyword localization behavior. Add/extend unit tests to verify at least one non-English language produces localized keywords (and that unknown keywords fall back to English) to prevent regressions in this lookup-table approach.

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added 5 new unit tests in tests/data-transformers.test.ts (commit 701a844):

  • German committee-reports keywords are localized (ausschuss, berichte, parlament) and no longer contain English equivalents
  • Japanese propositions keywords include 政府, 法律案, 立法, 議会
  • Arabic motions keywords include اقتراحات, معارضة, برلمان
  • Riksdag remains as a proper noun across all 7 non-Latin-script languages
  • breaking newsEilmeldung in German, not the English string

All 1783 tests pass.

@pethers
Copy link
Member

pethers commented Feb 24, 2026

@copilot apply changes based on the comments in this thread

@pethers pethers requested a review from Copilot February 24, 2026 12:29
@github-actions github-actions bot added testing Test coverage size-m Medium change (50-250 lines) labels Feb 24, 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 4 out of 4 changed files in this pull request and generated no new comments.

@pethers pethers marked this pull request as ready for review February 24, 2026 12:46
@pethers pethers merged commit 03ade64 into main Feb 24, 2026
19 checks passed
@pethers pethers deleted the copilot/fix-twitter-card-localization branch February 24, 2026 12:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

deployment Deployment configuration refactor Code refactoring size-m Medium change (50-250 lines) size-xl Extra large change (> 1000 lines) testing Test coverage

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(i18n): Twitter Card labels (twitter:label1, twitter:label2) not localized for non-English articles

2 participants