diff --git a/core/modules/locale/locale.pages.inc b/core/modules/locale/locale.pages.inc index 1411591..bfdf12a 100644 --- a/core/modules/locale/locale.pages.inc +++ b/core/modules/locale/locale.pages.inc @@ -602,10 +602,23 @@ function locale_translation_status_form($form, &$form_state) { return $form; } + // @todo It could be useful to consider refactoring theme_update_last_check(). + $last = state()->get('locale.translation_last_checked'); + $markup = '
'; + $markup .= $last ? t('Last checked: @time ago', array('@time' => format_interval(REQUEST_TIME - $last))) : t('Last checked: never'); + $markup .= ' (' . l(t('Check manually'), 'admin/reports/translations/check', array('query' => drupal_get_destination())) . ')'; + $markup .= "
\n"; + $form['last_checked'] = array( + '#markup' => $markup, + ); + module_load_include('compare.inc', 'locale'); locale_translation_flush_projects(); $projects = locale_translation_get_projects(); $status = state()->get('locale.translation_status'); + if (!$status) { + return $form; + } // Prepare information about projects which have available translation // updates. @@ -616,6 +629,7 @@ function locale_translation_status_form($form, &$form_state) { $projects_to_update[$langcode]['not_found'][] = array( 'name' => $project_info->name, 'version' => $project_info->version, + 'debug_info' => _locale_translation_status_debug_info($project_info->version, $project_info->files['remote']->uri, $project_info->files['local']->uri), ); } elseif ($project_info->type != 'current') { @@ -627,60 +641,63 @@ function locale_translation_status_form($form, &$form_state) { } } - // @todo It could be useful to consider refactoring theme_update_last_check(). - $last = state()->get('locale.translation_last_checked'); - $markup = '
'; - $markup .= $last ? t('Last checked: @time ago', array('@time' => format_interval(REQUEST_TIME - $last))) : t('Last checked: never'); - $markup .= ' (' . l(t('Check manually'), 'admin/reports/translations/check', array('query' => drupal_get_destination())) . ')'; - $markup .= "
\n"; - $form['last_checked'] = array( - '#markup' => $markup, - ); - - $form['langcodes_title'] = array( - '#type' => 'item', - '#title' => t('Languages'), - ); - $header = array( - 'title' => t('Title'), - 'operations' => t('Operations'), - ); $options = array(); foreach ($languages as $langcode => $language) { if (isset($projects_to_update[$langcode])) { + $project_list = array( + 'updates' => isset($projects_to_update[$langcode]['updates']) ? $projects_to_update[$langcode]['updates'] : NULL, + 'not_found' => isset($projects_to_update[$langcode]['not_found']) ? $projects_to_update[$langcode]['not_found'] : NULL, + ); $options[$langcode] = array( - 'title' => $language->name, + 'language' => $language->name, + 'description' => array( + 'class' => 'description', + 'data' => theme('locale_project_language_update_info', array( + 'projects' => $project_list, + 'type' => 'summary', + )), + ), 'operations' => array( 'class' => 'operations', 'data' => theme('locale_project_language_update_info', array( - 'projects' => array( - 'updates' => isset($projects_to_update[$langcode]['updates']) ? $projects_to_update[$langcode]['updates'] : NULL, - 'not_found' => isset($projects_to_update[$langcode]['not_found']) ? $projects_to_update[$langcode]['not_found'] : NULL, - ), - 'langcode' => $langcode, + 'projects' => $project_list, + 'type' => 'detailed', )), ), ); } } - $form['langcodes'] = array( - '#type' => 'tableselect', - '#header' => $header, - '#options' => $options, - '#default_value' => drupal_map_assoc(array_keys($options)), - ); - $form['actions'] = array( - '#type' => 'actions', - ); - $form['actions']['submit'] = array( - '#type' => 'submit', - '#value' => t('Update'), - ); - $form['#attached']['js'] = array( - drupal_get_path('module', 'locale') . '/locale.toggle-interface-update-details.js' => array( - 'type' => 'file', - ), - ); + if (!empty($options)) { + $header = array( + 'language' => t('Language'), + 'description' => t('Description'), + 'operations' => t('Operations'), + ); + $form['langcodes'] = array( + '#type' => 'tableselect', + '#header' => $header, + '#options' => $options, + '#default_value' => drupal_map_assoc(array_keys($options)), + ); + // Disable language rows without available updates. + foreach ($form['langcodes']['#options'] as $langcode => $language_row) { + if (!isset($language_row['operations']['data']['updates_info'])) { + $form['langcodes'][$langcode]['#disable'] = TRUE; + } + } + $form['actions'] = array( + '#type' => 'actions', + ); + $form['actions']['submit'] = array( + '#type' => 'submit', + '#value' => t('Update translations'), + ); + $form['#attached']['js'] = array( + drupal_get_path('module', 'locale') . '/locale.toggle-interface-update-details.js' => array( + 'type' => 'file', + ), + ); + } return $form; } @@ -711,6 +728,40 @@ function locale_translation_status_form_submit($form, &$form_state) { } /** + * Provides debug info when translation update were not found for a project. + * + * Translations files are being fetched either from Drupal translation server + * and local files or only from the local filesystem depending on the + * "Translation source" setting at admin/config/regional/translate/settings. + * This method will produce debug information including the respective path(s) + * based on this setting. + * Translations for development versions are never fetched, so the debug info + * for that is a fixed message. + * + * @param string $version + * Version of the project. + * @param string $remote_path + * Remote path where the translation file was tried to load from. + * @param string $local_path + * Local path where the translation file was tried to load from. + */ +function _locale_translation_status_debug_info($version, $remote_path, $local_path) { + if (strpos($version, 'dev') !== FALSE) { + return t('no translations provided for development releases'); + } + $config = config('locale.settings'); + if ($config->get('translation.use_source') == LOCALE_TRANSLATION_USE_SOURCE_REMOTE_AND_LOCAL) { + return t('File not found at %remote_path nor at %local_path', array( + '%remote_path' => $remote_path, + '%local_path' => $local_path, + )); + } + elseif ($config->get('translation.use_source') == LOCALE_TRANSLATION_USE_SOURCE_LOCAL) { + return t('File not found at %local_path', array('%local_path' => $local_path)); + } +} + +/** * Default theme function for translation edit form. */ function theme_locale_translate_edit_form_strings($variables) { @@ -746,11 +797,15 @@ function theme_locale_translate_edit_form_strings($variables) { } /** - * Returns HTML for interface translation update status. + * Returns HTML to be displayed in the interface translation status overview. * - * Output contains the list of projects which language updates will be applied - * to. A separated list is rendered which contains projects which language - * updates were not found for. + * Output can be rendered in two modes. "Summary" displays a short sentence with + * a simple flat list of modules which updates are available for, possibly along + * with another sentence informing us about the number of modules which updates + * were not found for. + * The detailed view displays the aforementioned sentences following with a list + * of modules together with version numbers and possibly with debug information + * when updates were not found. * * @param $variables * An associative array containing: @@ -765,57 +820,81 @@ function theme_locale_translate_edit_form_strings($variables) { * not found for. Each element of the array is an associative array with * the following keys: * - project: Human readable name of the project. - * - version: Version of the project. + * - version: Optional. Version of the project. + * - debug_info: Optional. Reason of why update were not found for the + * project. + * - type: Optional. 'summary' or 'detailed'. Summary view will be returned if + * parameter is not provided. * * @ingroup themeable */ function theme_locale_project_language_update_info($variables) { $output = array(); + $type = (isset($variables['type'])) ? $variables['type'] : 'summary'; $project_list = array(); - if (isset($variables['projects']['updates'])) { - foreach ($variables['projects']['updates'] as $project) { - $project_list['flat'][] = $project['name']; - $project_list['details'][] = format_string('!name (!version)', array( - '!name' => $project['name'], - '!version' => $project['version'], + + foreach ($variables['projects'] as $update_status => $projects) { + if (is_array($projects)) { + foreach ($projects as $project) { + if ($type == 'detailed') { + $project_display = $project['name']; + if (!empty($project['version'])) { + $project_display .= format_string(' (!version)', array('!version' => $project['version'])); + } + if (!empty($project['debug_info'])) { + $project_display .= format_string(': !info', array('!info' => $project['debug_info'])); + } + $project_list[$update_status][] = $project_display; + } + else { + $project_list[$update_status][] = $project['name']; + } + } + } + } + + if (!empty($project_list['updates'])) { + $output['updates_info'] = array(); + if ($type == 'detailed') { + $summary = t('Translation updates available for:'); + $output['updates_info']['#suffix'] = theme('item_list', array( + 'items' => $project_list['updates'], + 'attributes' => array( + 'class' => array('detailed-list'), + ), )); } - $output['updates_summary'] = array( - '#type' => 'markup', - '#markup' => '

' . t('This applies language updates to %projects.', array( - '%projects' => implode(', ', $project_list['flat']), - )) . "

", - ); - $output['updates_details'] = array( - '#theme' => 'item_list', - '#items' => $project_list['details'], - '#attributes' => array( - 'class' => array('details'), - ), - ); + else { + $summary = t('Translation updates available for: %projects.', array( + '%projects' => implode(', ', $project_list['updates']), + )); + } + $output['updates_info']['#markup'] = '

' . $summary . '

'; } - $project_list = array('count' => 0); - if (isset($variables['projects']['not_found'])) { - foreach ($variables['projects']['not_found'] as $project) { - $project_list['count']++; - $project_list['details'][] = format_string('!name (!version)', array( - '!name' => $project['name'], - '!version' => $project['version'], + + if (!empty($project_list['not_found'])) { + $output['not_found_info'] = array(); + if ($type == 'detailed') { + $summary = t('No translations found for:'); + $output['not_found_info']['#suffix'] = theme('item_list', array( + 'items' => $project_list['not_found'], + 'attributes' => array( + 'class' => array('detailed-list'), + ), )); } - $output['not_found_summary'] = array( - '#type' => 'markup', - '#markup' => '

' . t('No updates were found for %count projects.', array( - '%count' => $project_list['count'], - )) . '

', - ); - $output['not_found_details'] = array( - '#theme' => 'item_list', - '#items' => $project_list['details'], - '#attributes' => array( - 'class' => array('details'), - ), - ); + else { + $summary = t('No translations found for %count projects.', array( + '%count' => count($project_list['not_found']), + )); + } + $output['not_found_info']['#markup'] = '

' . $summary . '

'; + } + + if ($type == 'detailed') { + // Wrapping everything in a div helps adding toggle links with JS. + $output['#prefix'] = '
'; + $output['#suffix'] = '
'; } return $output; } diff --git a/core/modules/locale/locale.toggle-interface-update-details.js b/core/modules/locale/locale.toggle-interface-update-details.js index cf37891..fa2ff0c 100644 --- a/core/modules/locale/locale.toggle-interface-update-details.js +++ b/core/modules/locale/locale.toggle-interface-update-details.js @@ -7,12 +7,12 @@ */ Drupal.behaviors.toggleInterfaceUpdateDetails = { attach: function (context, settings) { - $('' + Drupal.t('Details') + '').insertAfter('td.operations > .summary') + $('' + Drupal.t('Show details') + '').insertBefore('td.operations > .details') .toggle(function() { $(this).text(Drupal.t('Hide details')); $(this).next().show(); }, function() { - $(this).text(Drupal.t('Details')); + $(this).text(Drupal.t('Show details')); $(this).next().hide(); }).next().hide() }