View source
<?php
define('L10N_UPDATE_USE_SOURCE_LOCAL', 2);
define('L10N_UPDATE_USE_SOURCE_REMOTE_AND_LOCAL', 3);
define('L10N_UPDATE_DEFAULT_SERVER_PATTERN', 'https://ftp.drupal.org/files/translations/%core/%project/%project-%release.%language.po');
define('L10N_UPDATE_DEFAULT_FILE_NAME', '%project-%release.%language.po');
define('L10N_UPDATE_DEFAULT_TRANSLATION_PATH', 'sites/all/translations');
define('L10N_UPDATE_STATUS_TTL', 600);
define('L10N_UPDATE_OVERWRITE_NON_CUSTOMIZED', 2);
define('L10N_UPDATE_REMOTE', 'remote');
define('L10N_UPDATE_LOCAL', 'local');
define('L10N_UPDATE_CURRENT', 'current');
define('L10N_UPDATE_PLURAL_DELIMITER', "\3");
define('L10N_UPDATE_NOT_CUSTOMIZED', 0);
define('L10N_UPDATE_STRING_CUSTOM', 1);
define('L10N_UPDATE_CUSTOMIZED', 1);
function l10n_update_help($path, $arg) {
$output = '';
switch ($path) {
case 'admin/config/regional/translate/update':
$output = '<p>' . t('Status of interface translations for each of the enabled languages.') . '</p>';
$output .= '<p>' . t('If there are available updates you can click on "Update translation" for them to be downloaded and imported now or you can edit the configuration for them to be updated automatically on the <a href="@update-settings">Update settings page</a>', array(
'@update-settings' => url('admin/config/regional/language/update'),
)) . '</p>';
break;
case 'admin/config/regional/language/update':
$output = '<p>' . t('These are the settings for the translation update system. To update your translations now, check out the <a href="@update-admin">Translation update administration page</a>.', array(
'@update-admin' => url('admin/config/regional/translate/update'),
)) . '</p>';
break;
}
return $output;
}
function l10n_update_menu() {
$items['admin/config/regional/translate/update'] = array(
'title' => 'Update',
'description' => 'Available updates',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'l10n_update_status_form',
),
'access arguments' => array(
'translate interface',
),
'file' => 'l10n_update.admin.inc',
'weight' => 20,
'type' => MENU_LOCAL_TASK,
);
$items['admin/config/regional/translate/check'] = array(
'title' => 'Update',
'description' => 'Available updates',
'page callback' => 'l10n_update_manual_status',
'access arguments' => array(
'translate interface',
),
'file' => 'l10n_update.admin.inc',
'weight' => 20,
'type' => MENU_CALLBACK,
);
$items['admin/config/regional/language/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;
}
function l10n_update_theme() {
return array(
'l10n_update_last_check' => array(
'variables' => array(
'last' => NULL,
),
'file' => 'l10n_update.admin.inc',
'template' => 'l10n_update-translation-last-check',
),
'l10n_update_update_info' => array(
'variables' => array(
'updates' => array(),
'not_found' => array(),
),
'file' => 'l10n_update.admin.inc',
'template' => 'l10n_update-translation-update-info',
),
);
}
function l10n_update_menu_alter(&$menu) {
if (module_exists('l10n_client')) {
$menu['l10n_client/save']['page callback'] = 'l10n_update_client_save_string';
}
}
function l10n_update_cron() {
if ($frequency = variable_get('l10n_update_check_frequency', '0') && l10n_update_translatable_language_list()) {
module_load_include('translation.inc', 'l10n_update');
l10n_update_cron_fill_queue();
}
}
function l10n_update_cron_queue_info() {
$queues['l10n_update'] = array(
'worker callback' => 'l10n_update_worker',
'time' => 30,
);
return $queues;
}
function l10n_update_worker(array $data) {
module_load_include('batch.inc', 'l10n_update');
list($function, $args) = $data;
$last = count($args) - 1;
if (!is_array($args[$last]) || !isset($args[$last]['finished'])) {
$batch_context = array(
'sandbox' => array(),
'results' => array(),
'finished' => 1,
'message' => '',
);
}
else {
$batch_context = $args[$last];
unset($args[$last]);
}
$args = array_merge($args, array(
&$batch_context,
));
call_user_func_array($function, $args);
if ($batch_context['finished'] < 1) {
unset($batch_context['strings']);
$queue = DrupalQueue::get('l10n_update', TRUE);
$queue
->createItem(array(
$function,
$args,
));
}
}
function l10n_update_stream_wrappers() {
if (!class_exists('TranslationsStreamWrapper')) {
require_once 'includes/locale/TranslationsStreamWrapper.php';
}
$wrappers['translations'] = array(
'name' => t('Translation files'),
'class' => 'TranslationsStreamWrapper',
'description' => t('Translation files.'),
'type' => STREAM_WRAPPERS_LOCAL_HIDDEN,
);
return $wrappers;
}
function l10n_update_form_alter(&$form, $form_state, $form_id) {
switch ($form_id) {
case 'locale_translate_edit_form':
case 'i18n_string_locale_translate_edit_form':
$form['#submit'][] = 'l10n_update_locale_translate_edit_form_submit';
break;
case 'locale_languages_predefined_form':
case 'locale_languages_custom_form':
$form['#submit'][] = 'l10n_update_languages_changed_submit';
break;
case 'locale_languages_delete_form':
$form['#submit'][] = 'l10n_update_languages_delete_submit';
break;
}
}
function l10n_update_modules_enabled($modules) {
$components['module'] = $modules;
l10n_update_system_update($components);
}
function l10n_update_modules_disabled($modules) {
if (!variable_get('l10n_update_check_disabled', FALSE)) {
db_update('l10n_update_project')
->fields(array(
'status' => 0,
))
->condition('name', $modules)
->execute();
}
}
function l10n_update_modules_uninstalled($modules) {
$components['module'] = $modules;
l10n_update_system_remove($components);
}
function l10n_update_themes_enabled($themes) {
$components['theme'] = $themes;
l10n_update_system_update($components);
}
function l10n_update_l10n_update_languages_alter(array &$langcodes) {
$disabled = array_filter(variable_get('l10n_update_disabled_languages', array()));
$langcodes = array_diff_key($langcodes, $disabled);
}
function l10n_update_languages_changed_submit($form, $form_state) {
if (variable_get('l10n_update_import_enabled', TRUE)) {
if (empty($form_state['values']['predefined_langcode']) || $form_state['values']['predefined_langcode'] == 'custom') {
$langcode = $form_state['values']['langcode'];
}
else {
$langcode = $form_state['values']['predefined_langcode'];
}
module_load_include('fetch.inc', 'l10n_update');
$options = _l10n_update_default_update_options();
$batch = l10n_update_batch_update_build(array(), array(
$langcode,
), $options);
batch_set($batch);
}
}
function l10n_update_languages_delete_submit($form, $form_state) {
$langcode = $form_state['values']['langcode'];
l10n_update_file_history_delete(array(), $langcode);
}
function l10n_update_locale_translate_edit_form_submit($form, &$form_state) {
$lid = $form_state['values']['lid'];
$languages = $form_state['values']['translations'];
$languages = array_intersect_key($languages, l10n_update_translatable_language_list());
foreach ($languages as $langcode => $value) {
if (!empty($value) && $value != $form_state['complete form']['translations'][$langcode]['#default_value']) {
db_update('locales_target')
->fields(array(
'l10n_status' => L10N_UPDATE_STRING_CUSTOM,
))
->condition('lid', $lid)
->condition('language', $langcode)
->execute();
}
}
}
function l10n_update_client_save_string() {
global $user, $language;
if (l10n_client_access()) {
if (isset($_POST['source']) && isset($_POST['target']) && !empty($_POST['textgroup']) && !empty($_POST['form_token']) && drupal_valid_token($_POST['form_token'], 'l10n_client_form')) {
$lid = db_query("SELECT lid FROM {locales_source} WHERE source = :source AND context = :context AND textgroup = :textgroup", array(
':source' => $_POST['source'],
':context' => '',
':textgroup' => $_POST['textgroup'],
))
->fetchField();
if (!empty($lid)) {
module_load_include('translation.inc', 'l10n_update');
$report = array(
'skips' => 0,
'additions' => 0,
'updates' => 0,
'deletes' => 0,
);
_l10n_update_locale_import_one_string_db($report, $language->language, '', $_POST['source'], $_POST['target'], $_POST['textgroup'], NULL, LOCALE_IMPORT_OVERWRITE, L10N_UPDATE_STRING_CUSTOM);
cache_clear_all('locale:', 'cache', TRUE);
_locale_invalidate_js($language->language);
if (!empty($report['skips'])) {
$message = theme('l10n_client_message', array(
'message' => t('Not saved locally due to invalid HTML content.'),
));
}
elseif (!empty($report['additions']) || !empty($report['updates'])) {
$message = theme('l10n_client_message', array(
'message' => t('Translation saved locally.'),
'level' => WATCHDOG_INFO,
));
}
elseif (!empty($report['deletes'])) {
$message = theme('l10n_client_message', array(
'message' => t('Translation successfully removed locally.'),
'level' => WATCHDOG_INFO,
));
}
else {
$message = theme('l10n_client_message', array(
'message' => t('Unknown error while saving translation locally.'),
));
}
if (variable_get('l10n_client_use_server', FALSE) && user_access('submit translations to localization server') && $_POST['textgroup'] == 'default') {
if (!empty($user->data['l10n_client_key'])) {
$remote_result = l10n_client_submit_translation($language->language, $_POST['source'], $_POST['target'], $user->data['l10n_client_key'], l10n_client_user_token($user));
$message .= theme('l10n_client_message', array(
'message' => $remote_result[1],
'level' => $remote_result[0] ? WATCHDOG_INFO : WATCHDOG_ERROR,
));
}
else {
$server_url = variable_get('l10n_client_server', 'https://localize.drupal.org');
$user_edit_url = url('user/' . $user->uid . '/edit', array(
'absolute' => TRUE,
));
$message .= theme('l10n_client_message', array(
'message' => t('You could share your work with !l10n_server if you set your API key at !user_link.', array(
'!l10n_server' => l($server_url, $server_url),
'!user_link' => l($user_edit_url, 'user/' . $user->uid . '/edit'),
)),
'level' => WATCHDOG_WARNING,
));
}
}
}
else {
$message = theme('l10n_client_message', array(
'message' => t('Not saved due to source string missing.'),
));
}
}
else {
$message = theme('l10n_client_message', array(
'message' => t('Not saved due to missing form values.'),
));
}
}
else {
$message = theme('l10n_client_message', array(
'message' => t('Not saved due to insufficient permissions.'),
));
}
drupal_json_output($message);
exit;
}
function l10n_update_system_update(array $components) {
$components += array(
'module' => array(),
'theme' => array(),
);
$list = array_merge($components['module'], $components['theme']);
if (!drupal_installation_attempted() && l10n_update_translatable_language_list() && variable_get('l10n_update_import_enabled', TRUE)) {
module_load_include('compare.inc', 'l10n_update');
$projects = array_keys(l10n_update_build_projects());
if ($list = array_intersect($list, $projects)) {
module_load_include('fetch.inc', 'l10n_update');
$options = _l10n_update_default_update_options();
$batch = l10n_update_batch_update_build($list, array(), $options);
batch_set($batch);
}
}
}
function l10n_update_system_remove(array $components) {
$components += array(
'module' => array(),
'theme' => array(),
);
$list = array_merge($components['module'], $components['theme']);
if ($language_list = l10n_update_translatable_language_list()) {
module_load_include('compare.inc', 'l10n_update');
module_load_include('bulk.inc', 'l10n_update');
$projects = array_keys(l10n_update_get_projects());
if ($list = array_intersect($list, $projects)) {
l10n_update_file_history_delete($list);
l10n_update_delete_translation_files($list, array());
db_delete('l10n_update_project')
->condition('name', $list)
->execute();
l10n_update_status_delete_projects($list);
}
}
}
function l10n_update_get_file_history() {
$history =& drupal_static(__FUNCTION__, array());
if (empty($history)) {
$result = db_query('SELECT project, language, filename, version, uri, timestamp, last_checked FROM {l10n_update_file}');
foreach ($result as $file) {
$file->langcode = $file->language;
$file->type = $file->timestamp ? L10N_UPDATE_CURRENT : '';
$history[$file->project][$file->langcode] = $file;
}
}
return $history;
}
function l10n_update_update_file_history($file) {
if (db_query("SELECT project FROM {l10n_update_file} WHERE project = :project AND language = :langcode", array(
':project' => $file->project,
':langcode' => $file->langcode,
))
->fetchField()) {
$update = array(
'project',
'language',
);
}
else {
$update = array();
}
$file->language = $file->langcode;
$result = drupal_write_record('l10n_update_file', $file, $update);
drupal_static_reset('l10n_update_get_file_history');
return $result;
}
function l10n_update_file_history_delete($projects = array(), $langcodes = array()) {
$query = db_delete('l10n_update_file');
if (!empty($projects)) {
$query
->condition('project', $projects);
}
if (!empty($langcodes)) {
$query
->condition('language', $langcodes);
}
$query
->execute();
}
function l10n_update_get_status($projects = NULL, $langcodes = NULL) {
module_load_include('translation.inc', 'l10n_update');
$result = array();
$cache = cache_get('l10n_update_status');
$status = $cache ? $cache->data : array();
$projects = $projects ? $projects : array_keys(l10n_update_get_projects());
$langcodes = $langcodes ? $langcodes : array_keys(l10n_update_translatable_language_list());
foreach ($projects as $project) {
foreach ($langcodes as $langcode) {
if (isset($status[$project][$langcode])) {
$result[$project][$langcode] = $status[$project][$langcode];
}
else {
$sources = l10n_update_build_sources(array(
$project,
), array(
$langcode,
));
if (isset($sources[$project][$langcode])) {
$result[$project][$langcode] = $sources[$project][$langcode];
}
}
}
}
return $result;
}
function l10n_update_status_save($project, $langcode, $type, $data) {
module_load_include('translation.inc', 'l10n_update');
$status = l10n_update_get_status();
if (empty($status)) {
$projects = l10n_update_get_projects(array(
$project,
));
if (isset($projects[$project])) {
$status[$project][$langcode] = l10n_update_source_build($projects[$project], $langcode);
}
}
if (isset($status[$project][$langcode])) {
switch ($type) {
case L10N_UPDATE_REMOTE:
case L10N_UPDATE_LOCAL:
$status[$project][$langcode]->files[$type] = $data;
if (isset($data->timestamp) && $data->timestamp) {
$version_changed = isset($status[$project][$langcode]->files[L10N_UPDATE_CURRENT]->version) && $status[$project][$langcode]->files[L10N_UPDATE_CURRENT]->version != $data->version;
if ($data->timestamp > $status[$project][$langcode]->timestamp || $version_changed) {
$status[$project][$langcode]->timestamp = $data->timestamp;
$status[$project][$langcode]->last_checked = REQUEST_TIME;
$status[$project][$langcode]->version = $data->version;
$status[$project][$langcode]->type = $type;
}
}
break;
case L10N_UPDATE_CURRENT:
$data->last_checked = REQUEST_TIME;
$status[$project][$langcode]->timestamp = $data->timestamp;
$status[$project][$langcode]->last_checked = $data->last_checked;
$status[$project][$langcode]->version = $data->version;
$status[$project][$langcode]->type = $type;
$status[$project][$langcode]->files[$type] = $data;
l10n_update_update_file_history($data);
break;
}
cache_set('l10n_update_status', $status);
variable_set('l10n_update_last_check', REQUEST_TIME);
}
}
function l10n_update_status_delete_languages(array $langcodes) {
if ($status = l10n_update_get_status()) {
foreach ($status as $project => $languages) {
foreach ($languages as $langcode => $source) {
if (in_array($langcode, $langcodes)) {
unset($status[$project][$langcode]);
}
}
}
cache_set('l10n_update_status', $status);
}
}
function l10n_update_status_delete_projects(array $projects) {
$status = l10n_update_get_status();
foreach ($status as $project => $languages) {
if (in_array($project, $projects)) {
unset($status[$project]);
}
}
cache_set('l10n_update_status', $status);
}
function l10n_update_translatable_language_list() {
$languages = locale_language_list('name');
unset($languages['en']);
drupal_alter('l10n_update_languages', $languages);
return $languages;
}
function l10n_update_clear_status() {
cache_clear_all('l10n_update_status', 'cache');
}
function l10n_update_use_remote_source() {
return variable_get('l10n_update_check_mode', L10N_UPDATE_USE_SOURCE_REMOTE_AND_LOCAL) == L10N_UPDATE_USE_SOURCE_REMOTE_AND_LOCAL;
}
function l10n_update_ensure_htaccess($directory = '') {
$directory = empty($directory) ? 'translations://' : $directory;
file_create_htaccess($directory, FALSE);
}