const TERABYTE = 10 ** 12 ; const GIGABYTE = 10 ** 9 ; const MEGABYTE = 10 ** 6 ; const KILOBYTE = 10 ** 3 ; const inWebApp = typeof window !== 'undefined' && typeof window . document !== 'undefined' ; interface FormatParams { value : number ; unit : 'terabyte' | 'gigabyte' | 'megabyte' | 'kilobyte' | 'byte' ; decimalPlaces : number ; } function getDataFormattingParams ( numBytes ) { if ( numBytes >= TERABYTE ) { return { value : numBytes / TERABYTE , unit : 'terabyte' , decimalPlaces : 2 } ; } else if ( numBytes >= GIGABYTE ) { return { value : numBytes / GIGABYTE , unit : 'gigabyte' , decimalPlaces : 2 } ; } else if ( numBytes >= MEGABYTE ) { return { value : numBytes / MEGABYTE , unit : 'megabyte' , decimalPlaces : 1 } ; } else if ( numBytes >= KILOBYTE ) { return { value : numBytes / KILOBYTE , unit : 'kilobyte' , decimalPlaces : 0 } ; } return { value : numBytes , unit : 'byte' , decimalPlaces : 0 } ; } function makeDataAmountFormatter ( language , params ) { const options = { style : 'unit' , unit : params . unit , unitDisplay : 'short' , maximumFractionDigits : params . decimalPlaces } as unknown as Intl . NumberFormatOptions ; return new Intl . NumberFormat ( language , options ) ; } interface DataAmountParts { value : string ; unit : string ; } param { number } numBytes param { string } language export function formatBytesParts ( numBytes , language ) { if ( ! inWebApp ) { throw new Error ( 'formatBytesParts only works in web app code. Node usage isn\'t supported.' ) ; } const params = getDataFormattingParams ( numBytes ) ; const parts = makeDataAmountFormatter ( language , params ) . formatToParts ( params . value ) ; const isUnit = ( part ) => ( part as { type : string ; } ) . type === 'unit' ; const unitText = parts . find ( isUnit ) . value ; return { value : parts . filter ( ( part ) => ! isUnit ( part ) ) . map ( ( part ) => part . value ) . join ( '' ) . trim ( ) , unit : unitText === 'byte' ? 'B' : unitText } ; } param { Number } numBytes param { string } language returns { string } export function formatBytes ( numBytes , language ) { if ( ! inWebApp ) { throw new Error ( 'formatBytes only works in web app code. Node usage isn\'t supported.' ) ; } const params = getDataFormattingParams ( numBytes ) ; return makeDataAmountFormatter ( language , params ) . format ( params . value ) ; } export interface DisplayDataAmount { unit : 'MB' | 'GB' ; value : number ; } param dataAmount returns export function displayDataAmountToBytes ( dataAmount ) { if ( ! dataAmount ) { return null ; } if ( dataAmount . unit === 'GB' ) { return dataAmount . value * ( 10 ** 9 ) ; } else if ( dataAmount . unit === 'MB' ) { return dataAmount . value * ( 10 ** 6 ) ; } } param bytes returns export function bytesToDisplayDataAmount ( bytes ) { if ( bytes === null || bytes === undefined ) { return null ; } if ( bytes >= 10 ** 9 ) { return { value : Math . floor ( bytes / ( 10 ** 9 ) ) , unit : 'GB' } ; } return { value : Math . floor ( bytes / ( 10 ** 6 ) ) , unit : 'MB' } ; }