Updated BOINC translation settings form

* Added fields to configure Transifex settings for BOINC project
* Added Tools section for Import translations button
* Collapse Transifex settings section when configuration is complete

(DBOINCP-141)
This commit is contained in:
Tristan Olive 2015-03-10 22:42:49 -04:00
parent dd26d1f7dc
commit 7389bf9b2d
2 changed files with 273 additions and 161 deletions

View File

@ -12,35 +12,47 @@
*/
function boinctranslate_admin_settings(&$form_state) {
$form = array();
$initialized = FALSE;
$import_enabled = FALSE;
$default = array(
'transifex_user' => variable_get('boinc_translate_transifex_user', ''),
'transifex_pass' => variable_get('boinc_translate_transifex_pass', ''),
'transifex_resources' => variable_get(
'transifex_boinc_name' => variable_get(
'boinc_translate_transifex_standard_name', 'boinc'
),
'transifex_boinc_resources' => variable_get(
'boinc_translate_transifex_standard_resources',
"project-generic\nweb"
),
'transifex_project_name' => variable_get(
'boinc_translate_transifex_project_name', ''
),
'transifex_project_resources' => variable_get(
'boinc_translate_transifex_project_resources', ''
),
);
// Define the form
if ($default['transifex_user'] AND $default['transifex_pass']) {
if (trim($default['transifex_resources'])) {
$form['import_now'] = array(
'#value' => '<div class="form-item">'
. '<label>' . t('Import translations') . ':</label>'
. '<p>'
. l(t('Run the import now'), 'admin/boinc/translation/import')
. '</p>'
. '</div>',
);
if (trim($default['transifex_boinc_resources'])
OR trim($default['transifex_project_resources'])) {
$import_enabled = TRUE;
}
if ($default['transifex_boinc_name']
AND $default['transifex_project_name']
AND trim($default['transifex_boinc_resources'])
AND trim($default['transifex_project_resources'])) {
$initialized = TRUE;
}
}
// Define the form
$form['transifex'] = array(
'#title' => t('Transifex settings'),
'#type' => 'fieldset',
'#description' => '',
'#collapsible' => TRUE,
'#collapsed' => FALSE,
'#collapsed' => $initialized,
'#attributes' => array('class' => '')
);
$form['transifex']['boinc_translate_transifex_user'] = array(
@ -55,18 +67,67 @@ function boinctranslate_admin_settings(&$form_state) {
'placeholder' => $default['transifex_pass'] ? '********' : '',
),
);
$form['transifex']['boinc_translate_transifex_standard_name'] = array(
'#type' => 'textfield',
'#title' => t('BOINC Transifex project'),
'#default_value' => $default['transifex_boinc_name'],
'#description' => t('The portion of the Transifex URL that identifies BOINC.'),
);
$form['transifex']['boinc_translate_transifex_standard_resources'] = array(
'#type' => 'textarea',
'#title' => t('BOINC resources'),
'#default_value' => $default['transifex_boinc_resources'],
'#description' => t('List BOINC Transifex resources to be used for
translating strings on this site (one resource string per line).
Resources will be imported in the order they are given, so
translations from the resources at the top of the list will be overridden
by any matching translations found in resources further down the list.'),
);
$form['transifex']['boinc_translate_transifex_project_name'] = array(
'#type' => 'textfield',
'#title' => t('Project-specific Transifex project'),
'#default_value' => $default['transifex_project_name'],
'#description' => t('The portion of the Transifex URL that identifies this project.'),
);
$form['transifex']['boinc_translate_transifex_project_resources'] = array(
'#type' => 'textarea',
'#title' => t('Project-specific resources'),
'#default_value' => $default['transifex_resources'],
'#description' => t('List Transifex project resources to be used for
translating strings on this site (one per line in "project:resource"
format). Resources will be imported in the order they are given, so
'#default_value' => $default['transifex_project_resources'],
'#description' => t('List project-specific Transifex resources to be used
for translating strings on this site (one resource string per line).
Resources will be imported in the order they are given, so
translations from the resources at the top of the list will be overridden
by any matching translations found in resources further down the list.'),
);
);
$form['transifex']['buttons']['submit'] = array(
'#type' => 'submit',
'#value' => t('Save configuration'),
);
return system_settings_form($form);
$form['tools'] = array(
'#title' => t('Tools'),
'#type' => 'fieldset',
'#description' => '',
'#collapsible' => TRUE,
'#collapsed' => FALSE,
'#attributes' => array('class' => '')
);
$form['tools']['import_now'] = array(
'#type' => 'button',
'#value' => t('Import translations'),
'#executes_submit_callback' => TRUE,
'#submit' => array('boinctranslate_admin_settings_import_now'),
'#disabled' => !$import_enabled,
);
$form['#submit'][] = 'system_settings_form_submit';
$form['#theme'] = 'system_settings_form';
return $form;
}
function boinctranslate_admin_settings_import_now() {
drupal_goto('admin/boinc/translation/import');
}
/**
@ -88,15 +149,30 @@ function boinctranslate_admin_settings_validate($form, &$form_state) {
unset($form_state['values']['boinc_translate_transifex_pass']);
}
}
if (!$values['boinc_translate_transifex_standard_name']) {
form_set_error('boinc_translate_transifex_standard_name',
t('BOINC Transifex project name is required.')
);
}
if (!$values['boinc_translate_transifex_standard_resources']) {
form_set_error('boinc_translate_transifex_standard_resources',
t('At least one BOINC Transifex project resource is required.')
);
}
$username = $values['boinc_translate_transifex_user'];
$password = ($values['boinc_translate_transifex_pass']) ? $values['boinc_translate_transifex_pass'] : variable_get('boinc_translate_transifex_pass', '');
$boinc_name = $values['boinc_translate_transifex_standard_name'];
$boinc_resources = boinctranslate_parse_resources(
$values['boinc_translate_transifex_standard_resources']
);
if ($username AND $password) {
if ($username AND $password AND $boinc_name AND $boinc_resources) {
// Test authentication
$authenticated = FALSE;
$ch = curl_init();
$resource_url = "{$api_base_url}/project/boinc/resource/project-generic";
$resource_url = "{$api_base_url}/project/{$boinc_name}";
$resource_url .= "/resource/{$boinc_resources[0]}";
curl_setopt($ch, CURLOPT_URL, "{$resource_url}/translation/en");
curl_setopt($ch, CURLOPT_HTTPHEADER,
array(
@ -122,46 +198,60 @@ function boinctranslate_admin_settings_validate($form, &$form_state) {
}
if ($authenticated) {
// Try to access the given resources
$project_resources = explode("\n", $values['boinc_translate_transifex_project_resources']);
foreach ($project_resources as $line => $project_resource) {
$project_resource = trim($project_resource);
if (!$project_resource OR $project_resource[0] == '#') {
// Ignore empty lines and comments
continue;
}
// Check that resources can be parsed
list($project, $resource) = array_pad(explode(':', $project_resource), 2, '');
if (!$project OR !$resource) {
form_set_error(
'boinc_translate_transifex_project_resources',
t('Project resource could not be parsed at line @line',
array('@line' => $line+1)
)
);
break;
}
$ch = curl_init();
$resource_url = "{$api_base_url}/project/{$project}/resource/{$resource}";
curl_setopt($ch, CURLOPT_URL, "{$resource_url}/translation/en");
curl_setopt($ch, CURLOPT_HTTPHEADER,
array(
"Authorization: Basic " . base64_encode($username . ":" . $password)
)
// Prepare list of resources to validate
$transifex_resources = array(
'boinc' => $boinc_resources,
);
// Parse project-specific resources
$project_name = trim($values['boinc_translate_transifex_project_name']);
$project_resources = boinctranslate_parse_resources(
$values['boinc_translate_transifex_project_resources']
);
if ($project_name AND $project_resources) {
$transifex_resources[$project_name] = $project_resources;
}
elseif ($project_name AND !$project_resources) {
drupal_set_message(
t('No project-specific resources were provided'),
'warning'
);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
$result = curl_exec($ch);
if (strstr($result, '404 NOT FOUND')) {
form_set_error(
'boinc_translate_transifex_project_resources',
t('Project resource %name not found.',
array('%name' => "{$project}:{$resource}")
}
elseif ($project_resources AND !$project_name) {
drupal_set_message(
t('No project-specific Transifex project name was provided'),
'warning'
);
}
// Try to access the given resources
foreach ($transifex_resources as $project => $resources) {
foreach ($resources as $resource) {
$ch = curl_init();
$resource_url = "{$api_base_url}/project/{$project}/resource/{$resource}";
curl_setopt($ch, CURLOPT_URL, "{$resource_url}/translation/en");
curl_setopt($ch, CURLOPT_HTTPHEADER,
array(
"Authorization: Basic " . base64_encode($username . ":" . $password)
)
);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
$result = curl_exec($ch);
list($response_header, $response_body) = explode("\r\n\r\n", $result, 2);
if (strstr($response_header, '404 NOT FOUND')) {
form_set_error(
'boinc_translate_transifex_' . ($project == $boinc_name ? 'standard' : 'project') . '_resources',
t('Resource %name not found in %project.',
array(
'%name' => $resource,
'%project' => $project,
)
)
);
}
}
}
}
@ -175,3 +265,4 @@ function boinctranslate_admin_settings_submit($form, &$form_state) {
drupal_set_message(t('BOINC translation settings have been updated.'));
}

View File

@ -78,45 +78,39 @@ function boinctranslate_refresh_translations() {
$username = variable_get('boinc_translate_transifex_user', '');
$password = variable_get('boinc_translate_transifex_pass', '');
$languages = locale_language_list();
$translation_resources = array(
'default' => array(
'resources' => array(
'boinc' => array(
'project-generic',
'web',
),
),
$translation_resources = array();
$boinc_name = variable_get(
'boinc_translate_transifex_standard_name', ''
);
$boinc_resources = boinctranslate_parse_resources(
variable_get('boinc_translate_transifex_standard_resources', array())
);
if ($boinc_name AND $boinc_resources) {
$translation_resources[$boinc_name] = array(
'resources' => $boinc_resources,
'textgroups' => array(
'default',
'taxonomy',
'views',
),
),
'project' => array(
'resources' => array(),
);
}
$project_name = variable_get(
'boinc_translate_transifex_project_name', ''
);
$project_resources = boinctranslate_parse_resources(
variable_get('boinc_translate_transifex_project_resources', array())
);
if ($project_name AND $project_resources) {
$translation_resources[$project_name] = array(
'resources' => $project_resources,
'textgroups' => array(
'blocks',
'menu',
'project',
),
),
);
$project_resources = explode("\n",
variable_get('boinc_translate_transifex_project_resources', array())
);
foreach ($project_resources as $line => $project_resource) {
$project_resource = trim($project_resource);
if (!$project_resource OR $project_resource[0] == '#') {
// Ignore empty lines and comments
continue;
}
// Check that resources can be parsed
list($project, $resource) = array_pad(explode(':', $project_resource), 2, '');
if (!$project OR !$resource) {
continue;
}
$translation_resources['project']['resources'][$project][] = $resource;
);
}
if ($username AND $password) {
@ -124,88 +118,96 @@ function boinctranslate_refresh_translations() {
if ($langcode == 'en') {
continue;
}
foreach ($translation_resources as $type => $translation) {
foreach ($translation['resources'] as $project => $resources) {
foreach ($resources as $resource) {
// Import the configured resources
$ch = curl_init();
$resource_url = "{$api_base_url}/project/{$project}/resource/{$resource}";
curl_setopt($ch, CURLOPT_URL, "{$resource_url}/translation/{$langcode}");
curl_setopt($ch, CURLOPT_HTTPHEADER,
array(
"Authorization: Basic " . base64_encode($username . ":" . $password)
)
);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
$result = curl_exec($ch);
list($response_header, $response_body) = explode("\r\n\r\n", $result, 2);
if (strstr($response_header, '404 NOT FOUND')) {
drupal_set_message(
t('Project resource %name not found in @language.',
array(
'%name' => "{$project}:{$resource}",
'@language' => $language,
)
), 'warning'
);
}
elseif ($response_body) {
// Process as JSON
$json_data = json_decode($response_body, TRUE);
if (!empty($json_data['content'])) {
$po_text = $json_data['content'];
// Write the translation file to a temporary location
$file = new stdClass();
$file->filepath = file_save_data($po_text, NULL);
$file->filename = basename($file->filepath);
if (!$file->filepath) {
drupal_set_message(t(
'Unable to create temporary file in %tmpdir for @language translation resource %name',
array(
'%tmpdir' => file_directory_temp(),
'@language' => $language,
'%name' => "{$project}:{$resource}",
)
), 'error');
continue;
}
foreach ($translation['textgroups'] as $textgroup) {
// Import the translations from the file to each related textgroup
if (!_boinctranslate_locale_import_po($file, $langcode, LOCALE_IMPORT_OVERWRITE, $textgroup)) {
$variables = array(
'@language' => $language,
'%resource' => "{$project}:{$resource}",
);
drupal_set_message(t('The @language translation import of %resource failed.', $variables), 'error');
watchdog('locale', 'The @language translation import of %resource failed.', $variables, WATCHDOG_ERROR);
break;
}
}
}
else {
$variables = array(
foreach ($translation_resources as $project => $translation) {
foreach ($translation['resources'] as $resource) {
// Import the configured resources
$ch = curl_init();
$resource_url = "{$api_base_url}/project/{$project}";
$resource_url .= "/resource/{$resource}";
curl_setopt($ch, CURLOPT_URL, "{$resource_url}/translation/{$langcode}");
curl_setopt($ch, CURLOPT_HTTPHEADER,
array(
"Authorization: Basic " . base64_encode($username . ":" . $password)
)
);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
$result = curl_exec($ch);
list($response_header, $response_body) = explode("\r\n\r\n", $result, 2);
if (strstr($response_header, '404 NOT FOUND')) {
drupal_set_message(
t('Project resource %name not found in @language.',
array(
'%name' => "{$project}:{$resource}",
'@language' => $language,
'%resource' => "{$project}:{$resource}",
);
drupal_set_message(t('Unable to read response for @language translation import of %resource.', $variables), 'error');
watchdog('locale', 'Unable to read response for @language translation import of %resource.', $variables, WATCHDOG_ERROR);
)
), 'warning'
);
}
elseif ($response_body) {
// Process as JSON
$json_data = json_decode($response_body, TRUE);
if (!empty($json_data['content'])) {
$po_text = $json_data['content'];
// Write the translation file to a temporary location
$file = new stdClass();
$file->filepath = file_save_data($po_text, NULL);
$file->filename = basename($file->filepath);
if (!$file->filepath) {
drupal_set_message(t(
'Unable to create temporary file in %tmpdir for @language translation resource %name',
array(
'%tmpdir' => file_directory_temp(),
'@language' => $language,
'%name' => "{$project}:{$resource}",
)
), 'error');
continue;
}
foreach ($translation['textgroups'] as $textgroup) {
watchdog(
'boinctranslate',
'Importing @language translation of %resource into %group textgroup',
array(
'@language' => $language,
'%resource' => "{$project}:{$resource}",
'%group' => $textgroup,
),
WATCHDOG_NOTICE);
// Import the translations from the file to each related textgroup
if (!_boinctranslate_locale_import_po($file, $langcode, LOCALE_IMPORT_OVERWRITE, $textgroup)) {
$variables = array(
'@language' => $language,
'%resource' => "{$project}:{$resource}",
);
drupal_set_message(t('The @language translation import of %resource failed.', $variables), 'error');
watchdog('locale', 'The @language translation import of %resource failed.', $variables, WATCHDOG_ERROR);
break;
}
}
}
else {
$variables = array(
$variables = array(
'@language' => $language,
'%resource' => "{$project}:{$resource}",
);
drupal_set_message(t('Translation data not found in response for @language translation import of %resource.', $variables), 'error');
watchdog('locale', 'Translation data not found in response for @language translation import of %resource.', $variables, WATCHDOG_ERROR);
drupal_set_message(t('Unable to read response for @language translation import of %resource.', $variables), 'error');
watchdog('locale', 'Unable to read response for @language translation import of %resource.', $variables, WATCHDOG_ERROR);
}
}
else {
$variables = array(
'@language' => $language,
'%resource' => "{$project}:{$resource}",
);
drupal_set_message(t('Translation data not found in response for @language translation import of %resource.', $variables), 'error');
watchdog('locale', 'Translation data not found in response for @language translation import of %resource.', $variables, WATCHDOG_ERROR);
}
}
}
}
@ -642,4 +644,23 @@ function _boinctranslate_locale_import_one_string($op, $value = NULL, $mode = NU
}
return $lid;
}
}
/**
* Parse valid resources out of configuration
*/
function boinctranslate_parse_resources($resource_text) {
$resources = array();
$resource_array = explode(
"\n", $resource_text
);
foreach ($resource_array as $resource) {
$resource = trim($resource);
if ($resource AND $resource[0] != '#') {
$resources[] = $resource;
}
}
return $resources;
}