feat: introduce useLocalized hook for bilingual value retrieval.(localization round 2)

- Added useLocalized hook to provide a stable function for retrieving bilingual values based on the current language.
- Updated various components across the portal and backoffice to utilize the new useLocalized hook for consistent bilingual label rendering.
- Refactored localized function in licensing.helpers to handle empty Amharic strings correctly.
- Enhanced localization handling in LicenseApplicationPage, ProfilePage, and other components to ensure proper language switching.
This commit is contained in:
estifanos
2026-08-12 11:31:20 +00:00
parent faf58850f0
commit 31c52c02e0
26 changed files with 154 additions and 64 deletions

View File

@@ -1,6 +1,7 @@
import { useState, useMemo, useEffect, useCallback } from 'react';
import { Stack, Select, Group, Text, Loader, Center, Badge } from '@mantine/core';
import { ErrorState } from '@ema-platform/ui';
import { useLocalized } from '@ema-platform/api';
import { useGetLocationTypesQuery, useGetLocationsQuery } from '../api/location-api';
import type { Location, LocationType } from '../types/location';
import { useTranslation } from 'react-i18next';
@@ -16,6 +17,7 @@ interface LocationPickerProps {
export function LocationPicker({ value, onChange, onChainChange, required, maxDepth }: LocationPickerProps) {
const { t } = useTranslation();
const localized = useLocalized();
const { data: typesRes, isLoading: typesLoading, isError: typesError, refetch: refetchTypes } = useGetLocationTypesQuery();
const { data: locsRes, isLoading: locsLoading, isError: locsError, refetch: refetchLocs } = useGetLocationsQuery({ take: 10000 });
@@ -74,10 +76,10 @@ export function LocationPicker({ value, onChange, onChainChange, required, maxDe
if (currentLevelChildren.length === 0) return '';
const typeIds = [...new Set(currentLevelChildren.map((c) => c.locationTypeId))];
const names = typeIds
.map((id) => typeMap.get(id)?.names.en)
.filter(Boolean) as string[];
.map((id) => localized(typeMap.get(id)?.names))
.filter(Boolean);
return names.join(' / ');
}, [currentLevelChildren, typeMap]);
}, [currentLevelChildren, typeMap, localized]);
const depth = selectedChain.length;
@@ -116,7 +118,7 @@ export function LocationPicker({ value, onChange, onChainChange, required, maxDe
if (levelIdx === 0) {
const roots = childrenByParentId.get('__root__') ?? [];
return roots
.map((loc) => ({ value: loc.id, label: loc.names.en }))
.map((loc) => ({ value: loc.id, label: localized(loc.names) }))
.sort((a, b) => a.label.localeCompare(b.label));
}
@@ -124,7 +126,7 @@ export function LocationPicker({ value, onChange, onChainChange, required, maxDe
if (!parent) return [];
const children = childrenByParentId.get(parent.id) ?? [];
return children
.map((loc) => ({ value: loc.id, label: loc.names.en }))
.map((loc) => ({ value: loc.id, label: localized(loc.names) }))
.sort((a, b) => a.label.localeCompare(b.label));
};
@@ -134,8 +136,8 @@ export function LocationPicker({ value, onChange, onChainChange, required, maxDe
if (roots.length === 0) return '';
const typeIds = [...new Set(roots.map((r) => r.locationTypeId))];
const names = typeIds
.map((id) => typeMap.get(id)?.names.en)
.filter(Boolean) as string[];
.map((id) => localized(typeMap.get(id)?.names))
.filter(Boolean);
return names.join(' / ');
}
@@ -144,16 +146,16 @@ export function LocationPicker({ value, onChange, onChainChange, required, maxDe
const children = childrenByParentId.get(parent.id) ?? [];
const typeIds = [...new Set(children.map((c) => c.locationTypeId))];
const names = typeIds
.map((id) => typeMap.get(id)?.names.en)
.filter(Boolean) as string[];
.map((id) => localized(typeMap.get(id)?.names))
.filter(Boolean);
return names.join(' / ');
};
const selectedPath = useMemo(() => {
return selectedChain
.map((loc) => loc.names.en)
.map((loc) => localized(loc.names))
.join(' → ');
}, [selectedChain]);
}, [selectedChain, localized]);
if (typesLoading || locsLoading) {
return (
@@ -236,8 +238,8 @@ export function LocationPicker({ value, onChange, onChainChange, required, maxDe
color="blue"
style={{ textTransform: 'none' }}
>
{typeInfo ? `${typeInfo.names.en}: ` : ''}
{loc.names.en}
{typeInfo ? `${localized(typeInfo.names)}: ` : ''}
{localized(loc.names)}
</Badge>
);
})}