strip_language_file.php 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. #!/usr/bin/env php
  2. <?php
  3. /* Copyright (C) 2014 by FromDual GmbH, licensed under GPL v2
  4. * Copyright (C) 2014 Laurent Destailleur <eldy@users.sourceforge.net>
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. *
  19. * -----
  20. *
  21. * Compares a secondary language translation file with its primary
  22. * language file and strips redundant translations.
  23. *
  24. * Todo: Check if it works with multi byte (mb_*) character sets!
  25. *
  26. * Usage:
  27. * cd htdocs/langs
  28. * ./dev/translation/strip_language_file.php <primary_lang_dir> <secondary_lang_dir> [file.lang|all]
  29. *
  30. * To rename all .delta files, you can do
  31. * for fic in `ls *.delta`; do f=`echo $fic | sed -e 's/\.delta//'`; echo $f; mv $f.delta $f; done
  32. *
  33. * Rules:
  34. * secondary string == primary string -> strip
  35. * secondary string redundant -> strip and warning
  36. * secondary string not in primary -> strip and warning
  37. * secondary string has no value -> strip and warning
  38. * secondary string != primary string -> secondary.lang.delta
  39. */
  40. /**
  41. * \file dev/translation/strip_language_file.php
  42. * \ingroup dev
  43. * \brief This script clean sub-languages from duplicate keys-values
  44. */
  45. $sapi_type = php_sapi_name();
  46. $script_file = basename(__FILE__);
  47. $path=dirname(__FILE__).'/';
  48. // Test if batch mode
  49. if (substr($sapi_type, 0, 3) == 'cgi') {
  50. echo "Error: You are using PHP for CGI. To execute ".$script_file." from command line, you must use PHP for CLI mode.\n";
  51. exit;
  52. }
  53. $rc = 0;
  54. // Get and check arguments
  55. $lPrimary = isset($argv[1])?$argv[1]:'';
  56. $lSecondary = isset($argv[2])?$argv[2]:'';
  57. $lEnglish = 'en_US';
  58. $filesToProcess = isset($argv[3])?$argv[3]:'';
  59. if (empty($lPrimary) || empty($lSecondary) || empty($filesToProcess))
  60. {
  61. $rc = 1;
  62. $msg = '***** Script to clean language files *****'."\n";
  63. $msg.= 'Usage: ./dev/translation/strip_language_file.php xx_XX xx_YY [file.lang|all]'."\n";
  64. print $msg . "(rc=$rc).\n";
  65. exit($rc);
  66. }
  67. $aPrimary = array();
  68. $aSecondary = array();
  69. $aEnglish = array();
  70. // Define array $filesToProcess
  71. if ($filesToProcess == 'all')
  72. {
  73. $dir = new DirectoryIterator('htdocs/langs/'.$lPrimary);
  74. while($dir->valid()) {
  75. if(!$dir->isDot() && $dir->isFile() && ! preg_match('/^\./',$dir->getFilename())) {
  76. $files[] = $dir->getFilename();
  77. }
  78. $dir->next();
  79. }
  80. $filesToProcess=$files;
  81. }
  82. else $filesToProcess=explode(',',$filesToProcess);
  83. // Arguments should be OK here.
  84. // Loop on each file
  85. foreach($filesToProcess as $fileToProcess)
  86. {
  87. $lPrimaryFile = 'htdocs/langs/'.$lPrimary.'/'.$fileToProcess;
  88. $lSecondaryFile = 'htdocs/langs/'.$lSecondary.'/'.$fileToProcess;
  89. $lEnglishFile = 'htdocs/langs/'.$lEnglish.'/'.$fileToProcess;
  90. $output = $lSecondaryFile . '.delta';
  91. print "---- Process language file ".$lSecondaryFile."\n";
  92. if ( ! is_readable($lPrimaryFile) ) {
  93. $rc = 2;
  94. $msg = "Cannot read primary language file $lPrimaryFile.";
  95. print $msg . " (rc=$rc).\n";
  96. exit($rc);
  97. }
  98. if ( ! is_readable($lSecondaryFile) ) {
  99. $rc = 3;
  100. $msg = "Cannot read secondary language file $lSecondaryFile. We discard this file.";
  101. print $msg . "\n";
  102. continue;
  103. }
  104. if ( ! is_readable($lEnglishFile) ) {
  105. $rc = 3;
  106. $msg = "Cannot read english language file $lEnglishFile. We discard this file.";
  107. print $msg . "\n";
  108. continue;
  109. }
  110. // Start reading and parsing Secondary
  111. if ( $handle = fopen($lSecondaryFile, 'r') )
  112. {
  113. print "Read Secondary File $lSecondaryFile:\n";
  114. $cnt = 0;
  115. while (($line = fgets($handle)) !== false)
  116. {
  117. $cnt++;
  118. // strip comments
  119. if ( preg_match("/^\w*#/", $line) ) {
  120. continue;
  121. }
  122. // strip empty lines
  123. if ( preg_match("/^\w*$/", $line) ) {
  124. continue;
  125. }
  126. $a = mb_split('=', trim($line), 2);
  127. if ( count($a) != 2 ) {
  128. print "ERROR in file $lSecondaryFile, line $cnt: " . trim($line) . "\n";
  129. continue;
  130. }
  131. list($key, $value) = $a;
  132. // key is redundant
  133. if ( array_key_exists($key, $aSecondary) ) {
  134. print "Key $key is redundant in file $lSecondaryFile (line: $cnt).\n";
  135. continue;
  136. }
  137. // String has no value
  138. if ( $value == '' ) {
  139. print "Key $key has no value in file $lSecondaryFile (line: $cnt).\n";
  140. continue;
  141. }
  142. $aSecondary[$key] = trim($value);
  143. }
  144. if ( ! feof($handle) )
  145. {
  146. $rc = 5;
  147. $msg = "Unexpected fgets() fail";
  148. print $msg . " (rc=$rc).\n";
  149. exit($rc);
  150. }
  151. fclose($handle);
  152. }
  153. else {
  154. $rc = 6;
  155. $msg = "Cannot open file $lSecondaryFile";
  156. print $msg . " (rc=$rc).\n";
  157. exit($rc);
  158. }
  159. // Start reading and parsing English
  160. if ( $handle = fopen($lEnglishFile, 'r') )
  161. {
  162. print "Read English File $lEnglishFile:\n";
  163. $cnt = 0;
  164. while (($line = fgets($handle)) !== false)
  165. {
  166. $cnt++;
  167. // strip comments
  168. if ( preg_match("/^\w*#/", $line) ) {
  169. continue;
  170. }
  171. // strip empty lines
  172. if ( preg_match("/^\w*$/", $line) ) {
  173. continue;
  174. }
  175. $a = mb_split('=', trim($line), 2);
  176. if ( count($a) != 2 ) {
  177. print "ERROR in file $lEnglishFile, line $cnt: " . trim($line) . "\n";
  178. continue;
  179. }
  180. list($key, $value) = $a;
  181. // key is redundant
  182. if ( array_key_exists($key, $aEnglish) ) {
  183. print "Key $key is redundant in file $lEnglishFile (line: $cnt).\n";
  184. continue;
  185. }
  186. // String has no value
  187. if ( $value == '' ) {
  188. print "Key $key has no value in file $lEnglishFile (line: $cnt).\n";
  189. continue;
  190. }
  191. $aEnglish[$key] = trim($value);
  192. }
  193. if ( ! feof($handle) )
  194. {
  195. $rc = 5;
  196. $msg = "Unexpected fgets() fail";
  197. print $msg . " (rc=$rc).\n";
  198. exit($rc);
  199. }
  200. fclose($handle);
  201. }
  202. else {
  203. $rc = 6;
  204. $msg = "Cannot open file $lEnglishFile";
  205. print $msg . " (rc=$rc).\n";
  206. exit($rc);
  207. }
  208. // Start reading and parsing Primary. See rules in header!
  209. $arrayofkeytoalwayskeep=array('DIRECTION','FONTFORPDF','FONTSIZEFORPDF','SeparatorDecimal','SeparatorThousand');
  210. if ( $handle = fopen($lPrimaryFile, 'r') )
  211. {
  212. if ( ! $oh = fopen($output, 'w') )
  213. {
  214. print "ERROR in writing to file $output\n";
  215. exit;
  216. }
  217. print "Read Primary File $lPrimaryFile and write ".$output.":\n";
  218. fwrite($oh, "# Dolibarr language file - Source file is en_US - ".(preg_replace('/\.lang$/','',$fileToProcess))."\n");
  219. $cnt = 0;
  220. while (($line = fgets($handle)) !== false)
  221. {
  222. $cnt++;
  223. // strip comments
  224. if ( preg_match("/^\w*#/", $line) ) {
  225. continue;
  226. }
  227. // strip empty lines
  228. if ( preg_match("/^\w*$/", $line) ) {
  229. continue;
  230. }
  231. $a = mb_split('=', trim($line), 2);
  232. if ( count($a) != 2 ) {
  233. print "ERROR in file $lPrimaryFile, line $cnt: " . trim($line) . "\n";
  234. continue;
  235. }
  236. list($key, $value) = $a;
  237. // key is redundant
  238. if ( array_key_exists($key, $aPrimary) ) {
  239. print "Key $key is redundant in file $lPrimaryFile (line: $cnt) - Already found into ".$fileFirstFound[$key]." (line: ".$lineFirstFound[$key].").\n";
  240. continue;
  241. }
  242. else
  243. {
  244. $fileFirstFound[$key] = $fileToProcess;
  245. $lineFirstFound[$key] = $cnt;
  246. }
  247. // String has no value
  248. if ( $value == '' ) {
  249. print "Key $key has no value in file $lPrimaryFile (line: $cnt).\n";
  250. continue;
  251. }
  252. $aPrimary[$key] = trim($value);
  253. $fileFirstFound[$key] = $fileToProcess;
  254. $lineFirstFound[$key] = $cnt;
  255. // ----- Process output now -----
  256. // Key not in other file
  257. if (in_array($key, $arrayofkeytoalwayskeep) || preg_match('/^FormatDate/',$key) || preg_match('/^FormatHour/',$key))
  258. {
  259. //print "Key $key is a key we always want to see into secondary file (line: $cnt).\n";
  260. }
  261. else if ( ! array_key_exists($key, $aSecondary))
  262. {
  263. //print "Key $key does NOT exist in secondary language (line: $cnt).\n";
  264. continue;
  265. }
  266. // String exists in both files and value into alternative language differs from main language but also from english files
  267. if (
  268. (! empty($aSecondary[$key]) && $aSecondary[$key] != $aPrimary[$key]
  269. && ! empty($aEnglish[$key]) && $aSecondary[$key] != $aEnglish[$key])
  270. || in_array($key, $arrayofkeytoalwayskeep) || preg_match('/^FormatDate/',$key) || preg_match('/^FormatHour/',$key)
  271. )
  272. {
  273. //print "Key $key differs so we add it into new secondary language (line: $cnt).\n";
  274. fwrite($oh, $key."=".(empty($aSecondary[$key])?$aPrimary[$key]:$aSecondary[$key])."\n");
  275. }
  276. }
  277. if ( ! feof($handle) ) {
  278. $rc = 7;
  279. $msg = "Unexpected fgets() fail";
  280. print $msg . " (rc=$rc).\n";
  281. exit($rc);
  282. }
  283. fclose($oh);
  284. fclose($handle);
  285. }
  286. else {
  287. $rc = 8;
  288. $msg = "Cannot open file $lPrimaryFile";
  289. print $msg . " (rc=$rc).\n";
  290. exit($rc);
  291. }
  292. print "Output can be found at $output.\n";
  293. print "To rename all .delta files, you can do:\n";
  294. print '> for fic in `ls htdocs/langs/'.$lSecondary.'/*.delta`; do f=`echo $fic | sed -e \'s/\.delta//\'`; echo $f; mv $f.delta $f; done'."\n";
  295. }
  296. return 0;