fix(i18n): localise attachment size displays

This commit is contained in:
cesnimda
2026-11-03 19:22:07 +01:00
parent 7a9de940df
commit 31ce702716
8 changed files with 59 additions and 5 deletions
@@ -104,6 +104,18 @@ function changeLanguage(language: UiLanguage) {
act(() => { window.dispatchEvent(new StorageEvent("storage", { key: "uiLanguage", newValue: language })); });
}
test('frozen attachment size follows UI language without changing stored package data', async () => {
const attachment = { id: 81, fileName: 'recorded.pdf', fileSize: 1536, fileType: 'application/pdf' };
const summary = { id: 91, version: 1, cvVariantId: 3, cvVariantName: 'Original CV', cvVariantVersion: 2, cvThemeId: 'nordic', hasCv: true, hasCoverLetter: true, createdAtUtc: '2026-07-19T10:00:00Z', attachments: [attachment] };
routeGet({ submittedPackages: [summary] });
render(<SubmittedPackagesSection jobId={7} />);
expect(await screen.findByRole('button', { name: /recorded.pdf.*1.5 KB/ })).toBeInTheDocument();
changeLanguage('nb');
expect(screen.getByRole('button', { name: /recorded.pdf.*1,5 KB/ })).toBeInTheDocument();
expect(summary.attachments[0]).toEqual(attachment);
expect(mockedApi.post).not.toHaveBeenCalled(); expect(mockedApi.put).not.toHaveBeenCalled();
});
function deferred<T>() {
let resolve!: (value: T) => void;
let reject!: (reason: unknown) => void;
+9
View File
@@ -22,6 +22,15 @@ const mockedApi = api as jest.Mocked<typeof api>;
beforeEach(() => jest.clearAllMocks());
test.each([['en', '1.5 MB'], ['nb', '1,5 MB']])('attachment size follows the UI locale (%s)', async (language, size) => {
const previous = localStorage.getItem('uiLanguage');
localStorage.setItem('uiLanguage', language);
mockedApi.get.mockResolvedValueOnce({ data: [{ id: 8, fileName: 'recorded.pdf', fileType: 'application/pdf', fileSize: 1572864, uploadDate: '2026-11-03T10:00:00Z' }] } as any);
const view = render(<ToastProvider><I18nProvider><ConfirmProvider><PromptProvider><Attachments jobId={42} /></PromptProvider></ConfirmProvider></I18nProvider></ToastProvider>);
try { expect(await screen.findByText(size)).toBeInTheDocument(); expect(mockedApi.post).not.toHaveBeenCalled(); }
finally { view.unmount(); if (previous === null) localStorage.removeItem('uiLanguage'); else localStorage.setItem('uiLanguage', previous); }
});
test.each([
['en', 'Preview: resume.pdf', 'Preview: resume.pdf'],
['nb', 'Forhåndsvis: resume.pdf', 'Forhåndsvisning: resume.pdf'],
@@ -357,7 +357,7 @@ export function SubmittedPackagesSection({ jobId, allowCapture = true }: { jobId
</Button>
{item.attachments.map((attachment) => (
<Button key={attachment.id} size="small" variant="text" disabled={pending} startIcon={<DownloadOutlinedIcon />} onClick={() => void download(item, attachment)} sx={{ alignSelf: "flex-start", maxWidth: "100%", overflowWrap: "anywhere", textAlign: "left" }}>
{attachment.fileName} · {(attachment.fileSize / 1024).toFixed(1)} KB
{attachment.fileName} · {new Intl.NumberFormat(language === "nb" ? "nb-NO" : "en", { minimumFractionDigits: 1, maximumFractionDigits: 1 }).format(attachment.fileSize / 1024)} KB
</Button>
))}
</Stack>
@@ -47,11 +47,12 @@ interface AttachmentItem {
useForAi: boolean;
}
function fmtSize(n: number) {
function fmtSize(n: number, language: string) {
if (!n) return "";
const kb = n / 1024;
if (kb < 1024) return `${kb.toFixed(0)} KB`;
return `${(kb / 1024).toFixed(1)} MB`;
const digits = kb < 1024 ? 0 : 1;
const value = new Intl.NumberFormat(language === "nb" ? "nb-NO" : "en", { minimumFractionDigits: digits, maximumFractionDigits: digits }).format(kb < 1024 ? kb : kb / 1024);
return `${value} ${kb < 1024 ? "KB" : "MB"}`;
}
function isImageType(t: string) {
@@ -303,7 +304,7 @@ export default function Attachments({ jobId }: { jobId: number }) {
</TableCell>
<TableCell>{kind}</TableCell>
<TableCell sx={{ color: "text.secondary" }}>{a.fileType ? a.fileType.replace("application/", "") : ""}</TableCell>
<TableCell sx={{ color: "text.secondary" }}>{a.fileSize ? fmtSize(a.fileSize) : ""}</TableCell>
<TableCell sx={{ color: "text.secondary" }}>{a.fileSize ? fmtSize(a.fileSize, language) : ""}</TableCell>
<TableCell sx={{ color: "text.secondary" }}>{a.uploadDate ? new Date(a.uploadDate).toLocaleString(language === "nb" ? "nb-NO" : "en") : ""}</TableCell>
<TableCell>
<FormControl size="small" fullWidth>