diff --git a/core/includes/common.inc b/core/includes/common.inc index 49cf6e104a72aafac9435f9aaf721716d9ab9634..23cecc8c778f6e9574be3d73ac08e7798fb8a5d9 100644 --- a/core/includes/common.inc +++ b/core/includes/common.inc @@ -251,42 +251,46 @@ function check_url($uri) { * A translated string representation of the size. */ function format_size($size, $langcode = NULL) { - if ($size < Bytes::KILOBYTE) { + $absolute_size = abs($size); + if ($absolute_size < Bytes::KILOBYTE) { return \Drupal::translation()->formatPlural($size, '1 byte', '@count bytes', [], ['langcode' => $langcode]); } - else { - // Convert bytes to kilobytes. - $size = $size / Bytes::KILOBYTE; - $units = ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; - foreach ($units as $unit) { - if (round($size, 2) >= Bytes::KILOBYTE) { - $size = $size / Bytes::KILOBYTE; - } - else { - break; - } - } - $args = ['@size' => round($size, 2)]; - $options = ['langcode' => $langcode]; - switch ($unit) { - case 'KB': - return new TranslatableMarkup('@size KB', $args, $options); - case 'MB': - return new TranslatableMarkup('@size MB', $args, $options); - case 'GB': - return new TranslatableMarkup('@size GB', $args, $options); - case 'TB': - return new TranslatableMarkup('@size TB', $args, $options); - case 'PB': - return new TranslatableMarkup('@size PB', $args, $options); - case 'EB': - return new TranslatableMarkup('@size EB', $args, $options); - case 'ZB': - return new TranslatableMarkup('@size ZB', $args, $options); - case 'YB': - return new TranslatableMarkup('@size YB', $args, $options); + // Create a multiplier to preserve the sign of $size. + $sign = $absolute_size / $size; + foreach (['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'] as $unit) { + $absolute_size /= Bytes::KILOBYTE; + $rounded_size = round($absolute_size, 2); + if ($rounded_size < Bytes::KILOBYTE) { + break; } } + $args = ['@size' => $rounded_size * $sign]; + $options = ['langcode' => $langcode]; + switch ($unit) { + case 'KB': + return new TranslatableMarkup('@size KB', $args, $options); + + case 'MB': + return new TranslatableMarkup('@size MB', $args, $options); + + case 'GB': + return new TranslatableMarkup('@size GB', $args, $options); + + case 'TB': + return new TranslatableMarkup('@size TB', $args, $options); + + case 'PB': + return new TranslatableMarkup('@size PB', $args, $options); + + case 'EB': + return new TranslatableMarkup('@size EB', $args, $options); + + case 'ZB': + return new TranslatableMarkup('@size ZB', $args, $options); + + case 'YB': + return new TranslatableMarkup('@size YB', $args, $options); + } } /** diff --git a/core/tests/Drupal/KernelTests/Core/Common/SizeTest.php b/core/tests/Drupal/KernelTests/Core/Common/SizeTest.php index 82ff53086ba3a006c40fc874fccb3f352c629331..f595cfcab5ec8dbfa2bf5aed11099fe62acae4ab 100644 --- a/core/tests/Drupal/KernelTests/Core/Common/SizeTest.php +++ b/core/tests/Drupal/KernelTests/Core/Common/SizeTest.php @@ -29,8 +29,12 @@ public function testCommonFormatSize($expected, $input) { public function providerTestCommonFormatSize() { $kb = Bytes::KILOBYTE; return [ + ['0 bytes', 0], ['1 byte', 1], + ['-1 bytes', -1], ['2 bytes', 2], + ['-2 bytes', -2], + ['1023 bytes', $kb - 1], ['1 KB', $kb], ['1 MB', pow($kb, 2)], ['1 GB', pow($kb, 3)], @@ -39,10 +43,13 @@ public function providerTestCommonFormatSize() { ['1 EB', pow($kb, 6)], ['1 ZB', pow($kb, 7)], ['1 YB', pow($kb, 8)], - // Rounded to 1 MB - not 1000 or 1024 kilobyte + ['1024 YB', pow($kb, 9)], + // Rounded to 1 MB - not 1000 or 1024 kilobytes ['1 MB', ($kb * $kb) - 1], + ['-1 MB', -(($kb * $kb) - 1)], // Decimal Megabytes ['3.46 MB', 3623651], + ['3.77 GB', 4053371676], // Decimal Petabytes ['59.72 PB', 67234178751368124], // Decimal Yottabytes