feat(14-05): add tenderRadar i18n namespace (DE + EN) with key-parity guard

Introduces the tenderRadar top-level namespace in de.json/en.json covering
page, results, filter (incl. Bundesland/CPV division labels), savedSearch,
detail, coverage, settings, sourceConfig, rssFeeds and emailAlerts groups.
EN translations authored with consistent Vergabe-domain terminology
(Ausschreibung->tender, Vergabestelle->contracting authority, Frist->
deadline, Auftragswert->estimated value). tenderRadar-parity.spec.ts
enforces recursively-flattened de/en key-set equality so no follow-up edit
can silently add a string to only one locale.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-23 14:07:41 +02:00
parent a4889f8399
commit d73171b052
3 changed files with 565 additions and 0 deletions
+253
View File
@@ -571,5 +571,258 @@
"wrongPassword": "Wrong password. Could not decrypt the PFX/P12 file.",
"unknownFormat": "Unknown format. The file could not be recognized as a certificate."
}
},
"tenderRadar": {
"page": {
"title": "Tender Radar",
"loading": "Loading…"
},
"results": {
"colTitle": "Title",
"colBuyer": "Contracting Authority",
"colDeadline": "Deadline",
"colValue": "Value",
"colPublished": "Published",
"colTriage": "Triage",
"noValue": "no value stated",
"error": "Could not load tenders.",
"emptyTitle": "No tenders found.",
"emptyBody": "Adjust the filters or disable \"open only\".",
"markUnread": "Mark as unread",
"markRead": "Mark as read",
"readLabel": "Read",
"unreadLabel": "Unread",
"removeFavorite": "Remove favorite",
"setFavorite": "Set favorite",
"favoriteOn": "★ Favorite",
"favoriteOff": "☆ Favorite",
"showingRange": "Showing {from}–{to} of {total}",
"prevPage": "← Back",
"nextPage": "Next →"
},
"filter": {
"sortPublished": "Publication date",
"sortDeadline": "Deadline",
"sortValue": "Estimated value",
"searchLabel": "Search",
"searchPlaceholder": "Title or contracting authority…",
"sortLabel": "Sort by",
"openOnlyLabel": "Open only",
"favOnlyLabel": "Favorites only",
"deadlineFromLabel": "Deadline from",
"deadlineToLabel": "Deadline to",
"plzLabel": "Postal code",
"plzPlaceholder": "e.g. 10",
"bundeslandLabel": "Federal state",
"bundeslandAll": "All federal states",
"cpvLabel": "Sector (CPV)",
"cpvPlaceholder": "e.g. construction, IT, health…",
"cpvRemoveAria": "Remove division {code}",
"valueMinLabel": "Estimated value from (€)",
"valueMinPlaceholder": "min.",
"valueMaxLabel": "Estimated value to (€)",
"valueMaxPlaceholder": "max.",
"includeNullValueLabel": "Include tenders without a stated value",
"bundeslandOptions": {
"DE1": "Baden-Württemberg",
"DE2": "Bavaria",
"DE3": "Berlin",
"DE4": "Brandenburg",
"DE5": "Bremen",
"DE6": "Hamburg",
"DE7": "Hesse",
"DE8": "Mecklenburg-Western Pomerania",
"DE9": "Lower Saxony",
"DEA": "North Rhine-Westphalia",
"DEB": "Rhineland-Palatinate",
"DEC": "Saarland",
"DED": "Saxony",
"DEE": "Saxony-Anhalt",
"DEF": "Schleswig-Holstein",
"DEG": "Thuringia"
},
"cpvDivisions": {
"03": "Agricultural, farming, fishing, forestry and related products",
"09": "Petroleum products, fuel, electricity and other sources of energy",
"14": "Mining, basic metals and related products",
"15": "Food, beverages, tobacco and related products",
"16": "Agricultural machinery",
"18": "Clothing, footwear, luggage articles and accessories",
"19": "Leather and textile fabrics, plastic and rubber materials",
"22": "Printed matter and related products",
"24": "Chemical products",
"30": "Office and computing machinery, equipment and supplies except furniture and software packages",
"31": "Electrical machinery, apparatus, equipment and consumables; lighting",
"32": "Radio, television, communication, telecommunication and related equipment",
"33": "Medical equipment, pharmaceutical products and personal care products",
"34": "Transport equipment and auxiliary products to transportation",
"35": "Security, fire-fighting, police and defence equipment",
"37": "Musical instruments, sport goods, games, toys, handicraft, art materials and accessories",
"38": "Laboratory, optical and precision equipment (excl. glasses)",
"39": "Furniture (including office furniture), furnishings, domestic appliances (excl. lighting) and cleaning products",
"41": "Collected and purified water",
"42": "Industrial machinery",
"43": "Machinery for mining, quarrying, construction equipment",
"44": "Construction structures and materials; auxiliary products to construction",
"45": "Construction work",
"48": "Software package and information systems",
"50": "Repair and maintenance services",
"51": "Installation services (except software)",
"55": "Hotel, restaurant and retail trade services",
"60": "Transport services (excl. waste transport)",
"63": "Supporting and auxiliary transport services; travel agency services",
"64": "Postal and telecommunications services",
"65": "Public utilities",
"66": "Financial and insurance services",
"70": "Real estate services",
"71": "Architectural, construction, engineering and inspection services",
"72": "IT services: consulting, software development, Internet and support",
"73": "Research and development services and related consultancy services",
"75": "Administration, defence and social security services",
"76": "Services related to the oil and gas industry",
"77": "Agricultural, forestry, horticultural, aquacultural and apicultural services",
"79": "Business services: law, marketing, consulting, recruitment, printing and security",
"80": "Education and training services",
"85": "Health and social work services",
"90": "Sewage, refuse, cleaning and environmental services",
"92": "Recreational, cultural and sporting services",
"98": "Other community, social and personal services"
}
},
"savedSearch": {
"title": "Saved Searches",
"saveAsLabel": "Save current filters as",
"namePlaceholder": "Name of the saved search…",
"save": "Save",
"cancel": "Cancel",
"loading": "Loading…",
"empty": "No saved searches yet.",
"loadTitle": "Load saved search",
"instantAlertTitle": "Instant email alert for new matches of this search",
"instantAlertLabel": "Instant alert",
"instantAlertAria": "Instant alert for {name}",
"renameTitle": "Rename",
"renameAria": "Rename {name}",
"renameConfirmAria": "Confirm rename of {name}",
"renameCancelAria": "Cancel rename",
"deleteTitle": "Delete",
"deleteAria": "Delete {name}",
"errorLoad": "Could not load saved searches.",
"errorSave": "Could not save the search.",
"errorRename": "Could not rename the search.",
"errorDelete": "Could not delete the search.",
"errorToggleAlert": "Could not toggle the instant alert."
},
"detail": {
"dialogAria": "Tender details",
"title": "Tender details",
"close": "Close",
"loading": "Loading…",
"error": "Could not load the tender.",
"fieldTitle": "Title",
"fieldBuyer": "Contracting Authority",
"fieldRegion": "Region / Postal code / Federal state",
"fieldCpv": "CPV codes",
"noCpv": "no CPV codes stated",
"fieldDeadline": "Deadline",
"noDeadline": "no deadline stated",
"fieldValue": "Estimated Value",
"noValue": "no value stated",
"fieldProcedureType": "Procedure Type",
"fieldStatus": "Status",
"fieldPublished": "Published",
"mirrorNotice": "Tender documents are not mirrored locally — the link below leads directly to the original on the source portal.",
"sourceLink": "{portal}: View tender on source portal →",
"noSourceLink": "{portal}: No source link available.",
"sourceLinkFallback": "View tender on source portal →",
"noSourceLinkFallback": "No source link available."
},
"coverage": {
"label": "Data coverage:",
"text": "Currently only EU-wide above-threshold tenders from the central DÖE source are ingested. Below-threshold tenders from individual contracting authorities are not yet included — a short result list is therefore not a defect.",
"denylistLabel": "Manual watch:",
"denylistText": "These portals do not permit automated access under their terms of use and must therefore be checked manually:"
},
"settings": {
"title": "Tender Radar — Settings",
"rssSectionTitle": "RSS Feeds",
"rssSectionBody": "Public, platform-wide RSS sources (e.g. service.bund.de or a subreport-elvis municipal feed) — applies equally to all tenants, not configurable per tenant.",
"emailSectionTitle": "Email Alerts",
"emailSectionBody": "Mailbox that tender portals send their notification emails to — configurable per tenant, separate from the DKV invoice mailbox. Tenders detected from these emails are only visible to your tenant.",
"notificationsSectionTitle": "Notifications",
"digestIntervalLabel": "Digest Interval",
"digestDaily": "Daily",
"digestWeekly": "Weekly",
"digestOff": "Off",
"digestHelp": "Summarizes new matches from your saved searches in a daily or weekly digest email. \"Off\" disables the digest — instant alerts per saved search remain usable independently.",
"saveSuccess": "Setting saved.",
"errorLoad": "Could not load notification setting",
"errorSave": "Could not save notification setting"
},
"sourceConfig": {
"errorLoad": "Could not load configuration",
"errorSave": "Could not save settings",
"validationError": "Interval must be between {min} and {max} minutes.",
"sourceLabel": "Source",
"lastIngestedLabel": "Last Ingested Day",
"neverIngested": "Not yet ingested",
"pollIntervalLabel": "Poll Interval (Minutes) *",
"minutesSuffix": "min.",
"pollIntervalHelp": "Cron tick frequency ({min}–{max} min.) — the actual DÖE poll is additionally throttled by the day cursor.",
"activeLabel": "Active",
"saving": "Saving...",
"save": "Save",
"saveSuccess": "Settings saved."
},
"rssFeeds": {
"errorLoad": "Could not load RSS feeds",
"errorAdd": "Could not save the RSS feed",
"errorRemove": "Could not remove the RSS feed",
"validationRequired": "URL and label are required.",
"empty": "No RSS feeds configured yet.",
"activeLabel": "active",
"inactiveLabel": "inactive",
"removeAria": "Remove RSS feed \"{label}\"",
"removing": "Removing...",
"remove": "Remove",
"urlLabel": "Feed URL *",
"urlPlaceholder": "https://www.service.bund.de/.../RSSGenerator_Ausschreibungen.xml",
"labelLabel": "Label *",
"labelPlaceholder": "e.g. service-bund",
"adding": "Adding...",
"add": "Add Feed"
},
"emailAlerts": {
"notSaved": "Not yet saved — fill in and save the mailbox configuration.",
"protocolLabel": "Protocol *",
"protocolImap": "IMAP",
"protocolExchange": "Exchange",
"hostLabelExchange": "EWS Endpoint URL",
"hostLabelImap": "IMAP Server",
"hostPlaceholderExchange": "https://mail.company.com/EWS/Exchange.asmx",
"hostPlaceholderImap": "imap.company.com",
"portLabel": "Port *",
"encryptionLabel": "Encryption *",
"encryptionNone": "None",
"encryptionStarttls": "STARTTLS",
"encryptionSslTls": "SSL-TLS",
"folderLabel": "Folder",
"folderPlaceholderExchange": "Inbox",
"folderPlaceholderImap": "INBOX",
"domainLabel": "Windows Domain",
"domainPlaceholder": "CONTOSO",
"senderFilterLabel": "Sender Filter",
"senderFilterPlaceholder": "alerts@tenderportal.com",
"usernameLabel": "Username",
"passwordLabel": "Password",
"passwordPlaceholder": "••••••••",
"showPassword": "Show password",
"hidePassword": "Hide password",
"activeLabel": "Active",
"saving": "Saving...",
"save": "Save",
"saveSuccess": "Settings saved.",
"errorSave": "Could not save settings"
}
}
}