From 7242f8425aa8a0da51356d75b6572f35b61ba81c Mon Sep 17 00:00:00 2001 From: estifanos Date: Wed, 12 Aug 2026 11:04:47 +0000 Subject: [PATCH] feat: add internationalization support for WaiverPage with translations for English and Amharic --- .../app/features/waiver/pages/WaiverPage.tsx | 68 +++++++++++-------- apps/portal/src/app/i18n/locales/am.ts | 34 ++++++++++ apps/portal/src/app/i18n/locales/en.ts | 34 ++++++++++ 3 files changed, 107 insertions(+), 29 deletions(-) diff --git a/apps/portal/src/app/features/waiver/pages/WaiverPage.tsx b/apps/portal/src/app/features/waiver/pages/WaiverPage.tsx index a7cdf20d4..28fa72c51 100644 --- a/apps/portal/src/app/features/waiver/pages/WaiverPage.tsx +++ b/apps/portal/src/app/features/waiver/pages/WaiverPage.tsx @@ -17,11 +17,13 @@ import { IconInfoCircle, } from '@tabler/icons-react'; import { useNavigate } from 'react-router-dom'; +import { useTranslation } from 'react-i18next'; import { STATUS_COLORS, STATUS_LABELS, TERMINAL_STATUSES, extractErrorMessage, + localized, useGetCertificateUrlMutation, useGetMyApplicationsQuery, useGetMyLicensesQuery, @@ -40,6 +42,7 @@ const WAIVER_TYPE_KEYS = ['PRE_WAIVER', 'POST_WAIVER']; * verifiable references (US-WAV-010). */ export function WaiverPage() { + const { t } = useTranslation(); const navigate = useNavigate(); const { data: applications, isLoading } = useGetMyApplicationsQuery(); const { data: licenses } = useGetMyLicensesQuery(); @@ -61,7 +64,7 @@ export function WaiverPage() { const result = await getCertificateUrl(licenseId).unwrap(); window.open(result.url, '_blank', 'noopener'); } catch (error) { - notify.error(extractErrorMessage(error, 'Could not fetch the letter')); + notify.error(extractErrorMessage(error, t('waiver.fetchFailed', 'Could not fetch the letter'))); } } @@ -76,65 +79,72 @@ export function WaiverPage() { return (
- Maritime Waiver + {t('waiver.title', 'Maritime Waiver')} - Apply for a waiver when Ethiopian Shipping & Logistics cannot - carry your shipment. Approval issues the bank waiver letter. + {t( + 'waiver.subtitle', + 'Apply for a waiver when Ethiopian Shipping & Logistics cannot carry your shipment. Approval issues the bank waiver letter.', + )}
- Pre-waiver + {t('waiver.preWaiver.title', 'Pre-waiver')} - The cargo has not yet arrived. Applying before arrival avoids the - post-waiver penalty. + {t( + 'waiver.preWaiver.body', + 'The cargo has not yet arrived. Applying before arrival avoids the post-waiver penalty.', + )} - Post-waiver + {t('waiver.postWaiver.title', 'Post-waiver')} - The cargo has already arrived. Granted once per shipment, and only - against a settled penalty with the receipt attached. + {t( + 'waiver.postWaiver.body', + 'The cargo has already arrived. Granted once per shipment, and only against a settled penalty with the receipt attached.', + )} }> - Each waiver covers one shipment, identified by its bill of lading. A - second application quoting the same bill of lading is refused while the - first is live. + {t( + 'waiver.oneShipmentNotice', + 'Each waiver covers one shipment, identified by its bill of lading. A second application quoting the same bill of lading is refused while the first is live.', + )} {inFlight.length > 0 && ( - Applications in progress + {t('waiver.inProgress', 'Applications in progress')} {inFlight.map((app) => (
{app.applicationNumber} - {app.licenseType?.name?.en} + {localized(app.licenseType?.name)}
- {STATUS_LABELS[app.status]} + {t(`applications.status.${app.status}`, STATUS_LABELS[app.status])}
@@ -157,11 +167,11 @@ export function WaiverPage() { )} - Issued waiver letters + {t('waiver.issuedLetters', 'Issued waiver letters')} {letters.length === 0 ? ( - No waiver letters issued yet. + {t('waiver.emptyLetters', 'No waiver letters issued yet.')} ) : ( @@ -169,10 +179,10 @@ export function WaiverPage() { - Reference - Kind - Issued - Status + {t('waiver.columns.reference', 'Reference')} + {t('waiver.columns.kind', 'Kind')} + {t('waiver.columns.issued', 'Issued')} + {t('waiver.columns.status', 'Status')} @@ -184,7 +194,7 @@ export function WaiverPage() { {license.certificateNumber} - {license.licenseType?.name?.en ?? '—'} + {localized(license.licenseType?.name) || '—'}{showDate(license.issueDate)} - {license.status} + {t(`waiver.licenseStatus.${license.status}`, license.status)} @@ -202,7 +212,7 @@ export function WaiverPage() { leftSection={} onClick={() => download(license.id)} > - Letter + {t('waiver.letter', 'Letter')} diff --git a/apps/portal/src/app/i18n/locales/am.ts b/apps/portal/src/app/i18n/locales/am.ts index 98747c918..5de71b937 100644 --- a/apps/portal/src/app/i18n/locales/am.ts +++ b/apps/portal/src/app/i18n/locales/am.ts @@ -352,4 +352,38 @@ export const am: Translations = { a4: 'በማመልከቻው ላይ "እርምጃ ያስፈልጋል" የሚል ማስታወሻ ያያሉ። ግምገማውን ለመቀጠል የተጠየቀውን ሰነድ ወይም ዝርዝር ያቅርቡ።', }, }, + + waiver: { + title: "የባህር ትራንስፖርት ነፃ ፈቃድ", + subtitle: "የኢትዮጵያ መርከብ እና ሎጂስቲክስ ጭነትዎን ማጓጓዝ በማይችልበት ጊዜ ነፃ ፈቃድ ያመልክቱ። መጽደቁ የባንክ ነፃ ፈቃድ ደብዳቤ ያወጣል።", + preWaiver: { + title: "ቅድመ ነፃ ፈቃድ", + body: "ጭነቱ ገና አልደረሰም። ከመድረሱ በፊት ማመልከት ድህረ-ነፃ ፈቃድ ቅጣትን ያስቀራል።", + apply: "ለቅድመ ነፃ ፈቃድ ያመልክቱ", + }, + postWaiver: { + title: "ድህረ ነፃ ፈቃድ", + body: "ጭነቱ አስቀድሞ ደርሷል። በአንድ ጭነት አንድ ጊዜ ብቻ ይሰጣል፣ እና ደረሰኙ ተያይዞ የተከፈለ ቅጣት ካለ ብቻ።", + apply: "ለድህረ ነፃ ፈቃድ ያመልክቱ", + }, + oneShipmentNotice: "እያንዳንዱ ነፃ ፈቃድ በማጫኛ ሰነዱ የሚለይ አንድ ጭነት ይሸፍናል። ተመሳሳይ የማጫኛ ሰነድ ጠቅሶ የሚቀርብ ሁለተኛ ማመልከቻ የመጀመሪያው ገና ንቁ ሆኖ ሳለ ውድቅ ይደረጋል።", + inProgress: "በሂደት ላይ ያሉ ማመልከቻዎች", + issuedLetters: "የወጡ ነፃ ፈቃድ ደብዳቤዎች", + emptyLetters: "እስካሁን የወጣ ነፃ ፈቃድ ደብዳቤ የለም።", + columns: { + reference: "ማጣቀሻ", + kind: "ዓይነት", + issued: "የወጣበት ቀን", + status: "ሁኔታ", + }, + letter: "ደብዳቤ", + fetchFailed: "ደብዳቤውን ማግኘት አልተቻለም", + licenseStatus: { + ACTIVE: "ንቁ", + EXPIRED: "ጊዜው ያለፈበት", + SUSPENDED: "ታግዷል", + CANCELLED: "ተሰርዟል", + SUPERSEDED: "ተተክቷል", + }, + }, }; diff --git a/apps/portal/src/app/i18n/locales/en.ts b/apps/portal/src/app/i18n/locales/en.ts index bbb221d44..f05f83645 100644 --- a/apps/portal/src/app/i18n/locales/en.ts +++ b/apps/portal/src/app/i18n/locales/en.ts @@ -351,6 +351,40 @@ export const en = { a4: 'You will see an "Action required" notice on the application. Provide the requested document or detail to resume the review.', }, }, + + waiver: { + title: 'Maritime Waiver', + subtitle: 'Apply for a waiver when Ethiopian Shipping & Logistics cannot carry your shipment. Approval issues the bank waiver letter.', + preWaiver: { + title: 'Pre-waiver', + body: 'The cargo has not yet arrived. Applying before arrival avoids the post-waiver penalty.', + apply: 'Apply for a pre-waiver', + }, + postWaiver: { + title: 'Post-waiver', + body: 'The cargo has already arrived. Granted once per shipment, and only against a settled penalty with the receipt attached.', + apply: 'Apply for a post-waiver', + }, + oneShipmentNotice: 'Each waiver covers one shipment, identified by its bill of lading. A second application quoting the same bill of lading is refused while the first is live.', + inProgress: 'Applications in progress', + issuedLetters: 'Issued waiver letters', + emptyLetters: 'No waiver letters issued yet.', + columns: { + reference: 'Reference', + kind: 'Kind', + issued: 'Issued', + status: 'Status', + }, + letter: 'Letter', + fetchFailed: 'Could not fetch the letter', + licenseStatus: { + ACTIVE: 'Active', + EXPIRED: 'Expired', + SUSPENDED: 'Suspended', + CANCELLED: 'Cancelled', + SUPERSEDED: 'Superseded', + }, + }, }; export type Translations = typeof en;