' . t('List of latest imported translations and available updates for each enabled project and language.') . '

'; $output .= '

' . t('If there are available updates you can click on Update for them to be downloaded and imported now or you can edit the configuration for them to be updated automatically on the Update settings page', array('@update-settings' => url('admin/settings/language/configure/update'))) . '

'; return $output; break; case 'admin/settings/language/configure/update': $output = '

' . t('These are the settings for the translation update system. To update your translations now, check out the Translation update administration page.', array('@update-admin' => url('admin/build/translate/update'))) . '

'; return $output; break; } } /** * Implementation of hook_menu(). */ function l10n_update_menu() { $items['admin/build/translate/update'] = array( 'title' => 'Update', 'description' => 'Available updates', 'page callback' => 'l10n_update_admin_overview', 'access arguments' => array('translate interface'), 'file' => 'l10n_update.admin.inc', 'weight' => 20, 'type' => MENU_LOCAL_TASK, ); $items['admin/settings/language/configure/update'] = array( 'title' => 'Translation updates', 'description' => 'Automatic update configuration', 'page callback' => 'drupal_get_form', 'page arguments' => array('l10n_update_admin_settings_form'), 'access arguments' => array('translate interface'), 'file' => 'l10n_update.admin.inc', 'weight' => 20, 'type' => MENU_LOCAL_TASK, ); return $items; } /** * Implemenation of hook_menu_alter(). */ function l10n_update_menu_alter(&$menu) { // Redirect l10n_client AJAX callback path for strings. $menu['l10n_client/save']['page callback'] = 'l10n_update_client_save_string'; } /** * Implementation of hook_cron(). * * Check one project/language at a time, download and import if update available */ function l10n_update_cron() { if ($frequency = variable_get('l10n_update_check_frequency', 0)) { module_load_include('check.inc', 'l10n_update'); list($checked, $updated) = l10n_update_check_translations(1, time() - $frequency * 24 * 3600); watchdog('l10n_update', 'Automatically checked @checked translations, updated @updated.', array('@checked' => count($checked), '@updated' => count($updated))); } } /** * Implementation of hook_form_alter(). */ function l10n_update_form_alter(&$form, $form_state, $form_id) { switch ($form_id) { case 'locale_translate_edit_form': // Replace the submit callback by our own customized version $form['#submit'] = array('l10n_update_locale_translate_edit_form_submit'); break; case 'system_modules': $form['#submit'][] = 'l10n_update_system_modules_submit'; break; case 'locale_languages_predefined_form': case 'locale_languages_custom_form': $form['#submit'][] = 'l10n_update_languages_changed_submit'; break; } } /** * Additional submit hander for System Modules form. * * Rebuild project information, update status, etc. When this callback runs, * locale module has already run and update cache is refreshed. * * @see l10n_update_form_alter(). */ function l10n_update_system_modules_submit($form, $form_state) { // Check we are not on the confirm form if (!isset($form_state['storage'])) { module_load_include('project.inc', 'l10n_update'); l10n_update_project_refresh(); } } /** * Aditional submit handler for language forms * * We need to refresh status when a new language is enabled / disabled */ function l10n_update_languages_changed_submit($form, $form_state) { module_load_include('check.inc', 'l10n_update'); $langcode = $form_state['values']['langcode']; l10n_update_language_refresh(array($langcode)); } /** * Replacement submit handler for translation edit form. * * Process string editing form submissions marking translations as customized. * Saves all translations of one string submitted from a form. * * @see l10n_update_form_alter(). * @todo Just mark as customized when string changed. */ function l10n_update_locale_translate_edit_form_submit($form, &$form_state) { module_load_include('inc', 'l10n_update'); $lid = $form_state['values']['lid']; foreach ($form_state['values']['translations'] as $key => $value) { $translation = db_result(db_query("SELECT translation FROM {locales_target} WHERE lid = %d AND language = '%s'", $lid, $key)); if (!empty($value)) { // Only update or insert if we have a value to use. if (!empty($translation)) { db_query("UPDATE {locales_target} SET translation = '%s', l10n_status = %d WHERE lid = %d AND language = '%s'", $value, L10N_UPDATE_STRING_CUSTOM, $lid, $key); } else { db_query("INSERT INTO {locales_target} (lid, translation, language, l10n_status) VALUES (%d, '%s', '%s', %d)", $lid, $value, $key, L10N_UPDATE_STRING_CUSTOM); } } elseif (!empty($translation)) { // Empty translation entered: remove existing entry from database. db_query("DELETE FROM {locales_target} WHERE lid = %d AND language = '%s'", $lid, $key); } // Force JavaScript translation file recreation for this language. _locale_invalidate_js($key); } drupal_set_message(t('The string has been saved.')); // Clear locale cache. _locale_invalidate_js(); cache_clear_all('locale:', 'cache', TRUE); $form_state['redirect'] = 'admin/build/translate/search'; return; } /** * Menu callback. Saves a string translation coming as POST data. */ function l10n_update_client_save_string() { global $user, $language; if (user_access('use on-page translation')) { if (isset($_POST['source']) && isset($_POST['target']) && !empty($_POST['form_token']) && drupal_valid_token($_POST['form_token'], 'l10n_client_form')) { module_load_include('inc', 'l10n_update'); $report = array(0, 0, 0); _l10n_update_locale_import_one_string_db($report, $language->language, $_POST['source'], $_POST['target'], 'default', NULL, LOCALE_IMPORT_OVERWRITE, L10N_UPDATE_STRING_CUSTOM); cache_clear_all('locale:', 'cache', TRUE); _locale_invalidate_js($language->language); // Submit to remote server if enabled. if (variable_get('l10n_client_use_server', FALSE) && user_access('submit translations to localization server') && !empty($user->l10n_client_key)) { l10n_client_submit_translation($language->language, $_POST['source'], $_POST['target'], $user->l10n_client_key, l10n_client_user_token($user)); } } } } /** * Get stored list of projects * * @param boolean $refresh * TRUE = refresh the project data. * @param boolean $disabled * TRUE = get enabled AND disabled projects. * FALSE = get enabled projects only. * * @return array * Array of project objects keyed by project name. */ function l10n_update_get_projects($refresh = FALSE, $disabled = FALSE) { static $projects, $enabled; if (!isset($projects) || $refresh) { if (variable_get('l10n_update_rebuild_projects', 0)) { module_load_include('project.inc', 'l10n_update'); variable_del('l10n_update_rebuild_projects'); l10n_update_build_projects(); } $projects = $enabled = array(); $result = db_query('SELECT * FROM {l10n_update_project}'); while ($project = db_fetch_object($result)) { $projects[$project->name] = $project; if ($project->status) { $enabled[$project->name] = $project; } } } return $disabled ? $projects : $enabled; } /** * Get server information, that can come from different sources. * * - From server list provided by modules. They can provide full server information or just the url * - From server_url in a project, we'll fetch latest data from the server itself * * @param string $name * Server name e.g. localize.drupal.org * @param string $url * Server url * @param boolean $refresh * TRUE = refresh the server data. * * @return array * Array of server data. */ function l10n_update_server($name = NULL, $url = NULL, $refresh = FALSE) { static $info, $server_list; // Retrieve server list from modules if (!isset($server_list) || $refresh) { $server_list = module_invoke_all('l10n_servers'); } // We need at least the server url to fetch all the information if (!$url && $name && isset($server_list[$name])) { $url = $server_list[$name]['server_url']; } // If we still don't have an url, cannot find this server, return false if (!$url) { return FALSE; } // Cache server information based on the url, refresh if asked $cid = 'l10n_update_server:' . $url; if ($refresh) { unset($info); cache_clear_all($cid, 'cache'); } if (!isset($info[$url])) { if ($cache = cache_get($cid)) { $info[$url] = $cache->data; } else { require_once 'l10n_update.parser.inc'; if ($name && !empty($server_list[$name])) { // The name is in our list, it can be full data or just an url $server = $server_list[$name]; } else { // This may be a new server provided by a module / package $server = array('name' => $name, 'server_url' => $url); // If searching by name, store the name => url mapping if ($name) { $server_list[$name] = $server; } } // Now fetch server meta information form the server itself if ($server = l10n_update_get_server($server)) { cache_set($cid, $server); $info[$url] = $server; } else { // If no server information, this will be FALSE. We won't search a server twice $info[$url] = FALSE; } } } return $info[$url]; } /** * Implementation of hook_l10n_servers * * @return array * Array of server data: * 'name' => server name * 'server_url' => server url * 'update_url' => update url */ function l10n_update_l10n_servers() { module_load_include('inc', 'l10n_update'); $server = l10n_update_default_server(); return array($server['name'] => $server ); } /** * Get update history. * * @param boolean $refresh * TRUE = refresh the history data. * @return * An array of translation files indexed by project and language. */ function l10n_update_get_history($refresh = NULL) { static $status; if ($refresh || !isset($status)) { // Now add downloads history to projects $result = db_query("SELECT * FROM {l10n_update_file}"); while ($update = db_fetch_object($result)) { $status[$update->project][$update->language] = $update; } } return $status; } /** * Get language list. * * @return array * Array of installed language names. English is the source language and * is therefore not included. * @todo remove the $field param. */ function l10n_update_language_list($field = 'name') { $languages = locale_language_list('name'); // Skip English language if (isset($languages['en'])) { unset($languages['en']); } return $languages; } /** * Implementation of the hook_theme() registry. */ function l10n_update_theme() { return array( 'l10n_update_project_status' => array( 'arguments' => array('projects' => NULL, 'languages' => NULL, 'history' => NULL, 'available' => NULL, 'updates' => NULL), 'file' => 'l10n_update.admin.inc', ), 'l10n_update_release' => array( 'arguments' => array('tag' => NULL, 'date' => NULL), 'file' => 'l10n_update.admin.inc', ), 'l10n_update_version_status' => array( 'arguments' => array('status' => NULL), 'file' => 'l10n_update.admin.inc', ), ); } /** * Build the warning message for when there is no data about available updates. * * @return sting * Message text with links. */ function _l10n_update_no_data() { $destination = drupal_get_destination(); return t('No information is available about potential new and updated translations for currently installed modules and themes. To check for updates, you may need to run cron or you can check manually. Please note that checking for available updates can take a long time, so please be patient.', array( '@run_cron' => url('admin/reports/status/run-cron', array('query' => $destination)), '@check_manually' => url('admin/build/translate/update', array('query' => $destination)), )); } /** * Get available updates. * * @param boolean $refresh * TRUE = refresh the history data. * * @return array * Array of all projects for which updates are available. For each project * an array of update objects, one per language. */ function l10n_update_available_updates($refresh = NULL) { module_load_include('check.inc', 'l10n_update'); if ($available = l10n_update_available_releases($refresh)) { $history = l10n_update_get_history(); return l10n_update_build_updates($history, $available); } } /** * Implementation of hook_flush_caches(). * * Called from update.php (among others) to flush the caches. */ function l10n_update_flush_caches() { variable_set('l10n_update_rebuild_projects', 1); }