2011-08-02 00:37:34 +00:00
< ? php
/**
2011-08-07 13:10:57 +00:00
* @ file
* Interface translation summary , editing and deletion user interfaces .
2011-08-02 00:37:34 +00:00
*/
/**
* String search screen .
*/
function locale_translate_seek_screen () {
// Add CSS.
drupal_add_css ( drupal_get_path ( 'module' , 'locale' ) . '/locale.css' );
$elements = drupal_get_form ( 'locale_translation_filter_form' );
$output = drupal_render ( $elements );
$output .= _locale_translate_seek ();
return $output ;
}
/**
* Perform a string search and display results in a table
*/
function _locale_translate_seek () {
$output = '' ;
// We have at least one criterion to match
if ( ! ( $query = _locale_translate_seek_query ())) {
$query = array (
'translation' => 'all' ,
'language' => 'all' ,
2012-04-09 18:24:12 +00:00
'customized' => 'all' ,
2011-08-02 00:37:34 +00:00
'string' => '' ,
);
}
$sql_query = db_select ( 'locales_source' , 's' );
$sql_query -> leftJoin ( 'locales_target' , 't' , 't.lid = s.lid' );
2011-08-07 13:10:57 +00:00
$sql_query -> fields ( 's' , array ( 'source' , 'location' , 'context' , 'lid' ));
2012-04-09 18:24:12 +00:00
$sql_query -> fields ( 't' , array ( 'translation' , 'language' , 'customized' ));
2011-08-02 00:37:34 +00:00
// Compute LIKE section.
switch ( $query [ 'translation' ]) {
case 'translated' :
$sql_query -> condition ( 't.translation' , '%' . db_like ( $query [ 'string' ]) . '%' , 'LIKE' );
$sql_query -> orderBy ( 't.translation' , 'DESC' );
2012-04-09 18:24:12 +00:00
if ( $query [ 'customized' ] != 'all' ) {
$sql_query -> condition ( 't.customized' , $query [ 'customized' ]);
}
2011-08-02 00:37:34 +00:00
break ;
case 'untranslated' :
$sql_query -> condition ( db_and ()
-> condition ( 's.source' , '%' . db_like ( $query [ 'string' ]) . '%' , 'LIKE' )
-> isNull ( 't.translation' )
);
$sql_query -> orderBy ( 's.source' );
break ;
case 'all' :
default :
$condition = db_or ()
-> condition ( 's.source' , '%' . db_like ( $query [ 'string' ]) . '%' , 'LIKE' );
2011-10-27 03:55:02 +00:00
if ( $query [ 'language' ] != LANGUAGE_SYSTEM ) {
// Only search in translations if the language is not forced to system language.
2011-08-02 00:37:34 +00:00
$condition -> condition ( 't.translation' , '%' . db_like ( $query [ 'string' ]) . '%' , 'LIKE' );
}
$sql_query -> condition ( $condition );
break ;
}
$limit_language = NULL ;
2011-10-27 03:55:02 +00:00
if ( $query [ 'language' ] != LANGUAGE_SYSTEM && $query [ 'language' ] != 'all' ) {
2011-08-02 00:37:34 +00:00
$sql_query -> condition ( 'language' , $query [ 'language' ]);
$limit_language = $query [ 'language' ];
}
$sql_query = $sql_query -> extend ( 'PagerDefault' ) -> limit ( 50 );
$locales = $sql_query -> execute ();
2011-08-07 13:10:57 +00:00
$header = array ( t ( 'String' ), t ( 'Context' ), ( $limit_language ) ? t ( 'Language' ) : t ( 'Languages' ), array ( 'data' => t ( 'Operations' ), 'colspan' => '2' ));
2011-08-02 00:37:34 +00:00
$strings = array ();
foreach ( $locales as $locale ) {
if ( ! isset ( $strings [ $locale -> lid ])) {
$strings [ $locale -> lid ] = array (
'languages' => array (),
'location' => $locale -> location ,
'source' => $locale -> source ,
'context' => $locale -> context ,
);
}
if ( isset ( $locale -> language )) {
$strings [ $locale -> lid ][ 'languages' ][ $locale -> language ] = $locale -> translation ;
}
}
$rows = array ();
foreach ( $strings as $lid => $string ) {
$rows [] = array (
2012-03-11 02:35:21 +00:00
array ( 'data' => check_plain ( truncate_utf8 ( str_replace ( LOCALE_PLURAL_DELIMITER , ', ' , $string [ 'source' ]), 150 , FALSE , TRUE )) . '<br /><small>' . $string [ 'location' ] . '</small>' ),
2011-08-02 00:37:34 +00:00
$string [ 'context' ],
array ( 'data' => _locale_translate_language_list ( $string [ 'languages' ], $limit_language ), 'align' => 'center' ),
array ( 'data' => l ( t ( 'edit' ), " admin/config/regional/translate/edit/ $lid " , array ( 'query' => drupal_get_destination ())), 'class' => array ( 'nowrap' )),
array ( 'data' => l ( t ( 'delete' ), " admin/config/regional/translate/delete/ $lid " , array ( 'query' => drupal_get_destination ())), 'class' => array ( 'nowrap' )),
);
}
$output .= theme ( 'table' , array ( 'header' => $header , 'rows' => $rows , 'empty' => t ( 'No strings available.' )));
$output .= theme ( 'pager' );
return $output ;
}
/**
* List languages in search result table
*/
function _locale_translate_language_list ( $translation , $limit_language ) {
// Add CSS.
drupal_add_css ( drupal_get_path ( 'module' , 'locale' ) . '/locale.css' );
$languages = language_list ();
2011-10-27 03:55:02 +00:00
if ( ! locale_translate_english ()) {
unset ( $languages [ 'en' ]);
}
2011-08-02 00:37:34 +00:00
$output = '' ;
foreach ( $languages as $langcode => $language ) {
if ( ! $limit_language || $limit_language == $langcode ) {
$output .= ( ! empty ( $translation [ $langcode ])) ? $langcode . ' ' : " <em class= \" locale-untranslated \" > $langcode </em> " ;
}
}
return $output ;
}
/**
* Build array out of search criteria specified in request variables
*/
function _locale_translate_seek_query () {
$query = & drupal_static ( __FUNCTION__ );
if ( ! isset ( $query )) {
$query = array ();
2012-04-09 18:24:12 +00:00
$fields = array ( 'string' , 'language' , 'translation' , 'customized' );
2011-08-02 00:37:34 +00:00
foreach ( $fields as $field ) {
if ( isset ( $_SESSION [ 'locale_translation_filter' ][ $field ])) {
$query [ $field ] = $_SESSION [ 'locale_translation_filter' ][ $field ];
}
}
}
return $query ;
}
/**
* List locale translation filters that can be applied .
*/
function locale_translation_filters () {
$filters = array ();
// Get all languages, except English
drupal_static_reset ( 'language_list' );
2012-01-23 15:46:29 +00:00
$languages = language_list ( TRUE );
$language_options = array ();
foreach ( $languages as $langcode => $language ) {
if ( $langcode != 'en' || locale_translate_english ()) {
$language_options [ $langcode ] = $language -> name ;
}
2011-10-27 03:55:02 +00:00
}
2011-08-02 00:37:34 +00:00
$filters [ 'string' ] = array (
'title' => t ( 'String contains' ),
'description' => t ( 'Leave blank to show all strings. The search is case sensitive.' ),
);
$filters [ 'language' ] = array (
'title' => t ( 'Language' ),
2012-01-23 15:46:29 +00:00
'options' => array_merge ( array ( 'all' => t ( 'All languages' ), LANGUAGE_SYSTEM => t ( 'System (English)' )), $language_options ),
2011-08-02 00:37:34 +00:00
);
$filters [ 'translation' ] = array (
'title' => t ( 'Search in' ),
2012-04-09 18:24:12 +00:00
'options' => array (
'all' => t ( 'Both translated and untranslated strings' ),
'translated' => t ( 'Only translated strings' ),
'untranslated' => t ( 'Untranslated strings' )
),
);
$filters [ 'customized' ] = array (
'title' => t ( 'Translation type' ),
'options' => array (
'all' => t ( 'All' ),
LOCALE_NOT_CUSTOMIZED => t ( 'Non-customized translation' ),
LOCALE_CUSTOMIZED => t ( 'Customized translation' ),
),
'states' => array (
'visible' => array (
':input[name=translation]' => array ( 'value' => 'translated' ),
)
),
2011-08-02 00:37:34 +00:00
);
return $filters ;
}
/**
* Return form for locale translation filters .
*
* @ ingroup forms
*/
function locale_translation_filter_form () {
$filters = locale_translation_filters ();
$form [ 'filters' ] = array (
'#type' => 'fieldset' ,
'#title' => t ( 'Filter translatable strings' ),
'#collapsible' => TRUE ,
'#collapsed' => FALSE ,
);
foreach ( $filters as $key => $filter ) {
// Special case for 'string' filter.
if ( $key == 'string' ) {
$form [ 'filters' ][ 'status' ][ 'string' ] = array (
2012-03-27 06:17:38 +00:00
'#type' => 'search' ,
2011-08-02 00:37:34 +00:00
'#title' => $filter [ 'title' ],
'#description' => $filter [ 'description' ],
);
}
else {
$form [ 'filters' ][ 'status' ][ $key ] = array (
'#title' => $filter [ 'title' ],
'#type' => 'select' ,
'#empty_value' => 'all' ,
'#empty_option' => $filter [ 'options' ][ 'all' ],
'#size' => 0 ,
'#options' => $filter [ 'options' ],
);
2012-04-09 18:24:12 +00:00
if ( isset ( $filter [ 'states' ])) {
$form [ 'filters' ][ 'status' ][ $key ][ '#states' ] = $filter [ 'states' ];
}
2011-08-02 00:37:34 +00:00
}
if ( ! empty ( $_SESSION [ 'locale_translation_filter' ][ $key ])) {
$form [ 'filters' ][ 'status' ][ $key ][ '#default_value' ] = $_SESSION [ 'locale_translation_filter' ][ $key ];
}
}
$form [ 'filters' ][ 'actions' ] = array (
'#type' => 'actions' ,
'#attributes' => array ( 'class' => array ( 'container-inline' )),
);
$form [ 'filters' ][ 'actions' ][ 'submit' ] = array (
'#type' => 'submit' ,
'#value' => t ( 'Filter' ),
);
if ( ! empty ( $_SESSION [ 'locale_translation_filter' ])) {
$form [ 'filters' ][ 'actions' ][ 'reset' ] = array (
'#type' => 'submit' ,
'#value' => t ( 'Reset' )
);
}
return $form ;
}
/**
* Validate result from locale translation filter form .
*/
function locale_translation_filter_form_validate ( $form , & $form_state ) {
2011-08-07 13:10:57 +00:00
if ( $form_state [ 'values' ][ 'op' ] == t ( 'Filter' ) && empty ( $form_state [ 'values' ][ 'language' ])) {
2011-08-02 00:37:34 +00:00
form_set_error ( 'type' , t ( 'You must select something to filter by.' ));
}
}
/**
* Process result from locale translation filter form .
*/
function locale_translation_filter_form_submit ( $form , & $form_state ) {
$op = $form_state [ 'values' ][ 'op' ];
$filters = locale_translation_filters ();
switch ( $op ) {
case t ( 'Filter' ) :
foreach ( $filters as $name => $filter ) {
if ( isset ( $form_state [ 'values' ][ $name ])) {
$_SESSION [ 'locale_translation_filter' ][ $name ] = $form_state [ 'values' ][ $name ];
}
}
break ;
case t ( 'Reset' ) :
$_SESSION [ 'locale_translation_filter' ] = array ();
break ;
}
$form_state [ 'redirect' ] = 'admin/config/regional/translate/translate' ;
}
/**
* User interface for string editing .
2011-08-07 13:10:57 +00:00
*
* @ ingroup forms
2011-08-02 00:37:34 +00:00
*/
function locale_translate_edit_form ( $form , & $form_state , $lid ) {
// Fetch source string, if possible.
2011-08-07 13:10:57 +00:00
$source = db_query ( 'SELECT source, context, location FROM {locales_source} WHERE lid = :lid' , array ( ':lid' => $lid )) -> fetchObject ();
2011-08-02 00:37:34 +00:00
if ( ! $source ) {
drupal_set_message ( t ( 'String not found.' ), 'error' );
drupal_goto ( 'admin/config/regional/translate/translate' );
}
2012-03-11 02:35:21 +00:00
// Split source to work with plural values.
$source_array = explode ( LOCALE_PLURAL_DELIMITER , $source -> source );
if ( count ( $source_array ) == 1 ) {
// Add original text value and mark as non-plural.
$form [ 'plural' ] = array (
'#type' => 'value' ,
'#value' => 0
);
$form [ 'original' ] = array (
'#type' => 'item' ,
'#title' => t ( 'Original text' ),
'#markup' => check_plain ( $source_array [ 0 ]),
);
}
else {
// Add original text value and mark as plural.
$form [ 'plural' ] = array (
'#type' => 'value' ,
'#value' => 1
);
$form [ 'original_singular' ] = array (
'#type' => 'item' ,
'#title' => t ( 'Original singular form' ),
'#markup' => check_plain ( $source_array [ 0 ]),
);
$form [ 'original_plural' ] = array (
'#type' => 'item' ,
'#title' => t ( 'Original plural form' ),
'#markup' => check_plain ( $source_array [ 1 ]),
);
}
2011-08-02 00:37:34 +00:00
if ( ! empty ( $source -> context )) {
$form [ 'context' ] = array (
'#type' => 'item' ,
'#title' => t ( 'Context' ),
'#markup' => check_plain ( $source -> context ),
);
}
$form [ 'lid' ] = array (
'#type' => 'value' ,
'#value' => $lid
);
$form [ 'location' ] = array (
'#type' => 'value' ,
'#value' => $source -> location
);
// Include default form controls with empty values for all languages.
// This ensures that the languages are always in the same order in forms.
$languages = language_list ();
2011-10-27 03:55:02 +00:00
if ( ! locale_translate_english ()) {
unset ( $languages [ 'en' ]);
}
2012-03-11 02:35:21 +00:00
// Store languages to iterate for validation and submission of the form.
$form_state [ 'langcodes' ] = array_keys ( $languages );
$plural_formulas = variable_get ( 'locale_translation_plurals' , array ());
$form [ 'translations' ] = array (
'#type' => 'vertical_tabs' ,
'#tree' => TRUE
);
2011-08-02 00:37:34 +00:00
// Approximate the number of rows to use in the default textarea.
2012-03-11 02:35:21 +00:00
$rows = min ( ceil ( str_word_count ( $source_array [ 0 ]) / 12 ), 10 );
2011-08-02 00:37:34 +00:00
foreach ( $languages as $langcode => $language ) {
$form [ 'translations' ][ $langcode ] = array (
2012-03-11 02:35:21 +00:00
'#type' => 'fieldset' ,
2011-10-26 07:48:38 +00:00
'#title' => $language -> name ,
2011-08-02 00:37:34 +00:00
);
2012-03-11 02:35:21 +00:00
if ( empty ( $form [ 'plural' ][ '#value' ])) {
$form [ 'translations' ][ $langcode ][ 0 ] = array (
'#type' => 'textarea' ,
'#title' => $language -> name ,
'#rows' => $rows ,
'#default_value' => '' ,
);
}
else {
// Dealing with plural strings.
if ( isset ( $plural_formulas [ $langcode ][ 'plurals' ]) && $plural_formulas [ $langcode ][ 'plurals' ] > 1 ) {
// Add a textarea for each plural variant.
for ( $i = 0 ; $i < $plural_formulas [ $langcode ][ 'plurals' ]; $i ++ ) {
$form [ 'translations' ][ $langcode ][ $i ] = array (
'#type' => 'textarea' ,
'#title' => ( $i == 0 ? t ( 'Singular form' ) : format_plural ( $i , 'First plural form' , '@count. plural form' )),
'#rows' => $rows ,
'#default_value' => '' ,
);
}
}
else {
// Fallback for unknown number of plurals.
$form [ 'translations' ][ $langcode ][ 0 ] = array (
'#type' => 'textarea' ,
'#title' => t ( 'Sigular form' ),
'#rows' => $rows ,
'#default_value' => '' ,
);
$form [ 'translations' ][ $langcode ][ 1 ] = array (
'#type' => 'textarea' ,
'#title' => t ( 'Plural form' ),
'#rows' => $rows ,
'#default_value' => '' ,
);
}
}
2011-08-02 00:37:34 +00:00
}
// Fetch translations and fill in default values in the form.
2011-08-07 13:10:57 +00:00
$result = db_query ( " SELECT DISTINCT translation, language FROM { locales_target} WHERE lid = :lid " , array ( ':lid' => $lid ));
2011-08-02 00:37:34 +00:00
foreach ( $result as $translation ) {
2012-03-11 02:35:21 +00:00
$translation_array = explode ( LOCALE_PLURAL_DELIMITER , $translation -> translation );
for ( $i = 0 ; $i < count ( $translation_array ); $i ++ ) {
$form [ 'translations' ][ $translation -> language ][ $i ][ '#default_value' ] = $translation_array [ $i ];
}
2011-08-02 00:37:34 +00:00
}
$form [ 'actions' ] = array ( '#type' => 'actions' );
$form [ 'actions' ][ 'submit' ] = array ( '#type' => 'submit' , '#value' => t ( 'Save translations' ));
return $form ;
}
/**
* Validate string editing form submissions .
*/
function locale_translate_edit_form_validate ( $form , & $form_state ) {
2012-03-11 02:35:21 +00:00
foreach ( $form_state [ 'langcodes' ] as $langcode ) {
foreach ( $form_state [ 'values' ][ 'translations' ][ $langcode ] as $key => $value ) {
if ( ! locale_string_is_safe ( $value )) {
form_set_error ( " translations][ $langcode ][ $key " , t ( 'The submitted string contains disallowed HTML: %string' , array ( '%string' => $value )));
watchdog ( 'locale' , 'Attempted submission of a translation string with disallowed HTML: %string' , array ( '%string' => $value ), WATCHDOG_WARNING );
}
2011-08-02 00:37:34 +00:00
}
}
}
/**
* Process string editing form submissions .
*
* Saves all translations of one string submitted from a form .
*/
function locale_translate_edit_form_submit ( $form , & $form_state ) {
$lid = $form_state [ 'values' ][ 'lid' ];
2012-03-11 02:35:21 +00:00
foreach ( $form_state [ 'langcodes' ] as $langcode ) {
// Serialize plural variants in one string by LOCALE_PLURAL_DELIMITER.
$value = implode ( LOCALE_PLURAL_DELIMITER , $form_state [ 'values' ][ 'translations' ][ $langcode ]);
$translation = db_query ( " SELECT translation FROM { locales_target} WHERE lid = :lid AND language = :language " , array ( ':lid' => $lid , ':language' => $langcode )) -> fetchField ();
// No translation when all strings are empty.
$has_translation = FALSE ;
foreach ( $form_state [ 'values' ][ 'translations' ][ $langcode ] as $string ) {
if ( ! empty ( $string )) {
$has_translation = TRUE ;
break ;
}
}
if ( $has_translation ) {
2011-08-02 00:37:34 +00:00
// Only update or insert if we have a value to use.
2012-04-09 18:24:12 +00:00
if ( ! empty ( $translation ) && $translation != $value ) {
2011-08-02 00:37:34 +00:00
db_update ( 'locales_target' )
-> fields ( array (
'translation' => $value ,
2012-04-09 18:24:12 +00:00
'customized' => LOCALE_CUSTOMIZED ,
2011-08-02 00:37:34 +00:00
))
-> condition ( 'lid' , $lid )
2012-03-11 02:35:21 +00:00
-> condition ( 'language' , $langcode )
2011-08-02 00:37:34 +00:00
-> execute ();
}
2012-04-09 18:24:12 +00:00
if ( empty ( $translation )) {
2011-08-02 00:37:34 +00:00
db_insert ( 'locales_target' )
-> fields ( array (
'lid' => $lid ,
'translation' => $value ,
2012-03-11 02:35:21 +00:00
'language' => $langcode ,
2012-04-09 18:24:12 +00:00
'customized' => LOCALE_CUSTOMIZED ,
2011-08-02 00:37:34 +00:00
))
-> execute ();
}
}
elseif ( ! empty ( $translation )) {
// Empty translation entered: remove existing entry from database.
db_delete ( 'locales_target' )
-> condition ( 'lid' , $lid )
2012-03-11 02:35:21 +00:00
-> condition ( 'language' , $langcode )
2011-08-02 00:37:34 +00:00
-> execute ();
}
// Force JavaScript translation file recreation for this language.
2012-03-11 02:35:21 +00:00
_locale_invalidate_js ( $langcode );
2011-08-02 00:37:34 +00:00
}
drupal_set_message ( t ( 'The string has been saved.' ));
// Clear locale cache.
_locale_invalidate_js ();
2011-09-11 16:14:18 +00:00
cache () -> deletePrefix ( 'locale:' );
2011-08-02 00:37:34 +00:00
$form_state [ 'redirect' ] = 'admin/config/regional/translate/translate' ;
return ;
}
/**
* String deletion confirmation page .
*/
function locale_translate_delete_page ( $lid ) {
if ( $source = db_query ( 'SELECT lid, source FROM {locales_source} WHERE lid = :lid' , array ( ':lid' => $lid )) -> fetchObject ()) {
return drupal_get_form ( 'locale_translate_delete_form' , $source );
}
else {
return drupal_not_found ();
}
}
/**
* User interface for the string deletion confirmation screen .
2011-08-07 13:10:57 +00:00
*
* @ ingroup forms
2011-08-02 00:37:34 +00:00
*/
function locale_translate_delete_form ( $form , & $form_state , $source ) {
$form [ 'lid' ] = array ( '#type' => 'value' , '#value' => $source -> lid );
return confirm_form ( $form , t ( 'Are you sure you want to delete the string "%source"?' , array ( '%source' => $source -> source )), 'admin/config/regional/translate/translate' , t ( 'Deleting the string will remove all translations of this string in all languages. This action cannot be undone.' ), t ( 'Delete' ), t ( 'Cancel' ));
}
/**
* Process string deletion submissions .
*/
function locale_translate_delete_form_submit ( $form , & $form_state ) {
db_delete ( 'locales_source' )
-> condition ( 'lid' , $form_state [ 'values' ][ 'lid' ])
-> execute ();
db_delete ( 'locales_target' )
-> condition ( 'lid' , $form_state [ 'values' ][ 'lid' ])
-> execute ();
// Force JavaScript translation file recreation for all languages.
_locale_invalidate_js ();
2011-09-11 16:14:18 +00:00
cache () -> deletePrefix ( 'locale:' );
2011-08-02 00:37:34 +00:00
drupal_set_message ( t ( 'The string has been removed.' ));
$form_state [ 'redirect' ] = 'admin/config/regional/translate/translate' ;
}