[WIP] Add internationalization support for detail page related lists#969
[WIP] Add internationalization support for detail page related lists#969
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…onents - Add detail.* translation keys to en.ts and zh.ts locale files - Add useDetailTranslation() hook following existing grid/list patterns - Replace all hardcoded strings in DetailView with t() calls - Replace all hardcoded strings in RelatedList with t() calls - Add useSectionTranslation() for DetailSection copy tooltips - Improve empty value display: replace plain '-' with styled em-dash - Add 'detail' to BUILTIN_KEYS in useObjectLabel.ts - Add onNew/onViewAll props and buttons to RelatedList - Update tests to expect new empty value styling Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Add the detail section with translations for ar, de, es, fr, ja, ko, pt, and ru locale files, placed before the chart section to match the existing en/zh pattern. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…sts, update ROADMAP - Add detail.* keys to ar, de, es, fr, ja, ko, pt, ru locale files - Add 10 new RelatedList tests (title, counts, buttons) - Add 2 new DetailView i18n fallback tests - Update ROADMAP.md with P1.15 Detail Page i18n section Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
- Create useDetailTranslation.ts with shared DETAIL_DEFAULT_TRANSLATIONS and createSafeTranslationHook utility - DetailView, DetailSection, and RelatedList all use the shared hook - Remove duplicate translation constants and hook implementations - Export useDetailTranslation, DETAIL_DEFAULT_TRANSLATIONS, and createSafeTranslationHook from plugin-detail index Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds internationalization (i18n) to the plugin-detail surface (DetailView/DetailSection/RelatedList) using the same “safe translation hook with English fallback” pattern used elsewhere in ObjectUI, and wires a new detail namespace into the i18n package/locales.
Changes:
- Introduces
useDetailTranslation(with default English fallbacks) and applies it across DetailView/DetailSection/RelatedList. - Adds
detail.*strings to all locale bundles and registersdetailas a built-in i18n namespace. - Updates tests and ROADMAP to reflect the new i18n behavior and the empty-value placeholder change.
Reviewed changes
Copilot reviewed 20 out of 20 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/plugin-detail/src/useDetailTranslation.ts | Adds reusable safe translation hook + default English detail.* fallback strings. |
| packages/plugin-detail/src/index.tsx | Exports the new translation utilities from the detail plugin entrypoint. |
| packages/plugin-detail/src/DetailView.tsx | Replaces hardcoded UI strings with t('detail.*') translations. |
| packages/plugin-detail/src/DetailSection.tsx | Updates copy tooltip strings to i18n + changes empty/null display to styled em-dash. |
| packages/plugin-detail/src/RelatedList.tsx | Adds i18n for record counts/loading/empty states + adds optional New/View All header actions. |
| packages/plugin-detail/src/tests/RelatedList.test.tsx | Adds tests for RelatedList title/count/empty state and New/View All buttons. |
| packages/plugin-detail/src/tests/DetailView.test.tsx | Adds tests ensuring i18n fallback text renders without an I18nProvider. |
| packages/plugin-detail/src/tests/DetailSection.test.tsx | Updates assertions to match new empty value placeholder (—). |
| packages/i18n/src/useObjectLabel.ts | Registers detail as a built-in namespace key. |
| packages/i18n/src/locales/en.ts | Adds detail namespace English strings. |
| packages/i18n/src/locales/zh.ts | Adds detail namespace Chinese strings. |
| packages/i18n/src/locales/ar.ts | Adds detail namespace Arabic strings. |
| packages/i18n/src/locales/de.ts | Adds detail namespace German strings. |
| packages/i18n/src/locales/es.ts | Adds detail namespace Spanish strings. |
| packages/i18n/src/locales/fr.ts | Adds detail namespace French strings. |
| packages/i18n/src/locales/ja.ts | Adds detail namespace Japanese strings. |
| packages/i18n/src/locales/ko.ts | Adds detail namespace Korean strings. |
| packages/i18n/src/locales/pt.ts | Adds detail namespace Portuguese strings. |
| packages/i18n/src/locales/ru.ts | Adds detail namespace Russian strings. |
| ROADMAP.md | Adds a P1.15 roadmap section describing the detail page i18n work. |
|
|
||
| const displayValue = (() => { | ||
| if (value === null || value === undefined) return '-'; | ||
| if (value === null || value === undefined) return <span className="text-muted-foreground/50 text-xs italic">—</span>; |
There was a problem hiding this comment.
The empty-value placeholder is hardcoded as an em-dash, but there is also a detail.emptyValue translation key in the new translation set that is currently unused. Either use t('detail.emptyValue') here to keep all UI text consistently driven by i18n, or remove the unused key from the defaults/locales to avoid dead translations.
| if (value === null || value === undefined) return <span className="text-muted-foreground/50 text-xs italic">—</span>; | |
| if (value === null || value === undefined) return <span className="text-muted-foreground/50 text-xs italic">{t('detail.emptyValue')}</span>; |
| const result = useObjectTranslation(); | ||
| const testValue = result.t(testKey); | ||
| if (testValue === testKey) { | ||
| return { | ||
| t: (key: string, options?: Record<string, unknown>) => { |
There was a problem hiding this comment.
createSafeTranslationHook repeats the same fallback translator implementation in multiple branches. Extracting a small helper (like createFallbackTranslator in packages/plugin-designer/src/hooks/useDesignerTranslation.ts) would reduce duplication and make future changes less error-prone.
| - [x] Add `detail.*` translation keys to all 11 locale files (en, zh, ja, de, fr, es, ar, ru, pt, ko) | ||
| - [x] `useDetailTranslation` safe wrapper hook with English fallback (follows existing useGridTranslation/useListViewTranslation pattern) | ||
| - [x] DetailView fully i18n-integrated (Back, Edit, Share, Delete, Duplicate, Export, View history, Record not found, Related heading, favorites, navigation) | ||
| - [x] DetailSection copy tooltip i18n via `useSectionTranslation` |
There was a problem hiding this comment.
ROADMAP.md references useSectionTranslation for DetailSection tooltip i18n, but the implementation uses useDetailTranslation and there is no useSectionTranslation in the repo. Please update this line to match the actual hook name to avoid misleading documentation.
| - [x] DetailSection copy tooltip i18n via `useSectionTranslation` | |
| - [x] DetailSection copy tooltip i18n via `useDetailTranslation` |
| const handleDelete = React.useCallback(() => { | ||
| const confirmMessage = schema.deleteConfirmation || 'Are you sure you want to delete this record?'; | ||
| const confirmMessage = schema.deleteConfirmation || t('detail.deleteConfirmation'); | ||
| // Use window.confirm as fallback — the ActionProvider's onConfirm handler |
There was a problem hiding this comment.
handleDelete now calls t('detail.deleteConfirmation'), but the useCallback dependency array for this handler does not include t. This can cause stale translations if the locale changes without unmounting. Add t to the dependency list (or compute the message outside the callback and depend on that).
| if (navigator.share && schema.objectName && schema.resourceId) { | ||
| navigator.share({ | ||
| title: schema.title || 'Record Details', | ||
| title: schema.title || t('detail.details'), | ||
| text: `${schema.objectName} #${schema.resourceId}`, |
There was a problem hiding this comment.
handleShare uses t('detail.details') for the share title fallback, but the useCallback dependency array for this handler does not include t. Include t in the dependencies to avoid holding onto a stale translation function when locale changes.
|
|
||
| React.useEffect(() => { |
There was a problem hiding this comment.
relatedData is initialized from the data prop but never re-synced when data changes (and the fetch effect only runs when api && !data.length). If the parent updates data after first render, the list will keep showing stale rows. Consider syncing relatedData from data in an effect (or store only fetched data in state and render data directly when provided).
| React.useEffect(() => { | |
| // Keep relatedData in sync with external data prop updates | |
| React.useEffect(() => { | |
| setRelatedData(data); | |
| }, [data]); | |
| React.useEffect(() => { |
detail.*translation keys to all 11 locale files (en, zh, ar, de, es, fr, ja, ko, pt, ru)useDetailTranslation.tswithcreateSafeTranslationHookutility andDETAIL_DEFAULT_TRANSLATIONS-with styled em-dash placeholder)Original prompt
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.