Problem/Motivation

format_size() is still a procedural function. Convert it to a object oriented code.

Proposed resolution

  • Add a \Drupal\Core\StringTranslation\ByteSizeMarkup::create() method that returns TranslatableMarkup
  • Deprecate and remove usages of format_size().
  • Add related PHP unit tests.

Remaining tasks

review/commit

User interface changes

none

API changes

  • format_size() is deprecated
  • A new Drupal\Core\StringTranslation\ByteSizeMarkup class is added
CommentFileSizeAuthor
#272 2157945-nr-bot.txt90 bytesneeds-review-queue-bot
#270 2157945-nr-bot.txt90 bytesneeds-review-queue-bot
#251 2157945-nr-bot.txt21.93 KBneeds-review-queue-bot
#243 interdiff-236-243.txt26.47 KBbhanu951
#236 2157945-236.patch40.54 KBalexpott
#236 2157945-9.4.x-236.patch41.33 KBalexpott
#236 233-236-interdiff.txt2.63 KBalexpott
#233 2157945-233.patch40.35 KBalexpott
#233 2157945-9.4.x-233.patch41.14 KBalexpott
#233 232-233-interdiff.txt523 bytesalexpott
#232 230-232-interdiff.txt51.84 KBalexpott
#232 2157945-232.patch40.32 KBalexpott
#232 2157945-9.4.x-232.patch41.11 KBalexpott
#230 interdiff_2157945_229-230.txt707 byteskarishmaamin
#230 2157945-230.patch41.83 KBkarishmaamin
#229 2157945-229.patch41.83 KBkarishmaamin
#221 2157945-221.patch43.3 KBandypost
#221 interdiff.txt3.9 KBandypost
#219 2157945-219.patch42.74 KBandypost
#219 interdiff.txt522 bytesandypost
#218 2157945-218.patch42.95 KBandypost
#218 interdiff.txt9.1 KBandypost
#214 2157945-214.patch40.14 KBandypost
#214 interdiff.txt2.15 KBandypost
#210 2157945-210.patch40.1 KBandypost
#210 interdiff.txt1016 bytesandypost
#207 2157945-207.patch40.1 KBandypost
#207 interdiff.txt1.48 KBandypost
#205 diff_reroll_2157945_203-205.txt3.91 KBankithashetty
#205 2157945-205.patch39.8 KBankithashetty
#203 diff_reroll_2157945_197-203.txt4.78 KBankithashetty
#203 2157945-203.patch39.79 KBankithashetty
#197 2157945-197.patch39.97 KBmondrake
#197 interdiff_195-197.txt943 bytesmondrake
#195 rawdiff_191-195.txt903 bytesmondrake
#195 2157945-195.patch40.2 KBmondrake
#191 2157945-191.patch40.19 KBandypost
#191 interdiff.txt1.59 KBandypost
#186 2157945-186.patch40.03 KBandypost
#186 interdiff.txt748 bytesandypost
#184 2157945-184.patch39.88 KBandypost
#184 interdiff.txt4.82 KBandypost
#181 2157945-181.patch39.65 KBandypost
#181 interdiff.txt7.54 KBandypost
#180 2157945-180.patch42.78 KBandypost
#180 interdiff.txt2.24 KBandypost
#179 2020-07-22 14_59_30.png37.45 KBmondrake
#172 2157945-172.patch42.3 KBandypost
#172 interdiff.txt33 KBandypost
#170 2157945-170.patch37.86 KBandypost
#170 interdiff.txt5.27 KBandypost
#2 size-oo-2157945-2.patch14.8 KBplach
#7 size-oo-2157945-7.interdiff.txt1.24 KBplach
#7 size-oo-2157945-7.patch15.42 KBplach
#11 size-oo-2157945-11.interdiff.txt580 bytesplach
#11 size-oo-2157945-11.patch15.43 KBplach
#15 size-oo-2157945-15.interdiff.txt6.42 KBplach
#15 size-oo-2157945-15.patch17.67 KBplach
#19 size-2157945-19.patch18.25 KBdawehner
#22 interdiff.txt3.06 KBdawehner
#23 size-2157945-22.patch20.18 KBdawehner
#30 2157945-29.patch5.47 KBjhedstrom
#33 2157945-33.patch8.79 KBmondrake
#36 2157945-36.patch11.96 KBmondrake
#36 interdiff_33-36.txt5.72 KBmondrake
#38 interdiff_36-38.txt737 bytesmondrake
#38 2157945-38.patch11.97 KBmondrake
#44 2157945-44.patch11.97 KBmondrake
#48 2157945-48.patch11.74 KBmondrake
#54 interdiff_48-54.txt5.34 KBmondrake
#54 2157945-54.patch12.41 KBmondrake
#55 2157945-55.patch33.09 KBmondrake
#55 interdiff_54-55.txt21.34 KBmondrake
#58 interdiff_55-58.txt2.53 KBmondrake
#58 2157945-58.patch33.17 KBmondrake
#60 interdiff_58-60.txt710 bytesmondrake
#60 2157945-60.patch33.22 KBmondrake
#62 interdiff_60-62.txt36.08 KBmondrake
#62 2157945-62.patch36.08 KBmondrake
#64 interdiff_60-62.txt29.88 KBmondrake
#71 2157945-71.patch28.97 KBmondrake
#78 2157945-78.patch27.83 KBmondrake
#78 interdiff_71-78.txt1.13 KBmondrake
#80 2157945-80.patch28.41 KBmondrake
#80 interdiff_78-80.txt6.65 KBmondrake
#83 2157945-83.patch28.43 KBmondrake
#83 interdiff_80-83.txt1.59 KBmondrake
#85 2157945-85.patch28.05 KBmondrake
#85 interdiff_83-85.txt26.57 KBmondrake
#86 interdiff_85-86.txt4.13 KBmondrake
#86 2157945-86.patch30.93 KBmondrake
#89 interdiff.txt17.13 KBandypost
#89 2157945-89.patch33.1 KBandypost
#93 2157945-93.patch32.16 KBjofitz
#95 interdiff_93-95.txt1.86 KBmondrake
#95 2157945-95.patch34.24 KBmondrake
#96 2157945-96.patch34.79 KBmondrake
#96 interdiff_95-96.txt3.69 KBmondrake
#101 2157945-101.patch34.9 KBmondrake
#103 2157945-103.patch34.9 KBmondrake
#103 interdiff_101-103.txt1.09 KBmondrake
#113 2157945-113.patch35.34 KBmondrake
#113 interdiff_103-113.txt10.54 KBmondrake
#115 2157945-115.patch35.35 KBmondrake
#118 2157945-118.patch34.23 KBmondrake
#120 2157945-120.patch35.59 KBmondrake
#120 interdiff_118-120.txt3.67 KBmondrake
#122 2157945-122.patch35.59 KBmondrake
#122 interdiff_120-122.txt787 bytesmondrake
#124 2157945-124.patch35.57 KBmondrake
#124 interdiff_122-124.txt2.01 KBmondrake
#127 2157945-127.patch36.76 KBmondrake
#127 interdiff_124-127.txt1.17 KBmondrake
#129 2157945-129.patch36.77 KBvoleger
#135 rerolled-2157945-135.patch36.73 KBshashikant_chauhan
#139 interdiff.txt2.62 KBandypost
#139 2157945-139.patch36.57 KBandypost
#141 2157945-141.patch35.44 KBkostyashupenko
#145 2157945-145.patch35.71 KBmartin107
#146 2157945-146.patch39.31 KBmartin107
#146 interdiff-145-146.txt3.6 KBmartin107
#148 2157945-148.patch38.01 KBmartin107
#148 2157945-148.patch38.01 KBmartin107
#149 interdiff-2157945-146-148.txt1.31 KBmartin107
#150 2157945-150.patch39.23 KBmartin107
#150 interdiff-2157945-148-150.txt3.6 KBmartin107
#153 2157945-153.patch38.37 KBlongwave
#156 2157945-156.patch38.35 KBmartin107
#161 interdiff.txt2.76 KBandypost
#161 2157945-161.patch38.39 KBandypost
#162 interdiff.txt1.13 KBandypost
#162 2157945-162.patch38.4 KBandypost
#165 2157945-165.patch38.23 KBmondrake

Issue fork drupal-2157945

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

plach’s picture

Status: Active » Needs review
StatusFileSize
new14.8 KB

Let's see whether a service works.

plach’s picture

+++ b/core/tests/Drupal/Tests/Core/Common/SizeUnitTest.php
@@ -0,0 +1,136 @@
+   * @inheritdoc
...
+   * @inheritdoc

bah

plach’s picture

Status: Needs work » Needs review
StatusFileSize
new1.24 KB
new15.42 KB

This should be better.

amateescu’s picture

+++ b/core/core.services.yml
@@ -589,6 +589,9 @@ services:
+  size:
+    class: Drupal\Core\Utility\Size
+    arguments: ['@string_translation']

Utility classes are not usually exposed as services, is there any reason this one needs to be?

plach’s picture

Well, it needs the string translation service. I tried also a singleton approach but was not very happy with it...

plach’s picture

Status: Needs work » Needs review
StatusFileSize
new580 bytes
new15.43 KB

This time for reals :)

tim.plunkett’s picture

  1. +++ b/core/lib/Drupal/Core/Utility/Size.php
    @@ -0,0 +1,104 @@
    +        $this->translation->translate('@size KB', array(), $options),
    +        $this->translation->translate('@size MB', array(), $options),
    +        $this->translation->translate('@size GB', array(), $options),
    +        $this->translation->translate('@size TB', array(), $options),
    +        $this->translation->translate('@size PB', array(), $options),
    +        $this->translation->translate('@size EB', array(), $options),
    +        $this->translation->translate('@size ZB', array(), $options),
    +        $this->translation->translate('@size YB', array(), $options),
    

    This won't work for localize.d.o. It *has* to be a method called t(), used like $this->t().
    You can copy/paste one of the various other t() methods with their shortened documentation, like in FormBase, until traits happen.

  2. +++ b/core/lib/Drupal/Core/Utility/Size.php
    @@ -0,0 +1,104 @@
    +   * @return
    ...
    +   * @param $langcode
    ...
    +   * @param $size
    ...
    +   * @param $size
    ...
    +   * @return
    

    Missing data types

  3. +++ b/core/lib/Drupal/Core/Utility/Size.php
    @@ -0,0 +1,104 @@
    +  function format($size, $langcode = NULL) {
    ...
    +  function parse($size) {
    

    public function

  4. +++ b/core/lib/Drupal/Core/Utility/Size.php
    @@ -0,0 +1,104 @@
    +namespace Drupal\Core\Utility;
    

    I'm not sure this is the best place for this. Every other Utility class contains only static methods, without any dependency on other services.

plach’s picture

Status: Needs work » Needs review
StatusFileSize
new6.42 KB
new17.67 KB

This should fix test failures and address #12, except for:

I'm not sure this is the best place for this. Every other Utility class contains only static methods, without any dependency on other services.

Drupal\Core\Utility\Service\Size?
Drupal\Core\Service\Size?
Drupal\Core\Service\Utility\Size?

or (less self-documenting):

Drupal\Core\Common\Size?

dawehner’s picture

+++ b/core/tests/Drupal/Tests/Core/Common/SizeUnitTest.php
@@ -0,0 +1,136 @@
+    foreach (array($this->exactTestCases, $this->roundedTestCases) as $test_cases) {
...
+  function testCommonFormatSize() {
...
+    foreach ($this->exactTestCases as $size) {
...
+  function testCommonParseSizeFormatSize() {
...
+  function testCommonParseSize() {
+    foreach ($this->exactTestCases as $string => $size) {

I wonder whether we should have the same dataProvider just reused multiple times?

plach’s picture

I was wondering that too and I had also an (apparently) good reason for not going that way, but I cannot recall it atm :)

Edit:

+++ b/core/tests/Drupal/Tests/Core/Common/SizeUnitTest.php
@@ -0,0 +1,136 @@
+    // Some custom parsing tests.
+    $string = '23476892 bytes';
+    $parsed_size = $this->size->parse($string);
+    $this->assertTrue($parsed_size == 23476892, $string . ' == ' . $parsed_size . ' bytes');
+
+    $string = '76MRandomStringThatShouldBeIgnoredByParseSize.'; // 76 MB
+    $parsed_size = $this->size->parse($string);
+    $this->assertTrue($parsed_size == 79691776, $string . ' == ' . $parsed_size . ' bytes');
+
+    $string = '76.24 Giggabyte'; // Misspeld text -> 76.24 GB
+    $parsed_size = $this->size->parse($string);
+    $this->assertTrue($parsed_size == 81862076662, $string . ' == ' . $parsed_size . ' bytes');
+  }

Oh, yes, I didn't want to split this out in its own method...

plach’s picture

+++ b/core/tests/Drupal/Tests/Core/Common/SizeUnitTest.php
@@ -0,0 +1,136 @@
+    $string = '76.24 Giggabyte'; // Misspeld text -> 76.24 GB

I hope the comment typo was intentional, or was it a recursive comment? :)

dawehner’s picture

StatusFileSize
new18.25 KB

using \Drupal\Core\Utility\Size is totally fine. We have other utility services like the link generator which aren't static ones.

Worked on making it more phpunit-ish

dawehner’s picture

Status: Needs work » Needs review
StatusFileSize
new3.06 KB

Let's see whether this is enough.

dawehner’s picture

StatusFileSize
new20.18 KB

.

sun’s picture

Status: Needs review » Needs work

I agree that we should do something about these helpers, but a "size" service (name) looks/sounds suboptimal.

In essence, these helper functions fall under the umbrella of language/locale dependent (string) output formatting (templating).

In addition, the output is meant for HTML - and may not be suitable for e.g. CLI output. However, code that generates plain text output for e.g. CLI often needs the identical helper functions, but sans HTML output escaping. Sorta like HtmlLocale extends Locale or similar.

FWIW, format_date() & Co fall under the same umbrella.

jhedstrom’s picture

Title: Convert format_size() and parse_size() to OO code » Convert format_size() Bytes component
Version: 8.2.x-dev » 8.3.x-dev

This was partly done (https://www.drupal.org/node/2253127).

jhedstrom’s picture

Status: Needs work » Needs review
StatusFileSize
new5.47 KB

This adds Bytes::format()

jhedstrom’s picture

Interesting fail here:

Checking for illegal reference to 'Drupal\Core' namespace in /var/www/html/core/lib/Drupal/Component/Utility/Bytes.php
Failed asserting that an array is empty.

which is caused by the class Drupal\Core\StringTranslation\TranslatableMarkup...

mondrake’s picture

Status: Needs work » Needs review
StatusFileSize
new8.79 KB

#32:

Interesting fail here

That's because you cannot call classes in the Drupal\Core namespace from the Drupal\Component namespace. The component would no longer be a 'component' (i.e. independent from Drupal), in that case.

We faced similar discussions in #2583041: GD toolkit & operations should catch \Throwable to fail gracefully in case of errors, comments #27 and #29.

With the patch here I am extracting a part of #2583041: GD toolkit & operations should catch \Throwable to fail gracefully in case of errors that can work in isolation and should be able to address the main point here, but does not get to the point of deprecating format_size and replacing it with a class. But that may be a next step.

Interdiff not relevant.

catch’s picture

Can create the component without the format method. Then add a \Drupal\Core class with a format method, extending from the component. Or move the whole lot into \Drupal\Core is another option.

mondrake’s picture

Title: Convert format_size() Bytes component » Convert format_size() to a class
Assigned: mondrake » Unassigned
Issue tags: +Needs issue summary update
StatusFileSize
new11.96 KB
new5.72 KB

This patch follows on #33.

We have:

  • Added a Bytes::toUnitAndSize() method to return separately a unit of measurement and the size expressed in the unit of measurement, given a byte quantity. Added unit test for that.
  • Added a FormatBytesSize class in \Drupal\Core\Utility with a format method where we call Bytes::toUnitAndSize() and format the size string. Adjusted test for that, and added test cases for formatting '0 bytes' and a quantity of bytes that in format_size was resulting improperly rounded.
  • Refactored format_size() to use FormatBytesSize::format().
  • Added a deprecation annotation for format_size().
mondrake’s picture

Status: Needs work » Needs review
StatusFileSize
new737 bytes
new11.97 KB

Yes, yes

mondrake’s picture

Assigned: mondrake » Unassigned
Status: Needs work » Needs review
Issue tags: -Needs reroll
StatusFileSize
new11.97 KB

Rerolled.

mondrake’s picture

StatusFileSize
new11.74 KB

Plain reroll of #44.

claudiu.cristea’s picture

Status: Needs review » Needs work

Nits.

  1. +++ b/core/includes/common.inc
    @@ -249,44 +249,13 @@ function check_url($uri) {
    + * @deprecated in Drupal 8.4.x, will be removed before Drupal 9.0.0.
    

    Needs a @see reference to the CR. See https://www.drupal.org/core/deprecation

  2. +++ b/core/includes/common.inc
    @@ -249,44 +249,13 @@ function check_url($uri) {
     function format_size($size, $langcode = NULL) {
    

    Should yell a @trigger_error(). See https://www.drupal.org/core/deprecation

  3. +++ b/core/includes/common.inc
    --- a/core/lib/Drupal/Component/Utility/Bytes.php
    +++ b/core/lib/Drupal/Component/Utility/Bytes.php
    

    Do we need to update the component composer.json description?

  4. +++ b/core/lib/Drupal/Component/Utility/Bytes.php
    @@ -39,4 +39,34 @@ public static function toInt($size) {
    +   *   A quantity of bytes.
    
    +++ b/core/lib/Drupal/Component/Utility/BytesUnitAndSize.php
    @@ -0,0 +1,63 @@
    + * A value object class to store a bytes quantity with an unit of measurement.
    ...
    +   * The bytes quantity.
    ...
    +   * The unit of measurement of this bytes quantity.
    ...
    +   *   The bytes quantity.
    ...
    +   * Gets the bytes quantity.
    ...
    +   * Gets the unit of measurement of this bytes quantity.
    ...
    +   *   The unit of measurement of this bytes quantity.
    

    Quantity? Sounds weird. Amount? Same. Maybe other word? Maybe "count"?

  5. +++ b/core/lib/Drupal/Component/Utility/Bytes.php
    @@ -39,4 +39,34 @@ public static function toInt($size) {
    +   *   NULL if the input value is negative, a
    

    Feels like The NULL explanation should go to the end of docs.

  6. +++ b/core/lib/Drupal/Component/Utility/Bytes.php
    @@ -39,4 +39,34 @@ public static function toInt($size) {
    +   * @see format_size
    

    Cannot refer a deprecated function.

  7. +++ b/core/lib/Drupal/Core/Utility/FormatBytesSize.php
    @@ -0,0 +1,53 @@
    +   *   (Optional) Language code to translate to a language other than what is
    

    s/(Optional)/(optional)

claudiu.cristea’s picture

And we should replace all occurrences of format_size().

mondrake’s picture

Assigned: Unassigned » mondrake
Issue tags: -Needs change record

Added draft CR https://www.drupal.org/node/2999981, working on #50

mondrake’s picture

Status: Needs work » Needs review
StatusFileSize
new5.34 KB
new12.41 KB

Thank for review @claudiu.cristea.

#50.1 done
#50.2 done
#50.3 I do not think we need to, 'other manipulations' seems good enough
#50.4,5,6,7 done

added a deprecation test for format_size, too.

Let's see how may deprecation error this gets, probably quite a few. Not sure we should do #52 here. Probably better adding a deprecation listener here and remove usages in a follow up.

mondrake’s picture

StatusFileSize
new33.09 KB
new21.34 KB

With all usages replaced.

mondrake’s picture

Status: Needs work » Needs review
StatusFileSize
new2.53 KB
new33.17 KB

Fix for failure in #55 + CS cleanup.

claudiu.cristea’s picture

Status: Needs review » Needs work

Nice!

  1. +++ b/core/includes/common.inc
    @@ -249,44 +248,14 @@ function check_url($uri) {
    + * @deprecated in Drupal 8.7.0, will be removed before Drupal 9.0.0.
    

    According Drupal core deprecation policy, the CR link should be added also as @see, after @deprecated.

  2. +++ b/core/includes/common.inc
    @@ -249,44 +248,14 @@ function check_url($uri) {
    +  @trigger_error('format_size() is deprecated in Drupal 8.7.0, will be removed before Drupal 9.0.0. Use \Drupal\Core\Utility\FormatBytesSize::format($size, $langcode) instead. See https://www.drupal.org/node/2999981', E_USER_DEPRECATED);
    
    +++ b/core/tests/Drupal/KernelTests/Core/Common/SizeTest.php
    @@ -58,16 +62,27 @@ public function testCommonFormatSize() {
    +   * @expectedDeprecation format_size() is deprecated in Drupal 8.7.0, will be removed before Drupal 9.0.0. Use \Drupal\Core\Utility\FormatBytesSize::format($size, $langcode) instead. See https://www.drupal.org/node/2999981
    

    The message should end with a dot.

  3. +++ b/core/lib/Drupal/Core/Utility/FormatBytesSize.php
    @@ -0,0 +1,55 @@
    +class FormatBytesSize {
    

    I'm not sure about the name FormatBytesSize. What is the generic name to describe something that is measuring in bytes, KB, MB, etc? Sometime is called "filesize" but that would be restrictive. Digital size? I see here https://en.wikipedia.org/wiki/Units_of_information the term "units of information". Or "storage size". For example if we use digital size, the the function call would be DigitalSize::format(), which for me would be more meaningful than FormatBytesSize::format(). StorageSize::format(). No idea :)

mondrake’s picture

Status: Needs work » Needs review
StatusFileSize
new710 bytes
new33.22 KB

#59.1 done
#59.2 not sure... see #2848137-66: Replace all calls to db_update, which is deprecated
#59.3 how about \Drupal\Core\Utility\Bytes::toTranslatableString?

claudiu.cristea’s picture

#59.2 not sure...

I think https://www.drupal.org/core/deprecation is the official reference. And the "official" pattern they are provided there for @trigger_error() ends with a dot.

#59.3: I was thinking on the FormatBytesSize name. When you see in a caller FormatBytesSize::format() it doesn't look great. But it's probably a matter of taste. I'm not insisting to change that.

mondrake’s picture

StatusFileSize
new36.08 KB
new36.08 KB

#59.2 done
#59.3 et later: I also didn't like the naming. Doing here what @catch suggested in #34. Added a Core/Utility/Byte class extending from Component/Utility/Bytes, with a single toTranslatableString method. So FormatBytesSize::format => Bytes::toTranslatableString

mondrake’s picture

StatusFileSize
new29.88 KB

Sorry wrong interdiff in #62, here's the good one.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work

I'm not sure about the direction this patch has taken.

+++ b/core/includes/file.inc
@@ -8,11 +8,11 @@
 use Drupal\Component\FileSystem\FileSystem as ComponentFileSystem;
 use Drupal\Component\Utility\UrlHelper;
 use Drupal\Component\PhpStorage\FileStorage;
-use Drupal\Component\Utility\Bytes;
 use Drupal\Core\File\FileSystem;
 use Drupal\Core\Site\Settings;
 use Drupal\Core\StreamWrapper\PublicStream;
 use Drupal\Core\StreamWrapper\PrivateStream;
+use Drupal\Core\Utility\Bytes;
 
 /**
  * Default mode for new directories. See drupal_chmod().

Having both Drupal\Component\Utility\Bytes and Drupal\Core\Utility\Bytes seems very weird. And unnecessarily importing the core version is odd too. How about doing something like TranslatableMarkup but as a TranslatableSize? And the new TranslatableSize class could contain all the logic from format_size()?

I think the patch here is unnecessarily complex and introduces new value objects like BytesUnitAndSize for little to no gain. We just have more API to support.

alexpott’s picture

Or do something like date_format()...

function format_date($timestamp, $type = 'medium', $format = '', $timezone = NULL, $langcode = NULL) {
  return \Drupal::service('date.formatter')->format($timestamp, $type, $format, $timezone, $langcode);
}

And introduce a size.formatter service.

mondrake’s picture

Thanks for review @alexpott. I will go for the service then.

alexpott’s picture

+1 and then we get to properly inject the translation service too.

mondrake’s picture

Status: Needs work » Needs review
StatusFileSize
new28.97 KB

Converted to using a byte_count.formatter service and removed the BytesUnitAndSize value object.

No interdiff, it would make no sense given the extent of changes.

alexpott’s picture

Looking at this makes me wonder if we should add this to \Drupal\Core\StringTranslation\TranslationInterface as a formatSize() method. Because it is always being used when you are outputting translated strings to the user. Or maybe we could introduce a new placeholder for FormattableMarkup that does translation for TranslatableMarkup.

Also this code

  $default_max_size = format_size(file_upload_max_size());
  $form['max_size'] = [
    '#type' => 'textfield',
    '#default_value' => $image_upload['max_size'],
    '#title' => t('Maximum file size'),
    '#description' => t('If this is left empty, then the file size will be limited by the PHP maximum upload size of @size.', ['@size' => $default_max_size]),
    '#maxlength' => 20,
    '#size' => 10,
    '#placeholder' => $default_max_size,
    '#states' => $show_if_image_uploads_enabled,
  ];

Is wrong. Because you need to enter a valid PHP file size so it shouldn't be translated. So this is an actual place where we should use new thing added to the utility. But that's not returning anything in a useful format.

  1. +++ b/core/lib/Drupal/Component/Utility/Bytes.php
    @@ -39,4 +39,33 @@ public static function toInt($size) {
    +    if ($size < 0) {
    +      return NULL;
    +    }
    

    This is odd. And an API change - before if you passed a negative number this would not happen.

  2. +++ b/core/tests/Drupal/KernelTests/Core/Common/SizeTest.php
    @@ -33,6 +34,8 @@ protected function setUp() {
    +      // Not 3.78 GB as before #2157945.
    +      '3.77 GB' => 4053371676,
    

    This is mixing a bugfix with a refactor which is never the right thing to do.

mondrake’s picture

Assigned: mondrake » Unassigned
Status: Needs review » Postponed

Let’s fix the bug first then, instead of refactoring it... :)

mondrake’s picture

Status: Active » Needs review
StatusFileSize
new27.83 KB
new1.13 KB

For now, just a reroll of #71 to see if it still passes. #72 next.

mondrake’s picture

Status: Needs work » Needs review
StatusFileSize
new28.41 KB
new6.65 KB

Dropping the Bytes::toUnitAndSize method in favour of Bytes::toString, stealing from @longwave patch at #3001402-2: editor_image_upload_settings_form() is wrongly translating the max file size.

voleger’s picture

+++ b/core/lib/Drupal/Component/Utility/Bytes.php
@@ -39,4 +39,33 @@ public static function toInt($size) {
+    $absolute_size = abs($size);
+    if ($absolute_size < Bytes::KILOBYTE) {
+      return $size . ' B'];
+    }
+    // Create a multiplier to preserve the sign of $size.

return $size . ' B'];
Needs more attention

mondrake’s picture

Status: Needs work » Needs review
StatusFileSize
new28.43 KB
new1.59 KB

Indeed.

andypost’s picture

Status: Needs review » Needs work

Looks great just needs more refactor to inject service and use local variable to cache calls to `\Drupal::service()`

  1. +++ b/core/lib/Drupal/Core/Form/EventSubscriber/FormAjaxSubscriber.php
    @@ -144,13 +144,13 @@ protected function getFormAjaxException(\Exception $e) {
       protected function formatSize($size) {
    -    return format_size($size);
    +    return \Drupal::service('byte_count.formatter')->format($size);
    

    This should use protected var for caching, and probably update constructor to inject new service but keep BC

  2. +++ b/core/modules/file/file.module
    @@ -382,12 +382,12 @@ function file_validate_size(FileInterface $file, $file_limit = 0, $user_limit =
    +    $errors[] = t('The file is %filesize exceeding the maximum file size of %maxsize.', ['%filesize' => \Drupal::service('byte_count.formatter')->format($file->getSize()), '%maxsize' => \Drupal::service('byte_count.formatter')->format($file_limit)]);
    ...
    +    $errors[] = t('The file is %filesize which would exceed your disk quota of %quota.', ['%filesize' => \Drupal::service('byte_count.formatter')->format($file->getSize()), '%quota' => \Drupal::service('byte_count.formatter')->format($user_limit)]);
    

    Please use local var instead of "disturbing" \Drupal so many times

  3. +++ b/core/modules/file/tests/src/Functional/FileFieldValidateTest.php
    @@ -92,13 +92,13 @@ public function testFileMaxSize() {
    +      $this->assertFileExists($node_file, format_string('File exists after uploading a file (%filesize) under the max limit (%maxsize).', ['%filesize' => \Drupal::service('byte_count.formatter')->format($small_file->getSize()), '%maxsize' => $max_filesize]));
    +      $this->assertFileEntryExists($node_file, format_string('File entry exists after uploading a file (%filesize) under the max limit (%maxsize).', ['%filesize' => \Drupal::service('byte_count.formatter')->format($small_file->getSize()), '%maxsize' => $max_filesize]));
    ...
    +      $error_message = t('The file is %filesize exceeding the maximum file size of %maxsize.', ['%filesize' => \Drupal::service('byte_count.formatter')->format($large_file->getSize()), '%maxsize' => \Drupal::service('byte_count.formatter')->format($file_limit)]);
    +      $this->assertRaw($error_message, format_string('Node save failed when file (%filesize) exceeded the max upload size (%maxsize).', ['%filesize' => \Drupal::service('byte_count.formatter')->format($large_file->getSize()), '%maxsize' => $max_filesize]));
    

    same here

mondrake’s picture

Status: Needs work » Needs review
StatusFileSize
new28.05 KB
new26.57 KB

Re. #72, removed the ByteCountFormatter class and service in favour of a new TranslationInterface::formatSize method.

Leaving service injection suggested in #84 for later.

mondrake’s picture

Issue tags: +Needs issue summary update
StatusFileSize
new4.13 KB
new30.93 KB

Added a formatSize method onto StringTranslationTrait. This way we can get rid of wrapper formatSize methods where we have translatability! Also added formatSize implementation for a test TranslationManager class.

Adding 'needs issue summary update' since IS is now pretty old.

andypost’s picture

Status: Needs work » Needs review
StatusFileSize
new17.13 KB
new33.1 KB

Fix migrate tests + minor clean-ups

andypost’s picture

Title: Convert format_size() to a class » Convert format_size() to a StringTranslationTrait::formatSize()
Status: Needs review » Needs work
Issue tags: +Needs tests

NW for tests

  1. +++ b/core/lib/Drupal/Core/StringTranslation/StringTranslationTrait.php
    @@ -80,6 +80,15 @@ protected function formatPlural($count, $singular, $plural, array $args = [], ar
    +  protected function formatSize($size, $langcode = NULL) {
    +    return $this->getStringTranslation()->formatSize($size, $langcode);
    

    that needs unit test coverage

  2. +++ b/core/lib/Drupal/Core/StringTranslation/TranslationManager.php
    @@ -153,6 +154,44 @@ public function formatPlural($count, $singular, $plural, array $args = [], array
    +  public function formatSize($size, $langcode = NULL) {
    

    new method also needs tests

  3. +++ b/core/modules/user/tests/src/Unit/PermissionHandlerTest.php
    @@ -460,4 +461,42 @@ public function formatPlural($count, $singular, $plural, array $args = [], array
    +  public function formatSize($size, $langcode = NULL) {
    +    $options = ['langcode' => $langcode];
    

    This duplicate of implementation still looks weird but I have no idea how to get rid of it, maybe mocking

jofitz’s picture

Assigned: Unassigned » jofitz
Status: Needs work » Needs review
StatusFileSize
new32.16 KB

Patch from #89 no longer applies. Re-rolled.

mondrake’s picture

Assigned: mondrake » Unassigned
StatusFileSize
new1.86 KB
new34.24 KB

Adding unit test for TranslationManager::formatSize.

mondrake’s picture

Issue tags: -Needs tests
StatusFileSize
new34.79 KB
new3.69 KB

#92.1 - added test coverage for StringTranslationTrait::formatSize
#92.3 - removed the duplicate implementation, just return the $size argument should be enough for the purposes of this test

mondrake’s picture

Status: Needs work » Needs review
Issue tags: -PHPUnit
StatusFileSize
new34.9 KB

Rerolled.

claudiu.cristea’s picture

Nits & a question.

  1. +++ b/core/includes/common.inc
    @@ -249,48 +247,16 @@ function check_url($uri) {
    + * @deprecated in Drupal 8.7.0, will be removed before Drupal 9.0.0. Use
    + *   \Drupal::translation()->formatSize($size, $langcode)
    + *   instead.
    

    The "instead" word can go one line up.

  2. +++ b/core/includes/common.inc
    @@ -249,48 +247,16 @@ function check_url($uri) {
    +  @trigger_error('format_size() is deprecated in Drupal 8.7.0, will be removed before Drupal 9.0.0. Use \\Drupal::translation()->formatSize($size, $langcode) instead. See https://www.drupal.org/node/2999981.', E_USER_DEPRECATED);
    

    Within single quotes there's no need to escape the backslash (\\Drupal::).

  3. +++ b/core/lib/Drupal/Component/Utility/Bytes.php
    @@ -39,4 +39,33 @@ public static function toInt($size) {
    +  public static function toString($size, $precision = 2) {
    

    I wonder if it's worth considering an external solution such as https://github.com/gabrielelana/byte-units. I have the feeling that we're reinventing the wheel.

  4. +++ b/core/lib/Drupal/Core/StringTranslation/TranslationManager.php
    @@ -153,6 +154,44 @@ public function formatPlural($count, $singular, $plural, array $args = [], array
    +    list($rounded_size, $unit) = explode(' ', Bytes::toString($size), 2);
    

    Not so happy with extracting the value from a formatted string. Normally that value should be provided directly from a API/method/function.

mondrake’s picture

Issue tags: +Needs framework manager review
StatusFileSize
new34.9 KB
new1.09 KB

Thanks @claudiu.cristea.

1. Done
2. Done
3. Very nice... but that would be a dependency addition, probably to be dealt with separately, and require postponing this one on that. I suppose we need a core committer's blessing for that. Adding tag for framework manager review.
4. Earlier patches were returning a value object here instead, but that were required to be dropped in #67.

alexpott’s picture

The dependency addition should definitely separately and probably will prove very tricky because these are translatable strings. For instance google suggests that the Japanese translation from 1mb is 1メガバイト

alexpott’s picture

Done the framework manager review for the dependency addition. Rule of thumb "don't add things in a refactor".

claudiu.cristea’s picture

Status: Needs review » Reviewed & tested by the community

OK with that. Just a note: I was not referring to the translatable part but to the component. From my point of view this is ready.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
+++ b/core/lib/Drupal/Component/Utility/Bytes.php
@@ -39,4 +39,33 @@ public static function toInt($size) {
+  /**
+   * Formats a given byte size in IEC binary units.
+   *
+   * @param int $size
+   *   A count of bytes.
+   * @param int $precision
+   *   (optional) the number of decimals to round to. Defaults to 2.
+   *
+   * @return string
+   *   The formatted string, followed by a space and the unit (e.g. "1023 B",
+   *   "2 KB", "5 MB", "10 GB").
+   */
+  public static function toString($size, $precision = 2) {
+    $absolute_size = abs($size);
+    if ($absolute_size < Bytes::KILOBYTE) {
+      return $size . ' B';
+    }
+    // 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, $precision);
+      if ($rounded_size < Bytes::KILOBYTE) {
+        break;
+      }
+    }
+    return ($rounded_size * $sign) . ' ' . $unit;
+  }

Actually I'm not sure about this addition. Providing this means that implementations might use this over the translated version - which would be wrong. Imo this shouldn't be public API.

claudiu.cristea’s picture

Re #107. Yeah, agree. Making it a protected method somewhere, would solve also #102.4.

mondrake’s picture

Status: Needs work » Reviewed & tested by the community
alexpott’s picture

@mondrake that's a fine point. We would need very very clear docs on both methods about when and were they should be used. But on the other hand I thins maybe the simplest thing is to not do this. And in https://www.drupal.org/project/drupal/issues/3001402 provide a langcode of 'en' for the translation to not translate it. We should however add docs to TranslationInterface::formatSize() about when it is appropriate to add a langcode = 'en' option - ie. when you when to suggest a value for php.ini etc...

mondrake’s picture

Assigned: Unassigned » mondrake
Status: Needs review » Needs work

OK, so will remove Bytes::toString and keep the implementation in TranslationManager::formatSize - even a protected method there could be misused.

mondrake’s picture

Status: Needs work » Needs review
StatusFileSize
new35.34 KB
new10.54 KB

Here we go. In the end I sticked to a protected method on TranslationManager, so that we can test it independently.

mondrake’s picture

StatusFileSize
new35.35 KB

Needed a re-roll.

mondrake’s picture

Status: Needs work » Needs review
Issue tags: -Needs reroll
StatusFileSize
new34.23 KB

Rereolled.

mondrake’s picture

StatusFileSize
new35.59 KB
new3.67 KB

Converted additional usages introduced since #115 and updated the deprecation message.

mondrake’s picture

StatusFileSize
new35.59 KB
new787 bytes

Converted a stray getMock.

andypost’s picture

rtbc+1 except

+++ b/core/includes/common.inc
@@ -250,48 +248,15 @@ function check_url($uri) {
+ * @deprecated in drupal:8.8.0 and will be removed before drupal:9.0.0. Use
+ *   \Drupal::translation()->formatSize($size, $langcode) instead.
...
+  @trigger_error('format_size() is deprecated in drupal:8.8.0 and will be removed before drupal:9.0.0. Use \Drupal::translation()->formatSize($size, $langcode) instead. See https://www.drupal.org/node/2999981.', E_USER_DEPRECATED);

+++ b/core/tests/Drupal/KernelTests/Core/Common/SizeTest.php
@@ -57,4 +57,15 @@ public function providerTestCommonFormatSize() {
+   * @expectedDeprecation format_size() is deprecated in drupal:8.8.0 and will be removed before drupal:9.0.0. Use \Drupal::translation()->formatSize($size, $langcode) instead. See https://www.drupal.org/node/2999981.

the format a bit different from #3024461: Adopt consistent deprecation format for core and contrib deprecation messages and phpcs

mondrake’s picture

StatusFileSize
new35.57 KB
new2.01 KB

Adjusted deprecation message according to #123

andypost’s picture

Status: Needs review » Reviewed & tested by the community

CR updates should be done after commit

mondrake’s picture

Status: Needs work » Reviewed & tested by the community
Issue tags: -Needs reroll
StatusFileSize
new36.76 KB
new1.17 KB

Rerolled and changed another usage just introduced.

voleger’s picture

Status: Needs work » Reviewed & tested by the community
Issue tags: -Needs reroll
StatusFileSize
new36.77 KB

Just reroll

mondrake’s picture

Issue summary: View changes

Updated the IS with the current solution.

shashikant_chauhan’s picture

Issue tags: -Needs reroll
StatusFileSize
new36.73 KB

Rerolled the patch.

mondrake’s picture

Status: Needs review » Reviewed & tested by the community

Thanks for the reroll, @shashikant_chauhan

voleger’s picture

Version: 8.9.x-dev » 9.1.x-dev
Status: Reviewed & tested by the community » Needs work

Deprecation message requires updates.
... in drupal:9.1.0 and is removed from drupal:10.0.0.

andypost’s picture

Version: 9.1.x-dev » 9.0.x-dev
Status: Needs work » Needs review
Issue tags: -Needs change record updates
StatusFileSize
new2.62 KB
new36.57 KB

Updated CR https://www.drupal.org/node/2999981/revisions/view/11116408/11659397

And here re-roll with updated core ref

kostyashupenko’s picture

Status: Needs work » Needs review
Issue tags: -Needs reroll
StatusFileSize
new35.44 KB

Reroll against 9.0.x

martin107’s picture

Status: Needs work » Needs review
StatusFileSize
new35.71 KB

Just a reroll.... lots of automerging .. no conflicts

martin107’s picture

StatusFileSize
new39.31 KB
new3.6 KB

A little fixup.

martin107’s picture

Issue tags: -Needs reroll
StatusFileSize
new38.01 KB
new38.01 KB

The problem :-

In system.install system_requirements() -- the container is not yet available. That old chestnut.

\Drupal::translation() returns null .. and errors

While I think about ways to get correctness .. I am just backing out that change.
Other changes in 146 are correctly.

martin107’s picture

StatusFileSize
new1.31 KB

Here is the interdiff.

martin107’s picture

Status: Needs work » Needs review
StatusFileSize
new39.23 KB
new3.6 KB

fewer failing tests.

longwave’s picture

Status: Needs work » Needs review
Issue tags: -Needs reroll
StatusFileSize
new38.37 KB
daffie’s picture

Status: Needs review » Reviewed & tested by the community

The function format_size() is being deprecated.
A @trigger_error() is added to the function.
A deprecation message test is added for the @trigger_error().
The functionality is being moved to the method Drupal/Core/StringTranslation/TranslationManager::formatSize() and the helper method Drupal/Core/StringTranslation/TranslationManager::bytesToSizeAndUnit().
For both methods is testing added.
The main method is added to the interface Drupal/Core/StringTranslation/TranslationInterface.
All function calls to format_size() have been replaced.
All changes look good to me.
Their is an CR added and it looks good to me.
For me it is RTBC.

martin107’s picture

Status: Needs work » Needs review
Issue tags: -Needs reroll
StatusFileSize
new38.35 KB

Reroll, no conflicts just automerging.

andypost’s picture

Status: Needs work » Needs review
Issue tags: -Needs reroll
StatusFileSize
new2.76 KB
new38.39 KB

Re-roll and added types to arguments of new method

andypost’s picture

StatusFileSize
new1.13 KB
new38.4 KB

Missed to fix translation manager

andypost’s picture

The change to int was wrong, it can accept floats and strings (as number)
moreover https://wiki.php.net/rfc/string_to_number_comparison is mostly accepted

mondrake’s picture

Status: Needs work » Reviewed & tested by the community
Issue tags: +Needs framework manager review
StatusFileSize
new38.23 KB

Plain reroll of #156. This issue has been hopping on and off the RTBC queue for the last year. I wonder what's preventing commit.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
  1. So one consideration we have to make here is that every class that uses StringTranslationTrait is suddenly going to get a new method. At least for contrib it looks like this will break one contrib module see - http://codcontrib.hank.vps-private.net/search?text=function+formatSize&f... and http://codcontrib.hank.vps-private.net/node/30322124

    Given the tiny number of usages of this method in core I'd be tempted to not add this method to the trait in this issue and call $this->getStringTranslation()->formatSize() instead.

  2. +++ b/core/lib/Drupal/Core/StringTranslation/StringTranslationTrait.php
    @@ -80,6 +80,15 @@ protected function formatPlural($count, $singular, $plural, array $args = [], ar
    +  /**
    +   * Generates a string representation for the given byte count.
    +   *
    +   * @see \Drupal\Core\StringTranslation\TranslationInterface::formatSize()
    +   */
    +  protected function formatSize($size, $langcode = NULL) {
    

    We need to add:

    • @param docs
    • typehints for param and return
    • @return docs
  3. +++ b/core/lib/Drupal/Core/StringTranslation/TranslationInterface.php
    @@ -109,4 +109,25 @@ public function translateString(TranslatableMarkup $translated_string);
    +   * @param int $size
    +   *   A size in bytes.
    

    '1 GB' is not an int.

  4. +++ b/core/lib/Drupal/Core/StringTranslation/TranslationInterface.php
    @@ -109,4 +109,25 @@ public function translateString(TranslatableMarkup $translated_string);
    +   * @return \Drupal\Core\StringTranslation\TranslatableMarkup|\Drupal\Core\StringTranslation\PluralTranslatableMarkup
    +   *   A translated string representation of the size.
    +   */
    +  public function formatSize($size, $langcode = NULL);
    

    We to add typehints - probably just for langcode. $size can be a string, int or float. I think we can add a return typehint of TranslatableMarkup because PluralTranslatableMarkup inherits from that.

  5. +++ b/core/lib/Drupal/Core/StringTranslation/TranslationManager.php
    @@ -153,6 +154,74 @@ public function formatPlural($count, $singular, $plural, array $args = [], array
    +  protected function bytesToSizeAndUnit($size, $precision = 2) {
    

    This was added in #36 without explanation. Is this expansion of API necessary here? I'm not convinced and can't find any explanation of why on the issue. Why isn't this inlined as before? If we add this anywhere it should be on the Bytes class - as this method has nothing to do with translation (in and of itself). But then people might be tempted to use it when really we want people to use the translated string. I think this should be inlined again unless there is a concrete reason.

    If we do add this we need scalar typehints and a return typehint.

  6. +++ b/core/tests/Drupal/Tests/Component/Utility/BytesTest.php
    @@ -17,7 +17,7 @@ class BytesTest extends TestCase {
    -   * @param int $size
    +   * @param string $size
    

    Out-of-scope here. This change is not touching Bytes::toInt()

  7. Lastly - given we're refactoring I think we should ask if formatSize() is a good name. There are many sizes - tshirt sizes and query counts to give examples that are both sizes but should never be passed to this method. Perhaps we should take this opportunity to improve upon the name. formatByteSize() for example is more descriptive.
mondrake’s picture

#168.5 I vaguely remember discussions at the time on another issue to allow different precisions in the formatting, but yea, oos here. I think I went for a separate method to allow testing it separately - I guess it can be reverted.

#168.7 that was kinda suggested earlier around #58-ish, too.

andypost’s picture

Assigned: Unassigned » andypost
StatusFileSize
new5.27 KB
new37.86 KB

Here's fixes for type-hints 161-162 with fix #168 (3, 4, 6)

Working on rename formatByteSize()

alexpott’s picture

+++ b/core/lib/Drupal/Core/StringTranslation/TranslationInterface.php
@@ -119,15 +119,15 @@ public function formatPlural($count, $singular, $plural, array $args = [], array
-   * @param int $size
+   * @param int|float|string $size

Whoops I got this wrong. I was thinking of bytes::toInt() which is kinda the opposite of this. This actually is an int I think. Sorry.

andypost’s picture

Assigned: andypost » Unassigned
Status: Needs work » Needs review
StatusFileSize
new33 KB
new42.3 KB

Here's a rename, let's see what bot will say, will explore more strict interface tomorrow

@alexpott As #162 tests show it's not always int, not sure about float but it could be numeric string

andypost’s picture

Yes, $size is passed as float as well in tests at least (otherwise it can't fit into big int)

EDIT Ref https://www.php.net/manual/en/language.types.integer.php#language.types....

For file item test the fix is type cast database value to int because db-layer returns ints as strings

--- a/core/modules/file/file.module
+++ b/core/modules/file/file.module
@@ -1489,7 +1489,7 @@ function template_preprocess_file_link(&$variables) {
   // Set file classes to the options array.
   $variables['attributes'] = new Attribute($variables['attributes']);
   $variables['attributes']->addClass($classes);
-  $variables['file_size'] = \Drupal::translation()->formatByteSize($file->getSize());
+  $variables['file_size'] = \Drupal::translation()->formatByteSize((int) $file->getSize());
 
   $variables['link'] = Link::fromTextAndUrl($link_text, Url::fromUri($url, $options))->toRenderable();
 }
andypost’s picture

Status: Needs work » Needs review
StatusFileSize
new1.09 KB
new42.78 KB

Fix broken test

alexpott’s picture

@andypost ah yeah - i see. If we had union types I think we'd have int|float here - because it does need to be a number type. See the docs for abs().

mondrake’s picture

Status: Needs review » Needs work

Thanks @andypost

  1. +++ b/core/lib/Drupal/Core/StringTranslation/StringTranslationTrait.php
    @@ -80,6 +80,24 @@ protected function formatPlural($count, $singular, $plural, array $args = [], ar
    +   * @param string|null $langcode
    +   *   (optional) Language code to translate to a language other than what is
    +   *   used to display the page.
    +   *
    +   * @return \Drupal\Core\StringTranslation\TranslatableMarkup
    +   *   A translated string representation of the size.
    +   *
    +   * @see \Drupal\Core\StringTranslation\TranslationInterface::formatByteSize()
    +   */
    +  protected function formatByteSize($size, string $langcode = NULL): TranslatableMarkup {
    +    return $this->getStringTranslation()->formatByteSize($size, $langcode);
    +  }
    

    Do we then agree to keep the method on the trait, re. #168.1? In any case, AFAIK, if we typehint string $langcode = NULL, we cannot pass a NULL to $langcode - it's only going to be initialized to NULL if the argument is missing. Different would be if we typehinted ?string $langcode = NULL, in that case it is possible to pass a null argument. So the doc is incorrect, it should be @param string $langcode.

  2. +++ b/core/lib/Drupal/Core/StringTranslation/TranslationInterface.php
    @@ -109,4 +109,25 @@ public function translateString(TranslatableMarkup $translated_string);
    +  /**
    +   * Generates a translated string representation for the given byte count.
    +   *
    +   * In some use cases, a size in IEC units (like for example 1 MB, 256 KB,
    +   * etc.) must not be translated to local language. This is the case for
    +   * writing a value in configuration files or objects (php.ini or others),
    +   * and when it is required to enter a value in a form (e.g. to indicate a
    +   * maximum file size). In such cases, this method should be called with an
    +   * 'en' $langcode parameter to keep the value language agnostic.
    +   *
    +   * @param int|float|string $size
    +   *   A size in bytes.
    +   * @param string|null $langcode
    +   *   (optional) Language code to translate to a language other than what is
    +   *   used to display the page.
    +   *
    +   * @return \Drupal\Core\StringTranslation\TranslatableMarkup
    +   *   A translated string representation of the size.
    +   */
    +  public function formatByteSize($size, string $langcode = NULL): TranslatableMarkup;
    +
    

    same as above (for the $langcode typehint)

  3. +++ b/core/lib/Drupal/Core/StringTranslation/TranslationManager.php
    @@ -153,6 +154,74 @@ public function formatPlural($count, $singular, $plural, array $args = [], array
    +  /**
    +   * Given a byte size, returns it in IEC binary units.
    +   *
    +   * @param int|float|string $size
    +   *   A count of bytes.
    +   * @param int $precision
    +   *   (optional) the number of decimals to round to. Defaults to 2.
    +   *
    +   * @return array
    +   *   A simple array, containing the size rounded to the highest IEC unit,
    +   *   and the IEC unit itself (e.g. [1023, 'B'], [2, 'KB'], [5, 'MB'], [10,
    +   *   'GB']).
    +   */
    +  protected function bytesToSizeAndUnit($size, int $precision = 2): array {
    

    should be removed and its code inlined per #168.5

  4. +++ b/core/tests/Drupal/Tests/Core/StringTranslation/TranslationManagerTest.php
    @@ -98,6 +144,67 @@ public function providerTestTranslatePlaceholder() {
    +  /**
    +   * Tests TranslationManager::testBytesToSizeAndUnit().
    +   *
    +   * @param array $expected
    +   *   The expected return value from
    +   *   TranslationManager::testBytesToSizeAndUnit().
    +   * @param int $size
    +   *   The value for the size argument for
    +   *   TranslationManager::testBytesToSizeAndUnit().
    +   * @param int $precision
    +   *   (Optional) the value for the precision argument for
    +   *   TranslationManager::testBytesToSizeAndUnit. Defaults to 2.
    +   *
    +   * @dataProvider providerTestBytesToSizeAndUnit
    +   */
    +  public function testBytesToSizeAndUnit(array $expected, $size, $precision = 2) {
    +    $translation_manager = $this->createMock(TranslationManager::class);
    +    $method = new \ReflectionMethod(get_class($translation_manager), 'bytesToSizeAndUnit');
    +    $method->setAccessible(TRUE);
    +    $this->assertSame($expected, $method->invoke($translation_manager, $size, $precision));
    +  }
    +
    +  /**
    +   * Provides data for testBytesToSizeAndUnit.
    +   *
    +   * @return array
    +   *   An array of arrays, each containing the argument for
    +   *   TranslationManager::testBytesToSizeAndUnit: expected return array,
    +   *   input size, input precision.
    +   */
    +  public function providerTestBytesToSizeAndUnit() {
    +    return [
    +      [['0', 'B'], 0],
    +      [['1', 'B'], 1],
    +      [['-1', 'B'], -1],
    +      [['1023', 'B'], Bytes::KILOBYTE - 1],
    +      [['1', 'KB'], Bytes::KILOBYTE],
    +      [['1', 'MB'], pow(Bytes::KILOBYTE, 2)],
    +      [['1', 'MB'], pow(Bytes::KILOBYTE, 2) - 1],
    +      [['-1', 'MB'], -(pow(Bytes::KILOBYTE, 2) - 1)],
    +      [['1', 'GB'], pow(Bytes::KILOBYTE, 3)],
    +      [['1', 'TB'], pow(Bytes::KILOBYTE, 4)],
    +      [['1', 'PB'], pow(Bytes::KILOBYTE, 5)],
    +      [['1', 'EB'], pow(Bytes::KILOBYTE, 6)],
    +      [['1', 'ZB'], pow(Bytes::KILOBYTE, 7)],
    +      [['1', 'YB'], pow(Bytes::KILOBYTE, 8)],
    +      [['22.39', 'MB'], 23476892],
    +      [['76', 'MB'], 79691776],
    +      [['1024', 'YB'], pow(Bytes::KILOBYTE, 9)],
    +      [['3.46', 'MB'], 3623651],
    +      [['3.8', 'GB'], 4053837095, 1],
    +      [['3.78', 'GB'], 4053837095, 2],
    +      [['3.775', 'GB'], 4053837095, 3],
    +      [['3.7754', 'GB'], 4053837095, 4],
    +      [['3.77543', 'GB'], 4053837095, 5],
    +      [['59.72', 'PB'], 67234178751368124],
    +      [['194.67', 'YB'], 235346823821125814962843827],
    +      [['76.24', 'GB'], 81862076662],
    +    ];
    +  }
    +
     }
    

    can be dropped when inlining the method's code.

alexpott’s picture

@mondrake see https://3v4l.org/VYaKq - string $langcode = NULL and ?string $langcode are exactly the same (as far as I know).

mondrake’s picture

StatusFileSize
new37.45 KB

#178 thanks. I thought I had this discussion already but it turns out it was in Doctrine/DBAL, not Drupal: https://github.com/doctrine/dbal/pull/2766

Does not really matter here, but I tend to agree if we want the argument to be nullable AND default to NULL, then we should add the ? too.

andypost’s picture

StatusFileSize
new2.24 KB
new42.78 KB

Fix for nullable string, it's already used in core https://git.drupalcode.org/project/drupal/-/blob/9.1.x/core/modules/sear...

Re #176 https://3v4l.org/mdHOv - it consumes any number (stringable numbers as well)

EDIT I was wrong about mixed types https://3v4l.org/Dp4VH

andypost’s picture

Status: Needs work » Needs review
StatusFileSize
new7.54 KB
new39.65 KB

Inlined method, also found strange that "factional bytes"

+      [0.1, NULL, '0.1 bytes'],
+      ['0.6', NULL, '0.6 bytes'],
mondrake’s picture

Status: Needs review » Needs work
  1. +++ b/core/tests/Drupal/Tests/Core/StringTranslation/TranslationManagerTest.php
    @@ -66,6 +67,53 @@ public function testFormatPlural($count, $singular, $plural, array $args, array
    +      ['0', NULL, '0 bytes'],
    

    We should pass 0 not '0', also later for '0.6'. Let's respect the types.

  2. +++ b/core/tests/Drupal/Tests/Core/StringTranslation/TranslationManagerTest.php
    @@ -66,6 +67,53 @@ public function testFormatPlural($count, $singular, $plural, array $args, array
    +      [0.1, NULL, '0.1 bytes'],
    +      ['0.6', NULL, '0.6 bytes'],
    

    I think this is just a bug now, we should not have fractions of bytes... should be '0 bytes' in both cases I would say.

  3. +++ b/core/tests/Drupal/Tests/Core/StringTranslation/TranslationManagerTest.php
    @@ -66,6 +67,53 @@ public function testFormatPlural($count, $singular, $plural, array $args, array
    +    $this->assertSame(is_null($langcode) ? '' : $langcode, $result->getOption('langcode'));
    

    can we use $langcode ?? '' instead of is_null($langcode) ? '' : $langcode?

  4. +++ b/core/tests/Drupal/KernelTests/Core/Common/SizeTest.php
    @@ -57,4 +57,15 @@ public function providerTestCommonFormatSize() {
    +  public function testFormatSizeDeprecation() {
    

    : void return typehint

  5. +++ b/core/tests/Drupal/Tests/Core/StringTranslation/StringTranslationTraitTest.php
    @@ -68,4 +72,20 @@ public function testFormatPlural() {
    +  public function testFormatByteSize() {
    

    same

  6. +++ b/core/tests/Drupal/Tests/Core/StringTranslation/TranslationManagerTest.php
    @@ -66,6 +67,53 @@ public function testFormatPlural($count, $singular, $plural, array $args, array
    +  public function providerTestFormatByteSize() {
    

    : array return typehint

  7. +++ b/core/tests/Drupal/Tests/Core/StringTranslation/TranslationManagerTest.php
    @@ -66,6 +67,53 @@ public function testFormatPlural($count, $singular, $plural, array $args, array
    +  public function testFormatByteSize($size, $langcode, $expected) {
    

    public function testFormatByteSize(int $size, string $langcode, string $expected): void {

andypost’s picture

Re #182
1) see #180 about strings and numbers - it's just extra test coverage
2) that's BC and not sure how to deal with it
Remains will address, thanks!

andypost’s picture

Status: Needs work » Needs review
StatusFileSize
new4.82 KB
new39.88 KB

Fix for #182 (except 2 point) - if we round/ceil/floor it to int then new method breaks BC

Also cleaned a bit doc blocks

andypost’s picture

Title: Convert format_size() to a TranslationInterface::formatSize() method and a StringTranslationTrait::formatSize() helper » Convert format_size() to a TranslationInterface::formatByteSize() method and a StringTranslationTrait::formatSize() helper
Issue summary: View changes
StatusFileSize
new748 bytes
new40.03 KB

Add more refs to deprecated function and fix title/summary with new name

mondrake’s picture

IMHO

1) we should file a follow-up to fix the bug in #182.2 - yeah let's not fix a bug in a refactor, but a file size of "345.56 bytes" does not make sense
2) we might consider a conditional deprecation to trigger an error if $size is a string, to be replaced in D10 by an \InvalidArgumentException. That way when time comes we may typehint $size to int|float in PHP8+
3)

  1. +++ b/core/tests/Drupal/Tests/Core/StringTranslation/TranslationManagerTest.php
    @@ -66,6 +67,57 @@ public function testFormatPlural($count, $singular, $plural, array $args, array
    +   * @param int $size
    

    int|float|string

  2. +++ b/core/tests/Drupal/Tests/Core/StringTranslation/TranslationManagerTest.php
    @@ -66,6 +67,57 @@ public function testFormatPlural($count, $singular, $plural, array $args, array
    +  public function testFormatByteSize($size, $langcode, $expected): void {
    

    ?string $langcode, string $expected

mondrake’s picture

Issue summary: View changes
andypost’s picture

Status: Needs work » Needs review
StatusFileSize
new1.59 KB
new40.19 KB

Filed follow-up and added TODO #3161118: Make \Drupal\Core\StringTranslation\TranslationManager::formatByteSize() to return integer amount of bytes
Fixed #188 but #188.1 is wrong about string, it expected to be int|float numeric strings are valid float and integeres are part of PHP, see union types at https://3v4l.org/Dp4VH

mondrake’s picture

Status: Needs review » Reviewed & tested by the community

Thanks @andypost - re. #188.3.1 the point is that in the dataprovider one of the input records has ‘0.6’ as $size which is a string. But OK, rather minor one this one.

andypost’s picture

Related issues:

One more related to conversion, which exposes one more rounding issue

mondrake’s picture

StatusFileSize
new40.2 KB
new903 bytes

Reroll.

mondrake’s picture

Status: Needs work » Needs review
StatusFileSize
new943 bytes
new39.97 KB

Let's hope this gets in sometime (#165)... Rerolled.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 197: 2157945-197.patch, failed testing. View results

ankithashetty’s picture

Status: Needs work » Needs review
Issue tags: -Needs reroll
StatusFileSize
new39.79 KB
new4.78 KB

Re-rolled the patch in #197. Thanks!

ankithashetty’s picture

Status: Reviewed & tested by the community » Needs review
StatusFileSize
new39.8 KB
new3.91 KB

Re-rolled the patch in #203...Thank you!

andypost’s picture

Status: Needs work » Needs review
StatusFileSize
new1.48 KB
new40.1 KB

Fixed following review, last reroll made first 2 points wrong

  1. +++ b/core/modules/file/file.module
    @@ -918,7 +925,10 @@ function _file_save_upload_single(\SplFileInfo $file_info, $form_field_name, $va
    -      \Drupal::messenger()->addError(t('The file %file could not be saved because it exceeds %maxsize, the maximum allowed size for uploads.', ['%file' => $original_file_name, '%maxsize' => format_size(Environment::getUploadMaxSize())]));
    ...
    +          '%file' => $file_info->getFilename(),
    

    This change is wrong and broke test

  2. +++ b/core/modules/file/file.module
    @@ -1192,7 +1202,7 @@ function file_tokens($type, $tokens, array $data, array $options, BubbleableMeta
    -          $replacements[$original] = format_size($file->getSize());
    +          $replacements[$original] = \Drupal::translation()->formatByteSize($file->getSize());
    

    should be moved out of loop

  3. +++ b/core/modules/file/src/Controller/FileWidgetAjaxController.php
    @@ -2,12 +2,14 @@
     class FileWidgetAjaxController {
    +  use StringTranslationTrait;
    

    that's tricky about BC but should be fine

andypost’s picture

Status: Needs work » Needs review
StatusFileSize
new1016 bytes
new40.1 KB
catch’s picture

Status: Reviewed & tested by the community » Needs work
  1. +++ b/core/lib/Drupal/Core/StringTranslation/TranslationInterface.php
    @@ -109,4 +109,25 @@ public function translateString(TranslatableMarkup $translated_string);
     
    +  /**
    +   * Generates a translated string representation for the given byte count.
    +   *
    +   * In some use cases, a size in IEC units (like for example 1 MB, 256 KB,
    +   * etc.) must not be translated to local language. This is the case for
    +   * writing a value in configuration files or objects (php.ini or others),
    +   * and when it is required to enter a value in a form (e.g. to indicate a
    +   * maximum file size). In such cases, this method should be called with an
    +   * 'en' $langcode parameter to keep the value language agnostic.
    +   *
    +   * @param int|float $size
    +   *   A size in bytes.
    +   * @param string|null $langcode
    +   *   (optional) Language code to translate to a language other than what is
    +   *   used to display the page.
    +   *
    +   * @return \Drupal\Core\StringTranslation\TranslatableMarkup
    +   *   A translated string representation of the size.
    +   */
    +  public function formatByteSize($size, ?string $langcode = NULL): TranslatableMarkup;
    +
    

    Discussed this with @alexpott and we think there's a way to avoid introducing the additional API surface here.

    format_size() is only used in string translations. So instead of manually calling a method on the arguments to t(), could we look at adding a new placeholder in translated strings - we'd then pass the raw bytes as argument and let the translation system do the conversion via the placeholder. Would mean all the logic staying in a protected method instead of a public one.

    If we were to do that later, we'd need to then deprecate the new methods added here, so it seems worth trying to address here if we can.

  2. +++ b/core/modules/file/file.module
    @@ -350,15 +350,22 @@ function file_validate_extensions(FileInterface $file, $extensions) {
     
       if ($file_limit && $file->getSize() > $file_limit) {
    -    $errors[] = t('The file is %filesize exceeding the maximum file size of %maxsize.', ['%filesize' => format_size($file->getSize()), '%maxsize' => format_size($file_limit)]);
    +    $errors[] = t('The file is ^filesize exceeding the maximum file size of ^maxsize.', [
    +      '^filesize' => $file->getSize(),
    +      '^maxsize' => $file_limit,
    +    ]);
       }
     
    

    The actual change for developers then looks something like this. One disadvantage is this changes the translated strings, but since we'd only change this in a minor release anyway that's not a problem.

    Note that ^placeholder isn't really a suggestion, it's just to have something to look at.

andypost’s picture

Status: Needs work » Needs review
StatusFileSize
new2.15 KB
new40.14 KB

Here's re-roll for 9.2 and re #213

format_size() is only used in string translations

It's mostly for core but it's also used in tokens and render

+++ b/core/modules/file/file.module
@@ -1192,7 +1203,7 @@ function file_tokens($type, $tokens, array $data, array $options, BubbleableMeta
-          $replacements[$original] = format_size($file->getSize());
+          $replacements[$original] = $translation->formatByteSize($file->getSize());

@@ -1486,7 +1497,7 @@ function template_preprocess_file_link(&$variables) {
-  $variables['file_size'] = format_size($file->getSize());
+  $variables['file_size'] = \Drupal::translation()->formatByteSize($file->getSize());

+++ b/core/modules/file/src/Plugin/Field/FieldFormatter/FileSize.php
@@ -33,7 +33,7 @@ public function viewElements(FieldItemListInterface $items, $langcode) {
-      $elements[$delta] = ['#markup' => format_size($item->value)];
+      $elements[$delta] = ['#markup' => $this->formatByteSize($item->value)];

+++ b/core/modules/file/src/Plugin/Field/FieldFormatter/TableFormatter.php
@@ -39,7 +39,7 @@ public function viewElements(FieldItemListInterface $items, $langcode) {
-          ['data' => format_size($file->getSize())],
+          ['data' => $this->formatByteSize($file->getSize())],

There's more usage except translation strings

daffie’s picture

Status: Needs review » Reviewed & tested by the community

Putting the issue back to RTBC, because the proposed fix by @catch and @alexpott does not work. As explained by @andypost in the previous post.

alexpott’s picture

Status: Reviewed & tested by the community » Needs review

I'm not sure I agree with the #214. In fact all those places are still string translations because format_size() always returns an instance of \Drupal\Core\StringTranslation\TranslatableMarkup. For example: $replacements[$original] = format_size($file->getSize()); could be $replacements[$original] = $this-t('#size', ['#size' => $file->getSize()]);

We're need to support %# for placeholdered sizes but that also feels possible and a good thing to solve incase we add support for other placeholders.

andypost’s picture

@alexpott I got your idea, other option could be ByteSizeTranslatableMarkup so auto-escaping will allow % to apply to value

Bringing more "magic" into \Drupal\Component\Render\FormattableMarkup::placeholderFormat() sounds making it more fragile (todo and deprecation already exist in the method)

andypost’s picture

StatusFileSize
new9.1 KB
new42.95 KB

Here's new approach a-la #217 - \Drupal\Core\StringTranslation\ByteSizeMarkup wraps logic

andypost’s picture

StatusFileSize
new522 bytes
new42.74 KB

Fix CS

andypost’s picture

Status: Needs work » Needs review
StatusFileSize
new3.9 KB
new43.3 KB

Fix tests except StringTranslationTraitTest

berdir’s picture

  1. +++ b/core/lib/Drupal/Core/Form/EventSubscriber/FormAjaxSubscriber.php
    @@ -143,16 +145,6 @@ protected function getFormAjaxException(\Exception $e) {
     
    -  /**
    -   * Wraps format_size()
    -   *
    -   * @return string
    -   *   The formatted size.
    -   */
    -  protected function formatSize($size) {
    -    return format_size($size);
    -  }
    -
    

    will need to be kept as a deprecated method.

  2. +++ b/core/lib/Drupal/Core/StringTranslation/StringTranslationTrait.php
    @@ -80,6 +80,22 @@ protected function formatPlural($count, $singular, $plural, array $args = [], ar
    +   * Generates a string representation for the given byte count.
    +   *
    +   * @param int|float $size
    +   *   A size in bytes.
    +   * @param string|null $langcode
    +   *   (optional) Language code to translate to a language other than what is
    +   *   used to display the page.
    +   *
    +   * @return \Drupal\Core\StringTranslation\ByteSizeMarkup
    +   *   A translated string representation of the size.
    +   */
    +  protected function formatByteSize($size, ?string $langcode = NULL): ByteSizeMarkup {
    +    return new ByteSizeMarkup($size, ['langcode' => $langcode], $this->getStringTranslation());
    +  }
    

    This doesn't really feel common enough to be worth adding to this trait.

    If I counted correctly there are 13 calls to this trait method then in core from 7 classes.

    I do agree with @andypost that exposing this (only) as a string translation placeholder feels strange. Additionally might be neat, but I'm sure about adding more magic there, seems like a somewhat unusual pattern to start.

    > For example: $replacements[$original] = format_size($file->getSize()); could be $replacements[$original] = $this-t('#size', ['#size' => $file->getSize()]);

    Yeah, but we don't do translations that consist of nothing but a placeholder, that's pointless, nothing can be translated here. Seems like a very weird pattern to enforce just so we could only have the placeholder thing.

    The class is an interesting idea, but it also feels a bit weird to basically recursively build a TranslatableMarkup object within render() in a subclass of TranslatableMarkup :-/

    We don't need the lazy-translation behavior TranslationMarkup here, so seems like we could just as well make it static method or method on a separate service then.

    Not sure.

  3. +++ b/core/modules/migrate/src/MigrateExecutable.php
    @@ -561,17 +561,4 @@ protected function attemptMemoryReclaim() {
    -  /**
    -   * Generates a string representation for the given byte count.
    -   *
    -   * @param int $size
    -   *   A size in bytes.
    -   *
    -   * @return string
    -   *   A translated string representation of the size.
    -   */
    -  protected function formatSize($size) {
    -    return format_size($size);
    -  }
    

    same.

  4. +++ b/core/modules/user/tests/src/Unit/PermissionHandlerTest.php
    @@ -419,4 +420,11 @@ public function formatPlural($count, $singular, $plural, array $args = [], array
     
    +  /**
    +   * {@inheritdoc}
    +   */
    +  public function formatByteSize($size, string $langcode = NULL): ByteSizeMarkup {
    +    return $size;
    +  }
    

    reminder to remove this once the method is gone from TranslationManager.

  5. +++ b/core/tests/Drupal/Tests/Core/Form/EventSubscriber/FormAjaxSubscriberTest.php
    @@ -166,13 +167,13 @@ public function testOnExceptionBrokenPostRequest() {
             $this->messenger,
           ])
    -      ->setMethods(['formatSize'])
    +      ->setMethods(['formatByteSize'])
           ->getMock();
     
         $this->subscriber->expects($this->once())
    -      ->method('formatSize')
    +      ->method('formatByteSize')
           ->with(32 * 1e6)
    -      ->willReturn('32M');
    +      ->willReturn(new ByteSizeMarkup('32M'));
    

    if we do keep the current trait behavior, that could/should go in \Drupal\Tests\UnitTestCase::getStringTranslationStub() then all of this can be removed.

    If we move it to a separate service then we'll have to mock that directly.

andypost’s picture

  1. +++ b/core/includes/common.inc
    @@ -133,48 +132,17 @@
    + * @deprecated in drupal:9.2.0 and is removed from drupal:10.0.0. Use
    ...
    +  @trigger_error('format_size() is deprecated in drupal:9.2.0 and is removed from drupal:10.0.0. Use \Drupal::translation()->formatByteSize($size, $langcode) instead. See https://www.drupal.org/node/2999981', E_USER_DEPRECATED);
    

    needs update to 9.3

  2. +++ b/core/lib/Drupal/Core/StringTranslation/ByteSizeMarkup.php
    @@ -0,0 +1,125 @@
    +  public function render() {
    +    if (!isset($this->markup)) {
    +      $absolute_size = abs($this->size);
    

    it needs to make sure that size is int or float #3240220-3: \Drupal\file\Entity\File::getSize() can cause deprecations on PHP 8.1

karishmaamin’s picture

Status: Needs work » Needs review
StatusFileSize
new41.83 KB

Re-rolled patch against 9.4.x. Please review

karishmaamin’s picture

StatusFileSize
new41.83 KB
new707 bytes

Fixed custom code failure

alexpott’s picture

Status: Needs work » Needs review
StatusFileSize
new41.11 KB
new40.32 KB
new51.84 KB

After reading @Berdir's feedback in #224 I've moved this patch to generator static method on class pattern. This keeps the code very similar - format_size() is replaced by ByteSizeMarkup::create() - the method generates the same TranslatableString object as format_size() would. There's no other new API. It's not part of the string translation service or the trait. I think this is about the simplest solution we've got. One thing I ponder is whether Drupal\Core\StringTranslation is the correct place for this. Maybe Drupal\Core\Utility is a better location because the translation aspect is really a secondary effect - the major part of this class and reason for using it is to convert a large number of bytes into something more human friendly.

Also we need 9.4.x and 10.0.x patches - once we've agreed on the approach we should refactor the internals in the 10.0.x patch to leverage the match() function is this will make it much easier to read.

alexpott’s picture

StatusFileSize
new523 bytes
new41.14 KB
new40.35 KB

Fixing the test groups.

alexpott’s picture

Status: Needs work » Needs review
Issue tags: -Needs reroll
StatusFileSize
new2.63 KB
new41.33 KB
new40.54 KB

Fixing the test fails.

alexpott’s picture

One thing I ponder is whether Drupal\Core\StringTranslation is the correct place for this. Maybe Drupal\Core\Utility is a better location because the translation aspect is really a secondary effect - the major part of this class and reason for using it is to convert a large number of bytes into something more human friendly.

Before updating the issue summary and change record with the latest changes I think we should sort this out. The more I think about the more I'm convinced that this belongs outside the translation system. The fact this thing produces translatable strings is an implementation detail. The important this is about converting a large number of bytes into a readable string. Utility is not a bad place for this - we've got a hodge-podge of things in there like TableSort - which is not that dissimilar - it's a helper for rendering sortable tables with only static methods.

bhanu951’s picture

Status: Needs work » Needs review
Issue tags: -Needs reroll +Needs change record updates
StatusFileSize
new26.47 KB

Rerolled Patch 2157945-236.patch for 10.1.x branch.

Seems it needs Draft CR Update as well.

If it is not going to make in 10.0 we need to update depreciated message as well.

bhanu951’s picture

Assigned: bhanu951 » Unassigned
spokje’s picture

Status: Needs review » Needs work

Reroll failed.

Besides that, let's first get a consensus on #237 before we start throwing code at this.

One thing I ponder is whether Drupal\Core\StringTranslation is the correct place for this. Maybe Drupal\Core\Utility is a better location because the translation aspect is really a secondary effect - the major part of this class and reason for using it is to convert a large number of bytes into something more human friendly.

Before updating the issue summary and change record with the latest changes I think we should sort this out. The more I think about the more I'm convinced that this belongs outside the translation system. The fact this thing produces translatable strings is an implementation detail. The important this is about converting a large number of bytes into a readable string. Utility is not a bad place for this - we've got a hodge-podge of things in there like TableSort - which is not that dissimilar - it's a helper for rendering sortable tables with only static methods.

andypost’s picture

Status: Needs work » Needs review

Looks code changes are ready, what's left to polish except change record?

...hiding files as MR has latest changes to review

bhanu951’s picture

@andypost

what's left to polish except change record?

There is one review comment, can you pls provide your's feedback on it ?

   core/lib/Drupal/Core/StringTranslation/ByteSizeMarkup.php

  /**
   * Gets the TranslatableMarkup object for the provided size.
   *
   * @return \Drupal\Core\StringTranslation\PluralTranslatableMarkup|\Drupal\Core\StringTranslation\TranslatableMarkup
   *   The translatable markup.
   */
  public static function create($size, string $langcode = NULL, TranslationInterface $stringTranslation = NULL): TranslatableMarkup {


Oleh Vehera
Missing documentation for arguments. What is the type of $size argument? Which values are allowed?

Bhanu951
I think $size can be either float or NULL ?

bhanu951’s picture

One more discussion we need to make is where the class should be placed as commented in #237

From @alexpott :

One thing I ponder is whether Drupal\Core\StringTranslation is the correct place for this. Maybe Drupal\Core\Utility is a better location because the translation aspect is really a secondary effect - the major part of this class and reason for using it is to convert a large number of bytes into something more human friendly.

Before updating the issue summary and change record with the latest changes I think we should sort this out. The more I think about the more I'm convinced that this belongs outside the translation system. The fact this thing produces translatable strings is an implementation detail. The important this is about converting a large number of bytes into a readable string. Utility is not a bad place for this - we've got a hodge-podge of things in there like TableSort - which is not that dissimilar - it's a helper for rendering sortable tables with only static methods.

mstrelan’s picture

Status: Needs review » Needs work

Added some comments to the MR. More importantly we need to update the title as it no longer reflects the implementation.

needs-review-queue-bot’s picture

Status: Needs review » Needs work
StatusFileSize
new21.93 KB

The Needs Review Queue Bot tested this issue. It fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".

Apart from a re-roll or rebase, this issue may need more work to address feedback in the issue or MR comments. To progress an issue, incorporate this feedback as part of the process of updating the issue. This helps other contributors to know what is outstanding.

Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.

kim.pepper’s picture

Needs an IS update as we are now calling \Drupal\Core\StringTranslation\ByteSizeMarkup::create() instead of TranslationInterface::formatByteSize()

kim.pepper’s picture

Issue summary: View changes
kim.pepper’s picture

Addressed most of the feedback. Still have to look at while \Drupal\Tests\file\Functional\FileFieldWidgetTest::testMaximumUploadFileSizeValidation() is failing because the value isn't being trimmed.

smustgrave’s picture

Removing credit from myself as all I did was a rebase to run the tests.

smustgrave’s picture

@kim.pepper I ran the test locally without the space around 5.1 megabytes and they pass. Are they just failing here?

And is that a stopper for this?

kim.pepper’s picture

Looks like those tests are passing now? Not sure why they were failing before.

smustgrave’s picture

Status: Needs review » Reviewed & tested by the community

Going to go ahead and mark but if that one change could be reverted back (if it matters at all)

zeeshan_khan made their first commit to this issue’s fork.

andypost’s picture

Status: Needs review » Reviewed & tested by the community

I think it ready as all feedback addressed

Meantime the main worries are about strong type requirement for function create(float|int $size,...) but
As All tests passing we can get more feedback (and address it) withing 10.2 cycle so contrib and custom can fix it properly

andypost’s picture

Checked uploadprogress code and it returns values as strings (probably will need type-cast) but can't test if it fails or throws deprecation, see https://github.com/php/pecl-php-uploadprogress/blob/master/uploadprogres...

In related there's APCu replacement #1561866: Add support for built-in PHP session upload progress
Moreover uploadprogress working only with Apache2 server and we have no testing env to be sure

needs-review-queue-bot’s picture

Status: Reviewed & tested by the community » Needs work
StatusFileSize
new90 bytes

The Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".

This does not mean that the patch needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.

Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.

needs-review-queue-bot’s picture

Status: Reviewed & tested by the community » Needs work
StatusFileSize
new90 bytes

The Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".

This does not mean that the patch needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.

Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.

xjm’s picture

This poor issue. Approaching its 10th birthday, and bumping in and out of RTBC for 5 years.

I pruned 135 empty-ish comments (status and metadata changes with no substantive info, test fail comments, etc.) and it still barely renders due to GitLab JS crossposts.

It's also been tagged for framework manager review for 3 years. A couple framework managers have been reviewing it, but not given signoff that I can see. I will reach out to other committers.

Part of the issue is also that it is a total 355 LOC change set, which is pushing the upper bound of reviewability. The conversions could perhaps be moved to a followup to manage the scope? Not going to require that ATM, but let's keep it in mind if this doesn't get signoff and land soon.

  • catch committed a9f3f72e on 11.x
    Issue #2157945 by mondrake, andypost, kim.pepper, Bhanu951, alexpott,...
catch’s picture

Status: Reviewed & tested by the community » Fixed
Issue tags: -Needs framework manager review

I hadn't reviewed this since before it moved to a value object/ByteSizeMarkup c. 2021/2022, it looks so much better using that.

I did think ByteSizeMarkup sounds like a cheeky name for some kind of HTML preprocessor - make your markup bite size! Not an actual problem.

There was one remaining question from @alexpott here about whether it should be in the translation or utility namespace. On the one hand yes it's not actually making things translatable (except in the sense it produces a translatable string), but it does seem extremely closely related to TranslatableMarkup and PluralTranslatableMarkup etc. so this feels fine to me. There haven't been any strong opinions since the question was asked, so I think we should go ahead here, seems 50/50 to me at worst. MarkupInterface and friends are in Drupal\Component\Render so that's definitely not the right place, but had to check.

Committed/pushed to 11.x, thanks!

xjm’s picture

🎉

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.