Issue #1978916 by likin, YesCT, disasm, ayelet_Cr, tim.plunkett, vijaycs85, Letharion: Convert locale_translate_page() to a Controller.

8.0.x
webchick 2013-09-11 01:14:17 -07:00
parent b8d150cc89
commit 89b5fea7b4
16 changed files with 854 additions and 545 deletions

View File

@ -0,0 +1,182 @@
<?php
/**
* @file
* Contains \Drupal\language\Form\ContentLanguageSettingsForm.
*/
namespace Drupal\language\Form;
use Drupal\Core\Config\ConfigFactory;
use Drupal\Core\Config\Context\ContextInterface;
use Drupal\Core\Entity\EntityManager;
use Drupal\system\SystemConfigFormBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Configure the content language settings for this site.
*/
class ContentLanguageSettingsForm extends SystemConfigFormBase {
/**
* The entity manager.
*
* @var \Drupal\Core\Entity\EntityManager
*/
protected $entityManager;
/**
* Constructs a ContentLanguageSettingsForm object.
*
* @param \Drupal\Core\Config\ConfigFactory $config_factory
* The config factory.
* @param \Drupal\Core\Config\Context\ContextInterface $context
* The configuration context to use.
* @param \Drupal\Core\Entity\EntityManager $entity_manager
* The entity manager.
*/
public function __construct(ConfigFactory $config_factory, ContextInterface $context, EntityManager $entity_manager) {
parent::__construct($config_factory, $context);
$this->entityManager = $entity_manager;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('config.factory'),
$container->get('config.context.free'),
$container->get('plugin.manager.entity')
);
}
/**
* Return a list of entity types for which language settings are supported.
*
* @return array
* A list of entity types which are translatable.
*/
protected function entitySupported() {
$supported = array();
foreach ($this->entityManager->getDefinitions() as $entity_type => $info) {
if (!empty($info['translatable'])) {
$supported[$entity_type] = $entity_type;
}
}
return $supported;
}
/**
* {@inheritdoc}
*/
public function getFormID() {
return 'language_content_settings_form';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, array &$form_state) {
$entity_info = $this->entityManager->getDefinitions();
$labels = array();
$default = array();
$bundles = entity_get_bundles();
$language_configuration = array();
foreach ($this->entitySupported() as $entity_type) {
$labels[$entity_type] = isset($entity_info[$entity_type]['label']) ? $entity_info[$entity_type]['label'] : $entity_type;
$default[$entity_type] = FALSE;
// Check whether we have any custom setting.
foreach ($bundles as $bundle => $bundle_info) {
$conf = language_get_default_configuration($entity_type, $bundle);
if (!empty($conf['language_show']) || $conf['langcode'] != 'site_default') {
$default[$entity_type] = $entity_type;
}
$language_configuration[$entity_type][$bundle] = $conf;
}
}
asort($labels);
$form = array(
'#labels' => $labels,
'#attached' => array(
'library' => array(
array('language', 'drupal.language.admin'),
),
),
);
$form['entity_types'] = array(
'#title' => $this->t('Custom language settings'),
'#type' => 'checkboxes',
'#options' => $labels,
'#default_value' => $default,
);
$form['settings'] = array('#tree' => TRUE);
foreach ($labels as $entity_type => $label) {
$info = $entity_info[$entity_type];
$form['settings'][$entity_type] = array(
'#title' => $label,
'#type' => 'container',
'#entity_type' => $entity_type,
'#theme' => 'language_content_settings_table',
'#bundle_label' => isset($info['bundle_label']) ? $info['bundle_label'] : $label,
'#states' => array(
'visible' => array(
':input[name="entity_types[' . $entity_type . ']"]' => array('checked' => TRUE),
),
),
);
foreach ($bundles as $bundle => $bundle_info) {
$form['settings'][$entity_type][$bundle]['settings'] = array(
'#type' => 'item',
'#label' => $bundle_info['label'],
'language' => array(
'#type' => 'language_configuration',
'#entity_information' => array(
'entity_type' => $entity_type,
'bundle' => $bundle,
),
'#default_value' => $language_configuration[$entity_type][$bundle],
),
);
}
}
$form['actions'] = array('#type' => 'actions');
$form['actions']['submit'] = array(
'#type' => 'submit',
'#value' => $this->t('Save'),
);
return parent::buildForm($form, $form_state);
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, array &$form_state) {
$config = $this->configFactory->get('language.settings');
foreach ($form_state['values']['settings'] as $entity_type => $entity_settings) {
foreach ($entity_settings as $bundle => $bundle_settings) {
$config->set(language_get_default_configuration_settings_key($entity_type, $bundle),
array(
'langcode' => $bundle_settings['settings']['language']['langcode'],
'language_show' => $bundle_settings['settings']['langcode']['language_show'],
)
);
}
}
$config->save();
parent::submitForm($form, $form_state);
}
}

View File

@ -122,25 +122,25 @@ class LanguageUILanguageNegotiationTest extends WebTestBase {
'string' => $default_string,
'langcode' => $langcode_browser_fallback,
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
$this->drupalPost('admin/config/regional/translate', $search, t('Filter'));
$textarea = current($this->xpath('//textarea'));
$lid = (string) $textarea[0]['name'];
$edit = array(
$lid => $language_browser_fallback_string,
);
$this->drupalPost('admin/config/regional/translate/translate', $edit, t('Save translations'));
$this->drupalPost('admin/config/regional/translate', $edit, t('Save translations'));
$search = array(
'string' => $default_string,
'langcode' => $langcode,
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
$this->drupalPost('admin/config/regional/translate', $search, t('Filter'));
$textarea = current($this->xpath('//textarea'));
$lid = (string) $textarea[0]['name'];
$edit = array(
$lid => $language_string,
);
$this->drupalPost('admin/config/regional/translate/translate', $edit, t('Save translations'));
$this->drupalPost('admin/config/regional/translate', $edit, t('Save translations'));
// Configure URL language rewrite.
variable_set('language_negotiation_url_type', Language::TYPE_INTERFACE);

View File

@ -6,43 +6,15 @@
namespace Drupal\locale\Controller;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Routing\UrlGeneratorInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Controller\ControllerBase;
use Drupal\locale\Form\TranslateEditForm;
use Drupal\locale\Form\TranslateFilterForm;
use Symfony\Component\HttpFoundation\RedirectResponse;
/**
* Return response for manual check translations.
*/
class LocaleController implements ContainerInjectionInterface {
/**
* The module handler.
*
* @var \Drupal\Core\Extension\ModuleHandlerInterface
*/
protected $moduleHandler;
/**
* Constructs a \Drupal\locale\Controller\LocaleController object.
*
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler.
*/
public function __construct(ModuleHandlerInterface $module_handler, UrlGeneratorInterface $url_generator) {
$this->moduleHandler = $module_handler;
$this->urlGenerator = $url_generator;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('module_handler'),
$container->get('url_generator')
);
}
class LocaleController extends ControllerBase {
/**
* Checks for translation updates and displays the translations status.
@ -53,11 +25,11 @@ class LocaleController implements ContainerInjectionInterface {
* A redirection to translations reports page.
*/
public function checkTranslation() {
$this->moduleHandler->loadInclude('locale', 'inc', 'locale.compare');
$this->moduleHandler()->loadInclude('locale', 'inc', 'locale.compare');
// Check translation status of all translatable project in all languages.
// First we clear the cached list of projects. Although not strictly
// nescessary, this is helpfull in case the project list is out of sync.
// necessary, this is helpful in case the project list is out of sync.
locale_translation_flush_projects();
locale_translation_check_projects();
@ -67,6 +39,21 @@ class LocaleController implements ContainerInjectionInterface {
return batch_process('admin/reports/translations');
}
return new RedirectResponse($this->urlGenerator->generateFromPath('admin/reports/translations', array('absolute' => TRUE)));
// @todo Use $this->redirect() after https://drupal.org/node/1978926.
return new RedirectResponse($this->urlGenerator()->generateFromPath('admin/reports/translations', array('absolute' => TRUE)));
}
/**
* Shows the string search screen.
*
* @return array
* The render array for the string search screen.
*/
public function translatePage() {
return array(
'filter' => drupal_get_form(TranslateFilterForm::create($this->container)),
'form' => drupal_get_form(TranslateEditForm::create($this->container)),
);
}
}

View File

@ -0,0 +1,244 @@
<?php
/**
* @file
* Contains \Drupal\locale\Form\TranslateEditForm.
*/
namespace Drupal\locale\Form;
use Drupal\Component\Utility\String;
use Drupal\locale\SourceString;
/**
* Defines a translation edit form.
*/
class TranslateEditForm extends TranslateFormBase {
/**
* {@inheritdoc}
*/
public function getFormID() {
return 'locale_translate_edit_form';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, array &$form_state) {
$filter_values = $this->translateFilterValues();
$langcode = $filter_values['langcode'];
drupal_static_reset('language_list');
$languages = language_list();
$langname = isset($langcode) ? $languages[$langcode]->name : "- None -";
$path = drupal_get_path('module', 'locale');
$form['#attached']['css'] = array(
$path . '/css/locale.admin.css',
);
$form['#attached']['library'][] = array('locale', 'drupal.locale.admin');
$form['langcode'] = array(
'#type' => 'value',
'#value' => $filter_values['langcode'],
);
$form['strings'] = array(
'#type' => 'item',
'#tree' => TRUE,
'#language' => $langname,
'#theme' => 'locale_translate_edit_form_strings',
);
if (isset($langcode)) {
$strings = $this->translateFilterLoadStrings();
$plural_formulas = $this->state->get('locale.translation.plurals') ?: array();
foreach ($strings as $string) {
// Cast into source string, will do for our purposes.
$source = new SourceString($string);
// Split source to work with plural values.
$source_array = $source->getPlurals();
$translation_array = $string->getPlurals();
if (count($source_array) == 1) {
// Add original string value and mark as non-plural.
$form['strings'][$string->lid]['plural'] = array(
'#type' => 'value',
'#value' => 0,
);
$form['strings'][$string->lid]['original'] = array(
'#type' => 'item',
'#title' => $this->t('Source string (@language)', array('@language' => $this->t('Built-in English'))),
'#title_display' => 'invisible',
'#markup' => '<span lang="en">' . String::checkPlain($source_array[0]) . '</span>',
);
}
else {
// Add original string value and mark as plural.
$form['strings'][$string->lid]['plural'] = array(
'#type' => 'value',
'#value' => 1,
);
$form['strings'][$string->lid]['original_singular'] = array(
'#type' => 'item',
'#title' => $this->t('Singular form'),
'#markup' => '<span lang="en">' . String::checkPlain($source_array[0]) . '</span>',
'#prefix' => '<span class="visually-hidden">' . $this->t('Source string (@language)', array('@language' => $this->t('Built-in English'))) . '</span>'
);
$form['strings'][$string->lid]['original_plural'] = array(
'#type' => 'item',
'#title' => $this->t('Plural form'),
'#markup' => '<span lang="en">' . String::checkPlain($source_array[1]) . '</span>',
);
}
if (!empty($string->context)) {
$form['strings'][$string->lid]['context'] = array(
'#type' => 'value',
'#value' => '<span lang="en">' . String::checkPlain($string->context) . '</span>',
);
}
// Approximate the number of rows to use in the default textarea.
$rows = min(ceil(str_word_count($source_array[0]) / 12), 10);
if (empty($form['strings'][$string->lid]['plural']['#value'])) {
$form['strings'][$string->lid]['translations'][0] = array(
'#type' => 'textarea',
'#title' => $this->t('Translated string (@language)', array('@language' => $langname)),
'#title_display' => 'invisible',
'#rows' => $rows,
'#default_value' => $translation_array[0],
'#attributes' => array('lang' => $langcode),
);
}
else {
// Dealing with plural strings.
if (isset($plural_formulas[$langcode]['plurals']) && $plural_formulas[$langcode]['plurals'] > 2) {
// Add a textarea for each plural variant.
for ($i = 0; $i < $plural_formulas[$langcode]['plurals']; $i++) {
$form['strings'][$string->lid]['translations'][$i] = array(
'#type' => 'textarea',
'#title' => ($i == 0 ? $this->t('Singular form') : format_plural($i, 'First plural form', '@count. plural form')),
'#rows' => $rows,
'#default_value' => isset($translation_array[$i]) ? $translation_array[$i] : '',
'#attributes' => array('lang' => $langcode),
'#prefix' => $i == 0 ? ('<span class="visually-hidden">' . $this->t('Translated string (@language)', array('@language' => $langname)) . '</span>') : '',
);
}
}
else {
// Fallback for unknown number of plurals.
$form['strings'][$string->lid]['translations'][0] = array(
'#type' => 'textarea',
'#title' => $this->t('Singular form'),
'#rows' => $rows,
'#default_value' => $translation_array[0],
'#attributes' => array('lang' => $langcode),
'#prefix' => '<span class="visually-hidden">' . $this->t('Translated string (@language)', array('@language' => $langname)) . '</span>',
);
$form['strings'][$string->lid]['translations'][1] = array(
'#type' => 'textarea',
'#title' => $this->t('Plural form'),
'#rows' => $rows,
'#default_value' => isset($translation_array[1]) ? $translation_array[1] : '',
'#attributes' => array('lang' => $langcode),
);
}
}
}
if (count(element_children($form['strings']))) {
$form['actions'] = array('#type' => 'actions');
$form['actions']['submit'] = array(
'#type' => 'submit',
'#value' => $this->t('Save translations'),
);
}
}
return $form;
}
/**
* {@inheritdoc}
*/
public function validateForm(array &$form, array &$form_state) {
$langcode = $form_state['values']['langcode'];
foreach ($form_state['values']['strings'] as $lid => $translations) {
foreach ($translations['translations'] as $key => $value) {
if (!locale_string_is_safe($value)) {
form_set_error("strings][$lid][translations][$key", $this->t('The submitted string contains disallowed HTML: %string', array('%string' => $value)));
form_set_error("translations][$langcode][$key", $this->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);
}
}
}
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, array &$form_state) {
$langcode = $form_state['values']['langcode'];
$updated = array();
// Preload all translations for strings in the form.
$lids = array_keys($form_state['values']['strings']);
$existing_translation_objects = array();
foreach ($this->localeStorage->getTranslations(array('lid' => $lids, 'language' => $langcode, 'translated' => TRUE)) as $existing_translation_object) {
$existing_translation_objects[$existing_translation_object->lid] = $existing_translation_object;
}
foreach ($form_state['values']['strings'] as $lid => $new_translation) {
$existing_translation = isset($existing_translation_objects[$lid]);
// Plural translations are saved in a delimited string. To be able to
// compare the new strings with the existing strings a string in the same format is created.
$new_translation_string_delimited = implode(LOCALE_PLURAL_DELIMITER, $new_translation['translations']);
// Generate an imploded string without delimiter, to be able to run
// empty() on it.
$new_translation_string = implode('', $new_translation['translations']);
$is_changed = FALSE;
if ($existing_translation && $existing_translation_objects[$lid]->translation != $new_translation_string_delimited) {
// If there is an existing translation in the DB and the new translation
// is not the same as the existing one.
$is_changed = TRUE;
}
elseif (!$existing_translation && !empty($new_translation_string)) {
// Newly entered translation.
$is_changed = TRUE;
}
if ($is_changed) {
// Only update or insert if we have a value to use.
$target = isset($existing_translation_objects[$lid]) ? $existing_translation_objects[$lid] : $this->localeStorage->createTranslation(array('lid' => $lid, 'language' => $langcode));
$target->setPlurals($new_translation['translations'])
->setCustomized()
->save();
$updated[] = $target->getId();
}
if (empty($new_translation_string) && isset($existing_translation_objects[$lid])) {
// Empty new translation entered: remove existing entry from database.
$existing_translation_objects[$lid]->delete();
$updated[] = $lid;
}
}
drupal_set_message($this->t('The strings have been saved.'));
// Keep the user on the current pager page.
$page = $this->getRequest()->query->get('page');
if (isset($page)) {
$form_state['redirect'] = array('admin/config/regional/translate', array('query' => array('page' => $page)));
}
if ($updated) {
// Clear cache and force refresh of JavaScript translations.
_locale_refresh_translations(array($langcode), $updated);
_locale_refresh_configuration(array($langcode), $updated);
}
}
}

View File

@ -0,0 +1,105 @@
<?php
/**
* @file
* Contains \Drupal\locale\Form\TranslateFilterForm.
*/
namespace Drupal\locale\Form;
/**
* Provides a filtered translation edit form.
*/
class TranslateFilterForm extends TranslateFormBase {
/**
* {@inheritdoc}
*/
public function getFormID() {
return 'locale_translate_filter_form';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, array &$form_state) {
$filters = $this->translateFilters();
$filter_values = $this->translateFilterValues();
$form['#attached']['css'] = array(
drupal_get_path('module', 'locale') . '/css/locale.admin.css',
);
$form['filters'] = array(
'#type' => 'details',
'#title' => $this->t('Filter translatable strings'),
'#collapsed' => FALSE,
);
foreach ($filters as $key => $filter) {
// Special case for 'string' filter.
if ($key == 'string') {
$form['filters']['status']['string'] = array(
'#type' => 'search',
'#title' => $filter['title'],
'#description' => $filter['description'],
'#default_value' => $filter_values[$key],
);
}
else {
$empty_option = isset($filter['options'][$filter['default']]) ? $filter['options'][$filter['default']] : '- None -';
$form['filters']['status'][$key] = array(
'#title' => $filter['title'],
'#type' => 'select',
'#empty_value' => $filter['default'],
'#empty_option' => $empty_option,
'#size' => 0,
'#options' => $filter['options'],
'#default_value' => $filter_values[$key],
);
if (isset($filter['states'])) {
$form['filters']['status'][$key]['#states'] = $filter['states'];
}
}
}
$form['filters']['actions'] = array(
'#type' => 'actions',
'#attributes' => array('class' => array('container-inline')),
);
$form['filters']['actions']['submit'] = array(
'#type' => 'submit',
'#value' => $this->t('Filter'),
);
if (!empty($_SESSION['locale_translate_filter'])) {
$form['filters']['actions']['reset'] = array(
'#type' => 'submit',
'#value' => $this->t('Reset'),
'#submit' => array(array($this, 'resetForm')),
);
}
return $form;
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, array &$form_state) {
$filters = $this->translateFilters();
foreach ($filters as $name => $filter) {
if (isset($form_state['values'][$name])) {
$_SESSION['locale_translate_filter'][$name] = $form_state['values'][$name];
}
}
$form_state['redirect'] = 'admin/config/regional/translate';
}
/**
* Provides a submit handler for the reset button.
*/
public function resetForm(array &$form, array &$form_state) {
$_SESSION['locale_translate_filter'] = array();
$form_state['redirect'] = 'admin/config/regional/translate';
}
}

View File

@ -0,0 +1,220 @@
<?php
/**
* @file
* Contains \Drupal\locale\Form\TranslateFormBase.
*/
namespace Drupal\locale\Form;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Language\Language;
use Drupal\Core\Language\LanguageManager;
use Drupal\locale\StringStorageInterface;
use Drupal\Core\KeyValueStore\KeyValueStoreInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Defines the locale user interface translation form base.
*
* Provides methods for searching and filtering strings.
*/
abstract class TranslateFormBase extends FormBase {
/**
* The locale storage.
*
* @var \Drupal\locale\StringStorageInterface
*/
protected $localeStorage;
/**
* The state store.
*
* @var \Drupal\Core\KeyValueStore\KeyValueStoreInterface
*/
protected $state;
/**
* The language manager.
*
* @var \Drupal\Core\Language\LanguageManager
*/
protected $languageManager;
/*
* Filter values. Shared between objects that inherit this class.
*
* @var array|null
*/
protected static $filterValues;
/**
* Constructs a new TranslationFormBase object.
*
* @param \Drupal\locale\StringStorageInterface $locale_storage
* The locale storage.
* @param \Drupal\Core\KeyValueStore\KeyValueStoreInterface $state
* The state service.
* @param \Drupal\Core\Language\LanguageManager $language_manager
* The language manager.
*/
public function __construct(StringStorageInterface $locale_storage, KeyValueStoreInterface $state, LanguageManager $language_manager) {
$this->localeStorage = $locale_storage;
$this->state = $state;
$this->languageManager = $language_manager;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('locale.storage'),
$container->get('state'),
$container->get('language_manager')
);
}
/**
* Builds a string search query and returns an array of string objects.
*
* @return \Drupal\locale\TranslationString[]
* Array of \Drupal\locale\TranslationString objects.
*/
protected function translateFilterLoadStrings() {
$filter_values = $this->translateFilterValues();
// Language is sanitized to be one of the possible options in
// translateFilterValues().
$conditions = array('language' => $filter_values['langcode']);
$options = array('pager limit' => 30, 'translated' => TRUE, 'untranslated' => TRUE);
// Add translation status conditions and options.
switch ($filter_values['translation']) {
case 'translated':
$conditions['translated'] = TRUE;
if ($filter_values['customized'] != 'all') {
$conditions['customized'] = $filter_values['customized'];
}
break;
case 'untranslated':
$conditions['translated'] = FALSE;
break;
}
if (!empty($filter_values['string'])) {
$options['filters']['source'] = $filter_values['string'];
if ($options['translated']) {
$options['filters']['translation'] = $filter_values['string'];
}
}
return $this->localeStorage->getTranslations($conditions, $options);
}
/**
* Builds an array out of search criteria specified in request variables.
*
* @param bool $reset
* If the list of values should be reset.
*
* @return array $filter_values
* The filter values.
*/
protected function translateFilterValues($reset = FALSE) {
if (!$reset && static::$filterValues) {
return static::$filterValues;
}
$filter_values = array();
$filters = $this->translateFilters();
foreach ($filters as $key => $filter) {
$filter_values[$key] = $filter['default'];
// Let the filter defaults be overwritten by parameters in the URL.
if ($this->getRequest()->query->has($key)) {
// Only allow this value if it was among the options, or
// if there were no fixed options to filter for.
$value = $this->getRequest()->query->get($key);
if (!isset($filter['options']) || isset($filter['options'][$value])) {
$filter_values[$key] = $value;
}
}
elseif (isset($_SESSION['locale_translate_filter'][$key])) {
// Only allow this value if it was among the options, or
// if there were no fixed options to filter for.
if (!isset($filter['options']) || isset($filter['options'][$_SESSION['locale_translate_filter'][$key]])) {
$filter_values[$key] = $_SESSION['locale_translate_filter'][$key];
}
}
}
return static::$filterValues = $filter_values;
}
/**
* Lists locale translation filters that can be applied.
*/
protected function translateFilters() {
$filters = array();
// Get all languages, except English.
drupal_static_reset('language_list');
$languages = language_list();
$language_options = array();
foreach ($languages as $langcode => $language) {
if ($langcode != 'en' || locale_translate_english()) {
$language_options[$langcode] = $language->name;
}
}
// Pick the current interface language code for the filter.
$default_langcode = $this->languageManager->getLanguage(Language::TYPE_INTERFACE)->id;
if (!isset($language_options[$default_langcode])) {
$available_langcodes = array_keys($language_options);
$default_langcode = array_shift($available_langcodes);
}
$filters['string'] = array(
'title' => $this->t('String contains'),
'description' => $this->t('Leave blank to show all strings. The search is case sensitive.'),
'default' => '',
);
$filters['langcode'] = array(
'title' => $this->t('Translation language'),
'options' => $language_options,
'default' => $default_langcode,
);
$filters['translation'] = array(
'title' => $this->t('Search in'),
'options' => array(
'all' => $this->t('Both translated and untranslated strings'),
'translated' => $this->t('Only translated strings'),
'untranslated' => $this->t('Only untranslated strings'),
),
'default' => 'all',
);
$filters['customized'] = array(
'title' => $this->t('Translation type'),
'options' => array(
'all' => $this->t('All'),
LOCALE_NOT_CUSTOMIZED => $this->t('Non-customized translation'),
LOCALE_CUSTOMIZED => $this->t('Customized translation'),
),
'states' => array(
'visible' => array(
':input[name=translation]' => array('value' => 'translated'),
),
),
'default' => 'all',
);
return $filters;
}
}

View File

@ -69,14 +69,14 @@ class LocaleConfigTranslationTest extends WebTestBase {
'langcode' => $langcode,
'translation' => 'all',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
$this->drupalPost('admin/config/regional/translate', $search, t('Filter'));
$textareas = $this->xpath('//textarea');
$textarea = current($textareas);
$lid = (string) $textarea[0]['name'];
$edit = array(
$lid => $site_name,
);
$this->drupalPost('admin/config/regional/translate/translate', $edit, t('Save translations'));
$this->drupalPost('admin/config/regional/translate', $edit, t('Save translations'));
$wrapper = $this->container->get('locale.config.typed')->get('system.site');
@ -115,13 +115,13 @@ class LocaleConfigTranslationTest extends WebTestBase {
'langcode' => $langcode,
'translation' => 'all',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
$this->drupalPost('admin/config/regional/translate', $search, t('Filter'));
$textarea = current($this->xpath('//textarea'));
$lid = (string) $textarea[0]['name'];
$edit = array(
$lid => $image_style_label,
);
$this->drupalPost('admin/config/regional/translate/translate', $edit, t('Save translations'));
$this->drupalPost('admin/config/regional/translate', $edit, t('Save translations'));
// Check the right single translation has been created.
$translations = $this->storage->getTranslations(array('language' => $langcode, 'type' => 'configuration', 'name' => 'image.style.medium'));

View File

@ -111,7 +111,7 @@ class LocaleImportFunctionalTest extends WebTestBase {
'langcode' => 'fr',
'translation' => 'translated',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
$this->drupalPost('admin/config/regional/translate', $search, t('Filter'));
$this->assertText(t('No strings available.'), 'String not overwritten by imported string.');
// This import should not have changed number of plural forms.
@ -133,7 +133,7 @@ class LocaleImportFunctionalTest extends WebTestBase {
'langcode' => 'fr',
'translation' => 'translated',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
$this->drupalPost('admin/config/regional/translate', $search, t('Filter'));
$this->assertNoText(t('No strings available.'), 'String overwritten by imported string.');
// This import should have changed number of plural forms.
$locale_plurals = \Drupal::state()->get('locale.translation.plurals') ?: array();
@ -169,7 +169,7 @@ class LocaleImportFunctionalTest extends WebTestBase {
'langcode' => 'fr',
'translation' => 'translated',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
$this->drupalPost('admin/config/regional/translate', $search, t('Filter'));
$this->assertText(t('No strings available.'), 'Customized string not overwritten by imported string.');
// Try importing a .po file with overriding strings, and ensure existing
@ -188,7 +188,7 @@ class LocaleImportFunctionalTest extends WebTestBase {
'langcode' => 'fr',
'translation' => 'translated',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
$this->drupalPost('admin/config/regional/translate', $search, t('Filter'));
$this->assertNoText(t('No strings available.'), 'Customized string overwritten by imported string.');
}
@ -233,7 +233,7 @@ class LocaleImportFunctionalTest extends WebTestBase {
'langcode' => $langcode,
'translation' => 'untranslated',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
$this->drupalPost('admin/config/regional/translate', $search, t('Filter'));
$this->assertText($str, 'Search found the string as untranslated.');
}
@ -287,7 +287,7 @@ class LocaleImportFunctionalTest extends WebTestBase {
'langcode' => $langcode,
'translation' => 'all',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
$this->drupalPost('admin/config/regional/translate', $search, t('Filter'));
$this->assertText($config_string[1], format_string('Translation of @string found.', array('@string' => $config_string[0])));
}

View File

@ -198,7 +198,7 @@ class LocalePluralFormatTest extends WebTestBase {
$search = array(
'langcode' => 'fr',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
$this->drupalPost('admin/config/regional/translate', $search, t('Filter'));
// Plural values for the langcode fr.
$this->assertText('@count heure');
$this->assertText('@count heures');
@ -221,7 +221,7 @@ class LocalePluralFormatTest extends WebTestBase {
'string' => '1 day',
'langcode' => 'fr',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
$this->drupalPost('admin/config/regional/translate', $search, t('Filter'));
// Save complete translations for the string in langcode fr.
$edit = array(
@ -235,7 +235,7 @@ class LocalePluralFormatTest extends WebTestBase {
'string' => '1 day',
'langcode' => 'hr',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
$this->drupalPost('admin/config/regional/translate', $search, t('Filter'));
$edit = array(
"strings[$lid][translations][0]" => '@count dan',

View File

@ -39,7 +39,7 @@ class LocaleTranslationUiTest extends WebTestBase {
$this->drupalLogin($admin_user);
$this->drupalPost('admin/config/regional/language/edit/en', array('locale_translate_english' => TRUE), t('Save language'));
$this->assertLinkByHref('/admin/config/regional/translate/translate?langcode=en', 0, 'Enabled interface translation to English.');
$this->assertLinkByHref('/admin/config/regional/translate?langcode=en', 0, 'Enabled interface translation to English.');
}
/**
@ -87,7 +87,7 @@ class LocaleTranslationUiTest extends WebTestBase {
'langcode' => $langcode,
'translation' => 'untranslated',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
$this->drupalPost('admin/config/regional/translate', $search, t('Filter'));
$this->assertText($name, 'Search found the string as untranslated.');
// Assume this is the only result, given the random name.
@ -105,7 +105,7 @@ class LocaleTranslationUiTest extends WebTestBase {
$this->drupalPost('admin/config/regional/language/edit/en', array('locale_translate_english' => TRUE), t('Save language'));
$this->drupalLogout();
$this->drupalLogin($translate_user);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
$this->drupalPost('admin/config/regional/translate', $search, t('Filter'));
$this->assertText($name, 'Search found the string as untranslated.');
// Assume this is the only result, given the random name.
@ -114,15 +114,15 @@ class LocaleTranslationUiTest extends WebTestBase {
$edit = array(
$lid => $translation,
);
$this->drupalPost('admin/config/regional/translate/translate', $edit, t('Save translations'));
$this->drupalPost('admin/config/regional/translate', $edit, t('Save translations'));
$this->assertText(t('The strings have been saved.'), 'The strings have been saved.');
$this->assertEqual($this->getUrl(), url('admin/config/regional/translate/translate', array('absolute' => TRUE)), 'Correct page redirection.');
$this->assertEqual($this->getUrl(), url('admin/config/regional/translate', array('absolute' => TRUE)), 'Correct page redirection.');
$search = array(
'string' => $name,
'langcode' => $langcode,
'translation' => 'translated',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
$this->drupalPost('admin/config/regional/translate', $search, t('Filter'));
$this->assertRaw($translation, 'Non-English translation properly saved.');
@ -131,19 +131,19 @@ class LocaleTranslationUiTest extends WebTestBase {
'langcode' => 'en',
'translation' => 'untranslated',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
$this->drupalPost('admin/config/regional/translate', $search, t('Filter'));
$textarea = current($this->xpath('//textarea'));
$lid = (string) $textarea[0]['name'];
$edit = array(
$lid => $translation_to_en,
);
$this->drupalPost('admin/config/regional/translate/translate', $edit, t('Save translations'));
$this->drupalPost('admin/config/regional/translate', $edit, t('Save translations'));
$search = array(
'string' => $name,
'langcode' => 'en',
'translation' => 'translated',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
$this->drupalPost('admin/config/regional/translate', $search, t('Filter'));
$this->assertRaw($translation_to_en, 'English translation properly saved.');
// Reset the tag cache on the tester side in order to pick up the call to
@ -164,7 +164,7 @@ class LocaleTranslationUiTest extends WebTestBase {
'langcode' => 'en',
'translation' => 'untranslated',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
$this->drupalPost('admin/config/regional/translate', $search, t('Filter'));
$this->assertText(t('No strings available.'), 'String is translated.');
$this->drupalLogout();
@ -190,14 +190,14 @@ class LocaleTranslationUiTest extends WebTestBase {
'langcode' => 'en',
'translation' => 'translated',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
$this->drupalPost('admin/config/regional/translate', $search, t('Filter'));
// Assume this is the only result, given the random name.
$textarea = current($this->xpath('//textarea'));
$lid = (string) $textarea[0]['name'];
$edit = array(
$lid => '',
);
$this->drupalPost('admin/config/regional/translate/translate', $edit, t('Save translations'));
$this->drupalPost('admin/config/regional/translate', $edit, t('Save translations'));
$this->assertRaw($name, 'The strings have been saved.');
$this->drupalLogin($translate_user);
$search = array(
@ -205,7 +205,7 @@ class LocaleTranslationUiTest extends WebTestBase {
'langcode' => 'en',
'translation' => 'untranslated',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
$this->drupalPost('admin/config/regional/translate', $search, t('Filter'));
$this->assertNoText(t('No strings available.'), 'The translation has been removed');
}
@ -248,14 +248,14 @@ class LocaleTranslationUiTest extends WebTestBase {
'langcode' => $langcode,
'translation' => 'all',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
$this->drupalPost('admin/config/regional/translate', $search, t('Filter'));
$textarea = current($this->xpath('//textarea'));
$lid = (string) $textarea[0]['name'];
$edit = array(
$lid => $this->randomName(),
);
$this->drupalPost('admin/config/regional/translate/translate', $edit, t('Save translations'));
$this->drupalPost('admin/config/regional/translate', $edit, t('Save translations'));
// Trigger JavaScript translation parsing and building.
_locale_rebuild_js($langcode);
@ -311,7 +311,7 @@ class LocaleTranslationUiTest extends WebTestBase {
'langcode' => $langcode,
'translation' => 'all',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
$this->drupalPost('admin/config/regional/translate', $search, t('Filter'));
// Find the edit path.
$textarea = current($this->xpath('//textarea'));
@ -320,7 +320,7 @@ class LocaleTranslationUiTest extends WebTestBase {
$edit = array(
$lid => $translation,
);
$this->drupalPost('admin/config/regional/translate/translate', $edit, t('Save translations'));
$this->drupalPost('admin/config/regional/translate', $edit, t('Save translations'));
// Check for a form error on the textarea.
$form_class = $this->xpath('//form[@id="locale-translate-edit-form"]//textarea/@class');
$this->assertNotIdentical(FALSE, strpos($form_class[0], 'error'), 'The string was rejected as unsafe.');
@ -380,7 +380,7 @@ class LocaleTranslationUiTest extends WebTestBase {
'langcode' => $langcode,
'translation' => 'all',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
$this->drupalPost('admin/config/regional/translate', $search, t('Filter'));
// assertText() seems to remove the input field where $name always could be
// found, so this is not a false assert. See how assertNoText succeeds
// later.
@ -393,7 +393,7 @@ class LocaleTranslationUiTest extends WebTestBase {
'langcode' => $langcode,
'translation' => 'translated',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
$this->drupalPost('admin/config/regional/translate', $search, t('Filter'));
$this->assertText(t('No strings available.'), "Search didn't find the string.");
// Ensure untranslated string appears if searching on 'only untranslated
@ -403,7 +403,7 @@ class LocaleTranslationUiTest extends WebTestBase {
'langcode' => $langcode,
'translation' => 'untranslated',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
$this->drupalPost('admin/config/regional/translate', $search, t('Filter'));
$this->assertNoText(t('No strings available.'), 'Search found the string.');
// Add translation.
@ -414,7 +414,7 @@ class LocaleTranslationUiTest extends WebTestBase {
$edit = array(
$lid => $translation,
);
$this->drupalPost('admin/config/regional/translate/translate', $edit, t('Save translations'));
$this->drupalPost('admin/config/regional/translate', $edit, t('Save translations'));
// Ensure translated string does appear if searching on 'only
// translated strings'.
@ -423,7 +423,7 @@ class LocaleTranslationUiTest extends WebTestBase {
'langcode' => $langcode,
'translation' => 'translated',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
$this->drupalPost('admin/config/regional/translate', $search, t('Filter'));
$this->assertNoText(t('No strings available.'), 'Search found the translation.');
// Ensure translated source string doesn't appear if searching on 'only
@ -433,7 +433,7 @@ class LocaleTranslationUiTest extends WebTestBase {
'langcode' => $langcode,
'translation' => 'untranslated',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
$this->drupalPost('admin/config/regional/translate', $search, t('Filter'));
$this->assertText(t('No strings available.'), "Search didn't find the source string.");
// Ensure translated string doesn't appear if searching on 'only
@ -443,7 +443,7 @@ class LocaleTranslationUiTest extends WebTestBase {
'langcode' => $langcode,
'translation' => 'untranslated',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
$this->drupalPost('admin/config/regional/translate', $search, t('Filter'));
$this->assertText(t('No strings available.'), "Search didn't find the translation.");
// Ensure translated string does appear if searching on the custom language.
@ -452,7 +452,7 @@ class LocaleTranslationUiTest extends WebTestBase {
'langcode' => $langcode,
'translation' => 'all',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
$this->drupalPost('admin/config/regional/translate', $search, t('Filter'));
$this->assertNoText(t('No strings available.'), 'Search found the translation.');
// Ensure translated string doesn't appear if searching in System (English).
@ -461,7 +461,7 @@ class LocaleTranslationUiTest extends WebTestBase {
'langcode' => 'yy',
'translation' => 'all',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
$this->drupalPost('admin/config/regional/translate', $search, t('Filter'));
$this->assertText(t('No strings available.'), "Search didn't find the translation.");
// Search for a string that isn't in the system.
@ -471,7 +471,7 @@ class LocaleTranslationUiTest extends WebTestBase {
'langcode' => $langcode,
'translation' => 'all',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
$this->drupalPost('admin/config/regional/translate', $search, t('Filter'));
$this->assertText(t('No strings available.'), "Search didn't find the invalid string.");
}
@ -508,7 +508,7 @@ class LocaleTranslationUiTest extends WebTestBase {
'translation' => 'translated',
'customized' => '0',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
$this->drupalPost('admin/config/regional/translate', $search, t('Filter'));
$source = $this->assertText($translation->getString(), 'Translation is found in search result.');
@ -518,7 +518,7 @@ class LocaleTranslationUiTest extends WebTestBase {
$edit = array(
$lid => $translation->getString(),
);
$this->drupalPost('admin/config/regional/translate/translate', $edit, t('Save translations'));
$this->drupalPost('admin/config/regional/translate', $edit, t('Save translations'));
// Ensure unchanged translation string does appear if searching non-customized translation.
$search = array(
@ -527,7 +527,7 @@ class LocaleTranslationUiTest extends WebTestBase {
'translation' => 'translated',
'customized' => '0',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
$this->drupalPost('admin/config/regional/translate', $search, t('Filter'));
$source = $this->assertText($string->getString(), 'Translation is not marked as customized.');
// Submit the translations with a new translation.
@ -536,7 +536,7 @@ class LocaleTranslationUiTest extends WebTestBase {
$edit = array(
$lid => $this->randomName(100),
);
$this->drupalPost('admin/config/regional/translate/translate', $edit, t('Save translations'));
$this->drupalPost('admin/config/regional/translate', $edit, t('Save translations'));
// Ensure changed translation string does appear if searching customized translation.
$search = array(
@ -545,7 +545,7 @@ class LocaleTranslationUiTest extends WebTestBase {
'translation' => 'translated',
'customized' => '1',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
$this->drupalPost('admin/config/regional/translate', $search, t('Filter'));
$this->assertText($string->getString(), "Translation is marked as customized.");
}
}

View File

@ -78,7 +78,7 @@ class LocaleUninstallTest extends WebTestBase {
// Build the JavaScript translation file for French.
$user = $this->drupalCreateUser(array('translate interface', 'access administration pages'));
$this->drupalLogin($user);
$this->drupalGet('admin/config/regional/translate/translate');
$this->drupalGet('admin/config/regional/translate');
// Get any of the javascript strings to translate.
$js_strings = $this->container->get('locale.storage')->getStrings(array('type' => 'javascript'));
$string = reset($js_strings);

View File

@ -452,7 +452,7 @@ class LocaleUpdateTest extends LocaleUpdateBase {
'langcode' => $langcode,
'translation' => 'translated',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
$this->drupalPost('admin/config/regional/translate', $search, t('Filter'));
$this->assertNoText(t('No strings available.'), 'String successfully imported.');
// Ensure the multiline string was imported.
@ -461,7 +461,7 @@ class LocaleUpdateTest extends LocaleUpdateBase {
'langcode' => $langcode,
'translation' => 'all',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
$this->drupalPost('admin/config/regional/translate', $search, t('Filter'));
$this->assertText('Multiline translation string to make sure that import works with it.', 'String successfully imported.');
// Ensure 'Allowed HTML source string' was imported but the translation for
@ -472,7 +472,7 @@ class LocaleUpdateTest extends LocaleUpdateBase {
'langcode' => $langcode,
'translation' => 'all',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
$this->drupalPost('admin/config/regional/translate', $search, t('Filter'));
$this->assertText('Allowed HTML source string', 'String successfully imported.');
$this->assertNoText('Another allowed HTML source string', 'String with disallowed translation not imported.');
}

View File

@ -173,9 +173,7 @@ function locale_menu() {
$items['admin/config/regional/translate'] = array(
'title' => 'User interface translation',
'description' => 'Translate the built-in user interface.',
'page callback' => 'locale_translate_page',
'access arguments' => array('translate interface'),
'file' => 'locale.pages.inc',
'route_name' => 'locale_translate_page',
'weight' => -5,
);
$items['admin/config/regional/translate/translate'] = array(
@ -203,7 +201,6 @@ function locale_menu() {
$items['admin/config/regional/translate/settings'] = array(
'title' => 'Settings',
'route_name' => 'locale_settings',
'access arguments' => array('translate interface'),
'weight' => 100,
'type' => MENU_LOCAL_TASK,
);
@ -758,7 +755,7 @@ function locale_form_language_admin_overview_form_alter(&$form, &$form_state) {
'@total' => $total_strings,
'@ratio' => $stats[$langcode]['ratio'],
)),
'admin/config/regional/translate/translate',
'admin/config/regional/translate',
array('query' => array('langcode' => $langcode))
),
);

View File

@ -13,460 +13,27 @@ use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
* Page callback: Shows the string search screen.
* Page callback: Checks for translation updates and displays the status.
*
* Manually checks the translation status without the use of cron.
*
* @see locale_menu()
*/
function locale_translate_page() {
return array(
'filter' => drupal_get_form('locale_translate_filter_form'),
'form' => drupal_get_form('locale_translate_edit_form'),
);
}
function locale_translation_manual_status() {
module_load_include('compare.inc', 'locale');
/**
* Builds a string search query and returns an array of string objects.
*
* @return array
* Array of Drupal\locale\TranslationString objects.
*/
function locale_translate_filter_load_strings() {
$filter_values = locale_translate_filter_values();
// Language is sanitized to be one of the possible options in
// locale_translate_filter_values().
$conditions = array('language' => $filter_values['langcode']);
$options = array('pager limit' => 30, 'translated' => TRUE, 'untranslated' => TRUE);
// Add translation status conditions and options.
switch ($filter_values['translation']) {
case 'translated':
$conditions['translated'] = TRUE;
if ($filter_values['customized'] != 'all') {
$conditions['customized'] = $filter_values['customized'];
}
break;
case 'untranslated':
$conditions['translated'] = FALSE;
break;
// 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();
// Execute a batch if required. A batch is only used when remote files
// are checked.
if (batch_get()) {
return batch_process('admin/reports/translations');
}
if (!empty($filter_values['string'])) {
$options['filters']['source'] = $filter_values['string'];
if ($options['translated']) {
$options['filters']['translation'] = $filter_values['string'];
}
}
return Drupal::service('locale.storage')->getTranslations($conditions, $options);
}
/**
* Build array out of search criteria specified in request variables.
*/
function locale_translate_filter_values() {
$filter_values = &drupal_static(__FUNCTION__);
if (!isset($filter_values)) {
$filter_values = array();
$filters = locale_translate_filters();
foreach ($filters as $key => $filter) {
$filter_values[$key] = $filter['default'];
// Let the filter defaults be overwritten by parameters in the URL.
if (isset($_GET[$key])) {
// Only allow this value if it was among the options, or
// if there were no fixed options to filter for.
if (!isset($filter['options']) || isset($filter['options'][$_GET[$key]])) {
$filter_values[$key] = $_GET[$key];
}
}
elseif (isset($_SESSION['locale_translate_filter'][$key])) {
// Only allow this value if it was among the options, or
// if there were no fixed options to filter for.
if (!isset($filter['options']) || isset($filter['options'][$_SESSION['locale_translate_filter'][$key]])) {
$filter_values[$key] = $_SESSION['locale_translate_filter'][$key];
}
}
}
}
return $filter_values;
}
/**
* List locale translation filters that can be applied.
*/
function locale_translate_filters() {
$filters = array();
// Get all languages, except English.
drupal_static_reset('language_list');
$languages = language_list();
$language_options = array();
foreach ($languages as $langcode => $language) {
if ($langcode != 'en' || locale_translate_english()) {
$language_options[$langcode] = $language->name;
}
}
// Pick the current interface language code for the filter.
$default_langcode = language(Language::TYPE_INTERFACE)->id;
if (!isset($language_options[$default_langcode])) {
$available_langcodes = array_keys($language_options);
$default_langcode = array_shift($available_langcodes);
}
$filters['string'] = array(
'title' => t('String contains'),
'description' => t('Leave blank to show all strings. The search is case sensitive.'),
'default' => '',
);
$filters['langcode'] = array(
'title' => t('Translation language'),
'options' => $language_options,
'default' => $default_langcode,
);
$filters['translation'] = array(
'title' => t('Search in'),
'options' => array(
'all' => t('Both translated and untranslated strings'),
'translated' => t('Only translated strings'),
'untranslated' => t('Only untranslated strings'),
),
'default' => 'all',
);
$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'),
),
),
'default' => 'all',
);
return $filters;
}
/**
* Return form for locale translation filters.
*
* @ingroup forms
*/
function locale_translate_filter_form($form, &$form_state) {
$filters = locale_translate_filters();
$filter_values = locale_translate_filter_values();
$form['#attached']['css'] = array(
drupal_get_path('module', 'locale') . '/css/locale.admin.css',
);
$form['filters'] = array(
'#type' => 'details',
'#title' => t('Filter translatable strings'),
'#collapsed' => FALSE,
);
foreach ($filters as $key => $filter) {
// Special case for 'string' filter.
if ($key == 'string') {
$form['filters']['status']['string'] = array(
'#type' => 'search',
'#title' => $filter['title'],
'#description' => $filter['description'],
'#default_value' => $filter_values[$key],
);
}
else {
$empty_option = isset($filter['options'][$filter['default']]) ? $filter['options'][$filter['default']] : '- None -';
$form['filters']['status'][$key] = array(
'#title' => $filter['title'],
'#type' => 'select',
'#empty_value' => $filter['default'],
'#empty_option' => $empty_option,
'#size' => 0,
'#options' => $filter['options'],
'#default_value' => $filter_values[$key],
);
if (isset($filter['states'])) {
$form['filters']['status'][$key]['#states'] = $filter['states'];
}
}
}
$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_translate_filter'])) {
$form['filters']['actions']['reset'] = array(
'#type' => 'submit',
'#value' => t('Reset'),
);
}
return $form;
}
/**
* Process result from locale translation filter form.
*/
function locale_translate_filter_form_submit($form, &$form_state) {
$op = $form_state['values']['op'];
$filters = locale_translate_filters();
switch ($op) {
case t('Filter'):
foreach ($filters as $name => $filter) {
if (isset($form_state['values'][$name])) {
$_SESSION['locale_translate_filter'][$name] = $form_state['values'][$name];
}
}
break;
case t('Reset'):
$_SESSION['locale_translate_filter'] = array();
break;
}
$form_state['redirect'] = 'admin/config/regional/translate/translate';
}
/**
* Form constructor for the string editing form.
*
* @see locale_menu()
* @see locale_translate_edit_form_validate()
* @see locale_translate_edit_form_submit()
*
* @ingroup forms
*/
function locale_translate_edit_form($form, &$form_state) {
$filter_values = locale_translate_filter_values();
$langcode = $filter_values['langcode'];
drupal_static_reset('language_list');
$languages = language_list();
$langname = isset($langcode) ? $languages[$langcode]->name : "- None -";
$path = drupal_get_path('module', 'locale');
$form['#attached']['css'] = array(
$path . '/css/locale.admin.css',
);
$form['#attached']['library'][] = array('locale', 'drupal.locale.admin');
$form['langcode'] = array(
'#type' => 'value',
'#value' => $filter_values['langcode'],
);
$form['strings'] = array(
'#type' => 'item',
'#tree' => TRUE,
'#language' => $langname,
'#theme' => 'locale_translate_edit_form_strings',
);
if (isset($langcode)) {
$strings = locale_translate_filter_load_strings();
$plural_formulas = Drupal::state()->get('locale.translation.plurals') ?: array();
foreach ($strings as $string) {
// Cast into source string, will do for our purposes.
$source = new SourceString($string);
// Split source to work with plural values.
$source_array = $source->getPlurals();
$translation_array = $string->getPlurals();
if (count($source_array) == 1) {
// Add original string value and mark as non-plural.
$form['strings'][$string->lid]['plural'] = array(
'#type' => 'value',
'#value' => 0,
);
$form['strings'][$string->lid]['original'] = array(
'#type' => 'item',
'#title' => t('Source string (@language)', array('@language' => t('Built-in English'))),
'#title_display' => 'invisible',
'#markup' => '<span lang="en">' . check_plain($source_array[0]) . '</span>',
);
}
else {
// Add original string value and mark as plural.
$form['strings'][$string->lid]['plural'] = array(
'#type' => 'value',
'#value' => 1,
);
$form['strings'][$string->lid]['original_singular'] = array(
'#type' => 'item',
'#title' => t('Singular form'),
'#markup' => '<span lang="en">' . check_plain($source_array[0]) . '</span>',
'#prefix' => '<span class="visually-hidden">' . t('Source string (@language)', array('@language' => t('Built-in English'))) . '</span>',
);
$form['strings'][$string->lid]['original_plural'] = array(
'#type' => 'item',
'#title' => t('Plural form'),
'#markup' => '<span lang="en">' . check_plain($source_array[1]) . '</span>',
);
}
if (!empty($string->context)) {
$form['strings'][$string->lid]['context'] = array(
'#type' => 'value',
'#value' => '<span lang="en">' . check_plain($string->context) . '</span>',
);
}
// Approximate the number of rows to use in the default textarea.
$rows = min(ceil(str_word_count($source_array[0]) / 12), 10);
if (empty($form['strings'][$string->lid]['plural']['#value'])) {
$form['strings'][$string->lid]['translations'][0] = array(
'#type' => 'textarea',
'#title' => t('Translated string (@language)', array('@language' => $langname)),
'#title_display' => 'invisible',
'#rows' => $rows,
'#default_value' => $translation_array[0],
'#attributes' => array('lang' => $langcode),
);
}
else {
// Dealing with plural strings.
if (isset($plural_formulas[$langcode]['plurals']) && $plural_formulas[$langcode]['plurals'] > 2) {
// Add a textarea for each plural variant.
for ($i = 0; $i < $plural_formulas[$langcode]['plurals']; $i++) {
$form['strings'][$string->lid]['translations'][$i] = array(
'#type' => 'textarea',
'#title' => ($i == 0 ? t('Singular form') : format_plural($i, 'First plural form', '@count. plural form')),
'#rows' => $rows,
'#default_value' => isset($translation_array[$i]) ? $translation_array[$i] : '',
'#attributes' => array('lang' => $langcode),
'#prefix' => $i == 0 ? ('<span class="visually-hidden">' . t('Translated string (@language)', array('@language' => $langname)) . '</span>') : '',
);
}
}
else {
// Fallback for unknown number of plurals.
$form['strings'][$string->lid]['translations'][0] = array(
'#type' => 'textarea',
'#title' => t('Singular form'),
'#rows' => $rows,
'#default_value' => $translation_array[0],
'#attributes' => array('lang' => $langcode),
'#prefix' => '<span class="visually-hidden">' . t('Translated string (@language)', array('@language' => $langname)) . '</span>',
);
$form['strings'][$string->lid]['translations'][1] = array(
'#type' => 'textarea',
'#title' => t('Plural form'),
'#rows' => $rows,
'#default_value' => isset($translation_array[1]) ? $translation_array[1] : '',
'#attributes' => array('lang' => $langcode),
);
}
}
}
if (count(element_children($form['strings']))) {
$form['actions'] = array('#type' => 'actions');
$form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Save translations'));
}
}
return $form;
}
/**
* Form validation handler for locale_translate_edit_form().
*
* @see locale_translate_edit_form_submit()
*/
function locale_translate_edit_form_validate($form, &$form_state) {
$langcode = $form_state['values']['langcode'];
foreach ($form_state['values']['strings'] as $lid => $translations) {
foreach ($translations['translations'] as $key => $value) {
if (!locale_string_is_safe($value)) {
form_set_error("strings][$lid][translations][$key", t('The submitted string contains disallowed HTML: %string', array('%string' => $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);
}
}
}
}
/**
* Form submission handler for locale_translate_edit_form().
*
* @see locale_translate_edit_form_validate()
*/
function locale_translate_edit_form_submit($form, &$form_state) {
$langcode = $form_state['values']['langcode'];
$updated = array();
// Preload all translations for strings in the form.
$lids = array_keys($form_state['values']['strings']);
$existing_translation_objects = array();
foreach (Drupal::service('locale.storage')->getTranslations(array('lid' => $lids, 'language' => $langcode, 'translated' => TRUE)) as $existing_translation_object) {
$existing_translation_objects[$existing_translation_object->lid] = $existing_translation_object;
}
foreach ($form_state['values']['strings'] as $lid => $new_translation) {
$existing_translation = isset($existing_translation_objects[$lid]);
// Plural translations are saved in a delimited string. To be able to
// compare the new strings with the existing strings a string in the same format is created.
$new_translation_string_delimited = implode(LOCALE_PLURAL_DELIMITER, $new_translation['translations']);
// Generate an imploded string without delimiter, to be able to run
// empty() on it.
$new_translation_string = implode('', $new_translation['translations']);
$is_changed = FALSE;
if ($existing_translation && $existing_translation_objects[$lid]->translation != $new_translation_string_delimited) {
// If there is an existing translation in the DB and the new translation
// is not the same as the existing one.
$is_changed = TRUE;
}
elseif (!$existing_translation && !empty($new_translation_string)) {
// Newly entered translation.
$is_changed = TRUE;
}
if ($is_changed) {
// Only update or insert if we have a value to use.
$target = isset($existing_translation_objects[$lid]) ? $existing_translation_objects[$lid] : Drupal::service('locale.storage')->createTranslation(array('lid' => $lid, 'language' => $langcode));
$target->setPlurals($new_translation['translations'])
->setCustomized()
->save();
$updated[] = $target->getId();
}
if (empty($new_translation_string) && isset($existing_translation_objects[$lid])) {
// Empty new translation entered: remove existing entry from database.
$existing_translation_objects[$lid]->delete();
$updated[] = $lid;
}
}
drupal_set_message(t('The strings have been saved.'));
// Keep the user on the current pager page.
if (isset($_GET['page'])) {
$form_state['redirect'] = array('admin/config/regional/translate', array('query' => array('page' => $_GET['page'])));
}
if ($updated) {
// Clear cache and refresh configuration and JavaScript translations.
_locale_refresh_translations(array($langcode), $updated);
_locale_refresh_configuration(array($langcode), $updated);
}
return new RedirectResponse(url('admin/reports/translations', array('absolute' => TRUE)));
}
/**

View File

@ -11,3 +11,10 @@ locale_check_translation:
_controller: 'Drupal\locale\Controller\LocaleController::checkTranslation'
requirements:
_permission: 'translate interface'
locale_translate_page:
pattern: '/admin/config/regional/translate'
defaults:
_content: 'Drupal\locale\Controller\LocaleController::translatePage'
requirements:
_permission: 'translate interface'

View File

@ -59,7 +59,7 @@ class ToolbarMenuTranslationTest extends WebTestBase {
'langcode' => $langcode,
'translation' => 'untranslated',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
$this->drupalPost('admin/config/regional/translate', $search, t('Filter'));
// Make sure will be able to translate the menu item.
$this->assertNoText('No strings available.', 'Search found the menu item as untranslated.');
@ -74,7 +74,7 @@ class ToolbarMenuTranslationTest extends WebTestBase {
$edit = array(
$lid => $menu_item_translated,
);
$this->drupalPost('admin/config/regional/translate/translate', $edit, t('Save translations'));
$this->drupalPost('admin/config/regional/translate', $edit, t('Save translations'));
// Search for the translated menu item.
$search = array(
@ -82,7 +82,7 @@ class ToolbarMenuTranslationTest extends WebTestBase {
'langcode' => $langcode,
'translation' => 'translated',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
$this->drupalPost('admin/config/regional/translate', $search, t('Filter'));
// Make sure the menu item string was translated.
$this->assertText($menu_item_translated, 'Search found the menu item as translated: ' . $menu_item_translated . '.');