diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc index b461342..b0f4734 100644 --- a/core/includes/install.core.inc +++ b/core/includes/install.core.inc @@ -1686,39 +1686,129 @@ function install_check_localization_server($uri) { } /** - * Gets the core release version for localization. + * Gets the core release version and release alternatives for localization. * - * In case core has a development version we fall back to the latest stable - * release. e.g. 8.2-dev falls back to 8.1. 8.0-dev falls back to 7.0. Fallback + * In case core is a development version or the translation file for the release + * is not available, fall back to the latest stable release. For example, + * 8.2-dev might fall back to 8.1 and 8.0-dev might fall back to 7.0. Fallback * is required because the localization server only provides translation files * for stable releases. * + * @param string $version + * (optional) Version of core trying to find translation files for. + * * @return array - * Associative array containing 'core' and 'version' of the release. + * Array of release data. Each array element is an associative array with: + * - core: Core compatibility version (e.g., 8.x). + * - version: Release version (e.g., 8.1). */ -function install_get_localization_release() { - if (strpos(\Drupal::VERSION, 'dev')) { - list($version, ) = explode('-', \Drupal::VERSION); - list($major, $minor) = explode('.', $version); - - // Calculate the major and minor release numbers to fall back to. - // E.g. 8.0-dev falls back to 7.0 and 8.2-dev falls back to 8.1. - if ($minor == 0) { - $major--; +function install_get_localization_release($version = \Drupal::VERSION) { + $releases = array(); + $matches = array(); + $info = _install_get_version_info($version); + + // Check if version is a regular stable release (no extra_text: 'rc', 'beta', + // 'dev', etc.) + if (!isset($info['extra_text'])) { + // Potential translation release to use is the same as the version. + $releases[] = array( + 'core' => $info['major'] . '.x', + 'version' => $version, + ); + // Potential translation release alternative to use is a previous minor + // release (e.g., 8.2 falls back to 8.1). + if ($info['minor'] > 0) { + $releases[] = array( + 'core' => $info['major'] . '.x', + 'version' => $info['major'] . '.' . ($info['minor'] - 1), + ); } + // Potential translation release alternative for a .0 version is a previous + // release candidate (e.g., 8.0 falls back to 8.0-rc-1). else { - $minor--; + $releases[] = array( + 'core' => $info['major'] . '.x', + 'version' => $info['major'] . '.0-rc1', + ); } - $release = "$major.$minor"; } else { - $release = \Drupal::VERSION; + switch ($info['extra_text']) { + // For a dev version, a release alternative is the previous point release + // (e.g., 8.2-dev falls back to 8.1). + case 'dev': + if ($info['minor'] >= 1) { + $releases[] = array( + 'core' => $info['major'] . '.x', + 'version' => $info['major'] . '.' . ($info['minor'] - 1), + ); + } + break; + + // For a release candidate, an alternative is the previous release + // candidate (e.g., 8.0-rc2 falls back to 8.0-rc1). + case 'rc': + $releases[] = array( + 'core' => $info['major'] . '.x', + 'version' => $version, + ); + if ($info['extra_number'] >= 2) { + $releases[] = array( + 'core' => $info['major'] . '.x', + 'version' => $info['major'] . '.' . $info['minor'] . '-rc' . ($info['extra_number'] - 1), + ); + } + break; + } } - return array( - 'core' => "$major.x", - 'version' => $release, + // All releases may a fallback to the previous major release (e.g., 8.1 falls + // back to 7.0). + $releases[] = array( + 'core' => $info['major'] - 1 . '.x', + 'version' => $info['major'] - 1 . '.0', ); + + return $releases; +} + +/** + * Extracts version information from a drupal core version string. + * + * @param string $version + * Version info string (e.g., 8.0, 8.1, 8.0-dev, 8.0-unstable1, 8.0-alpha2, + * 8.0-beta3, and 8.0-rc4). + * + * + * @return array + * Associative array of version info: + * - major: Major version (e.g., "8"). + * - minor: Minor version (e.g., "0"). + * - extra: Extra version info (e.g., "alpha2"). + * - extra_text: The text part of "extra" (e.g., "alpha"). + * - extra_number: The number part of "extra" (e.g., "2"). + */ +function _install_get_version_info($version) { + + $info = array(); + + preg_match('/ + ( + (?P[0-9]+) # Major release number. + \. # . + (?P[0-9]+) # Minor release number. + ) # + ( # + - # - separator for "extra" verion information. + (?P # + (?P[a-z]+) # Release extra text (e.g., "alpha"). + (?P[0-9]*) # Release extra number (no separator between text and number). + ) # + | # OR no "extra" information. + ) + /sx', $version, $matches); + + return $matches; } /** @@ -1863,7 +1953,7 @@ function install_import_translations(&$install_state) { language_delete('en'); // Set up a batch to import translations for the newly added language. - _install_prepare_import(); + _install_prepare_import($langcode); module_load_include('fetch.inc', 'locale'); if ($batch = locale_translation_batch_fetch_build(array(), array($langcode))) { return $batch; @@ -1873,23 +1963,41 @@ function install_import_translations(&$install_state) { /** * Tells the translation import process that Drupal core is installed. + * + * @param string $langcode + * Language code used for the translation. */ -function _install_prepare_import() { +function _install_prepare_import($langcode) { + $matches = array(); global $install_state; - $release = install_get_localization_release(); - db_insert('locale_project') - ->fields(array( - 'name' => 'drupal', - 'project_type' => 'module', - 'core' => $release['core'], - 'version' => $release['version'], - 'server_pattern' => $install_state['server_pattern'], - 'status' => 1, - )) - ->execute(); - module_load_include('compare.inc', 'locale'); - locale_translation_check_projects_local(array('drupal'), array($install_state['parameters']['langcode'])); + // Get the translation files located in the translations directory. + $files = locale_translate_get_interface_translation_files(array('drupal'), array($langcode)); + // We pick the first file which matches the installation language. + $file = reset($files); + $filename = $file->filename; + preg_match('/drupal-([0-9a-z\.-]+)\.' . $langcode . '\.po/', $filename, $matches); + // Get the version information. + if ($version = $matches[1]) { + $info = _install_get_version_info($version); + // Picking the first file does not necessarily result in the right file. So + // we check if at least the major version number is available. + if ($info['major']) { + $core = $info['major'] . '.x'; + db_insert('locale_project') + ->fields(array( + 'name' => 'drupal', + 'project_type' => 'module', + 'core' => $core, + 'version' => $version, + 'server_pattern' => $install_state['server_pattern'], + 'status' => 1, + )) + ->execute(); + module_load_include('compare.inc', 'locale'); + locale_translation_check_projects_local(array('drupal'), array($install_state['parameters']['langcode'])); + } + } } /** @@ -2078,28 +2186,35 @@ function install_check_translations($install_state) { } // Build URLs for the translation file and the translation server. - $release = install_get_localization_release(); + $releases = install_get_localization_release(); $langcode = $install_state['parameters']['langcode']; - $variables = array( - '%project' => 'drupal', - '%version' => $release['version'], - '%core' => $release['core'], - '%language' => $langcode, - ); - $translation_url = strtr($install_state['server_pattern'], $variables); - $elements = parse_url($translation_url); + $translation_urls = array(); + foreach ($releases as $release) { + $variables = array( + '%project' => 'drupal', + '%version' => $release['version'], + '%core' => $release['core'], + '%language' => $langcode, + ); + $translation_urls[] = strtr($install_state['server_pattern'], $variables); + } + $elements = parse_url(reset($translation_urls)); $server_url = $elements['scheme'] . '://' . $elements['host']; // Build the language name for display. $languages = LanguageManager::getStandardLanguageList(); $language = isset($languages[$langcode]) ? $languages[$langcode][0] : $langcode; - // Check if the desirered translation file is available and if the translation - // server can be reached, or in other words if we have an internet connection. - if ($translation_available = install_check_localization_server($translation_url)) { - $online = TRUE; + // Check if any of the desired translation files are available or if the + // translation server can be reached. In other words, check if we are online + // and have an internet connection. + foreach ($translation_urls as $translation_url) { + if ($translation_available = install_check_localization_server($translation_url)) { + $online = TRUE; + break; + } } - else { + if (!$translation_available) { if (install_check_localization_server($server_url)) { $online = TRUE; }