function LanguageUILanguageNegotiationTest::testUILanguageNegotiation

Tests for language switching by URL path.

File

drupal/core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php, line 75
Definition of Drupal\language\Tests\LanguageUILanguageNegotiationTest.

Class

LanguageUILanguageNegotiationTest
Test UI language negotiation

Namespace

Drupal\language\Tests

Code

function testUILanguageNegotiation() {

  // A few languages to switch to.
  // This one is unknown, should get the default lang version.
  $langcode_unknown = 'blah-blah';

  // For testing browser lang preference.
  $langcode_browser_fallback = 'vi';

  // For testing path prefix.
  $langcode = 'zh-hans';

  // For setting browser language preference to 'vi'.
  $http_header_browser_fallback = array(
    "Accept-Language: {$langcode_browser_fallback};q=1",
  );

  // For setting browser language preference to some unknown.
  $http_header_blah = array(
    "Accept-Language: blah;q=1",
  );

  // This domain should switch the UI to Chinese.
  $language_domain = 'example.cn';

  // Setup the site languages by installing two languages.
  $language = new Language(array(
    'langcode' => $langcode_browser_fallback,
  ));
  language_save($language);
  $language = new Language(array(
    'langcode' => $langcode,
  ));
  language_save($language);

  // We will look for this string in the admin/config screen to see if the
  // corresponding translated string is shown.
  $default_string = 'Configure languages for content and the user interface';

  // Set the default language in order for the translated string to be registered
  // into database when seen by t(). Without doing this, our target string
  // is for some reason not found when doing translate search. This might
  // be some bug.
  drupal_static_reset('language_list');
  $languages = language_list();
  variable_set('language_default', (array) $languages['vi']);

  // First visit this page to make sure our target string is searchable.
  $this
    ->drupalGet('admin/config');

  // Now the t()'ed string is in db so switch the language back to default.
  variable_del('language_default');

  // Translate the string.
  $language_browser_fallback_string = "In {$langcode_browser_fallback} In {$langcode_browser_fallback} In {$langcode_browser_fallback}";
  $language_string = "In {$langcode} In {$langcode} In {$langcode}";

  // Do a translate search of our target string.
  $search = array(
    'string' => $default_string,
    'langcode' => $langcode_browser_fallback,
  );
  $this
    ->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
  $textarea = current($this
    ->xpath('//textarea'));
  $lid = (string) $textarea[0]['name'];
  $edit = array(
    $lid => $language_browser_fallback_string,
  );
  $this
    ->drupalPost('admin/config/regional/translate/translate', $edit, t('Save translations'));
  $search = array(
    'string' => $default_string,
    'langcode' => $langcode,
  );
  $this
    ->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
  $textarea = current($this
    ->xpath('//textarea'));
  $lid = (string) $textarea[0]['name'];
  $edit = array(
    $lid => $language_string,
  );
  $this
    ->drupalPost('admin/config/regional/translate/translate', $edit, t('Save translations'));

  // Configure URL language rewrite.
  variable_set('language_negotiation_url_type', Language::TYPE_INTERFACE);

  // Configure selected language negotiation to use zh-hans.
  $edit = array(
    'selected_langcode' => $langcode,
  );
  $this
    ->drupalPost('admin/config/regional/language/detection/selected', $edit, t('Save configuration'));
  $test = array(
    'language_negotiation' => array(
      LANGUAGE_NEGOTIATION_SELECTED,
    ),
    'path' => 'admin/config',
    'expect' => $language_string,
    'expected_method_id' => LANGUAGE_NEGOTIATION_SELECTED,
    'http_header' => $http_header_browser_fallback,
    'message' => 'SELECTED: UI language is switched based on selected language.',
  );
  $this
    ->runTest($test);

  // An invalid language is selected.
  config('language.negotiation')
    ->set('selected_langcode', NULL)
    ->save();
  $test = array(
    'language_negotiation' => array(
      LANGUAGE_NEGOTIATION_SELECTED,
    ),
    'path' => 'admin/config',
    'expect' => $default_string,
    'expected_method_id' => LANGUAGE_NEGOTIATION_SELECTED,
    'http_header' => $http_header_browser_fallback,
    'message' => 'SELECTED > DEFAULT: UI language is switched based on selected language.',
  );
  $this
    ->runTest($test);

  // No selected language is available.
  config('language.negotiation')
    ->set('selected_langcode', $langcode_unknown)
    ->save();
  $test = array(
    'language_negotiation' => array(
      LANGUAGE_NEGOTIATION_SELECTED,
    ),
    'path' => 'admin/config',
    'expect' => $default_string,
    'expected_method_id' => LANGUAGE_NEGOTIATION_SELECTED,
    'http_header' => $http_header_browser_fallback,
    'message' => 'SELECTED > DEFAULT: UI language is switched based on selected language.',
  );
  $this
    ->runTest($test);
  $tests = array(
    // Default, browser preference should have no influence.
    array(
      'language_negotiation' => array(
        LANGUAGE_NEGOTIATION_URL,
        LANGUAGE_NEGOTIATION_SELECTED,
      ),
      'path' => 'admin/config',
      'expect' => $default_string,
      'expected_method_id' => LANGUAGE_NEGOTIATION_SELECTED,
      'http_header' => $http_header_browser_fallback,
      'message' => 'URL (PATH) > DEFAULT: no language prefix, UI language is default and the browser language preference setting is not used.',
    ),
    // Language prefix.
    array(
      'language_negotiation' => array(
        LANGUAGE_NEGOTIATION_URL,
        LANGUAGE_NEGOTIATION_SELECTED,
      ),
      'path' => "{$langcode}/admin/config",
      'expect' => $language_string,
      'expected_method_id' => LANGUAGE_NEGOTIATION_URL,
      'http_header' => $http_header_browser_fallback,
      'message' => 'URL (PATH) > DEFAULT: with language prefix, UI language is switched based on path prefix',
    ),
    // Default, go by browser preference.
    array(
      'language_negotiation' => array(
        LANGUAGE_NEGOTIATION_URL,
        LANGUAGE_NEGOTIATION_BROWSER,
      ),
      'path' => 'admin/config',
      'expect' => $language_browser_fallback_string,
      'expected_method_id' => LANGUAGE_NEGOTIATION_BROWSER,
      'http_header' => $http_header_browser_fallback,
      'message' => 'URL (PATH) > BROWSER: no language prefix, UI language is determined by browser language preference',
    ),
    // Prefix, switch to the language.
    array(
      'language_negotiation' => array(
        LANGUAGE_NEGOTIATION_URL,
        LANGUAGE_NEGOTIATION_BROWSER,
      ),
      'path' => "{$langcode}/admin/config",
      'expect' => $language_string,
      'expected_method_id' => LANGUAGE_NEGOTIATION_URL,
      'http_header' => $http_header_browser_fallback,
      'message' => 'URL (PATH) > BROWSER: with langage prefix, UI language is based on path prefix',
    ),
    // Default, browser language preference is not one of site's lang.
    array(
      'language_negotiation' => array(
        LANGUAGE_NEGOTIATION_URL,
        LANGUAGE_NEGOTIATION_BROWSER,
        LANGUAGE_NEGOTIATION_SELECTED,
      ),
      'path' => 'admin/config',
      'expect' => $default_string,
      'expected_method_id' => LANGUAGE_NEGOTIATION_SELECTED,
      'http_header' => $http_header_blah,
      'message' => 'URL (PATH) > BROWSER > DEFAULT: no language prefix and browser language preference set to unknown language should use default language',
    ),
  );
  foreach ($tests as $test) {
    $this
      ->runTest($test);
  }

  // Unknown language prefix should return 404.
  variable_set('language_negotiation_' . Language::TYPE_INTERFACE, language_language_negotiation_info());
  $this
    ->drupalGet("{$langcode_unknown}/admin/config", array(), $http_header_browser_fallback);
  $this
    ->assertResponse(404, "Unknown language path prefix should return 404");

  // Set preferred langcode for user to NULL.
  $account = $this->loggedInUser;
  $account->preferred_langcode = NULL;
  $account
    ->save();
  $test = array(
    'language_negotiation' => array(
      LANGUAGE_NEGOTIATION_USER,
      LANGUAGE_NEGOTIATION_SELECTED,
    ),
    'path' => 'admin/config',
    'expect' => $default_string,
    'expected_method_id' => LANGUAGE_NEGOTIATION_SELECTED,
    'http_header' => array(),
    'message' => 'USER > DEFAULT: no preferred user language setting, the UI language is default',
  );
  $this
    ->runTest($test);

  // Set preferred langcode for user to unknown language.
  $account = $this->loggedInUser;
  $account->preferred_langcode = $langcode_unknown;
  $account
    ->save();
  $test = array(
    'language_negotiation' => array(
      LANGUAGE_NEGOTIATION_USER,
      LANGUAGE_NEGOTIATION_SELECTED,
    ),
    'path' => 'admin/config',
    'expect' => $default_string,
    'expected_method_id' => LANGUAGE_NEGOTIATION_SELECTED,
    'http_header' => array(),
    'message' => 'USER > DEFAULT: invalid preferred user language setting, the UI language is default',
  );
  $this
    ->runTest($test);

  // Set preferred langcode for user to non default.
  $account->preferred_langcode = $langcode;
  $account
    ->save();
  $test = array(
    'language_negotiation' => array(
      LANGUAGE_NEGOTIATION_USER,
      LANGUAGE_NEGOTIATION_SELECTED,
    ),
    'path' => 'admin/config',
    'expect' => $language_string,
    'expected_method_id' => LANGUAGE_NEGOTIATION_USER,
    'http_header' => array(),
    'message' => 'USER > DEFAULT: defined prefereed user language setting, the UI language is based on user setting',
  );
  $this
    ->runTest($test);

  // Set preferred admin langcode for user to NULL.
  $account->preferred_admin_langcode = NULL;
  $account
    ->save();
  $test = array(
    'language_negotiation' => array(
      LANGUAGE_NEGOTIATION_USER_ADMIN,
      LANGUAGE_NEGOTIATION_SELECTED,
    ),
    'path' => 'admin/config',
    'expect' => $default_string,
    'expected_method_id' => LANGUAGE_NEGOTIATION_SELECTED,
    'http_header' => array(),
    'message' => 'USER ADMIN > DEFAULT: no preferred user admin language setting, the UI language is default',
  );
  $this
    ->runTest($test);

  // Set preferred admin langcode for user to unknown language.
  $account->preferred_admin_langcode = $langcode_unknown;
  $account
    ->save();
  $test = array(
    'language_negotiation' => array(
      LANGUAGE_NEGOTIATION_USER_ADMIN,
      LANGUAGE_NEGOTIATION_SELECTED,
    ),
    'path' => 'admin/config',
    'expect' => $default_string,
    'expected_method_id' => LANGUAGE_NEGOTIATION_SELECTED,
    'http_header' => array(),
    'message' => 'USER ADMIN > DEFAULT: invalid preferred user admin language setting, the UI language is default',
  );
  $this
    ->runTest($test);

  // Set preferred admin langcode for user to non default.
  $account->preferred_admin_langcode = $langcode;
  $account
    ->save();
  $test = array(
    'language_negotiation' => array(
      LANGUAGE_NEGOTIATION_USER_ADMIN,
      LANGUAGE_NEGOTIATION_SELECTED,
    ),
    'path' => 'admin/config',
    'expect' => $language_string,
    'expected_method_id' => LANGUAGE_NEGOTIATION_USER_ADMIN,
    'http_header' => array(),
    'message' => 'USER ADMIN > DEFAULT: defined prefereed user admin language setting, the UI language is based on user setting',
  );
  $this
    ->runTest($test);

  // Setup for domain negotiation, first configure the language to have domain
  // URL.
  $edit = array(
    "domain[{$langcode}]" => $language_domain,
  );
  $this
    ->drupalPost("admin/config/regional/language/detection/url", $edit, t('Save configuration'));

  // Set the site to use domain language negotiation.
  $tests = array(
    // Default domain, browser preference should have no influence.
    array(
      'language_negotiation' => array(
        LANGUAGE_NEGOTIATION_URL,
        LANGUAGE_NEGOTIATION_SELECTED,
      ),
      'language_negotiation_url_part' => LANGUAGE_NEGOTIATION_URL_DOMAIN,
      'path' => 'admin/config',
      'expect' => $default_string,
      'expected_method_id' => LANGUAGE_NEGOTIATION_SELECTED,
      'http_header' => $http_header_browser_fallback,
      'message' => 'URL (DOMAIN) > DEFAULT: default domain should get default language',
    ),
    // Language domain specific URL, we set the $_SERVER['HTTP_HOST'] in
    // \Drupal\language_test\LanguageTestManager to simulate this.
    array(
      'language_negotiation' => array(
        LANGUAGE_NEGOTIATION_URL,
        LANGUAGE_NEGOTIATION_SELECTED,
      ),
      'language_negotiation_url_part' => LANGUAGE_NEGOTIATION_URL_DOMAIN,
      'language_test_domain' => $language_domain . ':88',
      'path' => 'admin/config',
      'expect' => $language_string,
      'expected_method_id' => LANGUAGE_NEGOTIATION_URL,
      'http_header' => $http_header_browser_fallback,
      'message' => 'URL (DOMAIN) > DEFAULT: domain example.cn should switch to Chinese',
    ),
  );
  foreach ($tests as $test) {
    $this
      ->runTest($test);
  }
}