Advertisement
Guest User

Untitled

a guest
Jan 18th, 2017
83
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 11.96 KB | None | 0 0
  1. <?php
  2.  
  3. namespace WebBundle\Command;
  4.  
  5. use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
  6. use Symfony\Component\Console\Input\InputInterface;
  7. use Symfony\Component\Console\Input\InputOption;
  8. use Symfony\Component\Console\Output\OutputInterface;
  9. use Symfony\Component\Yaml\Parser;
  10. use Symfony\Component\Yaml\Dumper;
  11.  
  12. /**
  13. * Generic and extremely basic Symfony console command that merges translation files in src/<bundle>/Resources/translations/ directories
  14. * with translation files in the app/Resources/translations/ directory.
  15. *
  16. * Expected behaviour:
  17. * 1 - You have some translation files in src/<bundle>/Resources/translations/, but no translation files in app/Resources/translations/:
  18. * ---- This command will create a copy of translation files in src/<bundle>/Resources/translations/ in app/Resources/translations/.
  19. * Having translation files with identical filenames in multiple bundle folders will result in a merged copy, with duplicate key/value
  20. * pairs being overwritten by one another.
  21. *
  22. * 2 - You have some translation files in src/<bundle>/Resources/translations/ as well as translation files in app/Resources/translations/:
  23. * ---- This command will merge the translation files in app/Resources/translations/ with a copy of translation files in
  24. * src/<bundle>/Resources/translations/. Key/value pairs from the translation files in app/Resources/translations/ will have priority,
  25. * so no edited translations should be lost. The behaviour from (1) still applies.
  26. *
  27. * @author Kalman Olah <hello _AT_ kalmanolah _DOT_ net>
  28. */
  29. class TranslationMergeCommand extends ContainerAwareCommand
  30. {
  31. private $container;
  32.  
  33. private $input;
  34. private $output;
  35.  
  36. private $yaml_parser;
  37. private $yaml_dumper;
  38.  
  39. private $source_only;
  40.  
  41. private $base_dir;
  42.  
  43. private $source_dir;
  44. private $vendor_dir;
  45. private $target_dir;
  46.  
  47. private $translations_dir;
  48.  
  49. private $cache;
  50. private $cache_merged;
  51.  
  52. const LN_INFO = 'info';
  53. const LN_ERROR = 'error';
  54. const LN_COMMENT = 'comment';
  55. const LN_QUESTION = 'question';
  56.  
  57. const DS = DIRECTORY_SEPARATOR;
  58.  
  59. const YAML_INLINE = 10;
  60.  
  61. protected function configure()
  62. {
  63. $this
  64. ->setName('translations:merge')
  65. ->setDescription('Merges translation files in the src/<bundle>/Resources/translations/ folder with translation files in the app/Resources/translations/ folder')
  66. ->addOption(
  67. 'source-only',
  68. null,
  69. InputOption::VALUE_OPTIONAL,
  70. 'Should this command only look for bundles in the src/ folder? [TRUE/false]',
  71. true
  72. );
  73. }
  74.  
  75. protected function execute(InputInterface $input, OutputInterface $output)
  76. {
  77. $this->container = $this->getContainer();
  78.  
  79. $this->input = $input;
  80. $this->output = $output;
  81.  
  82. $this->yaml_parser = new Parser();
  83. $this->yaml_dumper = new Dumper();
  84.  
  85. $this->source_only = $this->getOption('source-only') == 'true';
  86.  
  87. $this->base_dir = $this->container->get('kernel')->getRootDir().self::DS.'..'.self::DS;
  88.  
  89. $this->source_dir = $this->base_dir.'src'.self::DS;
  90. $this->vendor_dir = $this->base_dir.'vendor'.self::DS;
  91. $this->target_dir = $this->base_dir.'app'.self::DS;
  92.  
  93. $this->translations_dir = 'Resources'.self::DS.'translations'.self::DS;
  94.  
  95. $this->cache = array();
  96. $this->cache_merged = array();
  97.  
  98. $this->performCommand();
  99. }
  100.  
  101. private function println($string = '', $style = null, $indent = false)
  102. {
  103. if ($indent) {
  104. if (is_bool($indent)) {
  105. $indent = 4;
  106. }
  107. $indenting = '';
  108. while ($indent > 0) {
  109. $indenting .= ' ';
  110. --$indent;
  111. }
  112. $string = $indenting.$string;
  113. }
  114.  
  115. if ($style !== null) {
  116. $string = '<'.$style.'>'.$string.'</'.$style.'>';
  117. }
  118.  
  119. $this->output->writeln($string);
  120. }
  121.  
  122. private function getOption($name)
  123. {
  124. return $this->input->getOption($name);
  125. }
  126.  
  127. private function performCommand()
  128. {
  129. $this->println();
  130. $this->println('Beginning the merging of translation files..', self::LN_INFO);
  131. $this->println();
  132.  
  133. $this->println('Searching for bundles..', self::LN_COMMENT, 2);
  134.  
  135. $bundles = $this->getBundles();
  136. $this->println('Found <comment>'.count($bundles).'</comment> bundle(s). Attempting to loop..', null, 2);
  137. $this->println();
  138.  
  139. if (count($bundles) == 0) {
  140. $this->println('No bundles were found, not looping.', null, 4);
  141. $this->println();
  142. } else {
  143. foreach ($bundles as $bundle) {
  144. if ($this->source_only && !$bundle[1]) {
  145. $this->println('Skipping bundle <question>'.$bundle[0].'</question> since it\'s not part of the source folder.', null, 4);
  146. $this->println();
  147. } else {
  148. $this->println('Looking for translation files in bundle <comment>'.$bundle[0].'</comment>..', self::LN_INFO, 4);
  149.  
  150. $bundle_trans_dir = $bundle[0].$this->translations_dir;
  151.  
  152. $this->println('Searching in <comment>'.$bundle_trans_dir.'</comment>..', null, 4);
  153.  
  154. $bundle_trans_path = $bundle[1] ? $this->source_dir : $this->vendor_dir;
  155. $bundle_trans_path .= $bundle_trans_dir;
  156.  
  157. if (!is_dir($bundle_trans_path)) {
  158. $this->println('The directory does not exist. Skipping.', null, 4);
  159. $this->println();
  160. } else {
  161. $translations = $this->getTranslationFiles($bundle_trans_path);
  162. $this->println('Found <comment>'.count($translations).'</comment> translation file(s). Attempting to loop..', null, 4);
  163. $this->println();
  164.  
  165. if (count($translations) === 0) {
  166. $this->println('No translation files were found, not looping.', null, 6);
  167. $this->println();
  168. } else {
  169. foreach ($translations as $translation) {
  170. $this->cacheTranslationFile($bundle[0], $bundle_trans_path, $translation);
  171. $this->println('Added parsed content of <info>'.$translation.'</info> to cache.', null, 6);
  172. }
  173. $this->println();
  174. }
  175. }
  176. }
  177. }
  178.  
  179. $this->println('Attempting to merge cached translation file content..', self::LN_COMMENT, 2);
  180.  
  181. $count = $this->getCachedTranslationFileCount();
  182. if ($count == 0) {
  183. $this->println('No cached translation files found. Skipping.', null, 2);
  184. $this->println();
  185. } else {
  186. $this->println('Merging <comment>'.$count.'</comment> translation file(s)..', null, 2);
  187. $this->println();
  188.  
  189. foreach ($this->cache as $file => $variants) {
  190. $this->mergeAndCacheTranslationFiles($file, array_values($variants));
  191. $this->println('Successfully merged <info>'.count($variants).'</info> variant(s) of <info>'.$file.'</info>.', null, 4);
  192. }
  193.  
  194. $this->println();
  195. }
  196.  
  197. $this->println('Attempting to write merged translation files..', self::LN_COMMENT, 2);
  198.  
  199. $count = count($this->cache_merged);
  200. if ($count == 0) {
  201. $this->println('No merged translation files found. Skipping.', null, 2);
  202. $this->println();
  203. } else {
  204. $this->println('Writing <comment>'.$count.'</comment> merged translation file(s)..', null, 2);
  205.  
  206. $write_path = $this->target_dir.$this->translations_dir;
  207.  
  208. $this->println('Writing to <comment>'.$write_path.'</comment>..', null, 2);
  209.  
  210. if (!is_dir($write_path)) {
  211. $this->println('The directory does not exist. Attempting to create it.', null, 2);
  212. mkdir($write_path, 0777, true);
  213. }
  214.  
  215. $this->println();
  216.  
  217. foreach ($this->cache_merged as $file => $content) {
  218. $this->println('Trying to write <info>'.$file.'</info>..', null, 4);
  219.  
  220. if (file_exists($write_path.$file)) {
  221. $this->println('The output file already exists. Merging contents..', null, 6);
  222.  
  223. $original_content = $this->getParsedTranslationFileContent($write_path, $file);
  224. $this->mergeAndCacheTranslationFiles($file, array($content, $original_content));
  225. }
  226.  
  227. $this->writeMergedTranslationFile($write_path, $file);
  228.  
  229. $this->println('Done!', self::LN_INFO, 6);
  230. }
  231.  
  232. $this->println();
  233. }
  234. }
  235.  
  236. $this->println('Merging of translation files was completed successfully.', self::LN_INFO);
  237. $this->println();
  238. }
  239.  
  240. private function getBundles()
  241. {
  242. $return = array();
  243.  
  244. $bundles = $this->container->getParameter('kernel.bundles');
  245.  
  246. foreach ($bundles as $bundle) {
  247. $bundle_split = explode('\\', $bundle);
  248.  
  249. $bundle_file = array_values($bundle_split);
  250. $bundle_file = end($bundle_file).'.php';
  251. $bundle_path = implode(self::DS, array_slice($bundle_split, 0, -1)).self::DS;
  252.  
  253. $bundle_in_source = file_exists($this->source_dir.$bundle_path.$bundle_file);
  254.  
  255. array_push($return, array($bundle_path, $bundle_in_source));
  256. }
  257.  
  258. return $return;
  259. }
  260.  
  261. private function getTranslationFiles($path)
  262. {
  263. $return = array();
  264.  
  265. if ($handle = opendir($path)) {
  266. while (($file = readdir($handle)) !== false) {
  267. // We're only going to read files ending in .yml
  268. if (preg_match('/.*\.yml$/', $file)) {
  269. array_push($return, $file);
  270. }
  271. }
  272. closedir($handle);
  273. }
  274.  
  275. return $return;
  276. }
  277.  
  278. private function getCachedTranslationFileCount()
  279. {
  280. $count = 0;
  281.  
  282. foreach ($this->cache as $tmp) {
  283. foreach ($tmp as $tmp_tmp) {
  284. ++$count;
  285. }
  286. }
  287.  
  288. return $count;
  289. }
  290.  
  291. private function getParsedTranslationFileContent($path, $file)
  292. {
  293. $content = file_get_contents($path.$file);
  294. $content_parsed = $this->yaml_parser->parse($content);
  295.  
  296. return $content_parsed;
  297. }
  298.  
  299. private function cacheTranslationFile($bundle, $path, $file)
  300. {
  301. if (!array_key_exists($file, $this->cache)) {
  302. $this->cache[$file] = array();
  303. }
  304.  
  305. $content_parsed = $this->getParsedTranslationFileContent($path, $file);
  306.  
  307. $this->cache[$file][$bundle] = $content_parsed;
  308. }
  309.  
  310. private function mergeAndCacheTranslationFiles($file, $variants)
  311. {
  312. $merged = array();
  313.  
  314. for ($i = 0; $i < count($variants); ++$i) {
  315. $merged = $this->mergeDistinctlyAndRecursively($merged, $variants[$i]);
  316. }
  317.  
  318. $this->cache_merged[$file] = $merged;
  319. }
  320.  
  321. private function mergeDistinctlyAndRecursively(&$array1, &$array2)
  322. {
  323. $return = $array1;
  324.  
  325. foreach ($array2 as $key => &$value) {
  326. if (is_array($value) && isset($return[$key]) && is_array($return[$key])) {
  327. $return[$key] = $this->mergeDistinctlyAndRecursively($return[$key], $value);
  328. } else {
  329. $return[$key] = $value;
  330. }
  331. }
  332.  
  333. return $return;
  334. }
  335.  
  336. private function writeMergedTranslationFile($path, $file)
  337. {
  338. $content = $this->cache_merged[$file];
  339. $content_dumped = $this->yaml_dumper->dump($content, self::YAML_INLINE);
  340. file_put_contents($path.$file, $content_dumped);
  341. }
  342. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement