l10n_update.batch.inc 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. <?php
  2. /**
  3. * @file
  4. * Reusable API for creating and running l10n update batches.
  5. */
  6. // module_load_include will not work in batch.
  7. include_once 'l10n_update.check.inc';
  8. /**
  9. * Create a batch to just download files.
  10. *
  11. * @param $updates
  12. * Translations sources to be downloaded.
  13. * Note: All update sources must have a 'fileurl'.
  14. * @return array
  15. * A batch definition for this download.
  16. */
  17. function l10n_update_batch_download($updates) {
  18. foreach ($updates as $update) {
  19. $id = $update->filename;
  20. $operations[] = array('_l10n_update_batch_download', array($id, $update));
  21. }
  22. return _l10n_update_create_batch($operations);
  23. }
  24. /**
  25. * Create a batch to just import files.
  26. *
  27. * All update sources must have a 'uri'.
  28. *
  29. * @param $updates
  30. * Translations sources to be imported.
  31. * Note: All update sources must have a 'fileurl'.
  32. * @param $import_mode
  33. * Import mode. How to treat existing and modified translations.
  34. * @return array
  35. * A batch definition for this import.
  36. */
  37. function l10n_update_batch_import($updates, $import_mode) {
  38. foreach ($updates as $update) {
  39. $id = $update->filename;
  40. $operations[] = array('_l10n_update_batch_import', array($id, $update, $import_mode));
  41. }
  42. return _l10n_update_create_batch($operations);
  43. }
  44. /**
  45. * Create a big batch for multiple projects and languages.
  46. *
  47. * @param $updates
  48. * Array of update sources to be run.
  49. * @param $mode
  50. * Import mode. How to treat existing and modified translations.
  51. * @return array
  52. */
  53. function l10n_update_batch_multiple($updates, $import_mode) {
  54. foreach ($updates as $update) {
  55. $id = $update->filename;
  56. if ($update->type == 'download') {
  57. $operations[] = array('_l10n_update_batch_download', array($id, $update));
  58. $operations[] = array('_l10n_update_batch_import', array($id, NULL, $import_mode));
  59. }
  60. else {
  61. $operations[] = array('_l10n_update_batch_import', array($id, $update, $import_mode));
  62. }
  63. // This one takes always parameters from results.
  64. $operations[] = array('_l10n_update_batch_history', array($id));
  65. }
  66. if (!empty($operations)) {
  67. return _l10n_update_create_batch($operations);
  68. }
  69. }
  70. /**
  71. * Create batch stub for this module.
  72. *
  73. * @param $operations
  74. * Operations to perform in this batch.
  75. * @return array
  76. * A batch definition:
  77. * - 'operations': Batch operations
  78. * - 'title': Batch title.
  79. * - 'init_message': Initial batch UI message.
  80. * - 'error_message': Batch error message.
  81. * - 'file': File containing callback function.
  82. * - 'finished': Batch completed callback function.
  83. */
  84. function _l10n_update_create_batch($operations = array()) {
  85. $t = get_t();
  86. $batch = array(
  87. 'operations' => $operations,
  88. 'title' => $t('Updating translation.'),
  89. 'init_message' => $t('Downloading and importing files.'),
  90. 'error_message' => $t('Error importing interface translations'),
  91. 'file' => drupal_get_path('module', 'l10n_update') . '/l10n_update.batch.inc',
  92. 'finished' => '_l10n_update_batch_finished',
  93. );
  94. return $batch;
  95. }
  96. /**
  97. * Batch process: Download a file.
  98. *
  99. * @param $id
  100. * Batch id to identify batch results.
  101. * Result of this batch function are stored in $context['result']
  102. * identified by this $id.
  103. * @param $file
  104. * File to be downloaded.
  105. * @param $context
  106. * Batch context array.
  107. */
  108. function _l10n_update_batch_download($id, $file, &$context) {
  109. $t = get_t();
  110. if (l10n_update_source_download($file)) {
  111. $context['message'] = $t('Importing: %name.', array('%name' => $file->filename));
  112. $context['results'][$id] = array('file' => $file);
  113. }
  114. else {
  115. $context['results'][$id] = array('file' => $file, 'fail' => TRUE);
  116. }
  117. }
  118. /**
  119. * Batch process: Update the download history table.
  120. *
  121. * @param $id
  122. * Batch id to identify batch results.
  123. * Result of this batch function are stored in $context['result']
  124. * identified by this $id.
  125. * @param $context
  126. * Batch context array.
  127. */
  128. function _l10n_update_batch_history($id, &$context) {
  129. $t = get_t();
  130. // The batch import is performed in a number of steps. History update is
  131. // always the last step. The details of the downloaded/imported file are
  132. // stored in $context['results'] array.
  133. if (isset($context['results'][$id]['file']) && !isset($context['results'][$id]['fail'])) {
  134. $file = $context['results'][$id]['file'];
  135. l10n_update_source_history($file);
  136. $context['message'] = $t('Imported: %name.', array('%name' => $file->filename));
  137. }
  138. }
  139. /**
  140. * Batch process: Import translation file.
  141. *
  142. * This takes a file parameter or continues from previous batch
  143. * which should have downloaded a file.
  144. *
  145. * @param $id
  146. * Batch id to identify batch results.
  147. * Result of this batch function are stored in $context['result']
  148. * identified by this $id.
  149. * @param $file
  150. * File to be imported. If empty, the file will be taken from $context['results'].
  151. * @param $mode
  152. * Import mode. How to treat existing and modified translations.
  153. * @param $context
  154. * Batch context array.
  155. */
  156. function _l10n_update_batch_import($id, $file, $mode, &$context) {
  157. $t = get_t();
  158. // The batch import is performed in two or three steps.
  159. // If import is performed after file download the file details of the download
  160. // are used which are stored in the $context['results'] array.
  161. // If a locally stored file is imported, the file details are placed in $file.
  162. if (empty($file) && isset($context['results'][$id]['file']) && !isset($context['results'][$id]['fail'])) {
  163. $file = $context['results'][$id]['file'];
  164. }
  165. if ($file) {
  166. // Create a result if none exists yet.
  167. if (!isset($context['results'][$id])) {
  168. $context['results'][$id] = array();
  169. }
  170. if ($import_result = l10n_update_source_import($file, $mode)) {
  171. $context['message'] = $t('Imported: %name.', array('%name' => $file->filename));
  172. $context['results'][$id] = array_merge((array)$context['results'][$id], $import_result, array('file' => $file));
  173. }
  174. else {
  175. $context['results'][$id] = array_merge((array)$context['results'][$id], array('fail' => TRUE), array('file' => $file));
  176. }
  177. }
  178. }
  179. /**
  180. * Batch finished callback: Set result message.
  181. *
  182. * @param $success
  183. * TRUE if batch succesfully completed.
  184. * @param $results
  185. * Batch results.
  186. */
  187. function _l10n_update_batch_finished($success, $results) {
  188. $totals = array(); // Sum of added, updated and deleted translations.
  189. $total_skip = 0; // Sum of skipped translations
  190. $messages = array(); // User feedback messages.
  191. $project_fail = $project_success = array(); // Project names of succesfull and failed imports.
  192. $t = get_t();
  193. if ($success) {
  194. // Summarize results of added, updated, deleted and skiped translations.
  195. // Added, updated and deleted are summarized per language to be displayed accordingly.
  196. foreach ($results as $result) {
  197. if (isset($result['fail'])) {
  198. // Collect project names of the failed imports.
  199. $project_fail[$result['file']->name] = $result['file']->name;
  200. }
  201. else {
  202. $language = $result['language'];
  203. // Initialize variables to prevent PHP Notices.
  204. if (!isset($totals[$language])) {
  205. $totals[$language] = array();
  206. $totals[$language]['add'] = $totals[$language]['update'] = $totals[$language]['delete'] = 0;
  207. }
  208. // Summarize added, updated, deleted and skiped translations.
  209. $totals[$language]['add'] += $result['add'];
  210. $totals[$language]['update'] += $result['update'];
  211. $totals[$language]['delete'] += $result['delete'];
  212. $total_skip += $result['skip'];
  213. // Collect project names of the succesfull imports.
  214. $project_success[$result['file']->name] = $result['file']->name;
  215. }
  216. }
  217. // Messages of succesfull translation update results.
  218. if ($project_success) {
  219. $messages[] = format_plural(count($project_success), 'One project updated: @projects.', '@count projects updated: @projects.', array('@projects' => implode(', ', $project_success)));
  220. $languages = language_list();
  221. foreach ($totals as $language => $total) {
  222. $messages[] = $t('%language translation strings added: !add, updated: !update, deleted: !delete.', array(
  223. '%language' => $languages[$language]->name,
  224. '!add' => $total['add'],
  225. '!update' => $total['update'],
  226. '!delete' => $total['delete'],
  227. ));
  228. }
  229. drupal_set_message(implode("<br />\n", $messages));
  230. // Warning for disallowed HTML.
  231. if ($total_skip) {
  232. drupal_set_message(
  233. format_plural(
  234. $total_skip,
  235. 'One translation string was skipped because it contains disallowed HTML. See !log_messages for details.',
  236. '@count translation strings were skipped because they contain disallowed HTML. See !log_messages for details.',
  237. array('!log_messages' => l(t('Recent log messages'), 'admin/reports/dblog'))),
  238. 'warning');
  239. }
  240. // Clear cache and force refresh of JavaScript translations and rebuild
  241. // the menu as strings may have changed.
  242. foreach (array_keys($totals) as $langcode) {
  243. _locale_invalidate_js($langcode);
  244. }
  245. cache_clear_all('locale:', 'cache', TRUE);
  246. menu_rebuild();
  247. }
  248. // Error for failed imports.
  249. if ($project_fail) {
  250. drupal_set_message(
  251. format_plural(
  252. count($project_fail),
  253. 'Translations of one project were not imported: @projects.',
  254. 'Translations of @count projects were not imported: @projects',
  255. array('@projects' => implode(', ', $project_fail))),
  256. 'error');
  257. }
  258. }
  259. else {
  260. drupal_set_message($t('Error importing translations.'), 'error');
  261. }
  262. }