tmgmt_i18n_string.test 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496
  1. <?php
  2. /**
  3. * Basic i18n String Source tests.
  4. */
  5. class TMGMTI18nStringSourceTestCase extends TMGMTBaseTestCase {
  6. static function getInfo() {
  7. return array(
  8. 'name' => 'i18n String Source tests',
  9. 'description' => 'Exporting source data from i18n string and saving translations back',
  10. 'group' => 'Translation Management',
  11. 'dependencies' => array('i18n_string'),
  12. );
  13. }
  14. function setUp() {
  15. parent::setUp(array('tmgmt_ui', 'tmgmt_i18n_string', 'taxonomy', 'i18n_taxonomy', 'i18n_block', 'i18n_field', 'list', 'i18n_menu'));
  16. $this->setEnvironment('de');
  17. $this->translator = $this->createTranslator();
  18. }
  19. function testI18nStringSourceTaxonomy() {
  20. // Test translation of a vocabulary.
  21. /////////////////////////////////////
  22. $config = array(
  23. 'name' => $this->randomName(),
  24. 'machine_name' => 'test_vocab',
  25. 'i18n_mode' => I18N_MODE_LOCALIZE,
  26. );
  27. $vocabulary = entity_create('taxonomy_vocabulary', $config);
  28. taxonomy_vocabulary_save($vocabulary);
  29. $string_object_name = "taxonomy:vocabulary:" . $vocabulary->vid;
  30. $source_text = $vocabulary->name;
  31. // Create the new job and job item.
  32. $job = $this->createJob();
  33. $job->translator = $this->translator->name;
  34. $job->settings = array();
  35. $job->save();
  36. $item1 = $job->addItem('i18n_string', 'taxonomy_vocabulary', $string_object_name);
  37. $this->assertEqual(t('Vocabulary'), $item1->getSourceType());
  38. $job->requestTranslation();
  39. foreach ($job->getItems() as $item) {
  40. /* @var $item TMGMTJobItem */
  41. $item->acceptTranslation();
  42. }
  43. // Check the structure of the imported data.
  44. $this->assertEqual($item1->item_id, $string_object_name, 'i18n Strings object correctly saved');
  45. // Check string translation.
  46. $this->assertEqual(i18n_string_translate('taxonomy:vocabulary:' . $vocabulary->vid . ':name', $source_text, array('langcode' => $job->target_language)), $job->target_language . '_' . $source_text);
  47. // Test translation of a taxonomy term.
  48. /////////////////////////////////////
  49. $term = entity_create('taxonomy_term', array(
  50. 'vid' => $vocabulary->vid,
  51. 'name' => $this->randomName(),
  52. 'description' => $this->randomName(),
  53. ));
  54. taxonomy_term_save($term);
  55. $string_object_name = "taxonomy:term:" . $term->tid;
  56. $source_text_name = $term->name;
  57. $source_text_description = $term->description;
  58. // Create the new job and job item.
  59. $job = $this->createJob();
  60. $job->translator = $this->translator->name;
  61. $job->settings = array();
  62. $job->save();
  63. $item1 = $job->addItem('i18n_string', 'taxonomy_term', $string_object_name);
  64. $this->assertEqual(t('Taxonomy term'), $item1->getSourceType());
  65. $job->requestTranslation();
  66. /* @var $item TMGMTJobItem */
  67. foreach ($job->getItems() as $item) {
  68. // The source is available only in en.
  69. $this->assertJobItemLangCodes($item, 'en', array('en'));
  70. $item->acceptTranslation();
  71. // The source should be now available in de and en.
  72. $this->assertJobItemLangCodes($item, 'en', array('de', 'en'));
  73. }
  74. // Check the structure of the imported data.
  75. $this->assertEqual($item1->item_id, $string_object_name);
  76. // Check string translation.
  77. $this->assertEqual(i18n_string_translate('taxonomy:term:' . $term->tid . ':name', $source_text_name,
  78. array('langcode' => $job->target_language)), $job->target_language . '_' . $source_text_name);
  79. $this->assertEqual(i18n_string_translate('taxonomy:term:' . $term->tid . ':description', $source_text_description,
  80. array('langcode' => $job->target_language)), $job->target_language . '_' . $source_text_description);
  81. }
  82. /**
  83. * Test if the source is able to pull content in requested language.
  84. */
  85. function testRequestDataForSpecificLanguage() {
  86. $this->setEnvironment('es');
  87. $this->setEnvironment('cs');
  88. $config = array(
  89. 'name' => $this->randomName(),
  90. 'machine_name' => 'test_vocab',
  91. 'i18n_mode' => I18N_MODE_LOCALIZE,
  92. );
  93. $vocabulary = entity_create('taxonomy_vocabulary', $config);
  94. taxonomy_vocabulary_save($vocabulary);
  95. $string_object_name = "taxonomy:vocabulary:" . $vocabulary->vid;
  96. i18n_string_translation_update($string_object_name . ':name', 'de translation', 'de');
  97. // Create new job item with a source language for which the translation
  98. // exits.
  99. $job = $this->createJob('de', 'cs');
  100. $job->save();
  101. $job->addItem('i18n_string', 'taxonomy_vocabulary', $string_object_name);
  102. $data = $job->getData();
  103. $this->assertEqual($data[1][$string_object_name . ':name']['#text'], 'de translation');
  104. // Create new job item with a source language for which the translation
  105. // does not exit.
  106. $job = $this->createJob('es', 'cs');
  107. $job->save();
  108. try {
  109. $job->addItem('i18n_string', 'taxonomy_vocabulary', $string_object_name);
  110. $this->fail('The job item should not be added as there is no translation for language "es"');
  111. }
  112. catch (TMGMTException $e) {
  113. $languages = language_list();
  114. $this->assertEqual(t('Unable to load %language translation for the string %title',
  115. array('%language' => $languages['es']->name, '%title' => 'Name')), $e->getMessage());
  116. }
  117. }
  118. function testI18nStringSourceMenu() {
  119. drupal_static_reset('_tmgmt_plugin_info');
  120. drupal_static_reset('_tmgmt_plugin_controller');
  121. // Test translation of a menu.
  122. /////////////////////////////////////
  123. $config = array(
  124. 'menu_name' => $this->randomName(),
  125. 'title' => $this->randomName(),
  126. 'description' => $this->randomName(),
  127. 'i18n_mode' => I18N_MODE_MULTIPLE,
  128. );
  129. menu_save($config);
  130. $menu = menu_load($config['menu_name']);
  131. $source_text = $menu['title'];
  132. $string_name = 'menu:menu:' . $menu['menu_name'];
  133. // Create the new job and job item.
  134. $job = $this->createJob();
  135. $job->translator = $this->translator->name;
  136. $job->settings = array();
  137. $item1 = $job->addItem('i18n_string', 'menu', $string_name);
  138. $this->assertEqual(t('Menu'), $item1->getSourceType());
  139. $job->requestTranslation();
  140. /* @var $item TMGMTJobItem */
  141. foreach ($job->getItems() as $item) {
  142. $this->assertJobItemLangCodes($item, 'en', array('en'));
  143. $item->acceptTranslation();
  144. $this->assertJobItemLangCodes($item, 'en', array('de', 'en'));
  145. }
  146. $data = $item1->getData();
  147. $this->assertEqual($data['menu:menu:' . $menu['menu_name'] . ':title']['#text'], $config['title']);
  148. $this->assertEqual($data['menu:menu:' . $menu['menu_name'] . ':description']['#text'], $config['description']);
  149. // Check the structure of the imported data.
  150. $this->assertEqual($item1->item_id, $string_name, 'String is correctly saved');
  151. // Check string translation.
  152. $this->assertEqual(i18n_string_translate($string_name . ':title', $source_text, array('langcode' => $job->target_language)), $job->target_language . '_' . $source_text);
  153. // Test translation of a menu item.
  154. /////////////////////////////////////
  155. $source_text = $this->randomName();
  156. $menu_link = array(
  157. 'link_path' => '<front>',
  158. 'link_title' => $source_text,
  159. // i18n_menu_link::get_title() uses the title, set that too.
  160. 'title' => $source_text,
  161. 'menu_name' => $menu['menu_name'],
  162. 'customized' => TRUE,
  163. );
  164. menu_link_save($menu_link);
  165. $string_name = 'menu:item:' . $menu_link['mlid'];
  166. // Create the new job and job item.
  167. $job = $this->createJob();
  168. $job->translator = $this->translator->name;
  169. $job->settings = array();
  170. $item1 = $job->addItem('i18n_string', 'menu_link', $string_name);
  171. $this->assertEqual(t('Menu link'), $item1->getSourceType());
  172. $job->requestTranslation();
  173. /* @var $item TMGMTJobItem */
  174. foreach ($job->getItems() as $item) {
  175. $this->assertJobItemLangCodes($item, 'en', array('en'));
  176. $item->acceptTranslation();
  177. $this->assertJobItemLangCodes($item, 'en', array('de', 'en'));
  178. }
  179. $data = $item1->getData();
  180. $this->assertEqual($data[$string_name . ':title']['#text'], $source_text);
  181. // Check the structure of the imported data.
  182. $this->assertEqual($item1->item_id, $string_name);
  183. // Check string translation.
  184. $this->assertEqual(i18n_string_translate($string_name . ':title', $source_text, array('langcode' => $job->target_language)), $job->target_language . '_' . $source_text);
  185. }
  186. function testI18nStringSourceLangCodes() {
  187. $config = array(
  188. 'name' => $this->randomName(),
  189. 'description' => 'description_' . $this->randomName(),
  190. 'machine_name' => 'test_vocab',
  191. 'i18n_mode' => I18N_MODE_LOCALIZE,
  192. );
  193. $vocabulary = entity_create('taxonomy_vocabulary', $config);
  194. taxonomy_vocabulary_save($vocabulary);
  195. $string_object_name = "taxonomy:vocabulary:" . $vocabulary->vid;
  196. // Create the new job and job item.
  197. $job = $this->createJob();
  198. $job->translator = $this->translator->name;
  199. $job->settings = array();
  200. $job->save();
  201. $item = $job->addItem('i18n_string', 'taxonomy_vocabulary', $string_object_name);
  202. $this->assertJobItemLangCodes($item, 'en', array('en'));
  203. i18n_string_translation_update($string_object_name . ':description', 'de_' . $config['description'], 'de');
  204. $this->assertJobItemLangCodes($item, 'en', array('en'));
  205. i18n_string_translation_update($string_object_name . ':name', 'de_' . $config['name'], 'de');
  206. $this->assertJobItemLangCodes($item, 'en', array('en', 'de'));
  207. }
  208. function testI18nStringPluginUI() {
  209. $this->loginAsAdmin(array('administer taxonomy', 'translate interface', 'translate user-defined strings'));
  210. $vocab_data = array(
  211. 'name' => $this->randomName(),
  212. 'machine_name' => 'test_vocab',
  213. 'i18n_mode' => I18N_MODE_LOCALIZE,
  214. );
  215. $term_data = array(
  216. 'name' => $this->randomName(),
  217. );
  218. $vocab_data_not_translated = array(
  219. 'name' => $this->randomName(),
  220. 'machine_name' => 'test_vocab3',
  221. 'i18n_mode' => I18N_MODE_LOCALIZE,
  222. );
  223. // Configure taxonomy and create vocab + term.
  224. $this->drupalPost('admin/structure/taxonomy/add', $vocab_data, t('Save'));
  225. $this->drupalGet('admin/structure/taxonomy');
  226. $this->clickLink(t('add terms'));
  227. $this->drupalPost(NULL, $term_data, t('Save'));
  228. $this->drupalPost('admin/structure/taxonomy/add', $vocab_data_not_translated, t('Save'));
  229. $this->drupalGet('admin/tmgmt/sources/i18n_string_taxonomy_vocabulary');
  230. $this->assertText($vocab_data['name']);
  231. // Request translation via i18n source tab
  232. $this->drupalPost(NULL, array('items[taxonomy:vocabulary:1]' => 1), t('Request translation'));
  233. // Test for the job checkout url.
  234. $this->assertTrue(strpos($this->getUrl(), 'admin/tmgmt/jobs') !== FALSE);
  235. entity_get_controller('tmgmt_job')->resetCache();
  236. $jobs = entity_load('tmgmt_job', FALSE);
  237. /** @var TMGMTJob $job */
  238. $job = array_pop($jobs);
  239. $this->assertFieldByName('label', $job->label());
  240. // Request translation via translate tab of i18n.
  241. $this->drupalPost('admin/structure/taxonomy/test_vocab/translate', array('languages[taxonomy:vocabulary:1:de]' => 1), t('Request translation'));
  242. $this->drupalPost(NULL, array(), t('Submit to translator'));
  243. // Verify that the job item status is shown.
  244. $this->assertText(t('Needs review'));
  245. $this->clickLink(t('review'));
  246. $this->drupalPost(NULL, array(), t('Save as completed'));
  247. $this->assertText(t('The translation for @label has been accepted.', array('@label' => $job->label())));
  248. // Test the missing translation filter.
  249. $this->drupalGet('admin/tmgmt/sources/i18n_string_taxonomy_vocabulary');
  250. // Check that the source language has been removed from the target language
  251. // select box.
  252. $elements = $this->xpath('//select[@name=:name]//option[@value=:option]', array(':name' => 'search[target_language]', ':option' => i18n_string_source_language()));
  253. $this->assertTrue(empty($elements));
  254. $edit = array(
  255. 'search[target_language]' => 'de',
  256. 'search[target_status]' => 'untranslated',
  257. );
  258. $this->drupalPost('admin/tmgmt/sources/i18n_string_taxonomy_vocabulary', $edit, t('Search'));
  259. // The vocabulary name is translated to "de" therefore it must not show up
  260. // in the list.
  261. $this->assertNoText($vocab_data['name']);
  262. $this->assertText($vocab_data_not_translated['name']);
  263. $edit = array(
  264. 'search[target_language]' => 'de',
  265. 'search[target_status]' => 'untranslated',
  266. );
  267. $this->drupalPost(NULL, $edit, t('Search'));
  268. $this->assertNoText($vocab_data['name']);
  269. $this->assertText($vocab_data_not_translated['name']);
  270. // Update the string status to I18N_STRING_STATUS_UPDATE.
  271. $lid = db_select('locales_source', 's')->fields('s', array('lid'))->condition('source', $vocab_data['name'])->execute()->fetchField();
  272. db_update('locales_target')->fields(array('i18n_status' => I18N_STRING_STATUS_UPDATE))->condition('lid', $lid)->execute();
  273. $edit = array(
  274. 'search[target_language]' => 'de',
  275. 'search[target_status]' => 'outdated',
  276. );
  277. $this->drupalPost(NULL, $edit, t('Search'));
  278. $this->assertText($vocab_data['name']);
  279. $this->assertNoText($vocab_data_not_translated['name']);
  280. $edit = array(
  281. 'search[target_language]' => 'de',
  282. 'search[target_status]' => 'untranslated_or_outdated',
  283. );
  284. $this->drupalPost(NULL, $edit, t('Search'));
  285. $this->assertText($vocab_data['name']);
  286. $this->assertText($vocab_data_not_translated['name']);
  287. }
  288. /**
  289. * Tests translation of blocks through the user interface.
  290. */
  291. function testI18nStringPluginUIBlock() {
  292. $this->loginAsAdmin(array('administer blocks', 'translate interface', 'translate user-defined strings'));
  293. // Make some blocks translatable.
  294. $navigation_edit = array(
  295. 'title' => $this->randomName(),
  296. 'i18n_mode' => 1,
  297. );
  298. $this->drupalPost('admin/structure/block/manage/system/navigation/configure', $navigation_edit, t('Save block'));
  299. $powered_edit = array(
  300. 'title' => $this->randomName(),
  301. 'i18n_mode' => 1,
  302. );
  303. $this->drupalPost('admin/structure/block/manage/system/powered-by/configure', $powered_edit, t('Save block'));
  304. $this->drupalGet('admin/tmgmt/sources/i18n_string_block');
  305. $this->assertText($navigation_edit['title']);
  306. $this->assertText($powered_edit['title']);
  307. // Request translation via i18n source tab.
  308. $edit = array(
  309. 'items[blocks:system:powered-by]' => 1,
  310. 'items[blocks:system:navigation]' => 1,
  311. );
  312. $this->drupalPost(NULL, $edit, t('Request translation'));
  313. $this->assertText($navigation_edit['title']);
  314. $this->assertText($powered_edit['title']);
  315. $this->drupalPost(NULL, array(), t('Submit to translator'));
  316. $this->assertRaw(t('Active job item: Needs review'));
  317. }
  318. /**
  319. * Tests translation of fields through the user interface.
  320. */
  321. function testI18nStringPluginUIField() {
  322. $this->loginAsAdmin(array('translate interface', 'translate user-defined strings'));
  323. $type = $this->drupalCreateContentType(array('type' => $type = $this->randomName()));
  324. // Create a field.
  325. $field = array(
  326. 'field_name' => 'list_test',
  327. 'type' => 'list_text',
  328. );
  329. for ($i = 0; $i < 5; $i++) {
  330. $field['settings']['allowed_values'][$this->randomName()] = $this->randomString();
  331. }
  332. field_create_field($field);
  333. // Create an instance of the previously created field.
  334. $instance = array(
  335. 'field_name' => 'list_test',
  336. 'entity_type' => 'node',
  337. 'bundle' => $type->type,
  338. 'label' => $this->randomName(10),
  339. 'description' => $this->randomString(30),
  340. );
  341. field_create_instance($instance);
  342. // The body field doesn't have anything that can be translated on the field
  343. // level, so it shouldn't show up in the field overview.
  344. $this->drupalGet('admin/tmgmt/sources/i18n_string_field');
  345. $this->assertNoText(t('Body'));
  346. // @todo: Label doesn't work here?
  347. $this->assertText('field:list_test:#allowed_values');
  348. $this->drupalGet('admin/tmgmt/sources/i18n_string_field_instance');
  349. $this->assertUniqueText(t('Body'));
  350. $this->assertUniqueText($instance['label']);
  351. // Request translation.
  352. $edit = array(
  353. 'items[field:body:' . $type->type . ']' => 1,
  354. 'items[field:list_test:' . $type->type . ']' => 1,
  355. );
  356. $this->drupalPost(NULL, $edit, t('Request translation'));
  357. $this->assertText(t('Body'));
  358. $this->assertText($instance['label']);
  359. $this->drupalPost(NULL, array(), t('Submit to translator'));
  360. $this->assertRaw(t('Active job item: Needs review'));
  361. // Review the first item.
  362. $this->clickLink(t('reviewed'));
  363. $this->drupalPost(NULL, array(), t('Save as completed'));
  364. // The overview should now have a translated field and a pending job item.
  365. $this->drupalGet('admin/tmgmt/sources/i18n_string_field_instance');
  366. $this->assertRaw(t('Translation up to date'));
  367. $this->assertRaw(t('Active job item: Needs review'));
  368. }
  369. /**
  370. * Test the i18n specific cart functionality.
  371. */
  372. function testCart() {
  373. $vocabulary1 = entity_create('taxonomy_vocabulary', array(
  374. 'name' => $this->randomName(),
  375. 'description' => 'description_' . $this->randomName(),
  376. 'machine_name' => 'test_vocab1',
  377. 'i18n_mode' => I18N_MODE_LOCALIZE,
  378. ));
  379. taxonomy_vocabulary_save($vocabulary1);
  380. $string1 = "taxonomy:vocabulary:" . $vocabulary1->vid;
  381. $vocabulary2 = entity_create('taxonomy_vocabulary', array(
  382. 'name' => $this->randomName(),
  383. 'description' => 'description_' . $this->randomName(),
  384. 'machine_name' => 'test_vocab2',
  385. 'i18n_mode' => I18N_MODE_LOCALIZE,
  386. ));
  387. taxonomy_vocabulary_save($vocabulary2);
  388. $string2 = "taxonomy:vocabulary:" . $vocabulary2->vid;
  389. $vocabulary3 = entity_create('taxonomy_vocabulary', array(
  390. 'name' => $this->randomName(),
  391. 'description' => 'description_' . $this->randomName(),
  392. 'machine_name' => 'test_vocab3',
  393. 'i18n_mode' => I18N_MODE_LOCALIZE,
  394. ));
  395. taxonomy_vocabulary_save($vocabulary3);
  396. $this->loginAsAdmin(array_merge($this->translator_permissions, array('translate interface', 'translate user-defined strings')));
  397. // Test source overview.
  398. $this->drupalPost('admin/tmgmt/sources/i18n_string_taxonomy_vocabulary', array(
  399. 'items[' . $string1 . ']' => TRUE,
  400. 'items[' . $string2 . ']' => TRUE,
  401. ), t('Add to cart'));
  402. $this->drupalGet('admin/tmgmt/cart');
  403. $this->assertText($vocabulary1->name);
  404. $this->assertText($vocabulary2->name);
  405. // Test translate tab.
  406. $this->drupalGet('admin/structure/taxonomy/test_vocab3/translate');
  407. $this->assertRaw(t('There are @count items in the <a href="@url">translation cart</a>.',
  408. array('@count' => 2, '@url' => url('admin/tmgmt/cart'))));
  409. $this->drupalPost(NULL, array(), t('Add to cart'));
  410. $this->assertRaw(t('@count content source was added into the <a href="@url">cart</a>.', array('@count' => 1, '@url' => url('admin/tmgmt/cart'))));
  411. $this->assertRaw(t('There are @count items in the <a href="@url">translation cart</a> including the current item.',
  412. array('@count' => 3, '@url' => url('admin/tmgmt/cart'))));
  413. }
  414. }