mirror of
https://github.com/arsvendg/Stirling-PDF.git
synced 2026-07-16 03:20:46 +02:00
fix(i18n): wrap hard-coded English strings in t() across UI (#6566)
## Summary
Audit + bulk fix of hard-coded English UI strings - `aria-label`,
`title`, `placeholder`, `label`, and raw JSX literals that bypassed i18n
entirely. Each literal now goes through `t("key", "English Default")`
from `react-i18next`, and every new key has a corresponding entry in
`en-GB/translation.toml` so translators can pick it up.
## What this fixes
Strings were rendered untranslated in every non-EN locale because they
never went through `t()` at all (not just "value not translated yet").
Affects screen-reader labels, tooltips, form placeholders, empty/loading
states, plan card content, and the entire workflow ParticipantView.
## Coverage (~143 keys / 50 files)
- **Viewer chrome** - search bar (close, clear, prev/next, "of N"
results), link/signature/redaction actions, viewer error state, zoom
labels
- **Page editor** - undo/redo/rotate/delete toolbar tooltips, empty
state, bulk selection operator chip tooltips
- **Shared primitives** - Tooltip close, InfoBanner dismiss, TextInput
clear, Toast dismiss/toggle, UpdateModal close, EditableSecretField
edit, DropdownListWithFooter search, FileCard/FileDropdownMenu actions,
EmptyFilesState + AddFileCard upload
- **Tools** - Image upload + hint, ColorControl eyedropper, sign Use
Signature, CompressSettings, OCR loading, PageLayout
margin/border/row/col placeholders, FormFill switch + save + re-scan
- **Proprietary admin** - OverviewHeader signed-in line + logout,
AdminPremiumSection moved-features list (via `<Trans>`),
AdminPlanSection no-data alert, AdminAdvancedSection temp-dir
placeholders, AdminEndpointsSection multiselect placeholders,
AdminMailSection + AdminDatabaseSection password placeholders
- **Onboarding** - MFASetupSlide QR loading + auth code label,
SecurityCheckSlide role select + options
- **ParticipantView** - entire sign-document UI (~30 strings: loading,
error, badges, headings, cert-type Select, all input labels and
placeholders, action buttons, completion + expired alerts) - file
previously imported `useTranslation` but only used `t()` for cert
validation
- **planConstants.ts refactor** - replaced `PLAN_FEATURES` /
`PLAN_HIGHLIGHTS` const exports with `usePlanFeatures()` /
`usePlanHighlights()` hooks. Service layer (`licenseService.getPlans`)
updated to accept feature/highlight maps so it stays hook-free. Callers
(`usePlans`, `CheckoutContext`) resolve the hooks at the React boundary
- **Previously catalogued offenders** - `FileSidebarFileItem`
open/close-viewer aria-labels, `quickAccessBar/ActiveToolButton` "Back
to all tools" tooltip + aria, `AppConfigModal` close button
## Notes
- One small refactor in `usePageSelectionTips.ts` was needed to resolve
a TOML key-shape conflict: the existing scalar keys
`bulkSelection.operators.{and,not,comma}` needed to become tables to
hold the new `.title` subkeys for OperatorsSection's chip tooltips. The
existing descriptions moved to `[bulkSelection.operators.descriptions]`
and the three i18n key paths in usePageSelectionTips were updated to
match.
- Viewer sidebar close buttons
(Bookmark/Layer/Thumbnail/Attachment/Comments) were on the audit list
but are NOT on main - they're added by the unmerged PR #6552
(feat/viewer-sidebar-ux). Those particular strings will need wrapping
when that PR lands.
- TOML hook (`toml-sort-fix`) ran and re-sorted the translation file.
## Test plan
- [ ] `task frontend:typecheck` passes (core + proprietary + desktop
variants)
- [ ] `task frontend:lint` passes
- [ ] Switching language to Deutsch / Русский: previously-English
`aria-label`s + tooltips + placeholders + plan card bullets now render
translated (when the locale has values) or fall back to the English
default (when it doesn't)
- [ ] Plan page bullet points in EN render unchanged
- [ ] Sign-document flow (ParticipantView) renders unchanged in EN
This commit is contained in:
@@ -34,7 +34,7 @@ interface FormFieldSidebarProps {
|
||||
}
|
||||
|
||||
export function FormFieldSidebar({ visible, onToggle }: FormFieldSidebarProps) {
|
||||
useTranslation();
|
||||
const { t } = useTranslation();
|
||||
const { state, setValue, setActiveField } = useFormFill();
|
||||
const { fields, activeFieldName, loading } = state;
|
||||
const activeFieldRef = useRef<HTMLDivElement>(null);
|
||||
@@ -119,7 +119,7 @@ export function FormFieldSidebar({ visible, onToggle }: FormFieldSidebarProps) {
|
||||
variant="subtle"
|
||||
size="sm"
|
||||
onClick={onToggle}
|
||||
aria-label="Close sidebar"
|
||||
aria-label={t("formFill.sidebar.close", "Close sidebar")}
|
||||
>
|
||||
<CloseIcon sx={{ fontSize: 16 }} />
|
||||
</ActionIcon>
|
||||
|
||||
@@ -27,6 +27,7 @@ import {
|
||||
Tooltip,
|
||||
ActionIcon,
|
||||
} from "@mantine/core";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import {
|
||||
useFormFill,
|
||||
useAllFormValues,
|
||||
@@ -120,6 +121,7 @@ const _MODE_TABS: ModeTabDef[] = [
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
const FormFill = (_props: BaseToolProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { selectedTool } = useNavigation();
|
||||
const { selectors, state: fileState } = useFileState();
|
||||
|
||||
@@ -488,7 +490,10 @@ const FormFill = (_props: BaseToolProps) => {
|
||||
|
||||
{/* Flatten toggle */}
|
||||
<Switch
|
||||
label="Flatten after filling"
|
||||
label={t(
|
||||
"formFill.flattenAfterFilling",
|
||||
"Flatten after filling",
|
||||
)}
|
||||
checked={flatten}
|
||||
onChange={(e) => setFlatten(e.currentTarget.checked)}
|
||||
size="xs"
|
||||
@@ -507,15 +512,22 @@ const FormFill = (_props: BaseToolProps) => {
|
||||
loading={saving}
|
||||
disabled={!formState.isDirty && !flattenChanged}
|
||||
>
|
||||
Save
|
||||
{t("formFill.save", "Save")}
|
||||
</Button>
|
||||
|
||||
<Tooltip label="Re-scan fields" withArrow position="bottom">
|
||||
<Tooltip
|
||||
label={t("formFill.rescanFields", "Re-scan fields")}
|
||||
withArrow
|
||||
position="bottom"
|
||||
>
|
||||
<ActionIcon
|
||||
variant="light"
|
||||
size="md"
|
||||
onClick={handleRefresh}
|
||||
aria-label="Re-scan form fields"
|
||||
aria-label={t(
|
||||
"formFill.rescanFormFields",
|
||||
"Re-scan form fields",
|
||||
)}
|
||||
>
|
||||
<RefreshIcon sx={{ fontSize: 16 }} />
|
||||
</ActionIcon>
|
||||
|
||||
Reference in New Issue
Block a user