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
*/
2013-09-11 06:53:36 +00:00
use Drupal\Component\Utility\String ;
2013-05-25 20:12:45 +00:00
use Drupal\Core\Language\Language ;
2012-10-08 18:10:13 +00:00
use Drupal\locale\SourceString ;
use Drupal\locale\TranslationString ;
Issue #1668866 by ParisLiakos, aspilicious, tim.plunkett, pdrake, g.oechsler, dawehner, Berdir, corvus_ch, damiankloip, disasm, marcingy, neclimdul: Replace drupal_goto() with RedirectResponse.
2013-06-19 16:07:30 +00:00
use Symfony\Component\HttpFoundation\RedirectResponse ;
2012-06-02 19:41:40 +00:00
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException ;
2011-08-02 00:37:34 +00:00
/**
2013-09-11 08:14:17 +00:00
* Page callback : Checks for translation updates and displays the status .
2012-10-05 15:42:46 +00:00
*
2013-09-11 08:14:17 +00:00
* Manually checks the translation status without the use of cron .
2012-10-05 15:42:46 +00:00
*
* @ see locale_menu ()
2011-08-02 00:37:34 +00:00
*/
2013-09-11 08:14:17 +00:00
function locale_translation_manual_status () {
module_load_include ( 'compare.inc' , 'locale' );
2011-08-02 00:37:34 +00:00
2013-09-11 08:14:17 +00:00
// Check the translation status of all translatable projects in all languages.
// First we clear the cached list of projects. Although not strictly
// necessary, this is helpful in case the project list is out of sync.
locale_translation_flush_projects ();
locale_translation_check_projects ();
Issue #1452188 by Schnitzel, droplet, Sutharsan, Bojhan, Kristen Pol, Gábor Hojtsy, ershov.andrey, perusio, nod_, rvilar, andypost: Added New UI for string translation.
2012-06-15 10:01:31 +00:00
2013-09-11 08:14:17 +00:00
// Execute a batch if required. A batch is only used when remote files
// are checked.
if ( batch_get ()) {
return batch_process ( 'admin/reports/translations' );
Issue #1452188 by Schnitzel, droplet, Sutharsan, Bojhan, Kristen Pol, Gábor Hojtsy, ershov.andrey, perusio, nod_, rvilar, andypost: Added New UI for string translation.
2012-06-15 10:01:31 +00:00
}
2013-09-11 08:14:17 +00:00
return new RedirectResponse ( url ( 'admin/reports/translations' , array ( 'absolute' => TRUE )));
2011-08-02 00:37:34 +00:00
}
2012-10-11 21:30:02 +00:00
/**
* Page callback : Display the current translation status .
*
* @ see locale_menu ()
*/
2012-12-07 18:17:37 +00:00
function locale_translation_status_form ( $form , & $form_state ) {
2012-12-19 22:11:34 +00:00
module_load_include ( 'translation.inc' , 'locale' );
2012-12-07 18:17:37 +00:00
module_load_include ( 'compare.inc' , 'locale' );
2012-12-19 22:11:34 +00:00
$updates = $options = array ();
$languages_update = $languages_not_found = array ();
2013-06-27 11:25:01 +00:00
$projects_update = array ();
2012-12-07 18:17:37 +00:00
2012-12-19 22:11:34 +00:00
// @todo Calling locale_translation_build_projects() is an expensive way to
// get a module name. In follow-up issue http://drupal.org/node/1842362
// the project name will be stored to display use, like here.
$project_data = locale_translation_build_projects ();
2012-10-11 21:30:02 +00:00
$languages = locale_translatable_language_list ();
2013-06-27 11:25:01 +00:00
$status = locale_translation_get_status ();
2012-12-07 18:17:37 +00:00
2012-12-19 22:11:34 +00:00
// Prepare information about projects which have available translation
// updates.
if ( $languages && $status ) {
foreach ( $status as $project_id => $project ) {
foreach ( $project as $langcode => $project_info ) {
// No translation file found for this project-language combination.
2013-06-27 11:25:01 +00:00
if ( empty ( $project_info -> type )) {
2012-12-19 22:11:34 +00:00
$updates [ $langcode ][ 'not_found' ][] = array (
'name' => $project_info -> name == 'drupal' ? t ( 'Drupal core' ) : $project_data [ $project_info -> name ] -> info [ 'name' ],
'version' => $project_info -> version ,
'info' => _locale_translation_status_debug_info ( $project_info ),
);
$languages_not_found [ $langcode ] = $langcode ;
}
// Translation update found for this project-language combination.
elseif ( $project_info -> type == LOCALE_TRANSLATION_LOCAL || $project_info -> type == LOCALE_TRANSLATION_REMOTE ) {
$local = isset ( $project_info -> files [ LOCALE_TRANSLATION_LOCAL ]) ? $project_info -> files [ LOCALE_TRANSLATION_LOCAL ] : NULL ;
$remote = isset ( $project_info -> files [ LOCALE_TRANSLATION_REMOTE ]) ? $project_info -> files [ LOCALE_TRANSLATION_REMOTE ] : NULL ;
$recent = _locale_translation_source_compare ( $local , $remote ) == LOCALE_TRANSLATION_SOURCE_COMPARE_LT ? $remote : $local ;
$updates [ $langcode ][ 'updates' ][] = array (
'name' => $project_data [ $project_info -> name ] -> info [ 'name' ],
'version' => $project_info -> version ,
'timestamp' => $recent -> timestamp ,
);
$languages_update [ $langcode ] = $langcode ;
2013-06-27 11:25:01 +00:00
$projects_update [ $project_info -> name ] = $project_info -> name ;
2012-12-19 22:11:34 +00:00
}
}
}
$languages_not_found = array_diff ( $languages_not_found , $languages_update );
// Build data options for the select table.
foreach ( $updates as $langcode => $update ) {
2013-09-11 06:53:36 +00:00
$title = String :: checkPlain ( $languages [ $langcode ] -> name );
2013-08-23 01:36:59 +00:00
$locale_translation_update_info = array ( '#theme' => 'locale_translation_update_info' );
foreach ( array ( 'updates' , 'not_found' ) as $update_status ) {
if ( isset ( $update [ $update_status ])) {
$locale_translation_update_info [ '#' . $update_status ] = $update [ $update_status ];
}
}
2012-12-19 22:11:34 +00:00
$options [ $langcode ] = array (
2013-09-11 06:53:36 +00:00
'title' => array (
'class' => array ( 'label' ),
'data' => array (
'#title' => $title ,
'#markup' => $title
),
),
2013-08-23 01:36:59 +00:00
'status' => array ( 'class' => array ( 'description' , 'expand' , 'priority-low' ), 'data' => drupal_render ( $locale_translation_update_info )),
2012-12-19 22:11:34 +00:00
);
}
// Sort the table data on language name.
2013-09-11 06:53:36 +00:00
uasort ( $options , function ( $a , $b ) {
return strcasecmp ( $a [ 'title' ][ 'data' ][ '#title' ], $b [ 'title' ][ 'data' ][ '#title' ]);
});
2012-10-11 21:30:02 +00:00
}
2013-09-16 03:58:06 +00:00
$last_checked = \Drupal :: state () -> get ( 'locale.translation_last_checked' );
2012-12-07 18:17:37 +00:00
$form [ 'last_checked' ] = array (
2013-06-16 23:54:01 +00:00
'#theme' => 'locale_translation_last_check' ,
'#last' => $last_checked ,
2012-12-07 18:17:37 +00:00
);
2012-12-19 22:11:34 +00:00
$header = array (
'title' => array (
'data' => t ( 'Language' ),
'class' => array ( 'title' ),
),
'status' => array (
'data' => t ( 'Status' ),
'class' => array ( 'status' , 'priority-low' ),
),
2012-12-07 18:17:37 +00:00
);
2012-12-19 22:11:34 +00:00
if ( ! $languages ) {
$empty = t ( 'No translatable languages available. <a href="@add_language">Add a language</a> first.' , array ( '@add_language' => url ( 'admin/config/regional/language' )));
}
elseif ( $status ) {
$empty = t ( 'All translations up to date.' );
}
else {
$empty = t ( 'No translation status available. <a href="@check">Check manually</a>.' , array ( '@check' => url ( 'admin/reports/translations/check' )));
}
2013-06-27 11:25:01 +00:00
// The projects which require an update. Used by the _submit callback.
$form [ 'projects_update' ] = array (
'#type' => 'value' ,
'#value' => $projects_update ,
);
2012-12-19 22:11:34 +00:00
$form [ 'langcodes' ] = array (
'#type' => 'tableselect' ,
'#header' => $header ,
'#options' => $options ,
'#default_value' => $languages_update ,
'#empty' => $empty ,
'#js_select' => TRUE ,
'#multiple' => TRUE ,
'#required' => TRUE ,
'#not_found' => $languages_not_found ,
'#after_build' => array ( 'locale_translation_language_table' ),
2012-12-07 18:17:37 +00:00
);
2012-12-19 22:11:34 +00:00
$form [ '#attached' ][ 'library' ][] = array ( 'locale' , 'drupal.locale.admin' );
2013-06-07 10:48:55 +00:00
$form [ '#attached' ][ 'css' ] = array ( drupal_get_path ( 'module' , 'locale' ) . '/css/locale.admin.css' );
2012-12-19 22:11:34 +00:00
$form [ 'actions' ] = array ( '#type' => 'actions' );
if ( $languages_update ) {
$form [ 'actions' ][ 'submit' ] = array (
'#type' => 'submit' ,
'#value' => t ( 'Update translations' ),
);
}
2012-12-07 18:17:37 +00:00
return $form ;
}
/**
2012-12-19 22:11:34 +00:00
* Form validation handler for locale_translation_status_form () .
*/
function locale_translation_status_form_validate ( $form , & $form_state ) {
// Check if a language has been selected. 'tableselect' doesn't.
if ( ! array_filter ( $form_state [ 'values' ][ 'langcodes' ])) {
form_set_error ( '' , t ( 'Select a language to update.' ));
}
}
/**
* Form submission handler for locale_translation_status_form () .
2012-12-07 18:17:37 +00:00
*/
function locale_translation_status_form_submit ( $form , & $form_state ) {
module_load_include ( 'fetch.inc' , 'locale' );
$langcodes = array_filter ( $form_state [ 'values' ][ 'langcodes' ]);
2013-06-27 11:25:01 +00:00
$projects = array_filter ( $form_state [ 'values' ][ 'projects_update' ]);
2012-12-07 18:17:37 +00:00
// Set the translation import options. This determines if existing
// translations will be overwritten by imported strings.
$options = _locale_translation_default_update_options ();
// If the status was updated recently we can immediately start fetching the
// translation updates. If the status is expired we clear it an run a batch to
// update the status and then fetch the translation updates.
2013-09-16 03:58:06 +00:00
$last_checked = \Drupal :: state () -> get ( 'locale.translation_last_checked' );
2012-12-07 18:17:37 +00:00
if ( $last_checked < REQUEST_TIME - LOCALE_TRANSLATION_STATUS_TTL ) {
locale_translation_clear_status ();
$batch = locale_translation_batch_update_build ( array (), $langcodes , $options );
batch_set ( $batch );
}
else {
2013-06-27 11:25:01 +00:00
$batch = locale_translation_batch_fetch_build ( $projects , $langcodes , $options );
2012-12-07 18:17:37 +00:00
batch_set ( $batch );
}
2012-10-11 21:30:02 +00:00
}
/**
2012-12-19 22:11:34 +00:00
* Form element callback : After build changes to the language update table .
*
* Adds labels to the languages and removes checkboxes from languages from which
* translation files could not be found .
*/
function locale_translation_language_table ( $form_element ) {
// Remove checkboxes of languages without updates.
if ( $form_element [ '#not_found' ]) {
foreach ( $form_element [ '#not_found' ] as $langcode ) {
$form_element [ $langcode ] = array ();
}
}
return $form_element ;
}
/**
* Provides debug info for projects in case translation files are not found .
*
* Translations files are being fetched either from Drupal translation server
* and local files or only from the local filesystem depending on the
* " Translation source " setting at admin / config / regional / translate / settings .
* This method will produce debug information including the respective path ( s )
* based on this setting .
*
* Translations for development versions are never fetched , so the debug info
* for that is a fixed message .
*
* @ param array $source
* An array which is the project information of the source .
*
* @ return string
* The string which contains debug information .
*/
function _locale_translation_status_debug_info ( $source ) {
$remote_path = isset ( $source -> files [ 'remote' ] -> uri ) ? $source -> files [ 'remote' ] -> uri : '' ;
$local_path = isset ( $source -> files [ 'local' ] -> uri ) ? $source -> files [ 'local' ] -> uri : '' ;
if ( strpos ( $source -> version , 'dev' ) !== FALSE ) {
return t ( 'No translation files are provided for development releases.' );
}
if ( locale_translation_use_remote_source () && $remote_path && $local_path ) {
return t ( 'File not found at %remote_path nor at %local_path' , array (
'%remote_path' => $remote_path ,
'%local_path' => $local_path ,
));
}
elseif ( $local_path ) {
return t ( 'File not found at %local_path' , array ( '%local_path' => $local_path ));
}
return t ( 'Translation file location could not be determined.' );
}
/**
* Returns HTML for translation edit form .
*
* @ param array $variables
* An associative array containing :
* - form : The form that contains the language information .
*
* @ see locale_translate_edit_form ()
* @ ingroup themeable
2011-08-02 00:37:34 +00:00
*/
Issue #1452188 by Schnitzel, droplet, Sutharsan, Bojhan, Kristen Pol, Gábor Hojtsy, ershov.andrey, perusio, nod_, rvilar, andypost: Added New UI for string translation.
2012-06-15 10:01:31 +00:00
function theme_locale_translate_edit_form_strings ( $variables ) {
$output = '' ;
$form = $variables [ 'form' ];
$header = array (
t ( 'Source string' ),
t ( 'Translation for @language' , array ( '@language' => $form [ '#language' ])),
);
$rows = array ();
foreach ( element_children ( $form ) as $lid ) {
$string = $form [ $lid ];
if ( $string [ 'plural' ][ '#value' ]) {
$source = drupal_render ( $string [ 'original_singular' ]) . '<br />' . drupal_render ( $string [ 'original_plural' ]);
}
else {
$source = drupal_render ( $string [ 'original' ]);
}
$source .= empty ( $string [ 'context' ]) ? '' : '<br /><small>' . t ( 'In Context' ) . ': ' . $string [ 'context' ][ '#value' ] . '</small>' ;
$rows [] = array (
array ( 'data' => $source ),
array ( 'data' => $string [ 'translations' ]),
);
2011-08-02 00:37:34 +00:00
}
2013-08-23 01:36:59 +00:00
$table = array (
'#theme' => 'table' ,
'#header' => $header ,
'#rows' => $rows ,
'#empty' => t ( 'No strings available.' ),
'#attributes' => array ( 'class' => array ( 'locale-translate-edit-table' )),
);
$output .= drupal_render ( $table );
$pager = array ( '#theme' => 'pager' );
$output .= drupal_render ( $pager );
Issue #1452188 by Schnitzel, droplet, Sutharsan, Bojhan, Kristen Pol, Gábor Hojtsy, ershov.andrey, perusio, nod_, rvilar, andypost: Added New UI for string translation.
2012-06-15 10:01:31 +00:00
return $output ;
2011-08-02 00:37:34 +00:00
}
2012-12-19 22:11:34 +00:00
/**
2013-06-16 23:54:01 +00:00
* Prepares variables for translation status information templates .
*
* Translation status information is displayed per language .
*
* Default template : locale - translate - edit - form - strings . html . twig .
2012-12-19 22:11:34 +00:00
*
* @ param array $variables
* An associative array containing :
* - updates : The projects which have updates .
* - not_found : The projects which updates are not found .
*
* @ see locale_translation_status_form ()
*/
2013-06-16 23:54:01 +00:00
function template_preprocess_locale_translation_update_info ( & $variables ) {
$details = array ();
2012-12-19 22:11:34 +00:00
// Build output for available updates.
if ( isset ( $variables [ 'updates' ])) {
2013-08-23 01:36:59 +00:00
$releases = array ();
2012-12-19 22:11:34 +00:00
if ( $variables [ 'updates' ]) {
foreach ( $variables [ 'updates' ] as $update ) {
$modules [] = $update [ 'name' ];
$releases [] = t ( '@module (@date)' , array ( '@module' => $update [ 'name' ], '@date' => format_date ( $update [ 'timestamp' ], 'html_date' )));
}
2013-06-16 23:54:01 +00:00
$variables [ 'modules' ] = $modules ;
2012-12-19 22:11:34 +00:00
}
2013-06-16 23:54:01 +00:00
$details [ 'available_updates_list' ] = array (
'#theme' => 'item_list' ,
'#items' => $releases ,
);
2012-12-19 22:11:34 +00:00
}
// Build output for updates not found.
if ( isset ( $variables [ 'not_found' ])) {
2013-08-23 01:36:59 +00:00
$releases = array ();
2013-06-16 23:54:01 +00:00
$variables [ 'missing_updates_status' ] = format_plural ( count ( $variables [ 'not_found' ]), 'Missing translations for one project' , 'Missing translations for @count projects' );
2012-12-19 22:11:34 +00:00
if ( $variables [ 'not_found' ]) {
foreach ( $variables [ 'not_found' ] as $update ) {
$version = $update [ 'version' ] ? $update [ 'version' ] : t ( 'no version' );
$releases [] = t ( '@module (@version).' , array ( '@module' => $update [ 'name' ], '@version' => $version )) . ' ' . $update [ 'info' ];
}
}
2013-06-16 23:54:01 +00:00
$details [ 'missing_updates_list' ] = array (
'#theme' => 'item_list' ,
'#items' => $releases ,
);
// Prefix the missing updates list if there is an available updates lists
// before it.
if ( ! empty ( $details [ 'available_updates_list' ][ '#items' ])) {
$details [ 'missing_updates_list' ][ '#prefix' ] = t ( 'Missing translations for:' );
2012-12-19 22:11:34 +00:00
}
}
2013-06-16 23:54:01 +00:00
$variables [ 'details' ] = $details ;
2012-12-19 22:11:34 +00:00
}
/**
2013-06-16 23:54:01 +00:00
* Prepares variables for most recent translation update templates .
*
* Displays the last time we checked for locale update data . In addition to
* properly formatting the given timestamp , this function also provides a " Check
* manually " link that refreshes the available update and redirects back to the
* same page .
2012-12-19 22:11:34 +00:00
*
2013-06-16 23:54:01 +00:00
* Default template : locale - translation - last - check . html . twig .
2012-12-19 22:11:34 +00:00
*
* @ param $variables
* An associative array containing :
* - last : The timestamp when the site last checked for available updates .
*
* @ see locale_translation_status_form ()
*/
2013-06-16 23:54:01 +00:00
function template_preprocess_locale_translation_last_check ( & $variables ) {
2012-12-19 22:11:34 +00:00
$last = $variables [ 'last' ];
2013-06-16 23:54:01 +00:00
$variables [ 'last_checked' ] = ( $last != NULL );
$variables [ 'time' ] = format_interval ( REQUEST_TIME - $last );
$variables [ 'link' ] = l ( t ( 'Check manually' ), 'admin/reports/translations/check' , array ( 'query' => drupal_get_destination ()));
2012-12-19 22:11:34 +00:00
}