PageRenderTime 51ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/php/lib/util/synch/synch.class.php

https://bitbucket.org/chamilo/chamilo-app-cda-dev/
PHP | 715 lines | 621 code | 23 blank | 71 comment | 12 complexity | 21553a2eeb45e5db5d6e7597cbc946af MD5 | raw file
  1. <?php
  2. namespace application\cda;
  3. use common\libraries\Path;
  4. use common\libraries\StringUtilities;
  5. use common\libraries\Filesystem;
  6. use common\libraries\Translation;
  7. use common\libraries\Filecompression;
  8. use common\libraries\EqualityCondition;
  9. use common\libraries\AndCondition;
  10. use common\libraries\Session;
  11. use common\libraries\Utilities;
  12. /**
  13. * Utility class to synch the file system with the database.
  14. *
  15. * For Chamilo2 with i18n translation.
  16. *
  17. * @author laurent.opprecht@unige.ch
  18. * @copyright (c)2011 University of Geneva.
  19. *
  20. */
  21. class Synch
  22. {
  23. const TRANSLATION_DIR = 'i18n';
  24. const EXT = 'i18n';
  25. public static function get_root()
  26. {
  27. return Path :: get(SYS_PATH);
  28. }
  29. /**
  30. * Not to be used with a long text or extensively i.e. in a loop.
  31. *
  32. * @param string $text
  33. * @param string $to_lang
  34. * @param string $from_lang
  35. * @return string
  36. */
  37. public static function google_translate($text, $to_lang, $from_lang = 'en')
  38. {
  39. $text = urlencode($text);
  40. $to_lang = urlencode($to_lang);
  41. $from_lang = urlencode($from_lang);
  42. $trans = file_get_contents("http://ajax.googleapis.com/ajax/services/language/translate?v=1.0&q={$text}&langpair={$from_lang}|{$to_lang}");
  43. $json = json_decode($trans, true);
  44. return $json['responseStatus'] == '200' ? $json['responseData']['translatedText'] : false;
  45. }
  46. /**
  47. *
  48. * @param string $lang
  49. * @param int $branch
  50. * @return Synch
  51. */
  52. public static function factory($lang = '', $branch = LanguagePack::BRANCH_LCMS)
  53. {
  54. $result = new self($lang, $branch);
  55. return $result;
  56. }
  57. private static $master = '';
  58. /**
  59. *
  60. * @return Synch
  61. */
  62. public static function master()
  63. {
  64. if (empty(self :: $master))
  65. {
  66. self :: $master = self :: factory('en');
  67. }
  68. return self :: $master;
  69. }
  70. private $branch;
  71. private $lang = '';
  72. private $time = 0;
  73. private $overwrite = false;
  74. private $verbose = true;
  75. public function __construct($lang, $branch)
  76. {
  77. $this->lang = $lang;
  78. $this->branch = $branch;
  79. $this->time = time();
  80. }
  81. /**
  82. * @return int the $branch
  83. */
  84. public function get_branch()
  85. {
  86. return $this->branch;
  87. }
  88. /**
  89. * @param int $branch the $branch to set
  90. */
  91. public function set_branch($branch)
  92. {
  93. $this->branch = $branch;
  94. }
  95. /**
  96. *
  97. * @return string
  98. */
  99. public function get_lang()
  100. {
  101. return $this->lang;
  102. }
  103. /**
  104. *
  105. * @return string
  106. */
  107. public function get_master()
  108. {
  109. return $this->master;
  110. }
  111. /**
  112. * Synch the DB with the file system.
  113. * New keys from master DB are copied.
  114. * New translations from files are copied.
  115. * Database is exported to the files.
  116. *
  117. * WARNING:
  118. *
  119. * !If you have a new translation into a file but the key is alredy in the DB the translation with a non-empty translation it will be lost!
  120. *
  121. *
  122. * @param bool $ovewrite_db If true all non-empty translations from the file system are copied to the DB. If false only keys that do not exist are imported.
  123. * @param string $master
  124. */
  125. public function synch($ovewrite_db = false, $master = 'en')
  126. {
  127. $this->copy($master); //ensure new keys are created
  128. $this->import($ovewrite_db); //import new translations
  129. $this->export(); //export the result
  130. }
  131. /**
  132. * Import files to the database.
  133. *
  134. * @param bool $overwrite
  135. * @param string|null $root
  136. */
  137. public function import($ovewrite = false, $root = null)
  138. {
  139. $this->overwrite = $ovewrite;
  140. $continuation = array($this, 'import_files');
  141. $this->iter($root, $continuation);
  142. $this->overwrite = false;
  143. }
  144. /**
  145. * Export DB content to the file system.
  146. *
  147. * @param bool $ovewrite
  148. * @param string|null $root
  149. */
  150. public function export($ovewrite = true, $root = null)
  151. {
  152. $this->overwrite = $ovewrite;
  153. $continuation = array($this, 'export_files');
  154. $this->iter($root, $continuation);
  155. $this->overwrite = false;
  156. }
  157. /**
  158. * If english translation is empty and variable is one word - i.e. one upper case
  159. * Then use the name of the variable as the english translation
  160. */
  161. public function default_master()
  162. {
  163. $language = $this->get_language(self :: master()->get_lang());
  164. $translations = $this->get_translations($language);
  165. $dm = CdaDataManager :: get_instance();
  166. if ($translations)
  167. {
  168. while ($translation = $translations->next_result())
  169. {
  170. $text = trim($translation->get_translation());
  171. if (! empty($text))
  172. {
  173. continue;
  174. }
  175. $variable = $dm->retrieve_variable($translation->get_variable_id());
  176. $variable_name = $variable->get_variable();
  177. if ($count = preg_match_all('/[A-Z]/', $variable_name, $matchesarray) < 2)
  178. {
  179. $translation->set_translation($variable_name);
  180. $translation->set_user_id(Session :: get_user_id());
  181. $translation->set_date($this->time);
  182. $translation->update();
  183. }
  184. else
  185. {
  186. $text = $variable_name;
  187. $text = Utilities :: camelcase_to_underscores($text);
  188. $text = str_replace('_', ' ', $text);
  189. $text = ucfirst($text);
  190. $words = explode(' ', $text);
  191. if (end($words) == 'component')
  192. {
  193. $text = ucfirst($words[count($words) - 2]);
  194. }
  195. $translation->set_translation($text);
  196. $translation->set_user_id(Session :: get_user_id());
  197. $translation->set_date($this->time);
  198. $translation->update();
  199. }
  200. }
  201. }
  202. }
  203. public function ucfirst()
  204. {
  205. $language = $this->get_language($this->get_lang());
  206. $translations = $this->get_translations($language);
  207. if ($translations)
  208. {
  209. while ($translation = $translations->next_result())
  210. {
  211. $text = ucfirst($translation->get_translation());
  212. $translation->set_translation($text);
  213. $translation->set_user_id(Session :: get_user_id());
  214. $translation->set_date($this->time);
  215. $translation->update();
  216. }
  217. }
  218. }
  219. public function cleanup_39()
  220. {
  221. $language = $this->get_language($this->get_lang());
  222. $translations = $this->get_translations($language);
  223. if ($translations)
  224. {
  225. while ($translation = $translations->next_result())
  226. {
  227. $text = $translation->get_translation();
  228. $text = str_replace('&#39;', "'", $text);
  229. $translation->set_translation($text);
  230. $translation->set_user_id(Session :: get_user_id());
  231. $translation->set_date($this->time);
  232. $translation->update();
  233. }
  234. }
  235. }
  236. /**
  237. * Look for translations in other packages with the same key.
  238. */
  239. public function guess()
  240. {
  241. $language = $this->get_language($this->lang);
  242. $translations = $this->get_translations($language);
  243. $dm = CdaDataManager :: get_instance();
  244. if ($translations)
  245. {
  246. while ($translation = $translations->next_result())
  247. {
  248. $text = trim($translation->get_translation());
  249. if (! empty($text))
  250. {
  251. continue;
  252. }
  253. $variable = $dm->retrieve_variable($translation->get_variable_id());
  254. $variable_name = $variable->get_variable();
  255. $condition = new EqualityCondition(Variable :: PROPERTY_VARIABLE, $variable_name);
  256. $variables = $dm->retrieve_variables($condition);
  257. while ($variable = $variables->next_result())
  258. {
  259. $t = $this->get_translation($language, $variable, '');
  260. $text = trim($t->get_translation());
  261. if (! empty($text))
  262. {
  263. $translation->set_translation($text);
  264. $translation->set_user_id(Session :: get_user_id());
  265. $translation->set_date($this->time);
  266. $translation->update();
  267. }
  268. }
  269. }
  270. }
  271. }
  272. /**
  273. * Generate two files: translation ids plus master translation (english)
  274. * To be used with an auto translation service.
  275. * The files are
  276. * translation/guess_id
  277. * translation/guess_en
  278. */
  279. public function generate_guess_files()
  280. {
  281. $master_language_code = self :: master()->get_lang();
  282. $master_language = $this->get_language($master_language_code);
  283. $language = $this->get_language($this->lang);
  284. $translations = $this->get_translations($language);
  285. $master_lines = array();
  286. $master_ids = array();
  287. if ($translations)
  288. {
  289. while ($translation = $translations->next_result())
  290. {
  291. $text = trim($translation->get_translation());
  292. if ($text)
  293. {
  294. continue;
  295. }
  296. $master_translation = $this->get_translation($master_language, $translation->get_variable_id(), '');
  297. $master_text = trim($master_translation->get_translation());
  298. if (empty($master_text))
  299. {
  300. continue;
  301. }
  302. $master_lines[] = $master_text;
  303. $master_ids[] = $translation->get_id();
  304. }
  305. }
  306. $glue = "\n";
  307. $path = dirname(__FILE__) . '/../translations/';
  308. file_put_contents($path . 'guess_id', implode($glue, $master_ids));
  309. file_put_contents($path . 'guess_en', implode($glue, $master_lines));
  310. }
  311. /**
  312. * Import files translated.
  313. * 1 generate the files through generate guess_file
  314. * 2 pass guess_en through a translation service
  315. * 3 rename the translation to guess_langcode
  316. * 4 run this function
  317. *
  318. */
  319. public function import_guess_files()
  320. {
  321. $glue = "\n";
  322. $path = dirname(__FILE__) . '/../translations/';
  323. $id_text = file_get_contents($path . 'guess_id', implode($glue, $master_ids));
  324. $trad_text = file_get_contents($path . 'guess_' . $this->lang, implode($glue, $master_lines));
  325. $ids = explode($glue, $id_text);
  326. $lines = explode($glue, $trad_text);
  327. $dm = CdaDataManager :: get_instance();
  328. foreach ($lines as $index => $line)
  329. {
  330. if (empty($line))
  331. {
  332. continue;
  333. }
  334. $id = $ids[$index];
  335. $translation = $dm->retrieve_variable_translation($id);
  336. $current_translation = trim($translation->get_translation());
  337. if ($current_translation)
  338. {
  339. continue;
  340. }
  341. $translation->set_translation($line);
  342. $translation->set_user_id(Session :: get_user_id());
  343. $translation->set_date($this->time);
  344. $translation->update();
  345. }
  346. }
  347. /**
  348. * Copy a language to another. Do not copy the translations. Only the keys.
  349. *
  350. * @param string $from_lang Iso code
  351. */
  352. public function copy($from_lang)
  353. {
  354. $from_language = $this->get_language($from_lang);
  355. $language = $this->get_language($this->lang);
  356. $translations = $this->get_translations($from_language);
  357. if ($translations)
  358. {
  359. $dm = CdaDataManager :: get_instance();
  360. $user_id = Session :: get_user_id();
  361. while ($translation = $translations->next_result())
  362. {
  363. $conditions = array();
  364. $conditions[] = new EqualityCondition(VariableTranslation :: PROPERTY_LANGUAGE_ID, $language->get_id());
  365. $conditions[] = new EqualityCondition(VariableTranslation :: PROPERTY_VARIABLE_ID, $translation->get_variable_id());
  366. $condition = new AndCondition($conditions);
  367. $result = $dm->retrieve_variable_translations($condition)->next_result();
  368. if (! $result)
  369. {
  370. $result = new VariableTranslation();
  371. $result->set_language_id($language->get_id());
  372. $result->set_variable_id($translation->get_variable_id());
  373. $result->set_translation('');
  374. $result->set_user_id($user_id);
  375. $result->set_date($this->time);
  376. //$result->set_status(VariableTranslation::STATUS_NORMAL);
  377. $result->create();
  378. if ($this->verbose)
  379. {
  380. echo __FUNCTION__ . "<br/>";
  381. }
  382. }
  383. }
  384. }
  385. }
  386. protected function iter($root = null, $continuation)
  387. {
  388. $root = $root ? $root : self :: get_root();
  389. $directories = Filesystem :: get_directory_content($root, Filesystem :: LIST_DIRECTORIES, false);
  390. foreach ($directories as $dir)
  391. {
  392. $path = $root . '/' . $dir;
  393. if (substr($dir, 0, 1) == '.' || $dir == 'php' || $dir == 'css')
  394. {
  395. continue;
  396. }
  397. else
  398. if ($dir == self :: TRANSLATION_DIR)
  399. {
  400. call_user_func($continuation, $path);
  401. }
  402. else
  403. {
  404. $this->iter($path, $continuation);
  405. }
  406. }
  407. }
  408. /**
  409. *
  410. * @param string $dir
  411. */
  412. protected function import_files($dir)
  413. {
  414. $dir = realpath($dir);
  415. $items = array_reverse(explode(DIRECTORY_SEPARATOR, $dir));
  416. $app_name = $items[2];
  417. $is_application = $items[3] != 'chamilo';
  418. $lang_path = $dir . '/' . $this->lang . '.' . self :: EXT;
  419. $translations = $this->read_files($lang_path);
  420. $language_pack = $this->get_language_pack($app_name, $is_application);
  421. $language = $this->get_language($this->lang);
  422. foreach ($translations as $key => $translation)
  423. {
  424. $variable = $this->get_variable($language_pack, $key);
  425. $this->update_translation($language, $variable, $translation);
  426. }
  427. }
  428. protected function export_files($dir)
  429. {
  430. $dir = realpath($dir);
  431. $items = array_reverse(explode(DIRECTORY_SEPARATOR, $dir));
  432. $app_name = $items[2];
  433. $is_application = $items[3] != 'chamilo';
  434. $lang_path = $dir . '/' . $this->lang . '.' . self :: EXT;
  435. $translations = $this->read_files($lang_path);
  436. $language_pack = $this->get_language_pack($app_name, $is_application);
  437. $variables = $this->get_language_pack_variables($language_pack);
  438. $language = $this->get_language($this->lang);
  439. while ($variable = $variables->next_result())
  440. {
  441. $translation = $this->get_translation($language, $variable, '');
  442. $text = trim($translation->get_translation());
  443. $key = $variable->get_variable();
  444. if (! empty($text) || $this->overwrite || ! isset($translations[$key]))
  445. {
  446. $translations[$key] = $text;
  447. }
  448. }
  449. $this->write_file($lang_path, $translations);
  450. if ($this->verbose)
  451. {
  452. echo __FUNCTION__ . " $app_name <br/>";
  453. }
  454. }
  455. /**
  456. *
  457. * @param string $iso
  458. * @return CdaLanguage
  459. */
  460. protected function get_language($iso)
  461. {
  462. $dm = CdaDataManager :: get_instance();
  463. $condition = new EqualityCondition(CdaLanguage :: PROPERTY_ISOCODE, $iso);
  464. $language = $dm->retrieve_cda_languages($condition)->next_result();
  465. if (! $language)
  466. {
  467. $language = new CdaLanguage();
  468. $language->set_english_name($iso);
  469. $language->set_original_name($iso);
  470. $language->set_rtl(0);
  471. $language->set_isocode($iso);
  472. $language->create();
  473. }
  474. return $language;
  475. }
  476. /**
  477. *
  478. * @param string $language_pack_name
  479. * @param bool $is_application
  480. * @return LanguagePack
  481. */
  482. protected function get_language_pack($language_pack_name, $is_application)
  483. {
  484. $dm = CdaDataManager :: get_instance();
  485. $conditions[] = new EqualityCondition(LanguagePack :: PROPERTY_NAME, $language_pack_name);
  486. $conditions[] = new EqualityCondition(LanguagePack :: PROPERTY_BRANCH, $this->get_branch());
  487. $condition = new AndCondition($conditions);
  488. $language_pack = $dm->retrieve_language_packs($condition)->next_result();
  489. if (! $language_pack)
  490. {
  491. $language_pack = new LanguagePack();
  492. $language_pack->set_branch($this->get_branch());
  493. $language_pack->set_name($language_pack_name);
  494. $language_pack->set_type($is_application ? LanguagePack :: TYPE_APPLICATION : LanguagePack :: TYPE_CORE);
  495. $language_pack->create();
  496. }
  497. return $language_pack;
  498. }
  499. /**
  500. *
  501. * @param LanguagePack $language_pack
  502. * @param string $variable_name
  503. * @return Variable
  504. */
  505. protected function get_variable($language_pack, $variable_name)
  506. {
  507. $dm = CdaDataManager :: get_instance();
  508. $conditions[] = new EqualityCondition(Variable :: PROPERTY_LANGUAGE_PACK_ID, $language_pack->get_id());
  509. $conditions[] = new EqualityCondition(Variable :: PROPERTY_VARIABLE, $variable_name);
  510. $condition = new AndCondition($conditions);
  511. $variable = $dm->retrieve_variables($condition)->next_result();
  512. if (! $variable)
  513. {
  514. $variable = new Variable();
  515. $variable->set_language_pack_id($language_pack->get_id());
  516. $variable->set_variable($variable_name);
  517. $variable->create();
  518. }
  519. return $variable;
  520. }
  521. /**
  522. *
  523. * @param CdaLanguage|string $language
  524. * @param Variable|string $variable
  525. * @param string $translation
  526. * @return VariableTranslation
  527. */
  528. protected function update_translation($language, $variable, $translation)
  529. {
  530. $dm = CdaDataManager :: get_instance();
  531. $language_id = is_object($language) ? $language->get_id() : $language;
  532. $variable_id = is_object($variable) ? $variable->get_id() : $variable;
  533. $conditions[] = new EqualityCondition(VariableTranslation :: PROPERTY_LANGUAGE_ID, $language_id);
  534. $conditions[] = new EqualityCondition(VariableTranslation :: PROPERTY_VARIABLE_ID, $variable_id);
  535. $condition = new AndCondition($conditions);
  536. $result = $dm->retrieve_variable_translations($condition)->next_result();
  537. if ($result)
  538. {
  539. if (empty($translation))
  540. {
  541. return;
  542. }
  543. $current_translation = trim($result->get_translation());
  544. if ($this->overwrite || empty($current_translation))
  545. {
  546. $result->set_translation($translation);
  547. $result->set_user_id(Session :: get_user_id());
  548. $result->set_date($this->time);
  549. $result->update();
  550. }
  551. }
  552. else
  553. {
  554. $result = new VariableTranslation();
  555. $result->set_language_id($language_id);
  556. $result->set_variable_id($variable_id);
  557. $result->set_translation($translation);
  558. $result->set_user_id(Session :: get_user_id());
  559. $result->set_date($this->time);
  560. //$result->set_status(VariableTranslation::STATUS_NORMAL);
  561. $result->create();
  562. }
  563. if ($this->verbose)
  564. {
  565. echo __FUNCTION__ . " {$variable_id} = $translation <br/>";
  566. }
  567. return $result;
  568. }
  569. /**
  570. *
  571. * @param CdaLanguage|string $language
  572. * @param Variable|string $variable
  573. * @param string $translation
  574. * @return VariableTranslation
  575. */
  576. protected function get_translation($language, $variable, $translation)
  577. {
  578. $dm = CdaDataManager :: get_instance();
  579. $language_id = is_object($language) ? $language->get_id() : $language;
  580. $variable_id = is_object($variable) ? $variable->get_id() : $variable;
  581. $conditions[] = new EqualityCondition(VariableTranslation :: PROPERTY_LANGUAGE_ID, $language_id);
  582. $conditions[] = new EqualityCondition(VariableTranslation :: PROPERTY_VARIABLE_ID, $variable_id);
  583. $condition = new AndCondition($conditions);
  584. $result = $dm->retrieve_variable_translations($condition)->next_result();
  585. if (! $result)
  586. {
  587. $result = new VariableTranslation();
  588. $result->set_language_id($language_id);
  589. $result->set_variable_id($variable_id);
  590. $result->set_translation($translation);
  591. $result->set_user_id(Session :: get_user_id());
  592. $result->set_date($this->time);
  593. // $result->set_status(VariableTranslation::STATUS_NORMAL);
  594. $result->create();
  595. }
  596. return $result;
  597. }
  598. /**
  599. *
  600. * @param type $language_pack
  601. * @return type
  602. */
  603. protected function get_language_pack_variables($language_pack)
  604. {
  605. $dm = CdaDataManager :: get_instance();
  606. $condition = new EqualityCondition(Variable :: PROPERTY_LANGUAGE_PACK_ID, $language_pack->get_id());
  607. $result = $dm->retrieve_variables($condition);
  608. return $result;
  609. }
  610. protected function get_translations($language)
  611. {
  612. $dm = CdaDataManager :: get_instance();
  613. $condition = new EqualityCondition(VariableTranslation :: PROPERTY_LANGUAGE_ID, $language->get_id());
  614. $result = $dm->retrieve_variable_translations($condition);
  615. return $result;
  616. }
  617. /**
  618. *
  619. * @param string $path
  620. * @return array
  621. */
  622. protected function read_files($path)
  623. {
  624. $strings = is_readable($path) ? parse_ini_file($path) : array();
  625. // $from_strings = is_readable($form_path) ? parse_ini_file($form_path) : array();
  626. // $result = $from_strings;
  627. foreach ($strings as $key => $value)
  628. {
  629. $result[$key] = $value;
  630. }
  631. return $result;
  632. }
  633. /**
  634. *
  635. * @param string $path
  636. * @param array $values
  637. */
  638. protected function write_file($path, $values)
  639. {
  640. ksort($values);
  641. $lines = array();
  642. foreach ($values as $key => $value)
  643. {
  644. $value = str_replace('"', '\"', $value);
  645. $lines[] = $key . ' = "' . $value . '"';
  646. }
  647. $content = implode(StringUtilities :: NEW_LINE, $lines);
  648. Filesystem :: write_to_file($path, $content, false);
  649. }
  650. }
  651. ?>