2011-08-27 22:04:48 +00:00
< ? php
/**
* @ file
* Mass import - export and batch import functionality for Gettext . po files .
*/
2011-10-31 04:05:57 +00:00
include_once DRUPAL_ROOT . '/core/includes/gettext.inc' ;
2011-08-27 22:04:48 +00:00
/**
* User interface for the translation import screen .
*/
2011-12-22 11:26:12 +00:00
function locale_translate_import_form ( $form , & $form_state ) {
2011-08-27 22:04:48 +00:00
drupal_static_reset ( 'language_list' );
2012-04-25 23:44:20 +00:00
$languages = language_list ();
2012-01-23 15:46:29 +00:00
// Initialize a language list to the ones available, including English if we
// are to translate Drupal to English as well.
$existing_languages = array ();
foreach ( $languages as $langcode => $language ) {
if ( $langcode != 'en' || locale_translate_english ()) {
$existing_languages [ $langcode ] = $language -> name ;
}
2011-10-27 03:55:02 +00:00
}
2011-08-27 22:04:48 +00:00
2012-01-23 15:46:29 +00:00
// If we have no languages available, present the list of predefined languages
// only. If we do have already added languages, set up two option groups with
// the list of existing and then predefined languages.
2011-12-22 11:26:12 +00:00
form_load_include ( $form_state , 'inc' , 'language' , 'language.admin' );
2012-01-23 15:46:29 +00:00
if ( empty ( $existing_languages )) {
$language_options = language_admin_predefined_list ();
$default = key ( $language_options );
2011-08-27 22:04:48 +00:00
}
else {
2012-01-23 15:46:29 +00:00
$default = key ( $existing_languages );
$language_options = array (
2012-04-09 18:24:12 +00:00
t ( 'Existing languages' ) => $existing_languages ,
2011-12-22 11:26:12 +00:00
t ( 'Languages not yet added' ) => language_admin_predefined_list ()
2011-08-27 22:04:48 +00:00
);
}
2012-04-09 18:24:12 +00:00
$form [ 'file' ] = array (
'#type' => 'file' ,
'#title' => t ( 'Translation file' ),
2011-08-27 22:04:48 +00:00
'#size' => 50 ,
'#description' => t ( 'A Gettext Portable Object (<em>.po</em>) file.' ),
);
2012-04-09 18:24:12 +00:00
$form [ 'langcode' ] = array (
'#type' => 'select' ,
'#title' => t ( 'Language' ),
2012-01-23 15:46:29 +00:00
'#options' => $language_options ,
2011-08-27 22:04:48 +00:00
'#default_value' => $default ,
);
2012-04-09 18:24:12 +00:00
$form [ 'customized' ] = array (
'#title' => t ( 'Treat imported strings as custom translations' ),
'#type' => 'checkbox' ,
);
$form [ 'overwrite_options' ] = array (
'#type' => 'container' ,
'#tree' => TRUE ,
);
$form [ 'overwrite_options' ][ 'not_customized' ] = array (
'#title' => t ( 'Overwrite non-customized translations' ),
'#type' => 'checkbox' ,
'#states' => array (
'checked' => array (
':input[name="customized"]' => array ( 'checked' => TRUE ),
),
2011-08-27 22:04:48 +00:00
),
);
2012-04-09 18:24:12 +00:00
$form [ 'overwrite_options' ][ 'customized' ] = array (
'#title' => t ( 'Overwrite existing customized translations' ),
'#type' => 'checkbox' ,
);
2011-08-27 22:04:48 +00:00
2012-04-09 18:24:12 +00:00
$form [ 'actions' ] = array (
'#type' => 'actions'
);
$form [ 'actions' ][ 'submit' ] = array (
'#type' => 'submit' ,
'#value' => t ( 'Import' )
);
2011-08-27 22:04:48 +00:00
return $form ;
}
/**
2012-04-09 18:24:12 +00:00
* Processes the locale import form submission .
2011-08-27 22:04:48 +00:00
*/
function locale_translate_import_form_submit ( $form , & $form_state ) {
$validators = array ( 'file_validate_extensions' => array ( 'po' ));
2012-04-09 18:24:12 +00:00
// Ensure we have the file uploaded.
2011-08-27 22:04:48 +00:00
if ( $file = file_save_upload ( 'file' , $validators )) {
2012-04-09 18:24:12 +00:00
// Add language, if not yet supported.
$language = language_load ( $form_state [ 'values' ][ 'langcode' ]);
if ( empty ( $language )) {
2011-10-31 04:05:57 +00:00
include_once DRUPAL_ROOT . '/core/includes/standard.inc' ;
2011-09-08 18:29:58 +00:00
$predefined = standard_language_list ();
2011-09-28 10:47:48 +00:00
$language = ( object ) array (
2012-04-09 18:24:12 +00:00
'langcode' => $form_state [ 'values' ][ 'langcode' ],
2011-09-28 10:47:48 +00:00
);
2012-04-09 18:24:12 +00:00
$language = language_save ( $language );
drupal_set_message ( t ( 'The language %language has been created.' , array ( '%language' => t ( $language -> name ))));
2011-08-27 22:04:48 +00:00
}
2012-04-09 18:24:12 +00:00
$customized = $form_state [ 'values' ][ 'customized' ] ? LOCALE_CUSTOMIZED : LOCALE_NOT_CUSTOMIZED ;
2011-08-27 22:04:48 +00:00
// Now import strings into the language
2012-04-09 18:24:12 +00:00
if ( $return = _locale_import_po ( $file , $language -> langcode , $form_state [ 'values' ][ 'overwrite_options' ], $customized ) == FALSE ) {
2011-08-27 22:04:48 +00:00
$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 );
}
}
else {
drupal_set_message ( t ( 'File to import not found.' ), 'error' );
$form_state [ 'redirect' ] = 'admin/config/regional/translate/import' ;
return ;
}
$form_state [ 'redirect' ] = 'admin/config/regional/translate' ;
return ;
}
/**
2012-04-09 18:24:12 +00:00
* Builds form to export Gettext translation files .
2011-08-27 22:04:48 +00:00
*/
2012-04-09 18:24:12 +00:00
function locale_translate_export_form ( $form , & $form_state ) {
2012-04-25 23:44:20 +00:00
$languages = language_list ();
2012-01-23 15:46:29 +00:00
$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
}
2012-04-09 18:24:12 +00:00
$language_default = language_default ();
2012-01-23 15:46:29 +00:00
2012-04-09 18:24:12 +00:00
if ( empty ( $language_options )) {
$form [ 'langcode' ] = array (
'#type' => 'value' ,
'#value' => LANGUAGE_SYSTEM ,
);
$form [ 'langcode_text' ] = array (
'#type' => 'item' ,
'#title' => t ( 'Language' ),
'#markup' => t ( 'No language available. The export will only contain source strings.' ),
);
}
else {
$form [ 'langcode' ] = array (
'#type' => 'select' ,
'#title' => t ( 'Language' ),
'#options' => $language_options ,
'#default_value' => $language_default -> langcode ,
'#empty_option' => t ( 'Source text only, no translations' ),
'#empty_value' => LANGUAGE_SYSTEM ,
);
$form [ 'content_options' ] = array (
'#type' => 'fieldset' ,
'#title' => t ( 'Export options' ),
'#collapsible' => TRUE ,
'#collapsed' => TRUE ,
'#tree' => TRUE ,
'#states' => array (
'invisible' => array (
':input[name="langcode"]' => array ( 'value' => LANGUAGE_SYSTEM ),
),
),
);
$form [ 'content_options' ][ 'not_customized' ] = array (
'#type' => 'checkbox' ,
'#title' => t ( 'Include non-customized translations' ),
'#default_value' => TRUE ,
);
$form [ 'content_options' ][ 'customized' ] = array (
'#type' => 'checkbox' ,
'#title' => t ( 'Include customized translations' ),
'#default_value' => TRUE ,
);
$form [ 'content_options' ][ 'not_translated' ] = array (
'#type' => 'checkbox' ,
'#title' => t ( 'Include untranslated text' ),
'#default_value' => TRUE ,
);
2011-08-27 22:04:48 +00:00
}
2012-04-09 18:24:12 +00:00
$form [ 'actions' ] = array (
'#type' => 'actions'
2011-08-27 22:04:48 +00:00
);
2012-04-09 18:24:12 +00:00
$form [ 'actions' ][ 'submit' ] = array (
'#type' => 'submit' ,
'#value' => t ( 'Export' )
2011-08-27 22:04:48 +00:00
);
return $form ;
}
/**
2012-04-09 18:24:12 +00:00
* Processes a translation ( or template ) export form submission .
2011-08-27 22:04:48 +00:00
*/
2012-04-09 18:24:12 +00:00
function locale_translate_export_form_submit ( $form , & $form_state ) {
2011-08-27 22:04:48 +00:00
// If template is required, language code is not given.
2012-04-09 18:24:12 +00:00
if ( $form_state [ 'values' ][ 'langcode' ] != LANGUAGE_SYSTEM ) {
$language = language_load ( $form_state [ 'values' ][ 'langcode' ]);
}
else {
$language = NULL ;
2011-08-27 22:04:48 +00:00
}
2012-04-09 18:24:12 +00:00
$content_options = isset ( $form_state [ 'values' ][ 'content_options' ]) ? $form_state [ 'values' ][ 'content_options' ] : array ();
_locale_export_po ( $language , _locale_export_po_generate ( $language , _locale_export_get_strings ( $language , $content_options )));
2011-08-27 22:04:48 +00:00
}
2011-12-22 11:26:12 +00:00
/**
* Set a batch for newly added language .
*/
function locale_translate_add_language_set_batch ( $langcode ) {
// See if we have language files to import for the newly added language,
// collect and import them.
if ( $batch = locale_translate_batch_import_files ( $langcode , TRUE )) {
batch_set ( $batch );
}
}
2011-08-27 22:04:48 +00:00
/**
2011-10-29 11:40:09 +00:00
* Prepare a batch to import all translations .
2011-08-27 22:04:48 +00:00
*
* @ param $langcode
2011-10-29 11:40:09 +00:00
* ( optional ) Language code to limit files being imported .
* @ param $finish_feedback
* ( optional ) Whether to give feedback to the user when finished .
2012-06-16 15:16:07 +00:00
* @ param $force
* ( optional ) Import all available files , even if they were imported before .
2011-08-27 22:04:48 +00:00
*
2011-10-29 11:40:09 +00:00
* @ todo
* Integrate with update status to identify projects needed and integrate
* l10n_update functionality to feed in translation files alike .
* See http :// drupal . org / node / 1191488.
2011-08-27 22:04:48 +00:00
*/
2012-06-16 15:16:07 +00:00
function locale_translate_batch_import_files ( $langcode = NULL , $finish_feedback = FALSE , $force = FALSE ) {
2011-11-25 06:22:29 +00:00
$files = array ();
if ( ! empty ( $langcode )) {
$langcodes = array ( $langcode );
}
else {
// If langcode was not provided, make sure to only import files for the
// languages we have enabled.
$langcodes = array_keys ( language_list ());
}
foreach ( $langcodes as $langcode ) {
2012-06-16 15:16:07 +00:00
$files = array_merge ( $files , locale_translate_get_interface_translation_files ( $langcode ));
}
if ( ! $force ) {
$result = db_select ( 'locale_file' , 'lf' )
-> fields ( 'lf' , array ( 'langcode' , 'uri' , 'timestamp' ))
-> condition ( 'langcode' , $langcodes )
-> execute ()
-> fetchAllAssoc ( 'uri' );
foreach ( $result as $uri => $info ) {
if ( isset ( $files [ $uri ]) && filemtime ( $uri ) <= $info -> timestamp ) {
// The file is already imported and it did not change since the import.
// Remove it from file list and don't import it again.
unset ( $files [ $uri ]);
}
}
2011-11-25 06:22:29 +00:00
}
2011-10-29 11:40:09 +00:00
return locale_translate_batch_build ( $files , $finish_feedback );
2011-08-27 22:04:48 +00:00
}
2012-06-16 15:16:07 +00:00
/**
* Get an array of available interface translation file .
*
* @ param $langcode
* The langcode for the interface translation files . Pass NULL to get all
* available interface translation files .
*
* @ return array
* An array of interface translation files .
*/
function locale_translate_get_interface_translation_files ( $langcode = NULL ) {
$directory = variable_get ( 'locale_translate_file_directory' , conf_path () . '/files/translations' );
return file_scan_directory ( $directory , '!' . ( ! empty ( $langcode ) ? '\.' . preg_quote ( $langcode , '!' ) : '' ) . '\.po$!' , array ( 'recurse' => FALSE ));
}
2011-08-27 22:04:48 +00:00
/**
* Build a locale batch from an array of files .
*
* @ param $files
2011-10-29 11:40:09 +00:00
* Array of file objects to import .
* @ param $finish_feedback
* ( optional ) Whether to give feedback to the user when finished .
2011-08-27 22:04:48 +00:00
*
* @ return
2011-10-29 11:40:09 +00:00
* A batch structure or FALSE if $files was empty .
2011-08-27 22:04:48 +00:00
*/
2011-10-29 11:40:09 +00:00
function locale_translate_batch_build ( $files , $finish_feedback = FALSE ) {
2011-08-27 22:04:48 +00:00
$t = get_t ();
if ( count ( $files )) {
$operations = array ();
foreach ( $files as $file ) {
2011-10-29 11:40:09 +00:00
// We call locale_translate_batch_import for every batch operation.
$operations [] = array ( 'locale_translate_batch_import' , array ( $file -> uri ));
2011-08-27 22:04:48 +00:00
}
$batch = array (
'operations' => $operations ,
'title' => $t ( 'Importing interface translations' ),
'init_message' => $t ( 'Starting import' ),
'error_message' => $t ( 'Error importing interface translations' ),
'file' => drupal_get_path ( 'module' , 'locale' ) . '/locale.bulk.inc' ,
);
2011-10-29 11:40:09 +00:00
if ( $finish_feedback ) {
$batch [ 'finished' ] = 'locale_translate_batch_finished' ;
2011-08-27 22:04:48 +00:00
}
return $batch ;
}
return FALSE ;
}
/**
* Perform interface translation import as a batch step .
*
* @ param $filepath
* Path to a file to import .
* @ param $results
* Contains a list of files imported .
*/
2011-10-29 11:40:09 +00:00
function locale_translate_batch_import ( $filepath , & $context ) {
2011-08-27 22:04:48 +00:00
// The filename is either {langcode}.po or {prefix}.{langcode}.po, so
// we can extract the language code to use for the import from the end.
if ( preg_match ( '!(/|\.)([^\./]+)\.po$!' , $filepath , $langcode )) {
2012-06-16 15:16:07 +00:00
$file = locale_translate_file_create ( $filepath , $langcode [ 2 ]);
$success = _locale_import_read_po ( 'db-store' , $file , array (), $langcode [ 2 ]);
if ( $success == NULL ) {
$file -> langcode = $langcode [ 2 ];
locale_translate_update_file_history ( $file );
}
2011-08-27 22:04:48 +00:00
$context [ 'results' ][] = $filepath ;
}
}
/**
* Finished callback of system page locale import batch .
*/
2011-10-29 11:40:09 +00:00
function locale_translate_batch_finished ( $success , $results ) {
2011-08-27 22:04:48 +00:00
if ( $success ) {
2011-10-29 11:40:09 +00:00
drupal_set_message ( format_plural ( count ( $results ), 'One translation file imported.' , '@count translation files imported.' ));
2011-08-27 22:04:48 +00:00
}
}
2012-06-16 15:16:07 +00:00
/**
* Creates a file object and populates the timestamp property .
*
* @ param $filepath
* The filepath of a file to import .
*
* @ return
* An object representing the file .
*/
function locale_translate_file_create ( $filepath ) {
$file = new stdClass ();
$file -> filename = drupal_basename ( $filepath );
$file -> uri = $filepath ;
$file -> timestamp = filemtime ( $file -> uri );
return $file ;
}
/**
* Update the { locale_file } table .
*
* @ param $file
* Object representing the file just imported .
*
* @ return integer
* FALSE on failure . Otherwise SAVED_NEW or SAVED_UPDATED .
*
* @ see drupal_write_record ()
*/
function locale_translate_update_file_history ( $file ) {
// Update or write new record.
if ( db_query ( " SELECT uri FROM { locale_file} WHERE uri = :uri AND langcode = :langcode " , array ( ':uri' => $file -> uri , ':langcode' => $file -> langcode )) -> fetchField ()) {
$update = array ( 'uri' , 'langcode' );
}
else {
$update = array ();
}
return drupal_write_record ( 'locale_file' , $file , $update );
}
/**
* Deletes all interface translation files depending on the langcode .
*
* @ param $langcode
* A langcode or NULL . Pass NULL to delete all interface translation files .
*/
function locale_translate_delete_translation_files ( $langcode ) {
$files = locale_translate_get_interface_translation_files ( $langcode );
2012-06-25 15:06:24 +00:00
$return = TRUE ;
2012-06-16 15:16:07 +00:00
if ( ! empty ( $files )) {
foreach ( $files as $file ) {
$success = file_unmanaged_delete ( $file -> uri );
if ( ! $success ) {
2012-06-25 15:06:24 +00:00
$return = FALSE ;
}
else {
// Remove the registered translation file if any.
db_delete ( 'locale_file' )
-> condition ( 'langcode' , $langcode )
-> condition ( 'uri' , $file -> uri )
-> execute ();
2012-06-16 15:16:07 +00:00
}
}
}
2012-06-25 15:06:24 +00:00
return $return ;
2012-06-16 15:16:07 +00:00
}