123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742 |
- <?php
- /**
- * @file
- * Mass import-export and batch import functionality for Gettext .po files.
- */
- /**
- * Form constructor for the translation import screen.
- *
- * @see l10n_update_import_form_submit()
- *
- * @ingroup forms
- */
- function l10n_update_import_form($form, &$form_state) {
- drupal_static_reset('language_list');
- $languages = language_list();
- // 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' || l10n_update_english()) {
- $existing_languages[$langcode] = $language->name;
- }
- }
- // 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.
- form_load_include($form_state, 'inc', 'language', 'language.admin');
- if (empty($existing_languages)) {
- $language_options = language_admin_predefined_list();
- $default = key($language_options);
- }
- else {
- $default = key($existing_languages);
- $language_options = array(
- t('Existing languages') => $existing_languages,
- t('Languages not yet added') => language_admin_predefined_list(),
- );
- }
- $validators = array(
- 'file_validate_extensions' => array('po'),
- 'file_validate_size' => array(file_upload_max_size()),
- );
- $form['file'] = array(
- '#type' => 'file',
- '#title' => t('Translation file'),
- '#description' => theme('file_upload_help', array('description' => t('A Gettext Portable Object file.'), 'upload_validators' => $validators)),
- '#size' => 50,
- '#upload_validators' => $validators,
- '#attributes' => array('class' => array('file-import-input')),
- '#attached' => array(
- 'js' => array(
- drupal_get_path('module', 'locale') . '/locale.bulk.js' => array(),
- ),
- ),
- );
- $form['langcode'] = array(
- '#type' => 'select',
- '#title' => t('Language'),
- '#options' => $language_options,
- '#default_value' => $default,
- '#attributes' => array('class' => array('langcode-input')),
- );
- $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),
- ),
- ),
- );
- $form['overwrite_options']['customized'] = array(
- '#title' => t('Overwrite existing customized translations'),
- '#type' => 'checkbox',
- );
- $form['actions'] = array(
- '#type' => 'actions',
- );
- $form['actions']['submit'] = array(
- '#type' => 'submit',
- '#value' => t('Import'),
- );
- return $form;
- }
- /**
- * Form submission handler for l10n_update_import_form().
- */
- function l10n_update_import_form_submit($form, &$form_state) {
- // Ensure we have the file uploaded.
- if ($file = file_save_upload('file', $form_state, $form['file']['#upload_validators'], 'translations://', 0)) {
- // Add language, if not yet supported.
- $language = language_load($form_state['values']['langcode']);
- if (empty($language)) {
- $language = new Language(array(
- 'id' => $form_state['values']['langcode'],
- ));
- $language = language_save($language);
- drupal_set_message(t('The language %language has been created.', array('%language' => t($language->name))));
- }
- $options = array(
- 'langcode' => $form_state['values']['langcode'],
- 'overwrite_options' => $form_state['values']['overwrite_options'],
- 'customized' => $form_state['values']['customized'] ? L10N_UPDATE_CUSTOMIZED : L10N_UPDATE_NOT_CUSTOMIZED,
- );
- $file = l10n_update_file_attach_properties($file, $options);
- $batch = l10n_update_batch_build(array($file->uri => $file), $options);
- batch_set($batch);
- }
- else {
- form_set_error('file', $form_state, t('File to import not found.'));
- $form_state['rebuild'] = TRUE;
- }
- $form_state['redirect_route']['route_name'] = 'locale.translate_page';
- }
- /**
- * Form constructor for the Gettext translation files export form.
- *
- * @see l10n_update_export_form_submit()
- *
- * @ingroup forms
- */
- function l10n_update_export_form($form, &$form_state) {
- global $language;
- $languages = language_list();
- $language_options = array();
- foreach ($languages as $langcode => $language) {
- if ($langcode != 'en' || l10n_update_english()) {
- $language_options[$langcode] = $language->name;
- }
- }
- $language_default = language_default();
- $groups = module_invoke_all('locale', 'groups');
- if (empty($language_options)) {
- $form['langcode'] = array(
- '#type' => 'value',
- '#value' => $language->language,
- );
- $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->id,
- '#empty_option' => t('Source text only, no translations'),
- '#empty_value' => $language->language,
- );
- $form['textgroup'] = array(
- '#type' => 'select',
- '#title' => t('Text group'),
- '#options' => $groups,
- '#default_value' => 'default',
- );
- $form['content_options'] = array(
- '#type' => 'details',
- '#title' => t('Export options'),
- '#collapsed' => TRUE,
- '#tree' => TRUE,
- '#states' => array(
- 'invisible' => array(
- ':input[name="langcode"]' => array('value' => $language->language),
- ),
- ),
- );
- $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,
- );
- }
- $form['actions'] = array(
- '#type' => 'actions',
- );
- $form['actions']['submit'] = array(
- '#type' => 'submit',
- '#value' => t('Export'),
- );
- return $form;
- }
- /**
- * Form submission handler for l10n_update_export_form().
- */
- function l10n_update_export_form_submit($form, &$form_state) {
- global $language;
- // If template is required, language code is not given.
- if ($form_state['values']['langcode'] != $language->language) {
- $languages = language_list();
- $language = isset($languages[$form_state['values']['langcode']]) ? $languages[$form_state['values']['langcode']] : NULL;
- }
- else {
- $language = NULL;
- }
- $content_options = isset($form_state['values']['content_options']) ? $form_state['values']['content_options'] : array();
- $textgroup = isset($form_state['values']['textgroup']) ? $form_state['values']['textgroup'] : NULL;
- $reader = new PoDatabaseReader();
- $languageName = '';
- if ($language != NULL) {
- $reader->setLangcode($language->id);
- $reader->setOptions($content_options);
- $reader->setTextgroup($textgroup);
- $languages = language_list();
- $languageName = isset($languages[$language->id]) ? $languages[$language->id]->name : '';
- $filename = $language->id . '.po';
- }
- else {
- // Template required.
- $filename = 'drupal.pot';
- }
- $item = $reader->readItem();
- if (!empty($item)) {
- $uri = tempnam('temporary://', 'po_');
- $header = $reader->getHeader();
- $header->setProjectName(variable_get('site_name'));
- $header->setLanguageName($languageName);
- $writer = new PoStreamWriter();
- $writer->setUri($uri);
- $writer->setHeader($header);
- $writer->open();
- $writer->writeItem($item);
- $writer->writeItems($reader);
- $writer->close();
- }
- else {
- drupal_set_message('Nothing to export.');
- }
- }
- /**
- * Prepare a batch to import all translations.
- *
- * @param array $options
- * An array with options that can have the following elements:
- * - 'langcode': The language code. Optional, defaults to NULL, which means
- * that the language will be detected from the name of the files.
- * - 'overwrite_options': Overwrite options array as defined in
- * PoDatabaseWriter. Optional, defaults to an empty array.
- * - 'customized': Flag indicating whether the strings imported from $file
- * are customized translations or come from a community source. Use
- * L10N_UPDATE_CUSTOMIZED or L10N_UPDATE_NOT_CUSTOMIZED. Optional, defaults
- * to L10N_UPDATE_NOT_CUSTOMIZED.
- * - 'finish_feedback': Whether or not to give feedback to the user when the
- * batch is finished. Optional, defaults to TRUE.
- * @param bool $force
- * (optional) Import all available files, even if they were imported before.
- *
- * @todo
- * Integrate with update status to identify projects needed and integrate
- * l10n_update functionality to feed in translation files alike.
- * See https://www.drupal.org/node/1191488.
- */
- function l10n_update_batch_import_files(array $options, $force = FALSE) {
- $options += array(
- 'overwrite_options' => array(),
- 'customized' => L10N_UPDATE_NOT_CUSTOMIZED,
- 'finish_feedback' => TRUE,
- );
- if (!empty($options['langcode'])) {
- $langcodes = array($options['langcode']);
- }
- else {
- // If langcode was not provided, make sure to only import files for the
- // languages we have enabled.
- $langcodes = array_keys(language_list());
- }
- $files = l10n_update_get_interface_translation_files(array(), $langcodes);
- if (!$force) {
- $result = db_select('l10n_update_file', 'lf')
- ->fields('lf', array('langcode', 'uri', 'timestamp'))
- ->condition('language', $langcodes)
- ->execute()
- ->fetchAllAssoc('uri');
- foreach ($result as $uri => $info) {
- if (isset($files[$uri]) && filemtime($uri) <= $info->timestamp) {
- // The file is already imported and not changed since the last import.
- // Remove it from file list and don't import it again.
- unset($files[$uri]);
- }
- }
- }
- return l10n_update_batch_build($files, $options);
- }
- /**
- * Get interface translation files present in the translations directory.
- *
- * @param array $projects
- * Project names from which to get the translation files and history.
- * Defaults to all projects.
- * @param array $langcodes
- * Language codes from which to get the translation files and history.
- * Defaults to all languages.
- *
- * @return array
- * An array of interface translation files keyed by their URI.
- */
- function l10n_update_get_interface_translation_files($projects = array(), $langcodes = array()) {
- module_load_include('compare.inc', 'l10n_update');
- $files = array();
- $projects = $projects ? $projects : array_keys(l10n_update_get_projects());
- $langcodes = $langcodes ? $langcodes : array_keys(l10n_update_translatable_language_list());
- // Scan the translations directory for files matching a name pattern
- // containing a project name and language code: {project}.{langcode}.po or
- // {project}-{version}.{langcode}.po.
- // Only files of known projects and languages will be returned.
- $directory = variable_get('l10n_update_download_store', L10N_UPDATE_DEFAULT_TRANSLATION_PATH);
- $result = file_scan_directory($directory, '![a-z_]+(\-[0-9a-z\.\-\+]+|)\.[^\./]+\.po$!', array('recurse' => FALSE));
- foreach ($result as $file) {
- // Update the file object with project name and version from the file name.
- $file = l10n_update_file_attach_properties($file);
- if (in_array($file->project, $projects)) {
- if (in_array($file->langcode, $langcodes)) {
- $files[$file->uri] = $file;
- }
- }
- }
- return $files;
- }
- /**
- * Build a locale batch from an array of files.
- *
- * @param array $files
- * Array of file objects to import.
- * @param array $options
- * An array with options that can have the following elements:
- * - 'langcode': The language code. Optional, defaults to NULL, which means
- * that the language will be detected from the name of the files.
- * - 'overwrite_options': Overwrite options array as defined in
- * PoDatabaseWriter. Optional, defaults to an empty array.
- * - 'customized': Flag indicating whether the strings imported from $file
- * are customized translations or come from a community source. Use
- * L10N_UPDATE_CUSTOMIZED or L10N_UPDATE_NOT_CUSTOMIZED. Optional, defaults
- * to L10N_UPDATE_NOT_CUSTOMIZED.
- * - 'finish_feedback': Whether or not to give feedback to the user when the
- * batch is finished. Optional, defaults to TRUE.
- *
- * @return array|bool
- * A batch structure or FALSE if $files was empty.
- */
- function l10n_update_batch_build(array $files, array $options) {
- $options += array(
- 'overwrite_options' => array(),
- 'customized' => L10N_UPDATE_NOT_CUSTOMIZED,
- 'finish_feedback' => TRUE,
- );
- if (count($files)) {
- $operations = array();
- foreach ($files as $file) {
- // We call l10n_update_batch_import for every batch operation.
- $operations[] = array('l10n_update_batch_import', array($file, $options));
- }
- // Save the translation status of all files.
- $operations[] = array('l10n_update_batch_import_save', array());
- // Add a final step to refresh JavaScript and configuration strings.
- $operations[] = array('l10n_update_batch_refresh', array());
- $batch = array(
- 'operations' => $operations,
- 'title' => t('Importing interface translations'),
- 'progress_message' => '',
- 'error_message' => t('Error importing interface translations'),
- 'file' => drupal_get_path('module', 'locale') . '/locale.bulk.inc',
- );
- if ($options['finish_feedback']) {
- $batch['finished'] = 'l10n_update_batch_finished';
- }
- return $batch;
- }
- return FALSE;
- }
- /**
- * Perform interface translation import as a batch step.
- *
- * @param object $file
- * A file object of the gettext file to be imported. The file object must
- * contain a language parameter. This is used as the language of the import.
- * @param array $options
- * An array with options that can have the following elements:
- * - 'langcode': The language code.
- * - 'overwrite_options': Overwrite options array as defined in
- * PoDatabaseWriter. Optional, defaults to an empty array.
- * - 'customized': Flag indicating whether the strings imported from $file
- * are customized translations or come from a community source. Use
- * L10N_UPDATE_CUSTOMIZED or L10N_UPDATE_NOT_CUSTOMIZED. Optional, defaults
- * to L10N_UPDATE_NOT_CUSTOMIZED.
- * - 'message': Alternative message to display during import. Note, this must
- * be sanitized text.
- * @param array $context
- * Contains a list of files imported.
- */
- function l10n_update_batch_import($file, array $options, &$context) {
- // Merge the default values in the $options array.
- $options += array(
- 'overwrite_options' => array(),
- 'customized' => L10N_UPDATE_NOT_CUSTOMIZED,
- );
- if (isset($file->langcode)) {
- try {
- if (empty($context['sandbox'])) {
- $context['sandbox']['parse_state'] = array(
- 'filesize' => filesize(drupal_realpath($file->uri)),
- 'chunk_size' => 200,
- 'seek' => 0,
- );
- }
- // Update the seek and the number of items in the $options array().
- $options['seek'] = $context['sandbox']['parse_state']['seek'];
- $options['items'] = $context['sandbox']['parse_state']['chunk_size'];
- $report = Gettext::fileToDatabase($file, $options);
- // If not yet finished with reading, mark progress based on size and
- // position.
- if ($report['seek'] < filesize($file->uri)) {
- $context['sandbox']['parse_state']['seek'] = $report['seek'];
- // Maximize the progress bar at 95% before completion, the batch API
- // could trigger the end of the operation before file reading is done,
- // because of floating point inaccuracies. See
- // https://www.drupal.org/node/1089472
- $context['finished'] = min(0.95, $report['seek'] / filesize($file->uri));
- if (isset($options['message'])) {
- $context['message'] = t('!message (@percent%).', array('!message' => $options['message'], '@percent' => (int) ($context['finished'] * 100)));
- }
- else {
- $context['message'] = t('Importing translation file: %filename (@percent%).', array('%filename' => $file->filename, '@percent' => (int) ($context['finished'] * 100)));
- }
- }
- else {
- // We are finished here.
- $context['finished'] = 1;
- // Store the file data for processing by the next batch operation.
- $file->timestamp = filemtime($file->uri);
- $context['results']['files'][$file->uri] = $file;
- $context['results']['languages'][$file->uri] = $file->langcode;
- }
- // Add the reported values to the statistics for this file.
- // Each import iteration reports statistics in an array. The results of
- // each iteration are added and merged here and stored per file.
- if (!isset($context['results']['stats']) || !isset($context['results']['stats'][$file->uri])) {
- $context['results']['stats'][$file->uri] = array();
- }
- foreach ($report as $key => $value) {
- if (is_numeric($report[$key])) {
- if (!isset($context['results']['stats'][$file->uri][$key])) {
- $context['results']['stats'][$file->uri][$key] = 0;
- }
- $context['results']['stats'][$file->uri][$key] += $report[$key];
- }
- elseif (is_array($value)) {
- $context['results']['stats'][$file->uri] += array($key => array());
- $context['results']['stats'][$file->uri][$key] = array_merge($context['results']['stats'][$file->uri][$key], $value);
- }
- }
- }
- catch (Exception $exception) {
- // Import failed. Store the data of the failing file.
- $context['results']['failed_files'][] = $file;
- watchdog('l10n_update', 'Unable to import translations file: @file (@message)', array('@file' => $file->uri, '@message' => $exception->getMessage()));
- }
- }
- }
- /**
- * Batch callback: Save data of imported files.
- *
- * @param array $context
- * Contains a list of imported files.
- */
- function l10n_update_batch_import_save($context) {
- if (isset($context['results']['files'])) {
- foreach ($context['results']['files'] as $file) {
- // Update the file history if both project and version are known. This
- // table is used by the automated translation update function which tracks
- // translation status of module and themes in the system. Other
- // translation files are not tracked and are therefore not stored in this
- // table.
- if ($file->project && $file->version) {
- $file->last_checked = REQUEST_TIME;
- l10n_update_update_file_history($file);
- }
- }
- $context['message'] = t('Translations imported.');
- }
- }
- /**
- * Refreshs translations after importing strings.
- *
- * @param array $context
- * Contains a list of strings updated and information about the progress.
- */
- function l10n_update_batch_refresh(&$context) {
- if (!isset($context['sandbox']['refresh'])) {
- $strings = $langcodes = array();
- if (isset($context['results']['stats'])) {
- // Get list of unique string identifiers and language codes updated.
- $langcodes = array_unique(array_values($context['results']['languages']));
- foreach ($context['results']['stats'] as $report) {
- $strings = array_merge($strings, $report['strings']);
- }
- }
- if ($strings) {
- // Initialize multi-step string refresh.
- $context['message'] = t('Updating translations for JavaScript and configuration strings.');
- $context['sandbox']['refresh']['strings'] = array_unique($strings);
- $context['sandbox']['refresh']['languages'] = $langcodes;
- $context['sandbox']['refresh']['names'] = array();
- $context['results']['stats']['config'] = 0;
- $context['sandbox']['refresh']['count'] = count($strings);
- // We will update strings on later steps.
- $context['finished'] = 1 - 1 / $context['sandbox']['refresh']['count'];
- }
- else {
- $context['finished'] = 1;
- }
- }
- elseif (!empty($context['sandbox']['refresh']['strings'])) {
- // Not perfect but will give some indication of progress.
- $context['finished'] = 1 - count($context['sandbox']['refresh']['strings']) / $context['sandbox']['refresh']['count'];
- // Pending strings, refresh 100 at a time, get next pack.
- $next = array_slice($context['sandbox']['refresh']['strings'], 0, 100);
- array_splice($context['sandbox']['refresh']['strings'], 0, count($next));
- // Clear cache and force refresh of JavaScript translations.
- _l10n_update_refresh_translations($context['sandbox']['refresh']['languages'], $next);
- }
- else {
- $context['finished'] = 1;
- }
- }
- /**
- * Finished callback of system page locale import batch.
- */
- function l10n_update_batch_finished($success, $results) {
- if ($success) {
- $additions = $updates = $deletes = $skips = $config = 0;
- if (isset($results['failed_files'])) {
- if (module_exists('dblog')) {
- $message = format_plural(count($results['failed_files']), 'One translation file could not be imported. <a href="@url">See the log</a> for details.', '@count translation files could not be imported. <a href="@url">See the log</a> for details.', array('@url' => url('admin/reports/dblog')));
- }
- else {
- $message = format_plural(count($results['failed_files']), 'One translation files could not be imported. See the log for details.', '@count translation files could not be imported. See the log for details.');
- }
- drupal_set_message($message, 'error');
- }
- if (isset($results['files'])) {
- $skipped_files = array();
- // If there are no results and/or no stats (eg. coping with an empty .po
- // file), simply do nothing.
- if ($results && isset($results['stats'])) {
- foreach ($results['stats'] as $filepath => $report) {
- $additions += $report['additions'];
- $updates += $report['updates'];
- $deletes += $report['deletes'];
- $skips += $report['skips'];
- if ($report['skips'] > 0) {
- $skipped_files[] = $filepath;
- }
- }
- }
- drupal_set_message(format_plural(count($results['files']),
- 'One translation file imported. %number translations were added, %update translations were updated and %delete translations were removed.',
- '@count translation files imported. %number translations were added, %update translations were updated and %delete translations were removed.',
- array(
- '%number' => $additions,
- '%update' => $updates,
- '%delete' => $deletes,
- )
- ));
- watchdog('l10n_update', 'Translations imported: %number added, %update updated, %delete removed.', array(
- '%number' => $additions,
- '%update' => $updates,
- '%delete' => $deletes,
- ));
- if ($skips) {
- if (module_exists('dblog')) {
- $message = format_plural($skips, 'One translation string was skipped because of disallowed or malformed HTML. <a href="@url">See the log</a> for details.', '@count translation strings were skipped because of disallowed or malformed HTML. <a href="@url">See the log</a> for details.', array('@url' => url('admin/reports/dblog')));
- }
- else {
- $message = format_plural($skips, 'One translation string was skipped because of disallowed or malformed HTML. See the log for details.', '@count translation strings were skipped because of disallowed or malformed HTML. See the log for details.');
- }
- drupal_set_message($message, 'warning');
- watchdog('l10n_update', '@count disallowed HTML string(s) in files: @files.', array(
- '@count' => $skips,
- '@files' => implode(',', $skipped_files),
- ), WATCHDOG_WARNING);
- }
- }
- }
- }
- /**
- * Creates a file object and populates the timestamp property.
- *
- * @param string $filepath
- * The file path of a file to import.
- *
- * @return object
- * An object representing the file.
- */
- function l10n_update_file_create($filepath) {
- $file = new stdClass();
- $file->filename = drupal_basename($filepath);
- $file->uri = $filepath;
- $file->timestamp = filemtime($file->uri);
- return $file;
- }
- /**
- * Generates file properties from filename and options.
- *
- * An attempt is made to determine the translation language, project name and
- * project version from the file name. Supported file name patterns are:
- * {project}-{version}.{langcode}.po, {prefix}.{langcode}.po or {langcode}.po.
- * Alternatively the translation language can be set using the $options.
- *
- * @param object $file
- * A file object of the gettext file to be imported.
- * @param array $options
- * An array with options:
- * - 'langcode': The language code. Overrides the file language.
- *
- * @return object
- * Modified file object.
- */
- function l10n_update_file_attach_properties($file, $options = array()) {
- // If $file is a file entity, convert it to a stdClass.
- if ($file instanceof FileInterface) {
- $file = (object) array(
- 'filename' => $file->getFilename(),
- 'uri' => $file->getFileUri(),
- );
- }
- // Extract project, version and language code from the file name. Supported:
- // {project}-{version}.{langcode}.po, {prefix}.{langcode}.po or {langcode}.po.
- preg_match('!
- ( # project OR project and version OR emtpy (group 1)
- ([a-z_]+) # project name (group 2)
- \. # .
- | # OR
- ([a-z_]+) # project name (group 3)
- \- # -
- ([0-9a-z\.\-\+]+) # version (group 4)
- \. # .
- | # OR
- ) # (empty)
- ([^\./]+) # language code (group 5)
- \. # .
- po # po extension
- $!x', $file->filename, $matches);
- if (isset($matches[5])) {
- $file->project = $matches[2] . $matches[3];
- $file->version = $matches[4];
- $file->langcode = isset($options['langcode']) ? $options['langcode'] : $matches[5];
- }
- return $file;
- }
- /**
- * Deletes interface translation files and translation history records.
- *
- * @param array $projects
- * Project names from which to delete the translation files and history.
- * Defaults to all projects.
- * @param array $langcodes
- * Language codes from which to delete the translation files and history.
- * Defaults to all languages.
- *
- * @return bool
- * TRUE if files are removed successfully. FALSE if one or more files could
- * not be deleted.
- */
- function l10n_update_delete_translation_files($projects = array(), $langcodes = array()) {
- $fail = FALSE;
- l10n_update_file_history_delete($projects, $langcodes);
- // Delete all translation files from the translations directory.
- if ($files = l10n_update_get_interface_translation_files($projects, $langcodes)) {
- foreach ($files as $file) {
- $success = file_unmanaged_delete($file->uri);
- if (!$success) {
- $fail = TRUE;
- }
- }
- }
- return !$fail;
- }
|