2012-08-26 15:45:11 +00:00
< ? php
/**
* @ file
* The API for comparing project translation status with available translation .
*/
2013-06-30 09:48:34 +00:00
use Drupal\Core\Utility\ProjectInfo ;
2012-08-26 15:45:11 +00:00
/**
2013-06-30 09:48:34 +00:00
* Load common APIs .
2012-08-26 15:45:11 +00:00
*/
2012-12-07 18:17:37 +00:00
// @todo Combine functions differently in files to avoid unnecessary includes.
2015-05-18 21:08:10 +00:00
// Follow-up issue: https://www.drupal.org/node/1834298.
2013-05-09 09:25:10 +00:00
require_once __DIR__ . '/locale.translation.inc' ;
2012-08-26 15:45:11 +00:00
/**
* Clear the project data table .
*/
function locale_translation_flush_projects () {
2014-08-29 06:43:16 +00:00
\Drupal :: service ( 'locale.project' ) -> deleteAll ();
2012-08-26 15:45:11 +00:00
}
/**
* Builds list of projects and stores the result in the database .
*
* The project data is based on the project list supplied by the Update module .
* Only the properties required by Locale module is included and additional
* ( custom ) modules and translation server data is added .
*
* In case the Update module is disabled this function will return an empty
* array .
*
* @ return array
* Array of project data :
* - " name " : Project system name .
* - " project_type " : Project type , e . g . 'module' , 'theme' .
* - " core " : Core release version , e . g . 8. x
* - " version " : Project release version , e . g . 8. x - 1.0
2012-09-13 07:25:54 +00:00
* See http :// drupalcode . org / project / drupalorg . git / blob / refs / heads / 7. x - 3. x :/ drupalorg_project / plugins / release_packager / DrupalorgProjectPackageRelease . class . php #l219
* for how the version strings are created .
2012-08-26 15:45:11 +00:00
* - " server_pattern " : Translation server po file pattern .
* - " status " : Project status , 1 = enabled .
*/
function locale_translation_build_projects () {
2013-03-06 22:51:39 +00:00
// Get the project list based on .info.yml files.
2012-08-26 15:45:11 +00:00
$projects = locale_translation_project_list ();
// Mark all previous projects as disabled and store new project data.
2014-08-29 06:43:16 +00:00
\Drupal :: service ( 'locale.project' ) -> disableAll ();
2012-08-26 15:45:11 +00:00
$default_server = locale_translation_default_translation_server ();
foreach ( $projects as $name => $data ) {
2015-10-05 22:39:44 +00:00
// For dev releases, remove the '-dev' part and trust the translation server
// to fall back to the latest stable release for that branch.
if ( isset ( $data [ 'info' ][ 'version' ]) && strpos ( $data [ 'info' ][ 'version' ], '-dev' )) {
if ( preg_match ( " /^( \ d+ \ .x- \ d+ \ .).* $ / " , $data [ 'info' ][ 'version' ], $matches )) {
// Example matches: 8.x-1.x-dev, 8.x-1.0-alpha1+5-dev => 8.x-1.x
$data [ 'info' ][ 'version' ] = $matches [ 1 ] . 'x' ;
2012-08-26 15:45:11 +00:00
}
2015-10-05 22:39:44 +00:00
elseif ( preg_match ( " /^( \ d+ \ . \ d+ \ .).* $ / " , $data [ 'info' ][ 'version' ], $matches )) {
// Example match: 8.0.0-dev => 8.0.x (Drupal core)
$data [ 'info' ][ 'version' ] = $matches [ 1 ] . 'x' ;
2012-08-26 15:45:11 +00:00
}
}
2012-09-13 07:25:54 +00:00
// For every project store information.
2017-03-04 01:20:24 +00:00
$data += [
2014-08-29 06:43:16 +00:00
'name' => $name ,
2012-08-26 15:45:11 +00:00
'version' => isset ( $data [ 'info' ][ 'version' ]) ? $data [ 'info' ][ 'version' ] : '' ,
2013-09-16 03:58:06 +00:00
'core' => isset ( $data [ 'info' ][ 'core' ]) ? $data [ 'info' ][ 'core' ] : \Drupal :: CORE_COMPATIBILITY ,
2012-08-26 15:45:11 +00:00
// A project can provide the path and filename pattern to download the
// gettext file. Use the default if not.
2012-12-07 18:17:37 +00:00
'server_pattern' => isset ( $data [ 'info' ][ 'interface translation server pattern' ]) && $data [ 'info' ][ 'interface translation server pattern' ] ? $data [ 'info' ][ 'interface translation server pattern' ] : $default_server [ 'pattern' ],
2012-09-13 07:25:54 +00:00
'status' => ! empty ( $data [ 'project_status' ]) ? 1 : 0 ,
2017-03-04 01:20:24 +00:00
];
2015-10-05 22:39:44 +00:00
2012-08-26 15:45:11 +00:00
$project = ( object ) $data ;
$projects [ $name ] = $project ;
// Create or update the project record.
2014-08-29 06:43:16 +00:00
\Drupal :: service ( 'locale.project' ) -> set ( $project -> name , $data );
2012-12-07 18:17:37 +00:00
2014-07-21 10:52:00 +00:00
// Invalidate the cache of translatable projects.
locale_translation_clear_cache_projects ();
2012-08-26 15:45:11 +00:00
}
return $projects ;
}
/**
* Fetch an array of projects for translation update .
*
* @ return array
2013-03-06 22:51:39 +00:00
* Array of project data including . info . yml file data .
2012-08-26 15:45:11 +00:00
*/
function locale_translation_project_list () {
2017-03-04 01:20:24 +00:00
$projects = & drupal_static ( __FUNCTION__ , []);
2012-08-26 15:45:11 +00:00
if ( empty ( $projects )) {
2017-03-04 01:20:24 +00:00
$projects = [];
2012-08-26 15:45:11 +00:00
2017-03-04 01:20:24 +00:00
$additional_whitelist = [
2012-08-26 15:45:11 +00:00
'interface translation project' ,
'interface translation server pattern' ,
2017-03-04 01:20:24 +00:00
];
2012-08-26 15:45:11 +00:00
$module_data = _locale_translation_prepare_project_list ( system_rebuild_module_data (), 'module' );
2015-03-13 23:10:36 +00:00
$theme_data = _locale_translation_prepare_project_list ( \Drupal :: service ( 'theme_handler' ) -> rebuildThemeData (), 'theme' );
2013-06-30 09:48:34 +00:00
$project_info = new ProjectInfo ();
$project_info -> processInfoList ( $projects , $module_data , 'module' , TRUE , $additional_whitelist );
$project_info -> processInfoList ( $projects , $theme_data , 'theme' , TRUE , $additional_whitelist );
2012-08-26 15:45:11 +00:00
// Allow other modules to alter projects before fetching and comparing.
2014-02-24 10:10:52 +00:00
\Drupal :: moduleHandler () -> alter ( 'locale_translation_projects' , $projects );
2012-08-26 15:45:11 +00:00
}
return $projects ;
}
/**
* Prepare module and theme data .
*
2013-06-30 09:48:34 +00:00
* Modify . info . yml file data before it is processed by
* \Drupal\Core\Utility\ProjectInfo -> processInfoList () . In order for
* \Drupal\Core\Utility\ProjectInfo -> processInfoList () to recognize a project ,
* it requires the 'project' parameter in the . info . yml file data .
2012-09-13 07:25:54 +00:00
*
2012-08-26 15:45:11 +00:00
* Custom modules or themes can bring their own gettext translation file . To
* enable import of this file the module or theme defines " interface translation
2013-03-06 22:51:39 +00:00
* project = myproject " in its .info.yml file. This function will add a project
2012-08-26 15:45:11 +00:00
* " myproject " to the info data .
*
2014-02-28 11:51:38 +00:00
* @ param \Drupal\Core\Extension\Extension [] $data
2013-03-06 22:51:39 +00:00
* Array of . info . yml file data .
2012-08-26 15:45:11 +00:00
* @ param string $type
* The project type . i . e . module , theme .
*
* @ return array
2013-03-06 22:51:39 +00:00
* Array of . info . yml file data .
2012-08-26 15:45:11 +00:00
*/
function _locale_translation_prepare_project_list ( $data , $type ) {
foreach ( $data as $name => $file ) {
2012-09-13 07:25:54 +00:00
// Include interface translation projects. To allow
2013-06-30 09:48:34 +00:00
// \Drupal\Core\Utility\ProjectInfo->processInfoList() to identify this as
// a project the 'project' property is filled with the
// 'interface translation project' value.
2012-08-26 15:45:11 +00:00
if ( isset ( $file -> info [ 'interface translation project' ])) {
$data [ $name ] -> info [ 'project' ] = $file -> info [ 'interface translation project' ];
}
}
return $data ;
}
/**
* Retrieve data for default server .
*
* @ return array
* Array of server parameters :
2017-05-30 18:50:33 +00:00
* - " pattern " : URI containing po file pattern .
2012-08-26 15:45:11 +00:00
*/
function locale_translation_default_translation_server () {
2013-09-16 03:58:06 +00:00
$pattern = \Drupal :: config ( 'locale.settings' ) -> get ( 'translation.default_server_pattern' );
2012-12-07 18:17:37 +00:00
// An additional check is required here. During the upgrade process
2014-07-21 10:52:00 +00:00
// \Drupal::config()->get() returns NULL. We use the defined value as
// fallback.
2012-12-07 18:17:37 +00:00
$pattern = $pattern ? $pattern : LOCALE_TRANSLATION_DEFAULT_SERVER_PATTERN ;
2017-03-04 01:20:24 +00:00
return [
2012-12-07 18:17:37 +00:00
'pattern' => $pattern ,
2017-03-04 01:20:24 +00:00
];
2012-08-26 15:45:11 +00:00
}
2012-10-11 21:30:02 +00:00
/**
* Check for the latest release of project translations .
*
* @ param array $projects
2012-12-07 18:17:37 +00:00
* Array of project names to check . Defaults to all translatable projects .
2012-10-11 21:30:02 +00:00
* @ param string $langcodes
2012-12-07 18:17:37 +00:00
* Array of language codes . Defaults to all translatable languages .
2012-10-11 21:30:02 +00:00
*
* @ return array
* Available sources indexed by project and language .
2014-07-21 10:52:00 +00:00
*
* @ todo Return batch or NULL .
2012-10-11 21:30:02 +00:00
*/
2017-03-04 01:20:24 +00:00
function locale_translation_check_projects ( $projects = [], $langcodes = []) {
2012-12-07 18:17:37 +00:00
if ( locale_translation_use_remote_source ()) {
2012-10-11 21:30:02 +00:00
// Retrieve the status of both remote and local translation sources by
// using a batch process.
locale_translation_check_projects_batch ( $projects , $langcodes );
}
else {
// Retrieve and save the status of local translations only.
locale_translation_check_projects_local ( $projects , $langcodes );
2013-09-16 03:58:06 +00:00
\Drupal :: state () -> set ( 'locale.translation_last_checked' , REQUEST_TIME );
2012-10-11 21:30:02 +00:00
}
}
/**
* Gets and stores the status and timestamp of remote po files .
*
* A batch process is used to check for po files at remote locations and ( when
* configured ) to check for po files in the local file system . The most recent
* translation source states are stored in the state variable
2012-12-07 18:17:37 +00:00
* 'locale.translation_status' .
*
* @ param array $projects
* Array of project names to check . Defaults to all translatable projects .
* @ param string $langcodes
* Array of language codes . Defaults to all translatable languages .
*/
2017-03-04 01:20:24 +00:00
function locale_translation_check_projects_batch ( $projects = [], $langcodes = []) {
2012-12-07 18:17:37 +00:00
// Build and set the batch process.
$batch = locale_translation_batch_status_build ( $projects , $langcodes );
batch_set ( $batch );
}
/**
* Builds a batch to get the status of remote and local translation files .
2012-10-11 21:30:02 +00:00
*
2013-06-27 11:25:01 +00:00
* The batch process fetches the state of both local and ( if configured ) remote
2012-12-07 18:17:37 +00:00
* translation files . The data of the most recent translation is stored per
* per project and per language . This data is stored in a state variable
* 'locale.translation_status' . The timestamp it was last updated is stored
* in the state variable 'locale.translation_last_checked' .
*
* @ param array $projects
* Array of project names for which to check the state of translation files .
* Defaults to all translatable projects .
* @ param array $langcodes
* Array of language codes . Defaults to all translatable languages .
*
* @ return array
* Batch definition array .
2012-10-11 21:30:02 +00:00
*/
2017-03-04 01:20:24 +00:00
function locale_translation_batch_status_build ( $projects = [], $langcodes = []) {
2012-12-07 18:17:37 +00:00
$projects = $projects ? $projects : array_keys ( locale_translation_get_projects ());
2012-10-11 21:30:02 +00:00
$langcodes = $langcodes ? $langcodes : array_keys ( locale_translatable_language_list ());
2013-06-27 11:25:01 +00:00
$options = _locale_translation_default_update_options ();
2012-12-07 18:17:37 +00:00
2013-06-27 11:25:01 +00:00
$operations = _locale_translation_batch_status_operations ( $projects , $langcodes , $options );
2012-12-07 18:17:37 +00:00
2017-03-04 01:20:24 +00:00
$batch = [
2012-12-07 18:17:37 +00:00
'operations' => $operations ,
2013-06-17 13:35:07 +00:00
'title' => t ( 'Checking translations' ),
2012-12-17 21:45:18 +00:00
'progress_message' => '' ,
2012-12-07 18:17:37 +00:00
'finished' => 'locale_translation_batch_status_finished' ,
2013-06-17 13:35:07 +00:00
'error_message' => t ( 'Error checking translation updates.' ),
2012-12-07 18:17:37 +00:00
'file' => drupal_get_path ( 'module' , 'locale' ) . '/locale.batch.inc' ,
2017-03-04 01:20:24 +00:00
];
2012-12-07 18:17:37 +00:00
return $batch ;
}
/**
* Helper function to construct batch operations checking remote translation
* status .
*
2013-06-27 11:25:01 +00:00
* @ param array $projects
2012-12-07 18:17:37 +00:00
* Array of project names to be processed .
2013-06-27 11:25:01 +00:00
* @ param array $langcodes
2012-12-07 18:17:37 +00:00
* Array of language codes .
2013-06-27 11:25:01 +00:00
* @ param array $options
* Batch processing options .
2012-12-07 18:17:37 +00:00
*
* @ return array
* Array of batch operations .
*/
2017-03-04 01:20:24 +00:00
function _locale_translation_batch_status_operations ( $projects , $langcodes , $options = []) {
$operations = [];
2012-12-07 18:17:37 +00:00
2013-06-27 11:25:01 +00:00
foreach ( $projects as $project ) {
foreach ( $langcodes as $langcode ) {
// Check status of local and remote translation sources.
2017-03-04 01:20:24 +00:00
$operations [] = [ 'locale_translation_batch_status_check' , [ $project , $langcode , $options ]];
2012-10-11 21:30:02 +00:00
}
}
2012-12-07 18:17:37 +00:00
return $operations ;
2012-10-11 21:30:02 +00:00
}
/**
* Check and store the status and timestamp of local po files .
*
* Only po files in the local file system are checked . Any remote translation
2013-06-27 11:25:01 +00:00
* files will be ignored .
2012-10-11 21:30:02 +00:00
*
* Projects may contain a server_pattern option containing a pattern of the
* path to the po source files . If no server_pattern is defined the default
* translation directory is checked for the po file . When a server_pattern is
* defined the specified location is checked . The server_pattern can be set in
2013-03-06 22:51:39 +00:00
* the module ' s . info . yml file or by using
* hook_locale_translation_projects_alter () .
2012-10-11 21:30:02 +00:00
*
2012-12-07 18:17:37 +00:00
* @ param array $projects
* Array of project names for which to check the state of translation files .
* Defaults to all translatable projects .
* @ param array $langcodes
* Array of language codes . Defaults to all translatable languages .
2012-10-11 21:30:02 +00:00
*/
2017-03-04 01:20:24 +00:00
function locale_translation_check_projects_local ( $projects = [], $langcodes = []) {
2012-12-07 18:17:37 +00:00
$projects = locale_translation_get_projects ( $projects );
2012-10-11 21:30:02 +00:00
$langcodes = $langcodes ? $langcodes : array_keys ( locale_translatable_language_list ());
// For each project and each language we check if a local po file is
// available. When found the source object is updated with the appropriate
// type and timestamp of the po file.
foreach ( $projects as $name => $project ) {
foreach ( $langcodes as $langcode ) {
$source = locale_translation_source_build ( $project , $langcode );
2013-06-27 11:25:01 +00:00
$file = locale_translation_source_check_file ( $source );
locale_translation_status_save ( $name , $langcode , LOCALE_TRANSLATION_LOCAL , $file );
2012-10-11 21:30:02 +00:00
}
}
}