Commit fff45d1f authored by Dries's avatar Dries
Browse files

- Patch #139970 by Gabor: locale cleanup.

parent 2a65f86b
......@@ -3,60 +3,18 @@
/**
* @file
* Admin-related functions for locale.module.
* Administration functions for locale.module.
*/
// ---------------------------------------------------------------------------------
// Language management functionality (administration only)
/**
* Helper function to add a language
*
* @param $code
* Language code.
* @param $name
* English name of the language
* @param $native
* Native name of the language
* @param $direction
* 0 for left to right, 1 for right to left direction
* @param $domain
* Optional custom domain name with protocol, without
* trailing slash (eg. http://de.example.com).
* @param $prefix
* Optional path prefix for the language. Defaults to the
* language code if omitted.
* @param $verbose
* Switch to omit the verbose message to the user when used
* only as a utility function.
* @defgroup locale-language-overview Language overview functionality
* @{
*/
function _locale_add_language($code, $name, $native, $direction = 0, $domain = '', $prefix = '', $verbose = TRUE) {
if (empty($prefix)) {
$prefix = $code;
}
db_query("INSERT INTO {languages} (language, name, native, direction, domain, prefix) VALUES ('%s', '%s', '%s', %d, '%s', '%s')", $code, $name, $native, $direction, $domain, $prefix);
$result = db_query("SELECT lid FROM {locales_source}");
while ($string = db_fetch_object($result)) {
db_query("INSERT INTO {locales_target} (lid, language, translation) VALUES (%d,'%s', '')", $string->lid, $code);
}
// If only the language was added, and not a PO file import triggered
// the language addition, we need to inform the user on how to start
// working with the language.
if ($verbose) {
drupal_set_message(t('The language %language has been created and can now be used. More information is available on the <a href="@locale-help">help screen</a>.', array('%language' => t($name), '@locale-help' => url('admin/help/locale'))));
}
else {
drupal_set_message(t('The language %language has been created.', array('%language' => t($name))));
}
watchdog('locale', 'The %language language (%code) has been created.', array('%language' => $name, '%code' => $code));
}
/**
* User interface for the language management screen.
* User interface for the language overview screen.
*/
function _locale_admin_manage_screen() {
function locale_languages_overview_form() {
$languages = language_list('language', TRUE);
$options = array();
......@@ -73,7 +31,7 @@ function _locale_admin_manage_screen() {
);
$form['name'][$langcode] = array('#value' => check_plain($language->name));
$form['native'][$langcode] = array('#value' => check_plain($language->native));
$form['direction'][$langcode] = array('#value' => ($language->direction ? 'Right to left' : 'Left to right'));
$form['direction'][$langcode] = array('#value' => ($language->direction == LANGUAGE_RTL ? 'Right to left' : 'Left to right'));
}
$form['enabled'] = array('#type' => 'checkboxes',
'#options' => $options,
......@@ -85,21 +43,20 @@ function _locale_admin_manage_screen() {
'#default_value' => $default->language,
);
$form['submit'] = array('#type' => 'submit', '#value' => t('Save configuration'));
$form['#submit']['_locale_admin_manage_screen_submit'] = array();
$form['#theme'] = 'locale_admin_manage_screen';
$form['#theme'] = 'locale_languages_overview_form';
return $form;
}
/**
* Theme the admin langauge manager form.
* Theme the langauge overview form.
*/
function theme_locale_admin_manage_screen($form) {
function theme_locale_languages_overview_form($form) {
$default = language_default();
foreach ($form['name'] as $key => $element) {
// Do not take form control structures.
if (is_array($element) && element_child($key)) {
$rows[] = array(array('data' => drupal_render($form['enabled'][$key]), 'align' => 'center'), check_plain($key), '<strong>'. drupal_render($form['name'][$key]) .'</strong>', drupal_render($form['native'][$key]), drupal_render($form['direction'][$key]), drupal_render($form['site_default'][$key]), drupal_render($form['weight'][$key]), l(t('edit'), 'admin/build/locale/language/edit/'. $key). (($key != 'en' && $key != $default->language) ? ' '. l(t('delete') ,'admin/build/locale/language/delete/'. $key) : ''));
$rows[] = array(array('data' => drupal_render($form['enabled'][$key]), 'align' => 'center'), check_plain($key), '<strong>'. drupal_render($form['name'][$key]) .'</strong>', drupal_render($form['native'][$key]), drupal_render($form['direction'][$key]), drupal_render($form['site_default'][$key]), drupal_render($form['weight'][$key]), l(t('edit'), 'admin/settings/language/edit/'. $key). (($key != 'en' && $key != $default->language) ? ' '. l(t('delete') ,'admin/settings/language/delete/'. $key) : ''));
}
}
$header = array(array('data' => t('Enabled')), array('data' => t('Code')), array('data' => t('English name')), array('data' => t('Native name')), array('data' => t('Direction')), array('data' => t('Default')), array('data' => t('Weight')), array('data' => t('Operations')));
......@@ -110,15 +67,15 @@ function theme_locale_admin_manage_screen($form) {
}
/**
* Process locale admin manager form submissions.
* Process language overview form submissions, updating existing languages.
*/
function _locale_admin_manage_screen_submit($form_id, $form_values) {
// Save changes to existing languages.
function locale_languages_overview_form_submit($form_id, $form_values) {
$languages = language_list();
$enabled_count = 0;
foreach ($languages as $langcode => $language) {
if ($form_values['site_default'] == $langcode) {
$form_values['enabled'][$langcode] = 1; // autoenable the default language
// Automatically enable the default language.
$form_values['enabled'][$langcode] = 1;
}
if ($form_values['enabled'][$langcode]) {
$enabled_count++;
......@@ -138,13 +95,30 @@ function _locale_admin_manage_screen_submit($form_id, $form_values) {
// Changing the language settings impacts the interface.
cache_clear_all('*', 'cache_page', TRUE);
return 'admin/build/locale/language/overview';
return 'admin/settings/language';
}
/**
* @} End of "locale-language-overview"
*/
/**
* @defgroup locale-language-add-edit Language addition and editing functionality
* @{
*/
/**
* User interface for the language addition screen.
*/
function locale_languages_add_screen() {
$output = drupal_get_form('locale_languages_predefined_form');
$output .= drupal_get_form('locale_languages_custom_form');
return $output;
}
/**
* Predefined language setup form.
*/
function locale_add_language_form() {
function locale_languages_predefined_form() {
$predefined = _locale_prepare_predefined_list();
$form = array();
$form['language list'] = array('#type' => 'fieldset',
......@@ -164,21 +138,20 @@ function locale_add_language_form() {
/**
* Custom language addition form.
*/
function locale_custom_language_form() {
function locale_languages_custom_form() {
$form = array();
$form['custom language'] = array('#type' => 'fieldset',
'#title' => t('Custom language'),
'#collapsible' => TRUE,
);
_locale_language_form($form['custom language']);
_locale_languages_common_controls($form['custom language']);
$form['custom language']['submit'] = array(
'#type' => 'submit',
'#value' => t('Add custom language')
);
// Use the validation and submit functions of the add language form.
$form['#submit']['locale_add_language_form_submit'] = array();
$form['#validate']['locale_add_language_form_validate'] = array();
$form['#theme'] = 'locale_add_language_form';
// Reuse the validation and submit functions of the predefined language setup form.
$form['#submit']['locale_languages_predefined_form_submit'] = array();
$form['#validate']['locale_languages_predefined_form_validate'] = array();
return $form;
}
......@@ -188,17 +161,16 @@ function locale_custom_language_form() {
* @param $langcode
* Language code of the language to edit.
*/
function _locale_admin_manage_edit_screen($langcode) {
function locale_languages_edit_form($langcode) {
if ($language = db_fetch_object(db_query("SELECT * FROM {languages} WHERE language = '%s'", $langcode))) {
$form = array();
_locale_language_form($form, $language);
_locale_languages_common_controls($form, $language);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Save language')
);
$form['#submit']['locale_edit_language_form_submit'] = array();
$form['#validate']['locale_edit_language_form_validate'] = array();
$form['#theme'] = 'locale_edit_language_form';
$form['#submit']['locale_languages_edit_form_submit'] = array();
$form['#validate']['locale_languages_edit_form_validate'] = array();
return $form;
}
else {
......@@ -207,14 +179,14 @@ function _locale_admin_manage_edit_screen($langcode) {
}
/**
* Common pieces of the language addition and editing form.
* Common elements of the language addition and editing form.
*
* @param $form
* A parent form item (or empty array) to add items below.
* @param $language
* Language object to edit.
*/
function _locale_language_form(&$form, $language = NULL) {
function _locale_languages_common_controls(&$form, $language = NULL) {
if (!is_object($language)) {
$language = new stdClass();
}
......@@ -271,63 +243,57 @@ function _locale_language_form(&$form, $language = NULL) {
'#required' => TRUE,
'#description' => t('Direction of the text being written in this language.'),
'#default_value' => @$language->direction,
'#options' => array(0 => t('Left to right'), 1 => t('Right to left'))
'#options' => array(LANGUAGE_LTR => t('Left to right'), LANGUAGE_RTL => t('Right to left'))
);
return $form;
}
/**
* User interface for the language addition screen.
*/
function _locale_admin_manage_add_screen() {
$output = drupal_get_form('locale_add_language_form');
$output .= drupal_get_form('locale_custom_language_form');
return $output;
}
/**
* Validate the language addition form.
*/
function locale_add_language_form_validate($form_id, $form_values) {
if ($duplicate = db_num_rows(db_query("SELECT language FROM {languages} WHERE language = '%s'", $form_values['langcode'])) != 0) {
form_set_error('langcode', t('The language %language (%code) already exists.', array('%language' => $form_values['name'], '%code' => $form_values['langcode'])));
function locale_languages_predefined_form_validate($form_id, $form_values) {
$langcode = $form_values['langcode'];
if ($duplicate = db_num_rows(db_query("SELECT language FROM {languages} WHERE language = '%s'", $langcode)) != 0) {
form_set_error('langcode', t('The language %language (%code) already exists.', array('%language' => $form_values['name'], '%code' => $langcode)));
}
if (!isset($form_values['name'])) {
// Predefined language selection.
$predefined = _locale_get_predefined_list();
if (!isset($predefined[$form_values['langcode']])) {
if (!isset($predefined[$langcode])) {
form_set_error('langcode', t('Invalid language code.'));
}
}
else {
// Reuse the editing form validation routine if we add a custom language
locale_edit_language_form_validate($form_id, $form_values);
// Reuse the editing form validation routine if we add a custom language.
locale_languages_edit_form_validate($form_id, $form_values);
}
}
/**
* Process the language addition form submission.
*/
function locale_add_language_form_submit($form_id, $form_values) {
function locale_languages_predefined_form_submit($form_id, $form_values) {
$langcode = $form_values['langcode'];
if (isset($form_values['name'])) {
// Custom language form.
_locale_add_language($form_values['langcode'], $form_values['name'], $form_values['native'], $form_values['direction'], $form_values['domain'], $form_values['prefix']);
locale_add_language($langcode, $form_values['name'], $form_values['native'], $form_values['direction'], $form_values['domain'], $form_values['prefix']);
}
else {
// Predefined language selection.
$predefined = _locale_get_predefined_list();
$lang = &$predefined[$form_values['langcode']];
_locale_add_language($form_values['langcode'], $lang[0], isset($lang[1]) ? $lang[1] : $lang[0], isset($lang[2]) ? $lang[2] : 0, '', $form_values['langcode']);
$lang = &$predefined[$langcode];
locale_add_language($langcode, $lang[0], isset($lang[1]) ? $lang[1] : $lang[0], isset($lang[2]) ? $lang[2] : 0, '', $langcode);
}
return 'admin/build/locale';
return 'admin/settings/language';
}
/**
* Validate the language editing form. Reused for custom language addition too.
*/
function locale_edit_language_form_validate($form_id, $form_values) {
function locale_languages_edit_form_validate($form_id, $form_values) {
if (!empty($form_values['domain']) && !empty($form_values['prefix'])) {
form_set_error('prefix', t('Domain and path prefix values should not be set at the same time.'));
}
......@@ -346,7 +312,7 @@ function locale_edit_language_form_validate($form_id, $form_values) {
/**
* Process the language editing form submission.
*/
function locale_edit_language_form_submit($form_id, $form_values) {
function locale_languages_edit_form_submit($form_id, $form_values) {
db_query("UPDATE {languages} SET name = '%s', native = '%s', domain = '%s', prefix = '%s', direction = %d WHERE language = '%s'", $form_values['name'], $form_values['native'], $form_values['domain'], $form_values['prefix'], $form_values['direction'], $form_values['langcode']);
$default = language_default();
if ($default->language == $form_values['langcode']) {
......@@ -356,13 +322,78 @@ function locale_edit_language_form_submit($form_id, $form_values) {
}
variable_set('language_default', $default);
}
return 'admin/build/locale';
return 'admin/settings/language';
}
/**
* @} End of "locale-language-add-edit"
*/
/**
* @defgroup locale-language-delete Language deletion functionality
* @{
*/
/**
* User interface for the language deletion confirmation screen.
*/
function locale_languages_delete_form($langcode) {
// Do not allow deletion of English locale.
if ($langcode == 'en') {
drupal_set_message(t('The English language cannot be deleted.'));
drupal_goto('admin/settings/language');
}
$default = language_default();
if ($default->language == $langcode) {
drupal_set_message(t('The default language cannot be deleted.'));
drupal_goto('admin/settings/language');
}
// For other languages, warn user that data loss is ahead.
$languages = language_list();
if (!isset($languages[$langcode])) {
drupal_not_found();
}
else {
$form['langcode'] = array('#type' => 'value', '#value' => $langcode);
return confirm_form($form, t('Are you sure you want to delete the language %name?', array('%name' => t($languages[$langcode]->name))), 'admin/settings/language', t('Deleting a language will remove all interface translations associated with it, and posts in this language will be set to be language neutral. This action cannot be undone.'), t('Delete'), t('Cancel'));
}
}
/**
* Process language deletion submissions.
*/
function locale_languages_delete_form_submit($form_id, $form_values) {
$languages = language_list();
if (isset($languages[$form_values['langcode']])) {
db_query("DELETE FROM {languages} WHERE language = '%s'", $form_values['langcode']);
db_query("DELETE FROM {locales_target} WHERE language = '%s'", $form_values['langcode']);
db_query("UPDATE {node} SET language = '' WHERE language = '%s'", $form_values['langcode']);
$variables = array('%locale' => $languages[$form_values['langcode']]->name);
drupal_set_message(t('The language %locale has been removed.', $variables));
watchdog('locale', 'The language %locale has been removed.', $variables);
}
// Changing the language settings impacts the interface:
cache_clear_all('*', 'cache_page', TRUE);
return 'admin/settings/language';
}
/**
* @} End of "locale-language-add-edit"
*/
/**
* @defgroup locale-languages-negotiation Language negotiation options screen
* @{
*/
/**
* Setting for language negotiation options
*/
function locale_configure_language_form() {
function locale_languages_configure_form() {
$form['language_negotiation'] = array(
'#title' => t('Language negotiation'),
'#type' => 'radios',
......@@ -372,7 +403,7 @@ function locale_configure_language_form() {
LANGUAGE_NEGOTIATION_PATH => t('Path prefix with language fallback. If a suitable path prefix is not identified, language is based on user preferences and browser language settings.'),
LANGUAGE_NEGOTIATION_DOMAIN => t('Domain name only. If a suitable domain name is not identified, the default language is used.')),
'#default_value' => variable_get('language_negotiation', LANGUAGE_NEGOTIATION_NONE),
'#description' => t('How should languages get detected? Changing this also changes how paths are constructed, so setting a different value breaks all URLs. Do not change on a live site without thinking twice!')
'#description' => t('The used language detection mode. Changing this also changes how paths are constructed, so setting a different value breaks all incoming links. Do not change on a live site without thinking twice!')
);
$form['submit'] = array(
'#type' => 'submit',
......@@ -384,21 +415,128 @@ function locale_configure_language_form() {
/**
* Submit function for language negotiation settings.
*/
function locale_configure_language_form_submit($form_id, $form_values) {
function locale_languages_configure_form_submit($form_id, $form_values) {
variable_set('language_negotiation', $form_values['language_negotiation']);
drupal_set_message(t('Language negotiation configuration saved.'));
return 'admin/build/locale';
return 'admin/settings/language';
}
/**
* @} End of "locale-languages-negotiation"
*/
/**
* @defgroup locale-translate-overview Translation overview screen.
* @{
*/
/**
* Overview screen for translations.
*/
function locale_translate_overview_screen() {
$languages = language_list('language', TRUE);
$groups = module_invoke_all('locale', 'groups');
// Build headers with all groups in order.
$headers = array_merge(array(t('Language')), array_values($groups));
// Collect summaries of all source strings in all groups.
$sums = db_query("SELECT COUNT(*) AS strings, textgroup FROM {locales_source} GROUP BY textgroup");
$groupsums = array();
while ($group = db_fetch_object($sums)) {
$groupsums[$group->textgroup] = $group->strings;
}
// Setup overview table with default values, ensuring common order for values.
$rows = array();
foreach ($languages as $langcode => $language) {
$rows[$langcode] = array('name' => ($langcode == 'en' ? t('English (built-in)') : t($language->name)));
foreach ($groups as $group => $name) {
$rows[$langcode][$group] = ($langcode == 'en' ? t('n/a') : '0/'. (isset($groupsums[$group]) ? $groupsums[$group] : 0) . ' (0%)');
}
}
// Languages with at least one record in the locale table.
$translations = db_query("SELECT COUNT(*) AS translation, t.language, s.textgroup FROM {locales_source} s LEFT JOIN {locales_target} t ON s.lid = t.lid WHERE translation != '' GROUP BY textgroup, language");
while ($data = db_fetch_object($translations)) {
$ratio = (!empty($groupsums[$data->textgroup]) && $data->translation > 0) ? round(($data->translation/$groupsums[$data->textgroup])*100., 2) : 0;
$rows[$data->language][$data->textgroup] = $data->translation .'/'. $groupsums[$data->textgroup] ." ($ratio%)";
}
return theme('table', $headers, $rows);
}
/**
* @} End of "locale-translate-overview"
*/
/**
* @defgroup locale-translate-seek Translation search screen.
* @{
*/
/**
* String search screen.
*/
function locale_translate_seek_screen() {
$output = _locale_translate_seek();
$output .= drupal_get_form('locale_translate_seek_form');
return $output;
}
/**
* User interface for the string search screen.
*/
function locale_translate_seek_form() {
// Get all languages, except English
$languages = locale_language_list('name', TRUE);
unset($languages['en']);
// Present edit form preserving previous user settings
$query = _locale_translate_seek_query();
$form = array();
$form['search'] = array('#type' => 'fieldset',
'#title' => t('Search'),
);
$form['search']['string'] = array('#type' => 'textfield',
'#title' => t('String contains'),
'#default_value' => @$query['string'],
'#description' => t('Leave blank to show all strings. The search is case sensitive.'),
);
$form['search']['language'] = array('#type' => 'radios',
'#title' => t('Language'),
'#default_value' => (!empty($query['language']) ? $query['language'] : 'all'),
'#options' => array_merge(array('all' => t('All languages'), 'en' => t('English (provided by Drupal)')), $languages),
);
$form['search']['translation'] = array('#type' => 'radios',
'#title' => t('Search in'),
'#default_value' => (!empty($query['translation']) ? $query['translation'] : 'all'),
'#options' => array('all' => t('All strings in that language'), 'translated' => t('Only translated strings'), 'untranslated' => t('Only untranslated strings')),
);
$groups = module_invoke_all('locale', 'groups');
$form['search']['group'] = array('#type' => 'radios',
'#title' => t('Limit search to'),
'#default_value' => (!empty($query['group']) ? $query['group'] : 'all'),
'#options' => array_merge(array('all' => t('All text groups')), $groups),
);
$form['search']['submit'] = array('#type' => 'submit', '#value' => t('Search'));
$form['#redirect'] = FALSE;
return $form;
}
/**
* @} End of "locale-translate-seek"
*/
// ---------------------------------------------------------------------------------
// Translation import/export screens (administration only)
/**
* @defgroup locale-translate-import Translation import screen.
* @{
*/
/**
* User interface for the translation import screen.
*/
function _locale_admin_import() {
// English means the factory default strings,
// we should not import into it.
function locale_translate_import_form() {
// Get all languages, except English
$names = locale_language_list('name', TRUE);
unset($names['en']);
......@@ -427,7 +565,13 @@ function _locale_admin_import() {
'#title' => t('Import into'),
'#options' => $languages,
'#default_value' => $default,
'#description' => t('Choose the language you want to add strings into. If you choose a language which is not yet set up, then it will be added.'),
'#description' => t('Choose the language you want to add strings into. If you choose a language which is not yet set up, it will be added.'),
);
$form['import']['group'] = array('#type' => 'radios',
'#title' => t('Text group'),
'#default_value' => 'default',
'#options' => module_invoke_all('locale', 'groups'),
'#description' => t('Imported translations will be added to this text group.'),
);
$form['import']['mode'] = array('#type' => 'radios',
'#title' => t('Mode'),
......@@ -443,20 +587,21 @@ function _locale_admin_import() {
/**
* Process the locale import form submission.
*/
function _locale_admin_import_submit($form_id, $form_values) {
function locale_translate_import_form_submit($form_id, $form_values) {
// Ensure we have the file uploaded
if ($file = file_check_upload('file')) {
// Add language, if not yet supported
$languages = language_list('language', TRUE);
if (!isset($languages[$form_values['langcode']])) {
$langcode = $form_values['langcode'];
if (!isset($languages[$langcode])) {
$predefined = _locale_get_predefined_list();
$lang = &$predefined[$form_values['langcode']];
_locale_add_language($form_values['langcode'], $lang[0], isset($lang[1]) ? $lang[1] : '', isset($lang[2]) ? $lang[2] : 0, '', '', FALSE);
$lang = &$predefined[$langcode];
locale_add_language($langcode, $lang[0], isset($lang[1]) ? $lang[1] : '', isset($lang[2]) ? $lang[2] : 0, '', '', FALSE);
}
// Now import strings into the language
if ($ret = _locale_import_po($file, $form_values['langcode'], $form_values['mode']) == FALSE) {
if ($ret = _locale_import_po($file, $langcode, $form_values['mode'], $form_values['group']) == FALSE) {
$variables = array('%filename' => $file->filename);
drupal_set_message(t('The translation import of %filename failed.', $variables), 'error');
watchdog('locale', 'The translation import of %filename failed.', $variables, WATCHDOG_ERROR);
......@@ -464,13 +609,43 @@ function _locale_admin_import_submit($form_id, $form_values) {
}
else {
drupal_set_message(t('File to import not found.'), 'error');
return 'admin/build/locale/string/import';
return 'admin/build/translate/import';
}
return 'admin/build/locale';
return 'admin/build/translate';
}
/**
* @} End of "locale-translate-import"
*/
/**
* @defgroup locale-translate-export Translation export screen.
* @{
*/
/**
* User interface for the translation export screen.
*/
function locale_translate_export_screen() {
// Get all languages, except English
$names = locale_language_list('name', TRUE);
unset($names['en']);
$output = '';
// Offer translation export if any language is set up.
if (count($names)) {
$output = drupal_get_form('locale_translate_export_po_form', $names);
}
$output .= drupal_get_form('locale_translate_export_pot_form');
return $output;
}
function _locale_export_po_form($names) {
/**
* Form to export PO files for the languages provided.
*
* @param $names
* An associate array with localized language names
*/
function locale_translate_export_po_form($names) {
$form['export'] = array('#type' => 'fieldset',
'#title' => t('Export translation'),
'#collapsible' => TRUE,
......@@ -480,99 +655,57 @@ function _locale_export_po_form($names) {