Summary
16 aria-label values across 10 components are hardcoded English string literals instead of resolving through useLocalizedStrings / contributions/localizedStrings.json. Screen-reader users in any non-English locale get English labels for these controls.
The gap is inconsistent within single files, which is what makes it easy to miss. SegmentListView.tsx:72 correctly localizes the merge button's label, while SegmentListView.tsx:382 hardcodes "Scroll to active verse" a few hundred lines later.
Inventory
Literal labels
| File |
Line |
Current value |
src/components/PhraseBox.tsx |
53 |
Phrase gloss |
src/components/PhraseBox.tsx |
354 |
Edit phrase |
src/components/PhraseBox.tsx |
366 |
Unlink phrase |
src/components/SegmentFreeTranslationInput.tsx |
52 |
Free translation |
src/components/TokenLinkIcon.tsx |
252 |
Unlink tokens |
src/components/TokenLinkIcon.tsx |
322 |
Link tokens |
src/components/ArcOverlay.tsx |
327 |
Split phrase here |
src/components/SegmentListView.tsx |
382 |
Scroll to active verse |
src/components/ContinuousView.tsx |
971 |
Previous token |
src/components/ContinuousView.tsx |
1056 |
Next token |
src/components/controls/ViewOptionsDropdown.tsx |
178 |
View options |
src/components/controls/ViewOptionsDropdown.tsx |
205 |
View options |
Interpolated labels
These need the {placeholder} pattern already established by %interlinearizer_morphemeGloss_label% ("Gloss for morpheme {form}").
| File |
Line |
Current value |
src/components/TokenChip.tsx |
358 |
`Remove ${token.surfaceText} from phrase` |
src/components/TokenChip.tsx |
454 |
`Gloss for ${token.surfaceText}` |
src/components/TokenChip.tsx |
497 |
`Show suggestions for ${token.surfaceText}` |
src/components/PhraseBox.tsx |
554 |
`Remove ${token.surfaceText} from phrase` |
Decisions needed before implementing
- Reconcile near-duplicates.
contributions/localizedStrings.json already defines %interlinearizer_boundaryControl_split% as "Split segment here", but ArcOverlay.tsx:327 hardcodes "Split phrase here". Are these one string or two? (Segment vs. phrase is a real domain distinction here, so this needs a decision rather than a merge.)
- Deduplicate
Remove {token} from phrase, which appears identically in both TokenChip.tsx:358 and PhraseBox.tsx:554 — one key, two call sites.
View options appears twice in the same file (ViewOptionsDropdown.tsx:178 and :205) — confirm both are the same control surface and share one key.
Test impact
Several tests query these controls via getByLabelText / aria-label. Localizing the labels means those queries resolve through the useLocalizedStrings stub in __mocks__/papi-frontend-react.ts, which will need to return the resolved English values for the new keys so existing assertions keep passing. Expect churn in the component test files, not just the components.
Notes
Found while investigating unrelated button-sizing regressions from the Tier 1 platform-bible-react migration (#165). No functional/visual bug — purely i18n/a11y coverage.
Summary
16
aria-labelvalues across 10 components are hardcoded English string literals instead of resolving throughuseLocalizedStrings/contributions/localizedStrings.json. Screen-reader users in any non-English locale get English labels for these controls.The gap is inconsistent within single files, which is what makes it easy to miss.
SegmentListView.tsx:72correctly localizes the merge button's label, whileSegmentListView.tsx:382hardcodes"Scroll to active verse"a few hundred lines later.Inventory
Literal labels
src/components/PhraseBox.tsxPhrase glosssrc/components/PhraseBox.tsxEdit phrasesrc/components/PhraseBox.tsxUnlink phrasesrc/components/SegmentFreeTranslationInput.tsxFree translationsrc/components/TokenLinkIcon.tsxUnlink tokenssrc/components/TokenLinkIcon.tsxLink tokenssrc/components/ArcOverlay.tsxSplit phrase heresrc/components/SegmentListView.tsxScroll to active versesrc/components/ContinuousView.tsxPrevious tokensrc/components/ContinuousView.tsxNext tokensrc/components/controls/ViewOptionsDropdown.tsxView optionssrc/components/controls/ViewOptionsDropdown.tsxView optionsInterpolated labels
These need the
{placeholder}pattern already established by%interlinearizer_morphemeGloss_label%("Gloss for morpheme {form}").src/components/TokenChip.tsx`Remove ${token.surfaceText} from phrase`src/components/TokenChip.tsx`Gloss for ${token.surfaceText}`src/components/TokenChip.tsx`Show suggestions for ${token.surfaceText}`src/components/PhraseBox.tsx`Remove ${token.surfaceText} from phrase`Decisions needed before implementing
contributions/localizedStrings.jsonalready defines%interlinearizer_boundaryControl_split%as"Split segment here", butArcOverlay.tsx:327hardcodes"Split phrase here". Are these one string or two? (Segment vs. phrase is a real domain distinction here, so this needs a decision rather than a merge.)Remove {token} from phrase, which appears identically in bothTokenChip.tsx:358andPhraseBox.tsx:554— one key, two call sites.View optionsappears twice in the same file (ViewOptionsDropdown.tsx:178and:205) — confirm both are the same control surface and share one key.Test impact
Several tests query these controls via
getByLabelText/aria-label. Localizing the labels means those queries resolve through theuseLocalizedStringsstub in__mocks__/papi-frontend-react.ts, which will need to return the resolved English values for the new keys so existing assertions keep passing. Expect churn in the component test files, not just the components.Notes
Found while investigating unrelated button-sizing regressions from the Tier 1
platform-bible-reactmigration (#165). No functional/visual bug — purely i18n/a11y coverage.