Merge branch 'IDTEAM-1.26.0' into 'main'
[ProtonMail-WebClient.git] / packages / shared / lib / helpers / humanSize.ts
blob022098c2d7073663a8914a19c51dd17730f152f8
1 import { c, msgid } from 'ttag';
3 import { sizeUnits } from './size';
5 export type SizeUnits = keyof typeof sizeUnits;
7 export const getSizeFormat = (key: SizeUnits, n: number) => {
8     if (key === 'B') {
9         return c('file size format').ngettext(msgid`byte`, `bytes`, n);
10     }
11     if (key === 'KB') {
12         return c('file size format').t`KB`;
13     }
14     if (key === 'MB') {
15         return c('file size format').t`MB`;
16     }
17     if (key === 'GB') {
18         return c('file size format').t`GB`;
19     }
20     if (key === 'TB') {
21         return c('file size format').t`TB`;
22     }
23     throw new Error('Unknown unit');
26 export const getLongSizeFormat = (key: SizeUnits, n: number) => {
27     if (key === 'B') {
28         return c('file size format, long').ngettext(msgid`Byte`, `Bytes`, n);
29     }
30     if (key === 'KB') {
31         return c('file size format, long').ngettext(msgid`Kilobyte`, `Kilobytes`, n);
32     }
33     if (key === 'MB') {
34         return c('file size format, long').ngettext(msgid`Megabyte`, `Megabytes`, n);
35     }
36     if (key === 'GB') {
37         return c('file size format, long').ngettext(msgid`Gigabyte`, `Gigabytes`, n);
38     }
39     if (key === 'TB') {
40         return c('file size format, long').ngettext(msgid`Terabyte`, `Terabytes`, n);
41     }
42     throw new Error('Unknown unit');
45 // Due to legacy reasons, we keep the default max to GB instead of TB to avoid changing expectations of current consumers
46 const defaultUnitOptions: { max?: SizeUnits } = {
47     max: 'GB',
49 export const getUnit = (bytes: number, options = defaultUnitOptions): SizeUnits => {
50     if (bytes < sizeUnits.KB || options?.max === 'B') {
51         return 'B';
52     }
54     if (bytes < sizeUnits.MB || options?.max === 'KB') {
55         return 'KB';
56     }
58     if (bytes < sizeUnits.GB || options?.max === 'MB') {
59         return 'MB';
60     }
62     if (bytes < sizeUnits.TB || options?.max === 'GB') {
63         return 'GB';
64     }
66     return 'TB';
69 const transformTo = ({
70     bytes,
71     unit,
72     withoutUnit,
73     fractionDigits = 2,
74     truncate,
75 }: {
76     bytes: number;
77     unit: SizeUnits;
78     withoutUnit?: boolean;
79     fractionDigits?: number;
80     truncate?: boolean;
81 }) => {
82     const completeValue = bytes / sizeUnits[unit];
83     let value: string;
84     if (fractionDigits === 0 && !truncate) {
85         value = `${Number(completeValue.toFixed(1))}`;
86     } else {
87         value = completeValue.toFixed(fractionDigits);
88     }
89     const suffix = withoutUnit ? '' : ` ${getSizeFormat(unit, Number(value))}`;
91     return value + suffix;
94 const humanSize = ({
95     bytes = 0,
96     unit: maybeUnit,
97     unitOptions,
98     fraction: maybeFraction,
99     withoutUnit,
100     truncate,
101 }: {
102     truncate?: boolean;
103     bytes: number | undefined;
104     unit?: SizeUnits;
105     unitOptions?: Parameters<typeof getUnit>[1];
106     withoutUnit?: boolean;
107     fraction?: number;
108 }) => {
109     const unit = maybeUnit || getUnit(bytes, unitOptions);
110     const fractionDigits = maybeFraction === undefined && unit === 'B' ? 0 : maybeFraction;
111     return transformTo({ bytes, unit, withoutUnit, fractionDigits, truncate });
114 export default humanSize;
117  * shortHumanSize makes the compact size version to the bytes precision. It drops
118  * the fractional part for sizes smaller than gigabyte--only for bigger files
119  * it shows one fractional digit. Examples:
121  * 12 bytes -> 12 bytes
122  * 567 bytes -> 1 KB
123  * 12.34 MB -> 12 MB
124  * 12.34 GB -> 12.3 GB
125  */
126 export const shortHumanSize = (bytes = 0) => {
127     if (bytes < sizeUnits.KB) {
128         return humanSize({ bytes, unit: 'B', truncate: true, fraction: 0 });
129     }
130     if (bytes < sizeUnits.GB) {
131         return humanSize({ bytes, truncate: true, fraction: 0 });
132     }
133     return humanSize({ bytes, fraction: 1 });
137  * Produces always readable version in bytes. Useful for titles where we
138  * might want to display the exact size.
139  */
140 export const bytesSize = (bytes = 0) => {
141     return `${bytes} ${getSizeFormat('B', bytes)}`;