updated core to 7.58 (right after the site was hacked)
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Drupal 7\\n"
|
||||
"MIME-Version: 1.0\\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\\n"
|
||||
"Content-Transfer-Encoding: 8bit\\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\\n"
|
||||
|
||||
msgid "Hello World"
|
||||
msgstr "Hallo Welt"
|
||||
|
||||
msgid "Example"
|
||||
msgstr "Beispiel"
|
@@ -0,0 +1,17 @@
|
||||
name = Locales Source
|
||||
description = Locales source plugin for the Translation Management system.
|
||||
package = Translation Management
|
||||
core = 7.x
|
||||
dependencies[] = tmgmt
|
||||
dependencies[] = locale
|
||||
files[] = tmgmt_locale.plugin.inc
|
||||
files[] = tmgmt_locale.test
|
||||
files[] = tmgmt_locale.ui.inc
|
||||
files[] = tmgmt_locale.ui.test
|
||||
|
||||
; Information added by Drupal.org packaging script on 2016-09-21
|
||||
version = "7.x-1.0-rc2+1-dev"
|
||||
core = "7.x"
|
||||
project = "tmgmt"
|
||||
datestamp = "1474446494"
|
||||
|
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Installation hooks for tmgmt_locale module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Update existing {locales_target}.l10n_status if any.
|
||||
*/
|
||||
function tmgmt_locale_update_7000() {
|
||||
if (module_exists('l10n_update')) {
|
||||
module_load_include('inc', 'l10n_update');
|
||||
$query = db_select('tmgmt_job_item', 'ji')
|
||||
->condition('ji.plugin', 'locale')
|
||||
->condition('ji.state', TMGMT_JOB_ITEM_STATE_ACCEPTED);
|
||||
$query->innerJoin('tmgmt_job', 'j', 'j.tjid = ji.tjid');
|
||||
$query->addField('ji', 'item_id', 'lid');
|
||||
$query->addField('j', 'target_language', 'language');
|
||||
foreach ($query->execute() as $row) {
|
||||
db_update('locales_target')
|
||||
->condition('lid', $row->lid)
|
||||
->condition('language', $row->language)
|
||||
->fields(array('l10n_status' => L10N_UPDATE_STRING_CUSTOM))
|
||||
->execute();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Source plugin for the Translation Management system that handles locale strings.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_tmgmt_source_plugin_info().
|
||||
*
|
||||
* @see TMGMTLocaleSourcePluginController
|
||||
*/
|
||||
function tmgmt_locale_tmgmt_source_plugin_info() {
|
||||
$info['locale'] = array(
|
||||
'label' => t('Locale source'),
|
||||
'description' => t('Source handler for locale strings.'),
|
||||
'plugin controller class' => 'TMGMTLocaleSourcePluginController',
|
||||
'ui controller class' => 'TMGMTLocaleSourceUIController',
|
||||
'item types' => array(
|
||||
'default' => t('Locale'),
|
||||
),
|
||||
);
|
||||
|
||||
return $info;
|
||||
}
|
@@ -0,0 +1,245 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Provides the locale source controller.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Translation plugin controller for locale strings.
|
||||
*/
|
||||
class TMGMTLocaleSourcePluginController extends TMGMTDefaultSourcePluginController {
|
||||
|
||||
/**
|
||||
* Updates translation associated to a specific locale source.
|
||||
*
|
||||
* @param string $lid
|
||||
* The Locale ID.
|
||||
* @param string $target_language
|
||||
* Target language to update translation.
|
||||
* @param string $translation
|
||||
* Translation value.
|
||||
*
|
||||
* @return bool
|
||||
* Success or not updating the locale translation.
|
||||
*/
|
||||
protected function updateTranslation($lid, $target_language, $translation) {
|
||||
|
||||
$languages = locale_language_list('name', TRUE);
|
||||
if (!$lid || !array_key_exists($target_language, $languages) || !$translation) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$exists = db_query("SELECT COUNT(lid) FROM {locales_target} WHERE lid = :lid AND language = :language", array(':lid' => $lid, ':language' => $target_language))
|
||||
->fetchField();
|
||||
|
||||
$fields = array(
|
||||
'translation' => $translation,
|
||||
);
|
||||
if (module_exists('l10n_update')) {
|
||||
module_load_include('inc', 'l10n_update');
|
||||
$fields += array(
|
||||
'l10n_status' => L10N_UPDATE_STRING_CUSTOM,
|
||||
);
|
||||
}
|
||||
|
||||
// @todo Only singular strings are managed here, we should take care of
|
||||
// plural information of processed string.
|
||||
if (!$exists) {
|
||||
$fields += array(
|
||||
'lid' => $lid,
|
||||
'language' => $target_language,
|
||||
);
|
||||
db_insert('locales_target')
|
||||
->fields($fields)
|
||||
->execute();
|
||||
}
|
||||
else {
|
||||
db_update('locales_target')
|
||||
->fields($fields)
|
||||
->condition('lid', $lid)
|
||||
->condition('language', $target_language)
|
||||
->execute();
|
||||
}
|
||||
// Clear locale caches.
|
||||
_locale_invalidate_js($target_language);
|
||||
cache_clear_all('locale:' . $target_language, 'cache');
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to obtain a locale object for given job item.
|
||||
*
|
||||
* @param TMGMTJobItem $job_item
|
||||
*
|
||||
* @return locale object
|
||||
*/
|
||||
protected function getLocaleObject(TMGMTJobItem $job_item) {
|
||||
$locale_lid = $job_item->item_id;
|
||||
|
||||
// Check existence of assigned lid.
|
||||
$exists = db_query("SELECT COUNT(lid) FROM {locales_source} WHERE lid = :lid", array(':lid' => $locale_lid))->fetchField();
|
||||
if (!$exists) {
|
||||
throw new TMGMTException(t('Unable to load locale with id %id', array('%id' => $job_item->item_id)));
|
||||
}
|
||||
|
||||
// This is necessary as the method is also used in the getLabel() callback
|
||||
// and for that case the job is not available in the cart.
|
||||
if (!empty($job_item->tjid)) {
|
||||
$source_language = $job_item->getJob()->source_language;
|
||||
}
|
||||
else {
|
||||
$source_language = $job_item->getSourceLangCode();
|
||||
}
|
||||
|
||||
if ($source_language == 'en') {
|
||||
$query = db_select('locales_source', 'ls');
|
||||
$query
|
||||
->fields('ls')
|
||||
->condition('ls.lid', $locale_lid);
|
||||
$locale_object = $query
|
||||
->execute()
|
||||
->fetchObject();
|
||||
|
||||
$locale_object->language = 'en';
|
||||
|
||||
if (empty($locale_object)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$locale_object->origin = 'source';
|
||||
}
|
||||
else {
|
||||
$query = db_select('locales_target', 'lt');
|
||||
$query->join('locales_source', 'ls', 'ls.lid = lt.lid');
|
||||
$query
|
||||
->fields('lt')
|
||||
->fields('ls')
|
||||
->condition('lt.lid', $locale_lid)
|
||||
->condition('lt.language', $source_language);
|
||||
$locale_object = $query
|
||||
->execute()
|
||||
->fetchObject();
|
||||
|
||||
if (empty($locale_object)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$locale_object->origin = 'target';
|
||||
}
|
||||
|
||||
return $locale_object;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getLabel(TMGMTJobItem $job_item) {
|
||||
if ($locale_object = $this->getLocaleObject($job_item)) {
|
||||
if ($locale_object->origin == 'source') {
|
||||
$label = $locale_object->source;
|
||||
}
|
||||
else {
|
||||
$label = $locale_object->translation;
|
||||
}
|
||||
return truncate_utf8(strip_tags($label), 30, FALSE, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* [@inheritdoc}
|
||||
*/
|
||||
public function getType(TMGMTJobItem $job_item) {
|
||||
return $this->getItemTypeLabel($job_item->item_type);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getData(TMGMTJobItem $job_item) {
|
||||
$locale_object = $this->getLocaleObject($job_item);
|
||||
if (empty($locale_object)) {
|
||||
$languages = language_list();
|
||||
throw new TMGMTException(t('Unable to load %language translation for the locale %id',
|
||||
array('%language' => $languages[$job_item->getJob()->source_language]->name, '%id' => $job_item->item_id)));
|
||||
}
|
||||
|
||||
if ($locale_object->origin == 'source') {
|
||||
$text = $locale_object->source;
|
||||
}
|
||||
else {
|
||||
$text = $locale_object->translation;
|
||||
}
|
||||
|
||||
// Identify placeholders that need to be escaped. Assume that placeholders
|
||||
// consist of alphanumeric characters and _,- only and are delimited by
|
||||
// non-alphanumeric characters. There are cases that don't match, for
|
||||
// example appended SI units like "@valuems", there only @value is the
|
||||
// actual placeholder.
|
||||
$escape = array();
|
||||
if (preg_match_all('/([@!%][a-zA-Z0-9_-]+)/', $text, $matches, PREG_OFFSET_CAPTURE)) {
|
||||
foreach ($matches[0] as $match) {
|
||||
$escape[$match[1]]['string'] = $match[0];
|
||||
}
|
||||
}
|
||||
$structure['singular'] = array(
|
||||
'#label' => t('Singular'),
|
||||
'#text' => (string) $text,
|
||||
'#translate' => TRUE,
|
||||
'#escape' => $escape,
|
||||
);
|
||||
return $structure;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function saveTranslation(TMGMTJobItem $job_item) {
|
||||
$job = tmgmt_job_load($job_item->tjid);
|
||||
$data = $job_item->getData();
|
||||
if (isset($data['singular'])) {
|
||||
$translation = $data['singular']['#translation']['#text'];
|
||||
// Update the locale string in the system.
|
||||
// @todo: Send error message to user if update fails.
|
||||
if ($this->updateTranslation($job_item->item_id, $job->target_language, $translation)) {
|
||||
$job_item->accepted();
|
||||
}
|
||||
}
|
||||
|
||||
// @todo: Temporary backwards compability with existing jobs, remove in next
|
||||
// release.
|
||||
if (isset($data[$job_item->item_id])) {
|
||||
$translation = $data[$job_item->item_id]['#translation']['#text'];
|
||||
// Update the locale string in the system.
|
||||
// @todo: Send error message to user if update fails.
|
||||
if ($this->updateTranslation($job_item->item_id, $job->target_language, $translation)) {
|
||||
$job_item->accepted();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSourceLangCode(TMGMTJobItem $job_item) {
|
||||
// For the locale source English is always the source language.
|
||||
return 'en';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getExistingLangCodes(TMGMTJobItem $job_item) {
|
||||
$query = db_select('locales_target', 'lt');
|
||||
$query->fields('lt', array('language'));
|
||||
$query->condition('lt.lid', $job_item->item_id);
|
||||
|
||||
$existing_lang_codes = array('en');
|
||||
foreach ($query->execute() as $language) {
|
||||
$existing_lang_codes[] = $language->language;
|
||||
}
|
||||
|
||||
return $existing_lang_codes;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,231 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Basic Locale Source tests.
|
||||
*/
|
||||
class TMGMTLocaleSourceTestCase extends TMGMTBaseTestCase {
|
||||
|
||||
static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Locale Source tests',
|
||||
'description' => 'Exporting source data from locale and saving translations back',
|
||||
'group' => 'Translation Management',
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp(array('tmgmt_locale'));
|
||||
$this->langcode = 'de';
|
||||
$this->context = 'default';
|
||||
$file = new stdClass();
|
||||
$file->uri = drupal_realpath(drupal_get_path('module', 'tmgmt_locale') . '/tests/test.xx.po');
|
||||
$this->pofile = file_save($file);
|
||||
$this->setEnvironment($this->langcode);
|
||||
$this->setEnvironment('es');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests translation of a locale singular term.
|
||||
*/
|
||||
function testSingularTerm() {
|
||||
// Load PO file to create a locale structure in the database.
|
||||
_locale_import_po($this->pofile, $this->langcode, LOCALE_IMPORT_OVERWRITE, $this->context);
|
||||
|
||||
// Obtain one locale string with translation.
|
||||
$locale_object = db_query('SELECT * FROM {locales_source} WHERE source = :source LIMIT 1', array(':source' => 'Hello World'))->fetchObject();
|
||||
$source_text = $locale_object->source;
|
||||
|
||||
// Create the new job and job item.
|
||||
$job = $this->createJob();
|
||||
$job->translator = $this->default_translator->name;
|
||||
$job->settings = array();
|
||||
$job->save();
|
||||
|
||||
$item1 = $job->addItem('locale', 'default', $locale_object->lid);
|
||||
|
||||
// Check the structure of the imported data.
|
||||
$this->assertEqual($item1->item_id, $locale_object->lid, 'Locale Strings object correctly saved');
|
||||
$this->assertEqual('Locale', $item1->getSourceType());
|
||||
$this->assertEqual('Hello World', $item1->getSourceLabel());
|
||||
$job->requestTranslation();
|
||||
|
||||
foreach ($job->getItems() as $item) {
|
||||
/* @var $item TMGMTJobItem */
|
||||
$item->acceptTranslation();
|
||||
$this->assertTrue($item->isAccepted());
|
||||
// The source is now available in en and de.
|
||||
$this->assertJobItemLangCodes($item, 'en', array('en', 'de'));
|
||||
}
|
||||
|
||||
// Check string translation.
|
||||
$expected_translation = $job->target_language . '_' . $source_text;
|
||||
$this->assertTranslation($locale_object->lid, 'de', $expected_translation);
|
||||
|
||||
// Translate the german translation to spanish.
|
||||
$target_langcode = 'es';
|
||||
$job = $this->createJob('de', $target_langcode);
|
||||
$job->translator = $this->default_translator->name;
|
||||
$job->settings = array();
|
||||
$job->save();
|
||||
|
||||
$item1 = $job->addItem('locale', 'default', $locale_object->lid);
|
||||
$this->assertEqual('Locale', $item1->getSourceType());
|
||||
$this->assertEqual($expected_translation, $item1->getSourceLabel());
|
||||
$job->requestTranslation();
|
||||
|
||||
foreach ($job->getItems() as $item) {
|
||||
/* @var $item TMGMTJobItem */
|
||||
$item->acceptTranslation();
|
||||
$this->assertTrue($item->isAccepted());
|
||||
|
||||
// The source should be now available for en, de and es languages.
|
||||
$this->assertJobItemLangCodes($item, 'en', array('en', 'de', 'es'));
|
||||
}
|
||||
|
||||
// Check string translation.
|
||||
$this->assertTranslation($locale_object->lid, $target_langcode, $job->target_language . '_' . $expected_translation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if the source is able to pull content in requested language.
|
||||
*/
|
||||
function testRequestDataForSpecificLanguage() {
|
||||
$this->setEnvironment('cs');
|
||||
|
||||
_locale_import_po($this->pofile, $this->langcode, LOCALE_IMPORT_OVERWRITE, $this->context);
|
||||
$locale_object = db_query('SELECT * FROM {locales_source} WHERE source = :source LIMIT 1', array(':source' => 'Hello World'))->fetchObject();
|
||||
|
||||
$plugin = new TMGMTLocaleSourcePluginController('locale', 'locale');
|
||||
$reflection_plugin = new ReflectionClass('TMGMTLocaleSourcePluginController');
|
||||
$updateTranslation = $reflection_plugin->getMethod('updateTranslation');
|
||||
$updateTranslation->setAccessible(TRUE);
|
||||
|
||||
$updateTranslation->invoke($plugin, $locale_object->lid, 'de', 'de translation');
|
||||
|
||||
// Create the new job and job item.
|
||||
$job = $this->createJob('de', 'cs');
|
||||
$job->save();
|
||||
$job->addItem('locale', 'default', $locale_object->lid);
|
||||
|
||||
$data = $job->getData();
|
||||
$this->assertEqual($data[1]['singular']['#text'], 'de translation');
|
||||
|
||||
// Create new job item with a source language for which the translation
|
||||
// does not exit.
|
||||
$job = $this->createJob('es', 'cs');
|
||||
$job->save();
|
||||
try {
|
||||
$job->addItem('locale', 'default', $locale_object->lid);
|
||||
$this->fail('The job item should not be added as there is no translation for language "es"');
|
||||
}
|
||||
catch (TMGMTException $e) {
|
||||
$languages = language_list();
|
||||
$this->assertEqual(t('Unable to load %language translation for the locale %id',
|
||||
array('%language' => $languages['es']->name, '%id' => $locale_object->lid)), $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that strings that need escaping are correctly identified.
|
||||
*/
|
||||
function testEscaping() {
|
||||
$lid = db_insert('locales_source')
|
||||
->fields(array(
|
||||
'source' => '@place-holders need %to be !esc_aped.',
|
||||
'textgroup' => 'default',
|
||||
'context' => '',
|
||||
))
|
||||
->execute();
|
||||
$job = $this->createJob('en', 'de');
|
||||
$job->translator = $this->default_translator->name;
|
||||
$job->settings = array();
|
||||
$job->save();
|
||||
|
||||
$item = $job->addItem('locale', 'default', $lid);
|
||||
$data = $item->getData();
|
||||
$expected_escape = array(
|
||||
0 => array('string' => '@place-holders'),
|
||||
20 => array('string' => '%to'),
|
||||
27 => array('string' => '!esc_aped'),
|
||||
);
|
||||
$this->assertEqual($data['singular']['#escape'], $expected_escape);
|
||||
|
||||
// Invalid patterns that should be ignored.
|
||||
$lid = db_insert('locales_source')
|
||||
->fields(array(
|
||||
'source' => '@ % ! example',
|
||||
'textgroup' => 'default',
|
||||
'context' => '',
|
||||
))
|
||||
->execute();
|
||||
|
||||
$item = $job->addItem('locale', 'default', $lid);
|
||||
$data = $item->getData();
|
||||
$this->assertTrue(empty($data[$lid]['#escape']));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that system behaves correctly with an non-existing locales.
|
||||
*/
|
||||
function testInexistantSource() {
|
||||
// Create inexistant locale object.
|
||||
$locale_object = new stdClass();
|
||||
$locale_object->lid = 0;
|
||||
|
||||
// Create the job.
|
||||
$job = $this->createJob();
|
||||
$job->translator = $this->default_translator->name;
|
||||
$job->settings = array();
|
||||
$job->save();
|
||||
|
||||
// Create the job item.
|
||||
try {
|
||||
$job->addItem('locale', 'default', $locale_object->lid);
|
||||
$this->fail('Job item add with an inexistant locale.');
|
||||
}
|
||||
catch (TMGMTException $e) {
|
||||
$this->pass('Exception thrown when trying to translate non-existing locale string');
|
||||
}
|
||||
|
||||
// Try to translate a source string without translation from german to
|
||||
// spanish.
|
||||
$lid = db_insert('locales_source')
|
||||
->fields(array(
|
||||
'source' => 'No translation',
|
||||
'textgroup' => 'default',
|
||||
'context' => '',
|
||||
))
|
||||
->execute();
|
||||
$job = $this->createJob('de', 'fr');
|
||||
$job->translator = $this->default_translator->name;
|
||||
$job->settings = array();
|
||||
$job->save();
|
||||
|
||||
try {
|
||||
$job->addItem('locale', 'default', $lid);
|
||||
$this->fail('Job item add with an non-existing locale did not fail.');
|
||||
}
|
||||
catch (TMGMTException $e) {
|
||||
$this->pass('Job item add with an non-existing locale did fail.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts a locale translation.
|
||||
*
|
||||
* @param int $lid
|
||||
* The locale source id.
|
||||
* @param string $target_langcode
|
||||
* The target language code.
|
||||
* @param string $expected_translation
|
||||
* The expected translation.
|
||||
*/
|
||||
public function assertTranslation($lid, $target_langcode, $expected_translation) {
|
||||
$actual_translation = db_query('SELECT translation FROM {locales_target} WHERE lid = :lid AND language = :language', array(
|
||||
':lid' => $lid,
|
||||
':language' => $target_langcode
|
||||
))->fetchField();
|
||||
$this->assertEqual($actual_translation, $expected_translation);
|
||||
}
|
||||
}
|
@@ -0,0 +1,316 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Provides the I18nString source controller.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class TMGMTI18nStringDefaultSourceUIController
|
||||
*
|
||||
* UI Controller fo i18n strings translation jobs.
|
||||
*/
|
||||
class TMGMTLocaleSourceUIController extends TMGMTDefaultSourceUIController {
|
||||
|
||||
/**
|
||||
* Gets locale strings.
|
||||
*
|
||||
* @param string $textgroup
|
||||
* The locale textgroup.
|
||||
* @param string $search_label
|
||||
* Label to search for.
|
||||
* @param string $missing_target_language
|
||||
* Missing translation language.
|
||||
*
|
||||
* @return array
|
||||
* List of i18n strings data.
|
||||
*/
|
||||
function getStrings($textgroup, $search_label = NULL, $missing_target_language = NULL) {
|
||||
$languages = drupal_map_assoc(array_keys(language_list()));
|
||||
$select = db_select('locales_source', 'ls')
|
||||
->fields('ls', array('lid', 'source'));
|
||||
|
||||
$select->addTag('tmgmt_sources_search');
|
||||
$select->addMetaData('plugin', 'locale');
|
||||
$select->addMetaData('type', $textgroup);
|
||||
|
||||
$select->condition('ls.textgroup', $textgroup);
|
||||
if (!empty($search_label)) {
|
||||
$select->condition('ls.source', "%$search_label%", 'LIKE');
|
||||
}
|
||||
if (!empty($missing_target_language) && in_array($missing_target_language, $languages)) {
|
||||
$select->isNull("lt_$missing_target_language.language");
|
||||
}
|
||||
|
||||
// Join locale targets for each language.
|
||||
// We want all joined fields to be named as langcodes, but langcodes could
|
||||
// contain hyphens in their names, which is not allowed by the most database
|
||||
// engines. So we create a langcode-to-filed_alias map, and rename fields
|
||||
// later.
|
||||
$langcode_to_filed_alias_map = array();
|
||||
foreach ($languages as $langcode) {
|
||||
$table_alias = $select->leftJoin('locales_target', db_escape_field("lt_$langcode"), "ls.lid = %alias.lid AND %alias.language = '$langcode'");
|
||||
$langcode_to_filed_alias_map[$langcode] = $select->addField($table_alias, 'language');
|
||||
}
|
||||
|
||||
$select = $select->extend('PagerDefault')->limit(variable_get('tmgmt_source_list_limit', 20));
|
||||
$rows = $select->execute()->fetchAll();
|
||||
foreach ($rows as $row) {
|
||||
foreach ($langcode_to_filed_alias_map as $langcode => $field_alias) {
|
||||
$row->{$langcode} = $row->{$field_alias};
|
||||
unset($row->{$field_alias});
|
||||
}
|
||||
}
|
||||
|
||||
return $rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets overview form header.
|
||||
*
|
||||
* @return array
|
||||
* Header array definition as expected by theme_tablesort().
|
||||
*/
|
||||
public function overviewFormHeader() {
|
||||
$languages = array();
|
||||
foreach (language_list() as $langcode => $language) {
|
||||
$languages['langcode-' . $langcode] = array(
|
||||
'data' => check_plain($language->name),
|
||||
);
|
||||
}
|
||||
|
||||
$header = array(
|
||||
'source' => array('data' => t('Source text')),
|
||||
) + $languages;
|
||||
|
||||
return $header;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements TMGMTSourceUIControllerInterface::overviewForm().
|
||||
*/
|
||||
public function overviewForm($form, &$form_state, $type) {
|
||||
$form += $this->overviewSearchFormPart($form, $form_state, $type);
|
||||
|
||||
$form['items'] = array(
|
||||
'#type' => 'tableselect',
|
||||
'#header' => $this->overviewFormHeader($type),
|
||||
'#empty' => t('No strings matching given criteria have been found.')
|
||||
);
|
||||
|
||||
$search_data = $this->getSearchFormSubmittedParams();
|
||||
|
||||
$strings = $this->getStrings($type, $search_data['label'], $search_data['missing_target_language']);
|
||||
|
||||
foreach ($this->getTranslationData($strings, $type) as $id => $data) {
|
||||
$form['items']['#options'][$id] = $this->overviewRow($type, $data);
|
||||
}
|
||||
|
||||
$form['pager'] = array('#markup' => theme('pager', array('tags' => NULL)));
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to create translation data list for the sources page list.
|
||||
*
|
||||
* @param array $strings
|
||||
* Result of the search query returned by tmgmt_i18n_string_get_strings().
|
||||
* @param string $type
|
||||
* I18n object type.
|
||||
*
|
||||
* @return array
|
||||
* Structured array with translation data.
|
||||
*/
|
||||
protected function getTranslationData($strings, $type) {
|
||||
$objects = array();
|
||||
// Source language of locale strings is always english.
|
||||
$source_language = 'en';
|
||||
|
||||
foreach ($strings as $string) {
|
||||
$id = $string->lid;
|
||||
|
||||
// Get existing translations and current job items for the entity
|
||||
// to determine translation statuses
|
||||
$current_job_items = tmgmt_job_item_load_latest('locale', $type, $id, $source_language);
|
||||
|
||||
$objects[$id] = array(
|
||||
'id' => $id,
|
||||
'object' => $string
|
||||
);
|
||||
// Load entity translation specific data.
|
||||
foreach (language_list() as $langcode => $language) {
|
||||
$translation_status = 'current';
|
||||
|
||||
if ($langcode == $source_language) {
|
||||
$translation_status = 'original';
|
||||
}
|
||||
elseif ($string->{$langcode} === NULL) {
|
||||
$translation_status = 'missing';
|
||||
}
|
||||
|
||||
$objects[$id]['current_job_items'][$langcode] = isset($current_job_items[$langcode]) ? $current_job_items[$langcode] : NULL;
|
||||
$objects[$id]['translation_statuses'][$langcode] = $translation_status;
|
||||
}
|
||||
}
|
||||
|
||||
return $objects;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds search form for entity sources overview.
|
||||
*
|
||||
* @param array $form
|
||||
* Drupal form array.
|
||||
* @param $form_state
|
||||
* Drupal form_state array.
|
||||
* @param $type
|
||||
* Entity type.
|
||||
*
|
||||
* @return array
|
||||
* Drupal form array.
|
||||
*/
|
||||
public function overviewSearchFormPart($form, &$form_state, $type) {
|
||||
|
||||
$options = array();
|
||||
foreach (language_list() as $langcode => $language) {
|
||||
$options[$langcode] = $language->name;
|
||||
}
|
||||
|
||||
$default_values = $this->getSearchFormSubmittedParams();
|
||||
|
||||
$form['search_wrapper'] = array(
|
||||
'#prefix' => '<div class="tmgmt-sources-wrapper tmgmt-i18n_string-sources-wrapper">',
|
||||
'#suffix' => '</div>',
|
||||
'#weight' => -15,
|
||||
);
|
||||
$form['search_wrapper']['search'] = array(
|
||||
'#tree' => TRUE,
|
||||
);
|
||||
$form['search_wrapper']['search']['label'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Source text'),
|
||||
'#default_value' => isset($default_values['label']) ? $default_values['label'] : NULL,
|
||||
);
|
||||
|
||||
// Unset English as it is the source language for all locale strings.
|
||||
unset($options['en']);
|
||||
|
||||
$form['search_wrapper']['search']['missing_target_language'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Not translated to'),
|
||||
'#options' => $options,
|
||||
'#empty_option' => '--',
|
||||
'#default_value' => isset($default_values['missing_target_language']) ? $default_values['missing_target_language'] : NULL,
|
||||
);
|
||||
$form['search_wrapper']['search_submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Search'),
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets submitted search params.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getSearchFormSubmittedParams() {
|
||||
$params = array(
|
||||
'label' => NULL,
|
||||
'missing_target_language' => NULL,
|
||||
);
|
||||
|
||||
if (isset($_GET['label'])) {
|
||||
$params['label'] = $_GET['label'];
|
||||
}
|
||||
if (isset($_GET['missing_target_language'])) {
|
||||
$params['missing_target_language'] = $_GET['missing_target_language'];
|
||||
}
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a table row for overview form.
|
||||
*
|
||||
* @param string $type
|
||||
* i18n type.
|
||||
* @param array $data
|
||||
* Data needed to build the list row.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function overviewRow($type, $data) {
|
||||
// Set the default item key, assume it's the first.
|
||||
$source = $data['object'];
|
||||
|
||||
$row = array(
|
||||
'id' => $data['id'],
|
||||
'source' => check_plain($source->source),
|
||||
);
|
||||
|
||||
foreach (language_list() as $langcode => $language) {
|
||||
$row['langcode-' . $langcode] = theme('tmgmt_ui_translation_language_status_single', array(
|
||||
'translation_status' => $data['translation_statuses'][$langcode],
|
||||
'job_item' => isset($data['current_job_items'][$langcode]) ? $data['current_job_items'][$langcode] : NULL,
|
||||
));
|
||||
}
|
||||
|
||||
return $row;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements TMGMTSourceUIControllerInterface::overviewFormSubmit().
|
||||
*/
|
||||
public function overviewFormSubmit($form, &$form_state, $type) {
|
||||
// Handle search redirect.
|
||||
$this->overviewSearchFormRedirect($form, $form_state, $type);
|
||||
$items = array_filter($form_state['values']['items']);
|
||||
$type = $form_state['item_type'];
|
||||
|
||||
$source_lang = 'en';
|
||||
|
||||
// Create only single job for all items as the source language is just
|
||||
// the same for all.
|
||||
$job = tmgmt_job_create($source_lang, NULL, $GLOBALS['user']->uid);
|
||||
|
||||
// Loop through entities and create individual jobs for each source language.
|
||||
foreach ($items as $item) {
|
||||
$job->addItem('locale', $type, $item);
|
||||
}
|
||||
|
||||
$form_state['redirect'] = array('admin/tmgmt/jobs/' . $job->tjid,
|
||||
array('query' => array('destination' => current_path())));
|
||||
drupal_set_message(t('One job needs to be checked out.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs redirect with search params appended to the uri.
|
||||
*
|
||||
* In case of triggering element is edit-search-submit it redirects to
|
||||
* current location with added query string containing submitted search form
|
||||
* values.
|
||||
*
|
||||
* @param array $form
|
||||
* Drupal form array.
|
||||
* @param $form_state
|
||||
* Drupal form_state array.
|
||||
* @param $type
|
||||
* Entity type.
|
||||
*/
|
||||
public function overviewSearchFormRedirect($form, &$form_state, $type) {
|
||||
if ($form_state['triggering_element']['#id'] == 'edit-search-submit') {
|
||||
|
||||
$query = array();
|
||||
|
||||
foreach ($form_state['values']['search'] as $key => $value) {
|
||||
$query[$key] = $value;
|
||||
}
|
||||
|
||||
drupal_goto($_GET['q'], array('query' => $query));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Basic Locale Source tests.
|
||||
*/
|
||||
class TMGMTLocaleSourceUiTestCase extends TMGMTBaseTestCase {
|
||||
|
||||
static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Locale Source UI tests',
|
||||
'description' => 'Tests the locale source overview',
|
||||
'group' => 'Translation Management',
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp(array('tmgmt_locale', 'tmgmt_ui'));
|
||||
$this->langcode = 'de';
|
||||
$this->context = 'default';
|
||||
$file = new stdClass();
|
||||
$file->uri = drupal_realpath(drupal_get_path('module', 'tmgmt_locale') . '/tests/test.xx.po');
|
||||
$this->pofile = file_save($file);
|
||||
$this->setEnvironment($this->langcode);
|
||||
$this->setEnvironment('gsw-berne');
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function testOverview() {
|
||||
// Load PO file to create a locale structure in the database.
|
||||
_locale_import_po($this->pofile, $this->langcode, LOCALE_IMPORT_OVERWRITE, $this->context);
|
||||
|
||||
$this->loginAsTranslator();
|
||||
$this->drupalGet('admin/tmgmt/sources/locale_default');
|
||||
|
||||
$this->assertText('Hello World');
|
||||
$this->assertText('Example');
|
||||
$rows = $this->xpath('//tbody/tr');
|
||||
foreach ($rows as $row) {
|
||||
if ($row->td[1] == 'Hello World') {
|
||||
$this->assertEqual((string) $row->td[3]->div['title'], t('Translation up to date'));
|
||||
$this->assertEqual((string) $row->td[4]->div['title'], t('Not translated'));
|
||||
}
|
||||
}
|
||||
|
||||
// Filter on the label.
|
||||
$edit = array('search[label]' => 'Hello');
|
||||
$this->drupalPost(NULL, $edit, t('Search'));
|
||||
|
||||
$this->assertText('Hello World');
|
||||
$this->assertNoText('Example');
|
||||
|
||||
$locale_object = db_query('SELECT * FROM {locales_source} WHERE source = :source LIMIT 1', array(':source' => 'Hello World'))->fetchObject();
|
||||
|
||||
// First add source to the cart to test its functionality.
|
||||
$edit = array(
|
||||
'items[' . $locale_object->lid . ']' => TRUE,
|
||||
);
|
||||
$this->drupalPost(NULL, $edit, t('Add to cart'));
|
||||
$this->assertRaw(t('@count content source was added into the <a href="@url">cart</a>.', array('@count' => 1, '@url' => url('admin/tmgmt/cart'))));
|
||||
$edit['target_language[]'] = array('gsw-berne');
|
||||
$this->drupalPost('admin/tmgmt/cart', $edit, t('Request translation'));
|
||||
|
||||
// Assert that the job item is displayed.
|
||||
$this->assertText('Hello World');
|
||||
$this->assertText(t('Locale'));
|
||||
$this->assertText('2');
|
||||
$this->drupalPost(NULL, array('target_language' => 'gsw-berne'), t('Submit to translator'));
|
||||
|
||||
// Test for the translation flag title.
|
||||
$this->drupalGet('admin/tmgmt/sources/locale_default');
|
||||
$this->assertRaw(t('Active job item: Needs review'));
|
||||
|
||||
// Review and accept the job item.
|
||||
$job_items = tmgmt_job_item_load_latest('locale', 'default', $locale_object->lid, 'en');
|
||||
$this->drupalGet('admin/tmgmt/items/' . $job_items['gsw-berne']->tjiid);
|
||||
$this->assertRaw('gsw-berne_Hello World');
|
||||
$this->drupalPost(NULL, array(), t('Save as completed'));
|
||||
$this->drupalGet('admin/tmgmt/sources/locale_default');
|
||||
|
||||
$this->assertNoRaw(t('Active job item: Needs review'));
|
||||
$rows = $this->xpath('//tbody/tr');
|
||||
foreach ($rows as $row) {
|
||||
if ($row->td[1] == 'Hello World') {
|
||||
$this->assertEqual((string) $row->td[3]->div['title'], t('Translation up to date'));
|
||||
$this->assertEqual((string) $row->td[4]->div['title'], t('Translation up to date'));
|
||||
}
|
||||
}
|
||||
|
||||
// Test the missing translation filter.
|
||||
$this->drupalGet('admin/tmgmt/sources/locale_default');
|
||||
// Check that the source language (en) has been removed from the target language
|
||||
// select box.
|
||||
$elements = $this->xpath('//select[@name=:name]//option[@value=:option]', array(':name' => 'search[target_language]', ':option' => 'en'));
|
||||
$this->assertTrue(empty($elements));
|
||||
|
||||
// Filter on the "Not translated to".
|
||||
$edit = array('search[missing_target_language]' => 'gsw-berne');
|
||||
$this->drupalPost(NULL, $edit, t('Search'));
|
||||
// Hello World is translated to "gsw-berne" therefore it must not show up in the
|
||||
// list.
|
||||
$this->assertNoText('Hello World');
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user