import { t, locale, formatNumber } from '@/i18n' export const MAX_IMAGE_BYTES = 10 * 1024 * 1024 export const ALLOWED_IMAGE_MIME_TYPES = ['image/png', 'image/jpeg', 'image/webp', 'image/svg+xml'] export const ALLOWED_IMAGE_EXTENSIONS = ['.png', '.jpg', '.jpeg', '.webp', '.svg'] export const IMAGE_TYPE_REJECTION_TEXT = 'Use a PNG, JPEG, WEBP or SVG image, up to 10 MB.' export type ImageRejectionKind = 'type' | 'size' export type ImageValidationResult = { ok: true } | { ok: false; kind: ImageRejectionKind } export function fileExtension(filename: string) { const index = filename.lastIndexOf('.') return index === -1 ? '' : filename.slice(index).toLowerCase() } export function validateImageFile(file: File): ImageValidationResult { if (file.size > MAX_IMAGE_BYTES) { return { ok: false, kind: 'size' } } const typeAllowed = ALLOWED_IMAGE_MIME_TYPES.includes(file.type) const extensionAllowed = ALLOWED_IMAGE_EXTENSIONS.includes(fileExtension(file.name)) if (!typeAllowed || !extensionAllowed) { return { ok: false, kind: 'type' } } return { ok: true } } const EXTENSIONS_BY_MIME_TYPE: Record = { 'image/png': ['.png'], 'image/jpeg': ['.jpg', '.jpeg'], 'image/webp': ['.webp'], 'image/svg+xml': ['.svg'], } export function extensionMatchesType(file: File) { return EXTENSIONS_BY_MIME_TYPE[file.type]?.includes(fileExtension(file.name)) ?? false } export function formatMegabytes(bytes: number) { const value = bytes / (1024 * 1024) return locale.value === 'fr' ? formatNumber(value, { minimumFractionDigits: 1, maximumFractionDigits: 1, }) : value.toFixed(1) } export function isSizeRejectionBody(body: string) { return body.toLowerCase().includes('exceed') } export function rejectionTitle(filename: string) { return t("\u0022{0}\u0022 can't be used", [filename]) } export function sizeRejectionText(filename: string, bytes: number) { return t('{0} is {1} MB. Images can be up to 10 MB.', [filename, formatMegabytes(bytes)]) } export function formatWholeKB(bytes: number): string { const kb = bytes / 1024 const rounded = Math.round(kb * 10) / 10 if (locale.value === 'fr') return formatNumber(rounded, { minimumFractionDigits: rounded === 0 ? 1 : 0, maximumFractionDigits: 1, }) if (rounded === 0) { return '0.0' } return Number.isInteger(rounded) ? String(rounded) : rounded.toFixed(1) } export function formatUploadProgress(loadedBytes: number, totalBytes: number): string { if (totalBytes < 1024 * 1024) { return t('Uploading {0} of {1} KB', [formatWholeKB(loadedBytes), formatWholeKB(totalBytes)]) } return t('Uploading {0} of {1} MB', [formatMegabytes(loadedBytes), formatMegabytes(totalBytes)]) }