Repository navigation
fix(i18n): es-ES names the quote object Cotización everywhere - #1754
Merged
Merged
Conversation
The es-ES pack called one object two names at once: its declared label was Cotización while eight strings called it Presupuesto — the generate-quote action and its success message, the quote_accepted win reason, the whole crm_quote_line_item object (label, pluralLabel, description and its lookup back to the quote), and the crm_contact help sentence. The help sentence also inflected the two status names to agree with the masculine el presupuesto, so it told users to look for Presentado/Aceptado while the picklist renders Presentada/Aceptada. The options were correct — they agree with the feminine Cotización — so they are unchanged; the sentence now names the right noun. Presupuesto is also ordinary Spanish for "budget". Every occurrence was graded by referent rather than swept: the five budget-sense uses (Presupuesto y ROI, Costo Presupuestado, the campaign cost validation message, and Sin Presupuesto as a disqualification and a loss reason) are deliberately untouched. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019YKN9TPqDSSXUaYqp2j7MZ
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
os-bill
marked this pull request as ready for review
September 8, 2026 00:25
This was referenced Sep 8, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of #1530
Deliberately a partial reference, not a closing one — this PR lands the content half of
the ruling only. The ruling's
required closing item, extending the #802 term guard to
es-ES, is not in this PR:it is not mechanical, and the dispatch instructed me to stop and report rather than
redesign a
test/**guard that belongs to another epic. Details and evidence below,so the card stays open for that half.
Ruling executed
Director seat, decision batch #74 (2026-09-07), maintainer reply verbatim 「同意」:
crm_quoteisCotizaciónines-ES— one term per object, the UI follows the pack,same direction as #837.
The pack named one object two ways at once. Its declared label was
Cotización, buteight strings called it
Presupuesto. A Spanish user reading "Línea de Presupuesto" andthen looking for Presupuesto in the navigation found Cotizaciones, with nothing in the
product saying these were the same record.
The
crm_contacthelp sentence carried the visible symptom the card was filed on: becauseit named the masculine
el presupuesto, it inflected the statuses to match and told usersto look for Presentado / Aceptado, while the picklist renders Presentada / Aceptada.
The options were right all along — they agree with the feminine
Cotización— so they areuntouched; the sentence now names the correct noun.
The 8 changed sites (all quote-sense)
objects.commerce.ts…en cuanto el presupuesto pasa a Presentado o Aceptado……en cuanto la cotización pasa a Presentada o Aceptada…objects.commerce.tslabel: 'Línea de Presupuesto'label: 'Línea de Cotización'objects.commerce.tspluralLabel: 'Líneas de Presupuesto'pluralLabel: 'Líneas de Cotización'objects.commerce.tsdescription: '…dentro de un presupuesto'description: '…dentro de una cotización'objects.commerce.tscrm_quote: { label: 'Presupuesto' }crm_quote: { label: 'Cotización' }objects.pipeline.tsquote_accepted: 'Presupuesto Aceptado'quote_accepted: 'Cotización Aceptada'objects.pipeline.tslabel: 'Generar Presupuesto'label: 'Generar Cotización'objects.pipeline.tssuccessMessage: '¡Presupuesto creado…'successMessage: '¡Cotización creada…'Each replacement was applied against an exact anchor asserted to match exactly once,
never by find-and-replace. Diff is 8 changed lines,
8 insertions(+), 8 deletions(-).Census finding — the keep count is 5, not 3
The ruling gave 8 change + 3 keep. My own enumeration of every
presupuest*occurrenceunder
src/translations/es-ES/**returns 13, graded by referent:Change — 8, quote-sense. Exactly the ruling's eight; every coordinate confirmed by text.
Keep — 5, budget-sense (the ruling named three of them):
objects.marketing.tsPresupuesto y ROIbudgetobjects.marketing.tsCosto Presupuestadobudgeted_costobjects.marketing.tsEl coste real supera el coste presupuestadoactual_cost_within_budgetobjects.pipeline.tsSin Presupuestono_budget(disqualification reason)objects.pipeline.tsSin Presupuestono_budget(loss reason)The two extra keeps are
presupuestado/Presupuestado— the participle "budgeted". Anexact-word grep for
Presupuestodoes not see them, which is why the ruling counted three.No change site was missed: the discrepancy is entirely on the keep side, and both extras
are budget-sense. Post-change census: 5
presupuest*remain, all five budget-sense.This matters beyond bookkeeping — see the guard section: a stem- or substring-grained guard
must spare
presupuestadotoo, not justPresupuesto.The required closing item is NOT here, and why
The ruling asks to extend
test/docs-object-term-consistency.test.tstoes-ES, "using theguard's
SPAREDlist to keep the budget sense ofpresupuesto". I read the guard beforejudging, as instructed. That shape cannot be built without changing the guard's
assertions, for four independent reasons — the last one is substantive, not cosmetic:
TERMSis keyed by object name andcrm_quoteis already taken by the Chinese term.A Spanish row for the same object needs a locale dimension in the key.
Pin.hantis mandatory and Chinese-specific (Traditional-script form). Spanish has noTraditional form, so the type itself must change.
Every rule hardcodes the Chinese surface —
packFor('zh-CN'),PACK_FILE,HANS_PAGES,HANT_PAGES,minPages. Measured:content/docsholds 67.zh-Hans.mdx, 67.zh-Hant.mdxand the English pages, and zero Spanish pages. The entire "the surviving terms are
actually there" family has no Spanish analogue to assert against.
The guard's criterion provably cannot discriminate the Spanish case. Its central pinned
rule is "no retired spelling is a substring of spared prose", and its reasoning is that a
status name is a complete word, so a ledger of complete words discriminates on its own —
in Chinese, retired
已呈现versus spared root到期are different words. In Spanish the twosenses are the identical complete word
Presupuesto. Retiring it and sparing the budgetsense makes that rule red by construction:
Word grain — the criterion [观察] 文档里的状态名/字段标签与语言包是否一致,无人检查——一周内同一缺陷类出现三次,全靠人眼撞见 #802 measured against three fix commits and deliberately adopted
over syntactic position — does not reach Spanish. A correct Spanish guard needs a
referent-aware criterion (judging by the metadata key:
no_budget,budget,budgeted_cost), which is precisely the position-based criterion that file measured andrejected for Chinese. Also
SPARED's own first rule checks each phrase against the zhpages, so any Spanish phrase added to it is red immediately.
That is a redesign of a
test/**guard, not an extension.test/**is epic #1579's declaredterritory and the ruling's override reaches only a mechanical closing item, so I stopped here
rather than reshaping it.
ja-JPlikewise not done (the ruling made it optional): it failson reasons 1-3 identically, and the guard already records why the Japanese pack sits outside
the scan surface —
案件is an ordinary Japanese word used incrm_opportunity's description.Out-of-scope finding, filed not fixed: the guard's pack rule is vacuous
While reading the guard I found a live defect and proved it.
PACK_FILEis'src/translations/zh-CN.ts', which since the #1311 locale split is a 77-line barrel of 8imports holding no pack strings at all — 0 occurrences of
工单, 0 of报价单, against 56 and12 in the split files it re-exports. So the rule the guard's own docblock calls out — "the pack
IS the product UI, so a label, an option or a
helpsentence left behind puts the old word backon screen" — scans a file that can never contain a label.
Ablation, on this branch: I re-injected the #1529 defect verbatim into the live pack —
src/translations/zh-CN/objects.commerce.ts,crm_quote.crm_contact.help,已提交back to theretired
已呈现— proved the mutation on disk (已呈现0 to 1) and by content hash, and ran theguard:
Green. The guard built to catch exactly that defect no longer catches it. Restored under a
trap and verified byte-identical to
HEAD(5e4e25b4…); the tree carries only the three filesof this PR. Filed as its own card, not fixed here — different defect class, and that file is the
epic's ground.
Gates
pnpm verifyfully green, exit 0, on the final commit:Changeset written rather than labelled: a language pack is product surface, and these strings
are what a Spanish user reads on screen.
Generated by Claude Code