diff --git a/docs/docusaurus/docs/admin_portal/03-Tutorials/06-admin_portal_tutorials_add-user-attributes-to-keycloak.md b/docs/docusaurus/docs/admin_portal/03-Tutorials/06-admin_portal_tutorials_add-user-attributes-to-keycloak.md index bd3583debf..97a8d14edf 100644 --- a/docs/docusaurus/docs/admin_portal/03-Tutorials/06-admin_portal_tutorials_add-user-attributes-to-keycloak.md +++ b/docs/docusaurus/docs/admin_portal/03-Tutorials/06-admin_portal_tutorials_add-user-attributes-to-keycloak.md @@ -44,3 +44,16 @@ To show a date input field: 1. In **Annotations** > **Add annotation**, set Key: `Input type`, Value: `multiselect-checkboxes` 2. **TODO:** Implementation pending + +## Localization Overrides + +To customize the display label of a user attribute, add a translation override via the Admin Portal under **Settings** > **Localization** > **Add**. + +User attribute keys must use the prefix `usersAndRolesScreen.users.fields.` followed by the attribute name. + +**Example:** to display the `personal_administrative_number` attribute as "PAN", add the following to the tenant's localization settings: + +Key: `usersAndRolesScreen.users.fields.personal_administrative_number` +Value: `PAN` + +This works for any attribute name, including custom ones not present in the default translations. diff --git a/packages/admin-portal/src/resources/User/EditUserForm.tsx b/packages/admin-portal/src/resources/User/EditUserForm.tsx index ee9795eb3a..0d69ae32c2 100644 --- a/packages/admin-portal/src/resources/User/EditUserForm.tsx +++ b/packages/admin-portal/src/resources/User/EditUserForm.tsx @@ -513,8 +513,8 @@ export const EditUserForm: React.FC = ({ const handleAttrChange = (attrName: string) => async (e: React.ChangeEvent) => { - const {name, value} = e.target - debouncedHandleChange(name, value) + const {value} = e.target + debouncedHandleChange(attrName, value) } const debouncedHandleChange = useCallback( diff --git a/packages/admin-portal/src/services/UserService.ts b/packages/admin-portal/src/services/UserService.ts index 13bbae08ea..14c377e73a 100644 --- a/packages/admin-portal/src/services/UserService.ts +++ b/packages/admin-portal/src/services/UserService.ts @@ -1,21 +1,30 @@ // SPDX-FileCopyrightText: 2025 Sequent Tech Inc -// - -import englishTranslation from "@/translations/en" - // SPDX-License-Identifier: AGPL-3.0-only + +// Works for both camelCase and snake_case, i.e. in the format of ${attributeName} or ${profile.attributes.attributeName} or +// in snake case like ${first_name} or ${profile.attributes.first_name} and we want to convert it to a more readable format like 'First Name' or 'Personal Administrative Number' +// ${firstName} => First Name +// ${profile.attributes.firstName} => First Name +// ${profile.attributes.personal_administrative_number} => Personal Administrative Number export const getAttributeLabel = (displayName: string) => { if (displayName?.includes("$")) { - return ( + const rawName = displayName // Step 1: Remove '${' from the start and '}' from the end .replace(/^\${|}$/g, "") // Step 2: Remove any leading or trailing whitespace .trim() - // Step 3: Add a space between a lowercase letter followed by an uppercase letter + // Step 3: Get the word after the last dot if it exists, otherwise use the whole string + .split(".") + .pop() ?? "" + return ( + rawName + // Step 4 : Replace underscores with spaces + .replace(/_/g, " ") + // Step 5 : Add a space between a lowercase letter followed by an uppercase letter .replace(/([a-z])([A-Z])/g, "$1 $2") - // Step 4: Capitalize the first letter - .replace(/^./, (match) => match.toUpperCase()) ?? "" + // Step 6: Capitalize the first letter and every letter after a space + .replace(/\b\w/g, (match) => match.toUpperCase()) ) } return displayName ?? "" @@ -26,8 +35,12 @@ export const getTranslationLabel = ( displayName: string | undefined | null, t: (key: string) => string ) => { - if (name && name in englishTranslation.translations.usersAndRolesScreen.users.fields) { - return t(`usersAndRolesScreen.users.fields.${name}`) + if (name) { + const key = `usersAndRolesScreen.users.fields.${name}` + const translated = t(key) + if (translated !== key) { + return translated + } } return getAttributeLabel(displayName ?? "") }