Problem/Motivation

I had an interesting problem today. I was running a few SimpleTest tests from the admin/config/development/testing page (which, I realize, many people think is a bad idea, but anyway).

In my test site, at that moment, I had locale.module enabled.

The test does a WebTestBase::drupalGet() on an autocomplete page, which returns just a few bytes of data. Inside WebTestBase::curlExec(), it formats a message like this:

   $message_vars = array(
      '@method' => !empty($curl_options[CURLOPT_NOBODY]) ? 'HEAD' : (empty($curl_options[CURLOPT_POSTFIELDS]) ? 'GET' : 'POST'),
      '@url' => isset($original_url) ? $original_url : $url,
      '@status' => $status,
      '@length' => format_size(strlen($this->getRawContent()))
    );
    $message = SafeMarkup::format('@method @url returned @status (@length).', $message_vars);
    $this->assertTrue($this->getRawContent() !== FALSE, $message, 'Browser');
 

So $message part itself would print out fine, but the @length thing is problematic. It calls format_size(), which does this:

if ($size < Bytes::KILOBYTE) {
    return \Drupal::translation()->formatPlural($size, '1 byte', '@count bytes', array(), array('langcode' => $langcode));
  }

In this particular test, $size is less than 1KB, so the result is a PluralTranslatableMarkup object. And when this object tries to do a __toString() to render itself, it does this (in its render() method, which calls its getPluralIndex() method):

protected function getPluralIndex() {
  if (!isset(static::$localeEnabled)) {
    static::$localeEnabled = function_exists('locale_get_plural');
  }
  if (function_exists('locale_get_plural')) {
    return locale_get_plural($this->count, $this->getOption('langcode'));
  }
  return -1;
}

So here's the problem. In my test site, the function locale_get_plural() does exist, so static::$localeEnabled gets value TRUE. However, when locale_get_plural() is called, it does this, somewhere down in the code:

  $plural_formulas = \Drupal::service('locale.plural.formula')->getFormula($langcode);

The problem is that in the test environment, the locale module is not enabled, so that call to \Drupal::service('locale.plural.formula') fails with an exception saying the locale.plural.formula service does not exist.

Obviously this is a bit of an edge case, and not a very critical bug, but I thought I would file it anyway.

It seems like the right fix would be to have PluralTranslatableMarkup check to see if the locale.plural.formula service exists rather than (or in addition to) checking for the existence of the locale_get_plural() function... but whether this is worth doing, I do not know.

Proposed resolution

Not sure.

Remaining tasks

Not sure.

User interface changes

Tests run in UI in Simpletest will work even if Locale module is enabled in the site and not in the test.

API changes

No.

Data model changes

No.

Comments

jhodgdon created an issue. See original summary.

jhodgdon’s picture

Oh. I should also mention that when this happens, the test gets into some kind of infinite loop trying to print this stuff out, and never finishes. It's normally a 2-minute test, and I waited for at least 10 minutes... it seemed to be trying to run itself over and over or else something weird happened in the printing out process or ... no idea, but it never ended.

jhodgdon’s picture

So looking at this piece of code from StringTranslationTrait gives an idea:

protected function getNumberOfPlurals($langcode = NULL) {
  if (\Drupal::hasService('locale.plural.formula')) {
    return \Drupal::service('locale.plural.formula')->getNumberOfPlurals($langcode);
  }
  // We assume 2 plurals if Locale's services are not available.
  return 2;
}

This is what pluralTranslatableMarkup::getPluralIndex() should be doing.

yukare’s picture

jhodgdon’s picture

Status: Active » Closed (duplicate)

Yes, it is a duplicate. Thanks!

jhodgdon’s picture