Commit 13c4788d authored by Riccardo Padovani's avatar Riccardo Padovani

Updated module l10n_update to version 7.x-1.0

parent db845230
File mode changed from 100644 to 100755
...@@ -26,42 +26,43 @@ Installation ...@@ -26,42 +26,43 @@ Installation
Download, unpack the module the usual way. Download, unpack the module the usual way.
Enable this module and the Locale module (core). Enable this module and the Locale module (core).
You need at least one language other than English. You need at least one language (besides the default English).
On Administration > Configuration > Regional and language: On Administration > Configuration > Regional and language > Languages:
Click "Add language" Click "Add language".
Pull-down menu: Choose your new language Select a language from the select list "Language name".
Then click "Add language" Then click the "Add language" button.
Drupal is now importing interface translations. This can take a few minutes. Drupal is now importing interface translations. This can take a few minutes.
When it's finished, you'll get a confirmation with a summary of all When it's finished, you'll get a confirmation with a summary of the
translation files that have been pulled in. translations that have been imported.
If required, enable the new language as default language. If required, enable the new language as default language.
Home > Administration > Configuration > Regional and language: Administration > Configuration > Regional and language > Languages:
Select your new language as default Select your new default language.
Update interface translations Update interface translations
----------------------------- -----------------------------
On Home > Administration > Configuration > Regional and language: You want to import translations regularly using cron. You can enable this
Choose the "Translation updates" tab on Administration > Configuration > Regional and language > Languages:
Change "Check for updates" to Daily or Weekly instead of the default "Never". Choose the "Translation updates" tab.
Change "Check for updates" to "Daily" or "Weekly" instead of the default "Never".
From now on cron will check for updated translations, and import them is required.
Cron will from now on check for updated translations, and will report the The status of the translations is reported on the "Status report" page at
update status on the status page (Home > Administration > Reports). Administration > Reports.
To check the translation status and execute updates manually, go to To check the translation status and execute updates manually, go to
Administration > Configuration > Regional and language > Translate inteface Administration > Configuration > Regional and language > Translate inteface
Here you see English and your new language. Choose the "Update" tab.
Choose the "Update" tab
You see a list of all modules and their translation status. You see a list of all modules and their translation status.
On the bottom of the page, you can manually update using "Update translations". On the bottom of the page, you can manually update using "Update translations".
Use Drush Use Drush
--------- ---------
You can also use drush to update your translations: You can also use drush to update your translations:
drush l10n-update # Update translations. drush l10n-update # Update translations.
drush l10n-update-refresh # Refresh available information. drush l10n-update-refresh # Refresh available information.
drush l10n-update-status # Show translation status of available project drush l10n-update-status # Show translation status of available project
Summary of administrative pages Summary of administrative pages
......
<?php
/**
* @file
* Definition of TranslationStreamWrapper.
*/
/**
* A Drupal interface translations (translations://) stream wrapper class.
*
* Supports storing translation files.
*/
class TranslationsStreamWrapper extends DrupalLocalStreamWrapper {
/**
* Implements abstract public function getDirectoryPath()
*/
public function getDirectoryPath() {
return variable_get('l10n_update_download_store', L10N_UPDATE_DEFAULT_TRANSLATION_PATH);
}
/**
* Overrides getExternalUrl().
*/
function getExternalUrl() {
throw new Exception('PO files URL should not be public.');
}
}
...@@ -59,7 +59,7 @@ function l10n_update_admin_overview() { ...@@ -59,7 +59,7 @@ function l10n_update_admin_overview() {
$build['admin_import_form'] = drupal_get_form('l10n_update_admin_import_form', $projects, $updates); $build['admin_import_form'] = drupal_get_form('l10n_update_admin_import_form', $projects, $updates);
} }
else { else {
$build['no_projects'] = array('#markup' => t('No projects or languages to update.')); $build['no_languages'] = array('#markup' => t('No translatable language defined. <a href="/admin/config/regional/language">Add a language</a>.'));
} }
return $build; return $build;
} }
...@@ -96,30 +96,29 @@ function l10n_update_admin_import_form($form, $form_state, $projects, $updates) ...@@ -96,30 +96,29 @@ function l10n_update_admin_import_form($form, $form_state, $projects, $updates)
'#type' => 'value', '#type' => 'value',
'#value' => $updates, '#value' => $updates,
); );
// @todo Only show this language fieldset if we have more than 1 language.
$form['lang'] = array( if (count($languages) > 1) {
'#type' => 'fieldset', $form['lang'] = array(
'#title' => t('Languages'), '#type' => 'fieldset',
'#collapsible' => TRUE, '#title' => t('Languages'),
'#collapsed' => TRUE, '#collapsible' => TRUE,
'#description' => t('Select one or more languages to download and update. If you select none, all of them will be updated.'), '#collapsed' => FALSE ,
); '#description' => t('Select one or more languages to download and update. If you select none, all of them will be updated.'),
$form['lang']['languages'] = array( );
'#type' => 'checkboxes', $form['lang']['languages'] = array(
'#options' => $languages, '#type' => 'checkboxes',
); '#options' => $languages,
$form['mode'] = array( );
'#type' => 'radios', }
'#title' => t('Update mode'),
'#default_value' => variable_get('l10n_update_import_mode', LOCALE_IMPORT_KEEP), if ($updates) {
'#options' => _l10n_update_admin_import_options(), $form['actions']['download'] = array(
); '#type' => 'submit',
$form['buttons']['download'] = array( '#value' => t('Update translations'),
'#type' => 'submit', );
'#value' => t('Update translations'), }
);
} }
$form['buttons']['refresh'] = array( $form['actions']['refresh'] = array(
'#type' => 'submit', '#type' => 'submit',
'#value' => t('Refresh information'), '#value' => t('Refresh information'),
); );
...@@ -137,9 +136,10 @@ function l10n_update_admin_import_form_submit($form, $form_state) { ...@@ -137,9 +136,10 @@ function l10n_update_admin_import_form_submit($form, $form_state) {
$projects = l10n_update_get_projects(); $projects = l10n_update_get_projects();
if ($op == t('Update translations')) { if ($op == t('Update translations')) {
$languages = array_filter($form_state['values']['languages']); $languages = isset($form_state['values']['languages']) ? array_filter($form_state['values']['languages']) : NULL;
$updates = $form_state['values']['updates']; $updates = $form_state['values']['updates'];
$mode = $form_state['values']['mode']; $mode = variable_get('l10n_update_import_mode', LOCALE_IMPORT_KEEP);
if ($projects && $updates) { if ($projects && $updates) {
module_load_include('batch.inc', 'l10n_update'); module_load_include('batch.inc', 'l10n_update');
// Filter out updates in other languages. If no languages, all of them will be updated // Filter out updates in other languages. If no languages, all of them will be updated
...@@ -147,9 +147,6 @@ function l10n_update_admin_import_form_submit($form, $form_state) { ...@@ -147,9 +147,6 @@ function l10n_update_admin_import_form_submit($form, $form_state) {
$batch = l10n_update_batch_multiple($updates, $mode); $batch = l10n_update_batch_multiple($updates, $mode);
batch_set($batch); batch_set($batch);
} }
else {
drupal_set_message(t('Cannot find any translation updates.'), 'error');
}
} }
elseif ($op == t('Refresh information')) { elseif ($op == t('Refresh information')) {
// Get current version of projects. // Get current version of projects.
......
...@@ -172,6 +172,10 @@ function _l10n_update_batch_import($id, $file, $mode, &$context) { ...@@ -172,6 +172,10 @@ function _l10n_update_batch_import($id, $file, $mode, &$context) {
$file = $context['results'][$id]['file']; $file = $context['results'][$id]['file'];
} }
if ($file) { if ($file) {
// Create a result if none exists yet.
if (!isset($context['results'][$id])) {
$context['results'][$id] = array();
}
if ($import_result = l10n_update_source_import($file, $mode)) { if ($import_result = l10n_update_source_import($file, $mode)) {
$context['message'] = $t('Imported: %name.', array('%name' => $file->filename)); $context['message'] = $t('Imported: %name.', array('%name' => $file->filename));
$context['results'][$id] = array_merge((array)$context['results'][$id], $import_result, array('file' => $file)); $context['results'][$id] = array_merge((array)$context['results'][$id], $import_result, array('file' => $file));
...@@ -249,6 +253,14 @@ function _l10n_update_batch_finished($success, $results) { ...@@ -249,6 +253,14 @@ function _l10n_update_batch_finished($success, $results) {
array('!log_messages' => l(t('Recent log messages'), 'admin/reports/dblog'))), array('!log_messages' => l(t('Recent log messages'), 'admin/reports/dblog'))),
'warning'); 'warning');
} }
// Clear cache and force refresh of JavaScript translations and rebuild
// the menu as strings may have changed.
foreach (array_keys($totals) as $langcode) {
_locale_invalidate_js($langcode);
}
cache_clear_all('locale:', 'cache', TRUE);
menu_rebuild();
} }
// Error for failed imports. // Error for failed imports.
......
...@@ -35,9 +35,7 @@ function l10n_update_available_releases($refresh = FALSE) { ...@@ -35,9 +35,7 @@ function l10n_update_available_releases($refresh = FALSE) {
else { else {
$projects = l10n_update_get_projects(TRUE); $projects = l10n_update_get_projects(TRUE);
$languages = l10n_update_language_list(); $languages = l10n_update_language_list();
$local = variable_get('l10n_update_check_mode', L10N_UPDATE_CHECK_ALL) & L10N_UPDATE_CHECK_LOCAL; $available = l10n_update_check_projects($projects, array_keys($languages));
$remote = variable_get('l10n_update_check_mode', L10N_UPDATE_CHECK_ALL) & L10N_UPDATE_CHECK_REMOTE;
$available = l10n_update_check_projects($projects, array_keys($languages), $local, $remote);
cache_set('l10n_update_available_releases', $available, 'cache_l10n_update', $frequency ? REQUEST_TIME + $frequency : CACHE_PERMANENT); cache_set('l10n_update_available_releases', $available, 'cache_l10n_update', $frequency ? REQUEST_TIME + $frequency : CACHE_PERMANENT);
return $available; return $available;
} }
...@@ -58,7 +56,14 @@ function l10n_update_available_releases($refresh = FALSE) { ...@@ -58,7 +56,14 @@ function l10n_update_available_releases($refresh = FALSE) {
* @return array * @return array
* Available sources indexed by project, language. * Available sources indexed by project, language.
*/ */
function l10n_update_check_projects($projects, $languages = NULL, $check_local = TRUE, $check_remote = TRUE) { function l10n_update_check_projects($projects, $languages = NULL, $check_local = NULL, $check_remote = NULL) {
if (!isset($check_local)) {
$check_local = (bool) (variable_get('l10n_update_check_mode', L10N_UPDATE_CHECK_ALL) & L10N_UPDATE_CHECK_LOCAL);
}
if (!isset($check_remote)) {
$check_remote = (bool) (variable_get('l10n_update_check_mode', L10N_UPDATE_CHECK_ALL) & L10N_UPDATE_CHECK_REMOTE);
}
$languages = $languages ? $languages : array_keys(l10n_update_language_list()); $languages = $languages ? $languages : array_keys(l10n_update_language_list());
$result = array(); $result = array();
foreach ($projects as $name => $project) { foreach ($projects as $name => $project) {
...@@ -132,8 +137,8 @@ function l10n_update_check_translations($count, $before, $limit = 1) { ...@@ -132,8 +137,8 @@ function l10n_update_check_translations($count, $before, $limit = 1) {
$result = $q->execute(); $result = $q->execute();
if ($result) { if ($result) {
$local = variable_get('l10n_update_check_mode', L10N_UPDATE_CHECK_ALL) & L10N_UPDATE_CHECK_LOCAL; $local = (bool) (variable_get('l10n_update_check_mode', L10N_UPDATE_CHECK_ALL) & L10N_UPDATE_CHECK_LOCAL);
$remote = variable_get('l10n_update_check_mode', L10N_UPDATE_CHECK_ALL) & L10N_UPDATE_CHECK_REMOTE; $remote = (bool) (variable_get('l10n_update_check_mode', L10N_UPDATE_CHECK_ALL) & L10N_UPDATE_CHECK_REMOTE);
foreach ($result as $check) { foreach ($result as $check) {
if (count($updated) >= $limit) { if (count($updated) >= $limit) {
break; break;
...@@ -230,7 +235,6 @@ function l10n_update_source_check($source, $check_local = TRUE, $check_remote = ...@@ -230,7 +235,6 @@ function l10n_update_source_check($source, $check_local = TRUE, $check_remote =
$remote = $check; $remote = $check;
} }
} }
// Get remote if newer than local only, they both can be empty // Get remote if newer than local only, they both can be empty
return _l10n_update_source_compare($local, $remote) < 0 ? $remote : $local; return _l10n_update_source_compare($local, $remote) < 0 ? $remote : $local;
} }
......
...@@ -23,7 +23,7 @@ function l10n_update_drush_command() { ...@@ -23,7 +23,7 @@ function l10n_update_drush_command() {
'description' => 'Update translations.', 'description' => 'Update translations.',
'options' => array( 'options' => array(
'languages' => 'Comma separated list of languages. Defaults to all available languages.', 'languages' => 'Comma separated list of languages. Defaults to all available languages.',
'mode' => 'Allowed values: overwrite, keep. Default value: keep.' 'mode' => 'Determine if existing translations are overwitten during import. Use "overwrite" to overwrite any existing translation, "replace" to replace previously imported translations but not overwrite edited strings, "keep" to keep any existing translation and only add new translations. Default value: keep'
), ),
); );
return $commands; return $commands;
...@@ -102,8 +102,8 @@ function drush_l10n_update_validate() { ...@@ -102,8 +102,8 @@ function drush_l10n_update_validate() {
// Check provided update mode is valid. // Check provided update mode is valid.
$mode = drush_get_option('mode', 'keep'); $mode = drush_get_option('mode', 'keep');
if (!in_array($mode, array('keep', 'overwrite'))) { if (!in_array($mode, array('keep', 'replace', 'overwrite'))) {
return drush_set_error('L10N_UPDATE_INVALID_MODE', dt('Invalid update mode. Valid options are keep, overwrite.')); return drush_set_error('L10N_UPDATE_INVALID_MODE', dt('Invalid update mode. Valid options are keep, replace, overwrite.'));
} }
} }
...@@ -118,6 +118,23 @@ function drush_l10n_update() { ...@@ -118,6 +118,23 @@ function drush_l10n_update() {
// Batch update all projects for selected languages. // Batch update all projects for selected languages.
$mode = drush_get_option('mode', 'keep'); $mode = drush_get_option('mode', 'keep');
switch ($mode) {
case 'keep':
$mode = LOCALE_IMPORT_KEEP;
break;
case 'replace':
$mode = LOCALE_UPDATE_OVERRIDE_DEFAULT;
break;
case 'overwrite':
$mode = LOCALE_IMPORT_OVERWRITE;
break;
default:
return drush_set_error('L10N_UPDATE_INVALID_MODE', dt('Invalid update mode. Valid options are keep, overwrite.'));
break;
}
$languages = drush_get_option('languages'); $languages = drush_get_option('languages');
module_load_include('batch.inc', 'l10n_update'); module_load_include('batch.inc', 'l10n_update');
$updates = _l10n_update_prepare_updates($updates, NULL, array_keys($languages)); $updates = _l10n_update_prepare_updates($updates, NULL, array_keys($languages));
......
...@@ -258,8 +258,29 @@ function l10n_update_flag_history($available) { ...@@ -258,8 +258,29 @@ function l10n_update_flag_history($available) {
*/ */
function l10n_update_http_check($url, $headers = array()) { function l10n_update_http_check($url, $headers = array()) {
$result = l10n_update_http_request($url, array('headers' => $headers, 'method' => 'HEAD')); $result = l10n_update_http_request($url, array('headers' => $headers, 'method' => 'HEAD'));
if ($result && $result->code == '200') { if (!isset($result->error)) {
$result->updated = isset($result->headers['last-modified']) ? strtotime($result->headers['last-modified']) : 0; if ($result && $result->code == 200) {
$result->updated = isset($result->headers['last-modified']) ? strtotime($result->headers['last-modified']) : 0;
}
return $result;
}
else {
switch ($result->code) {
case 404:
// File not found occurs when a translation file is not yet available
// at the translation server. But also if a custom module or custom
// theme does not define the location of a translation file. By default
// the file is checked at the translation server, but it will not be
// found there.
watchdog('l10n_update', 'File not found: @uri.', array('@uri' => $url));
return TRUE;
case 0:
watchdog('l10n_update', 'Error occurred when trying to check @remote: @errormessage.', array('@errormessage' => $result->error, '@remote' => $url), WATCHDOG_ERROR);
break;
default:
watchdog('l10n_update', 'HTTP error @errorcode occurred when trying to check @remote.', array('@errorcode' => $result->code, '@remote' => $url), WATCHDOG_ERROR);
break;
}
} }
return $result; return $result;
} }
...@@ -297,7 +318,8 @@ function l10n_update_http_check($url, $headers = array()) { ...@@ -297,7 +318,8 @@ function l10n_update_http_check($url, $headers = array()) {
* received. * received.
* - redirect_code: If redirected, an integer containing the initial response * - redirect_code: If redirected, an integer containing the initial response
* status code. * status code.
* - redirect_url: If redirected, a string containing the redirection location. * - redirect_url: If redirected, a string containing the URL of the redirect
* target.
* - error: If an error occurred, the error message. Otherwise not set. * - error: If an error occurred, the error message. Otherwise not set.
* - headers: An array containing the response headers as name/value pairs. * - headers: An array containing the response headers as name/value pairs.
* HTTP header names are case-insensitive (RFC 2616, section 4.2), so for * HTTP header names are case-insensitive (RFC 2616, section 4.2), so for
...@@ -333,10 +355,51 @@ function l10n_update_http_request($url, array $options = array()) { ...@@ -333,10 +355,51 @@ function l10n_update_http_request($url, array $options = array()) {
'timeout' => 30.0, 'timeout' => 30.0,
'context' => NULL, 'context' => NULL,
); );
// Merge the default headers.
$options['headers'] += array(
'User-Agent' => 'Drupal (+http://drupal.org/)',
);
// stream_socket_client() requires timeout to be a float. // stream_socket_client() requires timeout to be a float.
$options['timeout'] = (float) $options['timeout']; $options['timeout'] = (float) $options['timeout'];
// Use a proxy if one is defined and the host is not on the excluded list.
$proxy_server = variable_get('proxy_server', '');
if ($proxy_server && _drupal_http_use_proxy($uri['host'])) {
// Set the scheme so we open a socket to the proxy server.
$uri['scheme'] = 'proxy';
// Set the path to be the full URL.
$uri['path'] = $url;
// Since the URL is passed as the path, we won't use the parsed query.
unset($uri['query']);
// Add in username and password to Proxy-Authorization header if needed.
if ($proxy_username = variable_get('proxy_username', '')) {
$proxy_password = variable_get('proxy_password', '');
$options['headers']['Proxy-Authorization'] = 'Basic ' . base64_encode($proxy_username . (!empty($proxy_password) ? ":" . $proxy_password : ''));
}
// Some proxies reject requests with any User-Agent headers, while others
// require a specific one.
$proxy_user_agent = variable_get('proxy_user_agent', '');
// The default value matches neither condition.
if ($proxy_user_agent === NULL) {
unset($options['headers']['User-Agent']);
}
elseif ($proxy_user_agent) {
$options['headers']['User-Agent'] = $proxy_user_agent;
}
}
switch ($uri['scheme']) { switch ($uri['scheme']) {
case 'proxy':
// Make the socket connection to a proxy server.
$socket = 'tcp://' . $proxy_server . ':' . variable_get('proxy_port', 8080);
// The Host header still needs to match the real request.
$options['headers']['Host'] = $uri['host'];
$options['headers']['Host'] .= isset($uri['port']) && $uri['port'] != 80 ? ':' . $uri['port'] : '';
break;
case 'http': case 'http':
case 'feed': case 'feed':
$port = isset($uri['port']) ? $uri['port'] : 80; $port = isset($uri['port']) ? $uri['port'] : 80;
...@@ -346,12 +409,14 @@ function l10n_update_http_request($url, array $options = array()) { ...@@ -346,12 +409,14 @@ function l10n_update_http_request($url, array $options = array()) {
// checking the host that do not take into account the port number. // checking the host that do not take into account the port number.
$options['headers']['Host'] = $uri['host'] . ($port != 80 ? ':' . $port : ''); $options['headers']['Host'] = $uri['host'] . ($port != 80 ? ':' . $port : '');
break; break;
case 'https': case 'https':
// Note: Only works when PHP is compiled with OpenSSL support. // Note: Only works when PHP is compiled with OpenSSL support.
$port = isset($uri['port']) ? $uri['port'] : 443; $port = isset($uri['port']) ? $uri['port'] : 443;
$socket = 'ssl://' . $uri['host'] . ':' . $port; $socket = 'ssl://' . $uri['host'] . ':' . $port;
$options['headers']['Host'] = $uri['host'] . ($port != 443 ? ':' . $port : ''); $options['headers']['Host'] = $uri['host'] . ($port != 443 ? ':' . $port : '');
break; break;
default: default:
$result->error = 'invalid schema ' . $uri['scheme']; $result->error = 'invalid schema ' . $uri['scheme'];
$result->code = -1003; $result->code = -1003;
...@@ -376,7 +441,7 @@ function l10n_update_http_request($url, array $options = array()) { ...@@ -376,7 +441,7 @@ function l10n_update_http_request($url, array $options = array()) {
// Mark that this request failed. This will trigger a check of the web // Mark that this request failed. This will trigger a check of the web
// server's ability to make outgoing HTTP requests the next time that // server's ability to make outgoing HTTP requests the next time that
// requirements checking is performed. // requirements checking is performed.
// See system_requirements() // See system_requirements().
// variable_set('drupal_http_request_fails', TRUE); // variable_set('drupal_http_request_fails', TRUE);
return $result; return $result;
...@@ -388,11 +453,6 @@ function l10n_update_http_request($url, array $options = array()) { ...@@ -388,11 +453,6 @@ function l10n_update_http_request($url, array $options = array()) {
$path .= '?' . $uri['query']; $path .= '?' . $uri['query'];
} }
// Merge the default headers.
$options['headers'] += array(
'User-Agent' => 'Drupal (+http://drupal.org/)',
);
// Only add Content-Length if we actually have any content or if it is a POST // Only add Content-Length if we actually have any content or if it is a POST
// or PUT request. Some non-standard servers get confused by Content-Length in // or PUT request. Some non-standard servers get confused by Content-Length in
// at least HEAD/GET requests, and Squid always requires Content-Length in // at least HEAD/GET requests, and Squid always requires Content-Length in
...@@ -404,7 +464,7 @@ function l10n_update_http_request($url, array $options = array()) { ...@@ -404,7 +464,7 @@ function l10n_update_http_request($url, array $options = array()) {
// If the server URL has a user then attempt to use basic authentication. // If the server URL has a user then attempt to use basic authentication.
if (isset($uri['user'])) { if (isset($uri['user'])) {
$options['headers']['Authorization'] = 'Basic ' . base64_encode($uri['user'] . (!empty($uri['pass']) ? ":" . $uri['pass'] : '')); $options['headers']['Authorization'] = 'Basic ' . base64_encode($uri['user'] . (isset($uri['pass']) ? ':' . $uri['pass'] : ''));
} }
// If the database prefix is being used by SimpleTest to run the tests in a copied // If the database prefix is being used by SimpleTest to run the tests in a copied
...@@ -459,7 +519,9 @@ function l10n_update_http_request($url, array $options = array()) { ...@@ -459,7 +519,9 @@ function l10n_update_http_request($url, array $options = array()) {
return $result; return $result;
} }
// Parse response headers from the response body. // Parse response headers from the response body.
list($response, $result->data) = explode("\r\n\r\n", $response, 2); // Be tolerant of malformed HTTP responses that separate header and body with
// \n\n or \r\r instead of \r\n\r\n.
list($response, $result->data) = preg_split("/\r\n\r\n|\n\n|\r\r/", $response, 2);
$response = preg_split("/\r\n|\n|\r/", $response); $response = preg_split("/\r\n|\n|\r/", $response);
// Parse the response status line. // Parse the response status line.
...@@ -551,7 +613,9 @@ function l10n_update_http_request($url, array $options = array()) { ...@@ -551,7 +613,9 @@ function l10n_update_http_request($url, array $options = array()) {
$result = l10n_update_http_request($location, $options); $result = l10n_update_http_request($location, $options);
$result->redirect_code = $code; $result->redirect_code = $code;
} }
$result->redirect_url = $location; if (!isset($result->redirect_url)) {
$result->redirect_url = $location;
}
break; break;
default: default:
$result->error = $status_message; $result->error = $status_message;
......
...@@ -4,21 +4,12 @@ dependencies[] = locale ...@@ -4,21 +4,12 @@ dependencies[] = locale
core = 7.x core = 7.x
package = Multilingual package = Multilingual
files[] = l10n_update.admin.inc
files[] = l10n_update.api.php
files[] = l10n_update.batch.inc
files[] = l10n_update.check.inc
files[] = l10n_update.drush.inc
files[] = l10n_update.inc
files[] = l10n_update.install
files[] = l10n_update.locale.inc
files[] = l10n_update.module
files[] = l10n_update.parser.inc files[] = l10n_update.parser.inc
files[] = l10n_update.project.inc files[] = includes/locale/TranslationsStreamWrapper.php
; Information added by drupal.org packaging script on 2012-02-06 ; Information added by Drupal.org packaging script on 2014-04-12
version = "7.x-1.0-beta3" version = "7.x-1.0"
core = "7.x" core = "7.x"
project = "l10n_update" project = "l10n_update"
datestamp = "1328563848" datestamp = "1397295556"
...@@ -181,7 +181,7 @@ function l10n_update_uninstall() { ...@@ -181,7 +181,7 @@ function l10n_update_uninstall() {
* Implements hook_requirements(). * Implements hook_requirements().
*/ */
function l10n_update_requirements($phase) { function l10n_update_requirements($phase) {
if ($phase == 'runtime') { if ($phase == 'runtime' && variable_get('l10n_update_check_frequency', 0)) {
if (l10n_update_get_projects() && l10n_update_language_list()) { if (l10n_update_get_projects() && l10n_update_language_list()) {
$requirements['l10n_update']['title'] = t('Translation update status'); $requirements['l10n_update']['title'] = t('Translation update status');
if (l10n_update_available_updates()) { if (l10n_update_available_updates()) {
...@@ -282,3 +282,10 @@ function l10n_update_update_7004() { ...@@ -282,3 +282,10 @@ function l10n_update_update_7004() {
db_create_table('cache_l10n_update', $schema); db_create_table('cache_l10n_update', $schema);
} }
} }
/**
* Rebuild registry for 'translations' stream wrapper.
*/
function l10n_update_update_7005() {
registry_rebuild();
}
...@@ -46,13 +46,6 @@ function _l10n_update_locale_import_po($file, $langcode, $mode, $group = NULL) { ...@@ -46,13 +46,6 @@ function _l10n_update_locale_import_po($file, $langcode, $mode, $group = NULL) {
drupal_set_message(t('The translation file %filename appears to have a missing or malformed header.', array('%filename' => $file->filename)), 'error'); drupal_set_message(t('The translation file %filename appears to have a missing or malformed header.', array('%filename' => $file->filename)), 'error');
} }
// Clear cache and force refresh of JavaScript translations.
_locale_invalidate_js($langcode);
cache_clear_all('locale:', 'cache', TRUE);
// Rebuild the menu, strings may have changed.
menu_rebuild();
watchdog('locale', 'Imported %file into %locale: %number new strings added, %update updated and %delete removed.', array('%file' => $file->filename, '%locale' => $langcode, '%number' => $additions, '%update' => $updates, '%delete' => $deletes)); watchdog('locale', 'Imported %file into %locale: %number new strings added, %update updated and %delete removed.', array('%file' => $file->filename, '%locale' => $langcode, '%number' => $additions, '%update' => $updates, '%delete' => $deletes));
if ($skips) { if ($skips) {
watchdog('locale', '@count disallowed HTML string(s) in %file', array('@count' => $skips, '%file' => $file->uri), WATCHDOG_WARNING); watchdog('locale', '@count disallowed HTML string(s) in %file', array('@count' => $skips, '%file' => $file->uri), WATCHDOG_WARNING);
......
...@@ -87,7 +87,9 @@ function l10n_update_menu() { ...@@ -87,7 +87,9 @@ function l10n_update_menu() {
*/ */
function l10n_update_menu_alter(&$menu) { function l10n_update_menu_alter(&$menu) {
// Redirect l10n_client AJAX callback path for strings. // Redirect l10n_client AJAX callback path for strings.
$menu['l10n_client/save']['page callback'] = 'l10n_update_client_save_string'; if (module_exists('l10n_client')) {
$menu['l10n_client/save']['page callback'] = 'l10n_update_client_save_string';
}
} }
/** /**
...@@ -96,10 +98,15 @@ function l10n_update_menu_alter(&$menu) { ...@@ -96,10 +98,15 @@ function l10n_update_menu_alter(&$menu) {
* Check one project/language at a time, download and import if update available * Check one project/language at a time, download and import if update available
*/ */
function l10n_update_cron() { function l10n_update_cron() {
if ($frequency = variable_get('l10n_update_check_frequency', 0)) { $last = variable_get('l10n_update_last_check', 0);
$frequency = variable_get('l10n_update_check_frequency', 0) * 24 *3600;
if ($frequency && $last < REQUEST_TIME - $frequency) {
module_load_include('check.inc', 'l10n_update'); module_load_include('check.inc', 'l10n_update');
list($checked, $updated) = l10n_update_check_translations(L10N_UPDATE_CRON_PROJECTS, REQUEST_TIME - $frequency * 24 * 3600, L10N_UPDATE_CRON_UPDATES); list($checked, $updated) = l10n_update_check_translations(L10N_UPDATE_CRON_PROJECTS, REQUEST_TIME - $frequency, L10N_UPDATE_CRON_UPDATES);
watchdog('l10n_update', 'Automatically checked @checked translations, updated @updated.', array('@checked' => count($checked), '@updated' => count($updated))); if (count($checked) || count($updated)) {
watchdog('l10n_update', 'Automatically checked @checked translations, updated @updated.', array('@checked' => count($checked), '@updated' => count($updated)));
}
variable_set('l10n_update_last_check', REQUEST_TIME);
} }
} }
...@@ -109,8 +116,8 @@ function l10n_update_cron() { ...@@ -109,8 +116,8 @@ function l10n_update_cron() {
function l10n_update_form_alter(&$form, $form_state, $form_id) { function l10n_update_form_alter(&$form, $form_state, $form_id) {
switch ($form_id) { switch ($form_id) {
case 'locale_translate_edit_form': case 'locale_translate_edit_form':
// Replace the submit callback by our own customized version case 'i18n_string_locale_translate_edit_form':
$form['#submit'] = array('l10n_update_locale_translate_edit_form_submit'); $form['#submit'][] = 'l10n_update_locale_translate_edit_form_submit';
break; break;
case 'locale_languages_predefined_form': case 'locale_languages_predefined_form':
case 'locale_languages_custom_form': case 'locale_languages_custom_form':
...@@ -177,62 +184,47 @@ function l10n_update_languages_delete_submit($form, $form_state) { ...@@ -177,62 +184,47 @@ function l10n_update_languages_delete_submit($form, $form_state) {
} }
/** /**
* Replacement submit handler for translation edit form. * Additional submit handler for locale and i18n_string translation edit form.
* *
* Process string editing form submissions marking translations as customized. * Mark locally edited translations as customized.
* Saves all translations of one string submitted from a form.
* *
* @see l10n_update_form_alter() * @see l10n_update_form_alter()
* @todo Just mark as customized when string changed.
*/ */
function l10n_update_locale_translate_edit_form_submit($form, &$form_state) { function l10n_update_locale_translate_edit_form_submit($form, &$form_state) {
module_load_include('inc', 'l10n_update'); module_load_include('inc', 'l10n_update');
$lid = $form_state['values']['lid']; $lid = $form_state['values']['lid'];
foreach ($form_state['values']['translations'] as $key => $value) { foreach ($form_state['values']['translations'] as $langcode => $value) {
$translation = db_query("SELECT translation FROM {locales_target} WHERE lid = :lid AND language = :language", array(':lid' => $lid, ':language' => $key))->fetchField(); if (!empty($value) && $value != $form_state['complete form']['translations'][$langcode]['#default_value']) {
if (!empty($value)) { // An update has been made, mark the string as customized.
// Only update or insert if we have a value to use. db_update('locales_target')
if (!empty($translation)) { ->fields(array('l10n_status' => L10N_UPDATE_STRING_CUSTOM))
db_update('locales_target')
->fields(array(
'translation' => $value,
'l10n_status' => L10N_UPDATE_STRING_CUSTOM,
))
->condition('lid', $lid)
->condition('language', $key)
->execute();
}
else {
db_insert('locales_target')
->fields(array(
'lid' => $lid,
'translation' => $value,
'language' => $key,
'l10n_status' => L10N_UPDATE_STRING_CUSTOM,
))
->execute();
}
}
elseif (!empty($translation)) {
// Empty translation entered: remove existing entry from database.
db_delete('locales_target')
->condition('lid', $lid) ->condition('lid', $lid)
->condition('language', $key) ->condition('language', $langcode)
->execute(); ->execute();
} }
// Force JavaScript translation file recreation for this language.
_locale_invalidate_js($key);
} }
}
drupal_set_message(t('The string has been saved.')); /**
* Implements hook_stream_wrappers().
*
* Add a stream wrapper. The wrapper is not used in 7.x-1.x but is required to
* make upgrade to 7.x-2.x painless.
*/
function l10n_update_stream_wrappers() {
// Load the stream wrapper class if not automatically loaded. This happens when update.php is not yet executed.
if (!class_exists('TranslationsStreamWrapper')) {
require_once('includes/locale/TranslationsStreamWrapper.php');
}
// Clear locale cache. $wrappers['translations'] = array(
_locale_invalidate_js(); 'name' => t('Translation files'),
cache_clear_all('locale:', 'cache', TRUE); 'class' => 'TranslationsStreamWrapper',
'description' => t('Translation files.'),
'type' => STREAM_WRAPPERS_LOCAL_HIDDEN,
);
$form_state['redirect'] = 'admin/config/regional/translate/translate'; return $wrappers;
return;
} }
/** /**
...@@ -246,7 +238,7 @@ function l10n_update_client_save_string() { ...@@ -246,7 +238,7 @@ function l10n_update_client_save_string() {
// Ensure we have this source string before we attempt to save it. // Ensure we have this source string before we attempt to save it.
// @todo: add actual context support. // @todo: add actual context support.
$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(); $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)) { if (!empty($lid)) {
module_load_include('inc', 'l10n_update'); module_load_include('inc', 'l10n_update');
$report = array('skips' => 0, 'additions' => 0, 'updates' => 0, 'deletes' => 0); $report = array('skips' => 0, 'additions' => 0, 'updates' => 0, 'deletes' => 0);
......
...@@ -25,12 +25,16 @@ ...@@ -25,12 +25,16 @@
/** /**
* Rebuild project list * Rebuild project list
* *
* @param $refresh
* TRUE: Refresh project list.
*
* @return array * @return array
* Array of project objects to be considered for translation update.
*/ */
function l10n_update_build_projects() { function l10n_update_build_projects($refresh = FALSE) {
module_load_include('inc', 'l10n_update'); module_load_include('inc', 'l10n_update');
// Get all stored projects, including disabled ones // Get all stored projects, including disabled ones
$current = l10n_update_get_projects(NULL, TRUE); $current = l10n_update_get_projects($refresh, TRUE);
// Now get the new project list, just enabled ones // Now get the new project list, just enabled ones
$projects = l10n_update_project_list(); $projects = l10n_update_project_list();
...@@ -47,12 +51,25 @@ function l10n_update_build_projects() { ...@@ -47,12 +51,25 @@ function l10n_update_build_projects() {
$projects_info = update_get_available(TRUE); $projects_info = update_get_available(TRUE);
} }
foreach ($projects as $name => $data) { foreach ($projects as $name => $data) {
// Force update fetch of project data in cases where Drupal's performance
// optimized approach is missing out on some projects.
// @see http://drupal.org/node/1671570#comment-6216090
if (module_exists('update') && !isset($projects_info[$name])) {
module_load_include('fetch.inc', 'update');
_update_process_fetch_task($data);
$available = _update_get_cached_available_releases();
if (!empty($available[$name])) {
$projects_info[$name] = $available[$name];
}
}
if (isset($projects_info[$name]['releases']) && $projects_info[$name]['project_status'] != 'not-fetched') { if (isset($projects_info[$name]['releases']) && $projects_info[$name]['project_status'] != 'not-fetched') {
// Find out if a dev version is installed. // Find out if a dev version is installed.
if (preg_match("/^[0-9]+\.x-([0-9]+)\..*-dev$/", $data['info']['version'], $matches)) { if (preg_match("/^[0-9]+\.x-([0-9]+)\..*-dev$/", $data['info']['version'], $matches)) {
// Find a suitable release to use as alternative translation. // Find a suitable release to use as alternative translation.
foreach ($projects_info[$name]['releases'] as $project_release) { foreach ($projects_info[$name]['releases'] as $project_release) {
// The first release with the same major release number which is not // The first release with the same major release number which is not
// a dev release is the one. Releases are sorted the most recent first. // a dev release is the one. Releases are sorted the most recent first.
if ($project_release['version_major'] == $matches[1] && if ($project_release['version_major'] == $matches[1] &&
(!isset($project_release['version_extra']) || $project_release['version_extra'] != 'dev')) { (!isset($project_release['version_extra']) || $project_release['version_extra'] != 'dev')) {
...@@ -61,11 +78,6 @@ function l10n_update_build_projects() { ...@@ -61,11 +78,6 @@ function l10n_update_build_projects() {
} }
} }
} }
elseif ($name == "drupal" || preg_match("/HEAD/", $data['info']['version'], $matches)) {
// Pick latest available release.
$release = array_shift($projects_info[$name]['releases']);
}
if (!empty($release['version'])) { if (!empty($release['version'])) {
$data['info']['version'] = $release['version']; $data['info']['version'] = $release['version'];
} }
...@@ -101,7 +113,13 @@ function l10n_update_build_projects() { ...@@ -101,7 +113,13 @@ function l10n_update_build_projects() {
} }
// Create / update project record // Create / update project record
$update = empty($current[$name]) ? array() : array('name'); $update = empty($current[$name]) ? array() : array('name');
drupal_write_record('l10n_update_project', $project, $update); // @todo Use db_merge() to avoid problems with saving existing projects.
try {
drupal_write_record('l10n_update_project', $project, $update);
}
catch (Exception $e) {
watchdog('l10n_update', 'Could not insert a project into the l10n_update_project table, possibly because it already exists.', NULL, WATCHDOG_INFO);
}
$projects[$name] = $project; $projects[$name] = $project;
} }
return $projects; return $projects;
...@@ -136,7 +154,7 @@ function l10n_update_project_refresh($modules) { ...@@ -136,7 +154,7 @@ function l10n_update_project_refresh($modules) {
$projects = array(); $projects = array();
// Get all current projects, including the recently installed. // Get all current projects, including the recently installed.
$current_projects = l10n_update_build_projects(); $current_projects = l10n_update_build_projects(TRUE);
// Collect project data of newly installed projects. // Collect project data of newly installed projects.
foreach ($modules as $name) { foreach ($modules as $name) {
if (isset($current_projects[$name])) { if (isset($current_projects[$name])) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment