mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2026-09-02 21:03:34 +03:00
Add the missing en-US translations for classification labels (#7692)
Our classification labels were rendering their hardcoded English names because the en-US locale file had no `classification` section at all, so this adds the missing keys (labels and category names). Also wires the category names through i18n, since those had no `t()` call, and adds a test so a new label can't ship without its key.
This commit is contained in:
@@ -3001,6 +3001,293 @@ summary_one = "Ran 1 tool"
|
||||
summary_other = "Ran {{count}} tools"
|
||||
unknownTool = "Unknown tool"
|
||||
|
||||
[classification.families]
|
||||
correspondence = "Correspondence"
|
||||
education = "Education"
|
||||
engineering = "Engineering"
|
||||
finance = "Financial"
|
||||
forms = "Forms"
|
||||
government = "Government"
|
||||
health = "Medical"
|
||||
hr = "HR"
|
||||
legal = "Legal"
|
||||
operations = "Operations"
|
||||
projects = "Projects"
|
||||
property = "Property"
|
||||
reports = "Reports"
|
||||
sales = "Marketing"
|
||||
travel = "Travel"
|
||||
|
||||
[classification.labels]
|
||||
academic-record = "Academic record"
|
||||
action-plan = "Action plan"
|
||||
addendum = "Addendum"
|
||||
advertisement = "Advertisement"
|
||||
affidavit = "Affidavit"
|
||||
agenda = "Agenda"
|
||||
amendment = "Amendment"
|
||||
analytics-report = "Analytics report"
|
||||
announcement = "Announcement"
|
||||
annual-report = "Annual report"
|
||||
api-documentation = "API documentation"
|
||||
application-form = "Application form"
|
||||
appraisal-report = "Appraisal report"
|
||||
architecture-document = "Architecture document"
|
||||
articles-of-incorporation = "Articles of incorporation"
|
||||
assignment-brief = "Assignment brief"
|
||||
audit-report = "Audit report"
|
||||
balance-sheet = "Balance sheet"
|
||||
bank-statement = "Bank statement"
|
||||
benefits-summary = "Benefits summary"
|
||||
bill-of-lading = "Bill of lading"
|
||||
bill-of-materials = "Bill of materials"
|
||||
blueprint = "Blueprint"
|
||||
board-report = "Board report"
|
||||
board-resolution = "Board resolution"
|
||||
booking-confirmation = "Booking confirmation"
|
||||
brochure = "Brochure"
|
||||
budget = "Budget"
|
||||
business-plan = "Business plan"
|
||||
business-proposal = "Business proposal"
|
||||
bylaws = "Bylaws"
|
||||
campaign-brief = "Campaign brief"
|
||||
case-study = "Case study"
|
||||
cash-flow-statement = "Cash flow statement"
|
||||
catalog = "Catalog"
|
||||
cease-and-desist = "Cease and desist"
|
||||
certificate = "Certificate"
|
||||
certificate-of-completion = "Certificate of completion"
|
||||
change-log = "Change log"
|
||||
checklist = "Checklist"
|
||||
claim-form = "Claim form"
|
||||
closing-statement = "Closing statement"
|
||||
complaint-letter = "Complaint letter"
|
||||
compliance-document = "Compliance document"
|
||||
confirmation-letter = "Confirmation letter"
|
||||
consent-form = "Consent form"
|
||||
contract = "Contract"
|
||||
course-syllabus = "Course syllabus"
|
||||
court-filing = "Court filing"
|
||||
cover-letter = "Cover letter"
|
||||
credit-note = "Credit note"
|
||||
customs-declaration = "Customs declaration"
|
||||
customs-form = "Customs form"
|
||||
cv = "CV"
|
||||
datasheet = "Datasheet"
|
||||
debit-note = "Debit note"
|
||||
deed = "Deed"
|
||||
delivery-note = "Delivery note"
|
||||
demand-letter = "Demand letter"
|
||||
design-document = "Design document"
|
||||
diploma = "Diploma"
|
||||
discharge-summary = "Discharge summary"
|
||||
dissertation = "Dissertation"
|
||||
donation-receipt = "Donation receipt"
|
||||
dunning-letter = "Dunning letter"
|
||||
email-thread = "Email thread"
|
||||
employee-handbook = "Employee handbook"
|
||||
employment-contract = "Employment contract"
|
||||
estimate = "Estimate"
|
||||
event-agenda = "Event agenda"
|
||||
event-program = "Event program"
|
||||
eviction-notice = "Eviction notice"
|
||||
exam-paper = "Exam paper"
|
||||
expense-report = "Expense report"
|
||||
expense-summary = "Expense summary"
|
||||
explanation-of-benefits = "Explanation of benefits"
|
||||
fact-sheet = "Fact sheet"
|
||||
faq-document = "FAQ document"
|
||||
feasibility-study = "Feasibility study"
|
||||
feedback-form = "Feedback form"
|
||||
financial-forecast = "Financial forecast"
|
||||
financial-statement = "Financial statement"
|
||||
floor-plan = "Floor plan"
|
||||
flyer = "Flyer"
|
||||
form = "Form"
|
||||
franchise-agreement = "Franchise agreement"
|
||||
freight-document = "Freight document"
|
||||
gift-certificate = "Gift certificate"
|
||||
glossary = "Glossary"
|
||||
government-notice = "Government notice"
|
||||
grade-report = "Grade report"
|
||||
grant-agreement = "Grant agreement"
|
||||
grant-application = "Grant application"
|
||||
hoa-document = "HOA document"
|
||||
home-inspection-report = "Home inspection report"
|
||||
hr-memo = "HR memo"
|
||||
hr-policy = "HR policy"
|
||||
immigration-document = "Immigration document"
|
||||
immunization-record = "Immunization record"
|
||||
incident-report = "Incident report"
|
||||
income-statement = "Income statement"
|
||||
index = "Index"
|
||||
inspection-report = "Inspection report"
|
||||
insurance-certificate = "Insurance certificate"
|
||||
insurance-claim = "Insurance claim"
|
||||
insurance-policy = "Insurance policy"
|
||||
intake-form = "Intake form"
|
||||
inventory-list = "Inventory list"
|
||||
investment-summary = "Investment summary"
|
||||
invitation = "Invitation"
|
||||
invoice = "Invoice"
|
||||
itinerary = "Itinerary"
|
||||
job-application = "Job application"
|
||||
job-description = "Job description"
|
||||
lab-report = "Lab report"
|
||||
lease-agreement = "Lease agreement"
|
||||
leave-request = "Leave request"
|
||||
legal-brief = "Legal brief"
|
||||
legal-filing = "Legal filing"
|
||||
legal-notice = "Legal notice"
|
||||
legal-opinion = "Legal opinion"
|
||||
lesson-plan = "Lesson plan"
|
||||
letter = "Letter"
|
||||
letter-of-intent = "Letter of intent"
|
||||
license = "License"
|
||||
license-agreement = "License agreement"
|
||||
loan-agreement = "Loan agreement"
|
||||
loan-document = "Loan document"
|
||||
maintenance-log = "Maintenance log"
|
||||
manual = "Manual"
|
||||
market-research = "Market research"
|
||||
marketing-plan = "Marketing plan"
|
||||
media-kit = "Media kit"
|
||||
medical-invoice = "Medical invoice"
|
||||
medical-report = "Medical report"
|
||||
meeting-agenda = "Meeting agenda"
|
||||
meeting-minutes = "Meeting minutes"
|
||||
meeting-notes = "Meeting notes"
|
||||
membership-document = "Membership document"
|
||||
memo = "Memo"
|
||||
memorandum-of-understanding = "Memorandum of understanding"
|
||||
mortgage-document = "Mortgage document"
|
||||
nda = "NDA"
|
||||
newsletter = "Newsletter"
|
||||
non-compete-agreement = "Non-compete agreement"
|
||||
notice = "Notice"
|
||||
offer-letter = "Offer letter"
|
||||
onboarding-document = "Onboarding document"
|
||||
order-confirmation = "Order confirmation"
|
||||
order-form = "Order form"
|
||||
organization-chart = "Organization chart"
|
||||
packing-slip = "Packing slip"
|
||||
partnership-agreement = "Partnership agreement"
|
||||
patent = "Patent"
|
||||
pathology-report = "Pathology report"
|
||||
payment-reminder = "Payment reminder"
|
||||
payroll-document = "Payroll document"
|
||||
payslip = "Payslip"
|
||||
performance-review = "Performance review"
|
||||
permit = "Permit"
|
||||
petition = "Petition"
|
||||
pitch-deck = "Pitch deck"
|
||||
power-of-attorney = "Power of attorney"
|
||||
prescription = "Prescription"
|
||||
presentation = "Presentation"
|
||||
press-release = "Press release"
|
||||
price-list = "Price list"
|
||||
pricing-sheet = "Pricing sheet"
|
||||
privacy-policy = "Privacy policy"
|
||||
product-sheet = "Product sheet"
|
||||
proforma-invoice = "Proforma invoice"
|
||||
progress-report = "Progress report"
|
||||
project-charter = "Project charter"
|
||||
project-plan = "Project plan"
|
||||
promotional-material = "Promotional material"
|
||||
property-listing = "Property listing"
|
||||
proposal = "Proposal"
|
||||
public-notice = "Public notice"
|
||||
purchase-agreement = "Purchase agreement"
|
||||
purchase-order = "Purchase order"
|
||||
quality-report = "Quality report"
|
||||
quarterly-report = "Quarterly report"
|
||||
questionnaire = "Questionnaire"
|
||||
quick-start-guide = "Quick start guide"
|
||||
quote = "Quote"
|
||||
radiology-report = "Radiology report"
|
||||
receipt = "Receipt"
|
||||
recommendation-letter = "Recommendation letter"
|
||||
reference-letter = "Reference letter"
|
||||
referral-letter = "Referral letter"
|
||||
registration-confirmation = "Registration confirmation"
|
||||
registration-form = "Registration form"
|
||||
regulatory-filing = "Regulatory filing"
|
||||
release-notes = "Release notes"
|
||||
remittance-advice = "Remittance advice"
|
||||
rental-agreement = "Rental agreement"
|
||||
report = "Report"
|
||||
request-for-proposal = "Request for proposal"
|
||||
request-for-quotation = "Request for quotation"
|
||||
requirements-document = "Requirements document"
|
||||
research-abstract = "Research abstract"
|
||||
research-paper = "Research paper"
|
||||
reservation = "Reservation"
|
||||
resignation-letter = "Resignation letter"
|
||||
resume = "Resume"
|
||||
retrospective = "Retrospective"
|
||||
return-authorization = "Return authorization"
|
||||
risk-assessment = "Risk assessment"
|
||||
roadmap = "Roadmap"
|
||||
safety-data-sheet = "Safety data sheet"
|
||||
safety-procedure = "Safety procedure"
|
||||
sales-proposal = "Sales proposal"
|
||||
sales-report = "Sales report"
|
||||
schematic = "Schematic"
|
||||
scope-of-work = "Scope of work"
|
||||
service-agreement = "Service agreement"
|
||||
service-report = "Service report"
|
||||
settlement-agreement = "Settlement agreement"
|
||||
shareholder-agreement = "Shareholder agreement"
|
||||
shipping-confirmation = "Shipping confirmation"
|
||||
specification = "Specification"
|
||||
sponsorship-agreement = "Sponsorship agreement"
|
||||
standard-operating-procedure = "Standard operating procedure"
|
||||
statement-of-account = "Statement of account"
|
||||
statement-of-work = "Statement of work"
|
||||
status-report = "Status report"
|
||||
stock-report = "Stock report"
|
||||
study-guide = "Study guide"
|
||||
subpoena = "Subpoena"
|
||||
subscription-confirmation = "Subscription confirmation"
|
||||
supply-order = "Supply order"
|
||||
survey-form = "Survey form"
|
||||
survey-results = "Survey results"
|
||||
sustainability-report = "Sustainability report"
|
||||
table-of-contents = "Table of contents"
|
||||
tax-form = "Tax form"
|
||||
tax-return = "Tax return"
|
||||
tax-statement = "Tax statement"
|
||||
technical-drawing = "Technical drawing"
|
||||
technical-specification = "Technical specification"
|
||||
tenancy-agreement = "Tenancy agreement"
|
||||
tender-document = "Tender document"
|
||||
termination-letter = "Termination letter"
|
||||
terms-and-conditions = "Terms and conditions"
|
||||
terms-of-service = "Terms of service"
|
||||
test-plan = "Test plan"
|
||||
test-report = "Test report"
|
||||
thesis = "Thesis"
|
||||
ticket = "Ticket"
|
||||
timeline = "Timeline"
|
||||
timesheet = "Timesheet"
|
||||
title-document = "Title document"
|
||||
training-material = "Training material"
|
||||
transcript = "Transcript"
|
||||
travel-itinerary = "Travel itinerary"
|
||||
trust-document = "Trust document"
|
||||
user-guide = "User guide"
|
||||
utility-bill = "Utility bill"
|
||||
vendor-agreement = "Vendor agreement"
|
||||
visa-document = "Visa document"
|
||||
waiver = "Waiver"
|
||||
warehouse-receipt = "Warehouse receipt"
|
||||
warranty-document = "Warranty document"
|
||||
waybill = "Waybill"
|
||||
white-paper = "White paper"
|
||||
will = "Will"
|
||||
work-instruction = "Work instruction"
|
||||
work-order = "Work order"
|
||||
|
||||
[cloudBadge]
|
||||
tooltip = "This operation will use your cloud credits"
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ export function ClassificationLabelsSection() {
|
||||
)}
|
||||
<LocalIcon icon={family.icon} width="1.1rem" />
|
||||
<span className="classification-category-name">
|
||||
{family.name}
|
||||
{t(`classification.families.${family.id}`, family.name)}
|
||||
</span>
|
||||
</span>
|
||||
}
|
||||
|
||||
+3
-1
@@ -40,7 +40,9 @@ export function ClassificationCategoryManager({
|
||||
<span className="category-visibility-icon">
|
||||
<LocalIcon icon={category.icon} width="1.1rem" />
|
||||
</span>
|
||||
<span className="category-visibility-name">{category.name}</span>
|
||||
<span className="category-visibility-name">
|
||||
{t(`classification.families.${category.id}`, category.name)}
|
||||
</span>
|
||||
{count !== undefined && (
|
||||
<span className="category-visibility-count">{count}</span>
|
||||
)}
|
||||
|
||||
@@ -56,7 +56,7 @@ export function buildLabelGroups(
|
||||
if (members.length === 0) continue;
|
||||
visible.push({
|
||||
id: `category:${category.id}`,
|
||||
label: category.name,
|
||||
label: t(`classification.families.${category.id}`, category.name),
|
||||
icon: category.icon,
|
||||
stubs: members,
|
||||
defaultExpanded: false,
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { parse } from "smol-toml";
|
||||
import {
|
||||
DEFAULT_CLASSIFICATION_LABELS,
|
||||
LABEL_FAMILIES,
|
||||
} from "@app/data/classificationLabels";
|
||||
|
||||
// Label and family names are rendered through `classification.labels.<id>` /
|
||||
// `classification.families.<id>`, with the built-in English name as the fallback.
|
||||
// A fallback renders fine but is never translated (and logs a missingKey), so a
|
||||
// label added to classificationLabels.json without its en-US key silently ships
|
||||
// English to every locale. This guards that the en-US vocabulary stays complete.
|
||||
|
||||
const EN_US_TRANSLATIONS = path.join(
|
||||
__dirname,
|
||||
"../../../public/locales/en-US/translation.toml",
|
||||
);
|
||||
|
||||
function readSection(section: string): Record<string, unknown> {
|
||||
const parsed = parse(fs.readFileSync(EN_US_TRANSLATIONS, "utf8")) as {
|
||||
classification?: Record<string, Record<string, unknown>>;
|
||||
};
|
||||
return parsed.classification?.[section] ?? {};
|
||||
}
|
||||
|
||||
describe("classification vocabulary (en-US coverage)", () => {
|
||||
const labels = readSection("labels");
|
||||
const families = readSection("families");
|
||||
|
||||
it("has an en-US key for every label id, matching its built-in name", () => {
|
||||
for (const label of DEFAULT_CLASSIFICATION_LABELS) {
|
||||
expect(
|
||||
labels[label.id],
|
||||
`en-US missing classification.labels.${label.id}`,
|
||||
).toBe(label.name);
|
||||
}
|
||||
});
|
||||
|
||||
it("has an en-US key for every family id, matching its built-in name", () => {
|
||||
for (const family of LABEL_FAMILIES) {
|
||||
expect(
|
||||
families[family.id],
|
||||
`en-US missing classification.families.${family.id}`,
|
||||
).toBe(family.name);
|
||||
}
|
||||
});
|
||||
|
||||
it("has no en-US keys for labels or families that no longer exist", () => {
|
||||
const labelIds = new Set(DEFAULT_CLASSIFICATION_LABELS.map((l) => l.id));
|
||||
const familyIds = new Set(LABEL_FAMILIES.map((f) => f.id));
|
||||
expect(Object.keys(labels).filter((id) => !labelIds.has(id))).toEqual([]);
|
||||
expect(Object.keys(families).filter((id) => !familyIds.has(id))).toEqual(
|
||||
[],
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user