sanity_check_en_langfiles.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. #!/usr/bin/env php
  2. <?php
  3. /* Copyright (c) 2015 Tommaso Basilici <t.basilici@19.coop>
  4. * Copyright (c) 2015 Laurent Destailleur <eldy@destailleur.fr>
  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. $sapi_type = php_sapi_name();
  20. $script_file = basename(__FILE__);
  21. $path=dirname(__FILE__).'/';
  22. $web=0;
  23. // Test if batch mode
  24. if (substr($sapi_type, 0, 3) == 'cgi')
  25. {
  26. $web=1;
  27. }
  28. if ($web)
  29. {
  30. echo "<html>";
  31. echo "<head>";
  32. echo "<STYLE type=\"text/css\">
  33. table {
  34. background: #f5f5f5;
  35. border-collapse: separate;
  36. box-shadow: inset 0 1px 0 #fff;
  37. font-size: 12px;
  38. line-height: 24px;
  39. margin: 30px auto;
  40. text-align: left;
  41. width: 800px;
  42. }
  43. th {
  44. background-color: #777;
  45. border-left: 1px solid #555;
  46. border-right: 1px solid #777;
  47. border-top: 1px solid #555;
  48. border-bottom: 1px solid #333;
  49. color: #fff;
  50. font-weight: bold;
  51. padding: 10px 15px;
  52. position: relative;
  53. text-shadow: 0 1px 0 #000;
  54. }
  55. td {
  56. border-right: 1px solid #fff;
  57. border-left: 1px solid #e8e8e8;
  58. border-top: 1px solid #fff;
  59. border-bottom: 1px solid #e8e8e8;
  60. padding: 10px 15px;
  61. position: relative;
  62. }
  63. tr {
  64. background-color: #f1f1f1;
  65. }
  66. tr:nth-child(odd) td {
  67. background-color: #f1f1f1;
  68. }
  69. </STYLE>";
  70. echo "<body>";
  71. }
  72. echo "If you call this with argument \"unused=true\" it searches for the translation strings that exist in en_US but are never used.\n";
  73. if ($web) print "<br>";
  74. echo "IMPORTANT: that can take quite a lot of time (up to 10 minutes), you need to tune the max_execution_time on your php.ini accordingly.\n";
  75. if ($web) print "<br>";
  76. // STEP 1 - Search duplicates keys
  77. // directory containing the php and lang files
  78. $htdocs = $path."../../htdocs/";
  79. $scripts = $path."../../scripts/";
  80. // directory containing the english lang files
  81. $workdir = $htdocs."langs/en_US/";
  82. $files = scandir($workdir);
  83. if (empty($files))
  84. {
  85. echo "Can't scan workdir = ".$workdir;
  86. exit;
  87. }
  88. $dups=array();
  89. $exludefiles = array('.','..','README');
  90. $files = array_diff($files,$exludefiles);
  91. // To force a file: $files=array('myfile.lang');
  92. if (isset($argv[2]))
  93. {
  94. $files = array($argv[2]);
  95. }
  96. $langstrings_3d = array();
  97. $langstrings_full = array();
  98. foreach ($files AS $file) {
  99. $path_file = pathinfo($file);
  100. // we're only interested in .lang files
  101. if ($path_file['extension']=='lang') {
  102. $content = file($workdir.$file);
  103. foreach ($content AS $line => $row) {
  104. // don't want comment lines
  105. if (substr($row,0,1) !== '#') {
  106. // don't want lines without the separator (why should those even be here, anyway...)
  107. if (strpos($row,'=')!==false) {
  108. $row_array = explode('=',$row); // $row_array[0] = key
  109. $langstrings_3d[$path_file['basename']][$line+1]=$row_array[0];
  110. $langstrings_3dtrans[$path_file['basename']][$line+1]=$row_array[1];
  111. $langstrings_full[]=$row_array[0];
  112. $langstrings_dist[$row_array[0]]=$row;
  113. }
  114. }
  115. }
  116. }
  117. }
  118. foreach ($langstrings_3d AS $filename => $file)
  119. {
  120. foreach ($file AS $linenum => $value)
  121. {
  122. $keys = array_keys($langstrings_full, $value);
  123. if (count($keys)>1)
  124. {
  125. foreach ($keys AS $key) {
  126. $dups[$value][$filename][$linenum] = trim($langstrings_3dtrans[$filename][$linenum]);
  127. }
  128. }
  129. }
  130. }
  131. if ($web) print "<h2>";
  132. print "Duplicate strings in lang files in $workdir - ".count($dups)." found\n";
  133. if ($web) print "</h2>";
  134. if ($web)
  135. {
  136. echo '<table border_bottom="1">'."\n";
  137. echo "<thead><tr><th align=\"center\">#</th><th>String</th><th>File and lines</th></thead>\n";
  138. echo "<tbody>\n";
  139. }
  140. $sduplicateinsamefile='';
  141. $sinmainandother='';
  142. $sininstallandadmin='';
  143. $sother='';
  144. $count = 0;
  145. foreach ($dups as $string => $pages)
  146. {
  147. $count++;
  148. $s='';
  149. // Keyword $string
  150. if ($web) $s.="<tr>";
  151. if ($web) $s.="<td align=\"center\">";
  152. if ($web) $s.=$count;
  153. if ($web) $s.="</td>";
  154. if ($web) $s.="<td>";
  155. $s.=$string;
  156. if ($web) $s.="</td>";
  157. if ($web) $s.="<td>";
  158. if (! $web) $s.= ' : ';
  159. // Loop on each files keyword was found
  160. $duplicateinsamefile=0;
  161. $inmain=0;
  162. $inadmin=0;
  163. foreach ($pages AS $file => $lines)
  164. {
  165. if ($file == 'main.lang') { $inmain=1; $inadmin=0; }
  166. if ($file == 'admin.lang' && ! $inmain) { $inadmin=1; }
  167. $s.=$file." ";
  168. // Loop on each line keword was found into file.
  169. $listoffilesforthisentry=array();
  170. foreach ($lines as $line => $translatedvalue)
  171. {
  172. if (! empty($listoffilesforthisentry[$file])) $duplicateinsamefile=1;
  173. $listoffilesforthisentry[$file]=1;
  174. $s.= "(".$line." - ".htmlentities($translatedvalue).") ";
  175. }
  176. if ($web) $s.="<br>";
  177. }
  178. if ($web) $s.="</td></tr>";
  179. $s.="\n";
  180. if ($duplicateinsamefile) $sduplicateinsamefile .= $s;
  181. else if ($inmain) $sinmainandother .= $s;
  182. else if ($inadmin) $sininstallandadmin .= $s;
  183. else $sother .= $s;
  184. }
  185. if (! $web) print "\n***** Entries duplicated in same file\n";
  186. print $sduplicateinsamefile;
  187. if (! $web && empty($sduplicateinsamefile)) print "None\n";
  188. if (! $web) print "\n";
  189. if (! $web) print "***** Entries in main and another (keep only entry in main)\n";
  190. print $sinmainandother;
  191. if (! $web && empty($sinmainandother)) print "None\n";
  192. if (! $web) print "\n";
  193. if (! $web) print "***** Entries in admin and another\n";
  194. print $sininstallandadmin;
  195. if (! $web && empty($sininstallandadmin)) print "None\n";
  196. if (! $web) print "\n";
  197. if (! $web) print "***** Other\n";
  198. print $sother;
  199. if (! $web && empty($sother)) print "None\n";
  200. if (! $web) print "\n";
  201. if ($web)
  202. {
  203. echo "</tbody>\n";
  204. echo "</table>\n";
  205. }
  206. // STEP 2 - Search key not used
  207. if ((! empty($_REQUEST['unused']) && $_REQUEST['unused'] == 'true') || (isset($argv[1]) && $argv[1]=='unused=true'))
  208. {
  209. print "***** Strings in en_US that are never used:\n";
  210. $unused=array();
  211. foreach ($langstrings_dist AS $value => $line)
  212. {
  213. $qualifiedforclean=1;
  214. // Check if we must keep this key to be into file for removal
  215. if (preg_match('/^Module\d+/', $value)) $qualifiedforclean=0;
  216. if (preg_match('/^Permission\d+/', $value)) $qualifiedforclean=0;
  217. if (preg_match('/^PermissionAdvanced\d+/', $value)) $qualifiedforclean=0;
  218. if (preg_match('/^ProfId\d+/', $value)) $qualifiedforclean=0;
  219. if (preg_match('/^Delays_/', $value)) $qualifiedforclean=0;
  220. if (preg_match('/^BarcodeDesc/', $value)) $qualifiedforclean=0;
  221. if (preg_match('/^Extrafield/', $value)) $qualifiedforclean=0;
  222. if (preg_match('/^LocalTax/', $value)) $qualifiedforclean=0;
  223. if (preg_match('/^Country/', $value)) $qualifiedforclean=0;
  224. if (preg_match('/^Civility/', $value)) $qualifiedforclean=0;
  225. if (preg_match('/^Currency/', $value)) $qualifiedforclean=0;
  226. if (preg_match('/^DemandReasonTypeSRC/', $value)) $qualifiedforclean=0;
  227. if (preg_match('/^PaperFormat/', $value)) $qualifiedforclean=0;
  228. if (preg_match('/^Duration/', $value)) $qualifiedforclean=0;
  229. if (preg_match('/^AmountLT/', $value)) $qualifiedforclean=0;
  230. if (preg_match('/^TotalLT/', $value)) $qualifiedforclean=0;
  231. if (preg_match('/^Month/', $value)) $qualifiedforclean=0;
  232. if (preg_match('/^MonthShort/', $value)) $qualifiedforclean=0;
  233. if (preg_match('/^Day\d/', $value)) $qualifiedforclean=0;
  234. if (preg_match('/^Short/', $value)) $qualifiedforclean=0;
  235. if (preg_match('/^ExportDataset_/', $value)) $qualifiedforclean=0;
  236. if (preg_match('/^ImportDataset_/', $value)) $qualifiedforclean=0;
  237. if (preg_match('/^ActionAC_/', $value)) $qualifiedforclean=0;
  238. if (preg_match('/^TypeLocaltax/', $value)) $qualifiedforclean=0;
  239. if (preg_match('/^StatusProspect/', $value)) $qualifiedforclean=0;
  240. if (preg_match('/^PL_/', $value)) $qualifiedforclean=0;
  241. if (preg_match('/^TE_/', $value)) $qualifiedforclean=0;
  242. if (preg_match('/^JuridicalStatus/', $value)) $qualifiedforclean=0;
  243. if (preg_match('/^CalcMode/', $value)) $qualifiedforclean=0;
  244. if (preg_match('/^newLT/', $value)) $qualifiedforclean=0;
  245. if (preg_match('/^LT\d/', $value)) $qualifiedforclean=0;
  246. if (preg_match('/^TypeContact_contrat_/', $value)) $qualifiedforclean=0;
  247. if (preg_match('/^ErrorPriceExpression/', $value)) $qualifiedforclean=0;
  248. if (preg_match('/^Language_/', $value)) $qualifiedforclean=0;
  249. if (preg_match('/^DescADHERENT_/', $value)) $qualifiedforclean=0;
  250. if (preg_match('/^SubmitTranslation/', $value)) $qualifiedforclean=0;
  251. if (preg_match('/^ModuleCompanyCode/', $value)) $qualifiedforclean=0;
  252. // main.lang
  253. if (preg_match('/^Duration/', $value)) $qualifiedforclean=0;
  254. if (preg_match('/^FormatDate/', $value)) $qualifiedforclean=0;
  255. if (preg_match('/^DateFormat/', $value)) $qualifiedforclean=0;
  256. if (preg_match('/^.b$/', $value)) $qualifiedforclean=0;
  257. if (preg_match('/^.*Bytes$/', $value)) $qualifiedforclean=0;
  258. if (preg_match('/^NoteSomeFeaturesAreDisabled/', $value)) $qualifiedforclean=0;
  259. if (preg_match('/^(DoTest|Under|Limits|Cards|CurrentValue|DateLimit|DateAndHour|NbOfLines|NbOfObjects|NbOfReferes|TotalTTCShort|VATs)/', $value)) $qualifiedforclean=0;
  260. // orders
  261. if (preg_match('/^OrderSource/', $value)) $qualifiedforclean=0;
  262. if (preg_match('/^TypeContact_/', $value)) $qualifiedforclean=0;
  263. // other.lang
  264. if (preg_match('/^Notify_/', $value)) $qualifiedforclean=0;
  265. if (preg_match('/^PredefinedMail/', $value)) $qualifiedforclean=0;
  266. if (preg_match('/^DemoCompany/', $value)) $qualifiedforclean=0;
  267. if (preg_match('/^WeightUnit/', $value)) $qualifiedforclean=0;
  268. if (preg_match('/^LengthUnit/', $value)) $qualifiedforclean=0;
  269. if (preg_match('/^SurfaceUnit/', $value)) $qualifiedforclean=0;
  270. if (preg_match('/^VolumeUnit/', $value)) $qualifiedforclean=0;
  271. if (preg_match('/^SizeUnit/', $value)) $qualifiedforclean=0;
  272. if (preg_match('/^EMailText/', $value)) $qualifiedforclean=0;
  273. if (preg_match('/ById$/', $value)) $qualifiedforclean=0;
  274. if (preg_match('/ByLogin$/', $value)) $qualifiedforclean=0;
  275. // printing
  276. if (preg_match('/PrintingDriverDesc$/', $value)) $qualifiedforclean=0;
  277. if (preg_match('/PrintTestDesc$/', $value)) $qualifiedforclean=0;
  278. // products
  279. if (preg_match('/GlobalVariableUpdaterType$/', $value)) $qualifiedforclean=0;
  280. if (preg_match('/GlobalVariableUpdaterHelp$/', $value)) $qualifiedforclean=0;
  281. if (preg_match('/OppStatus/', $value)) $qualifiedforclean=0;
  282. if (preg_match('/AvailabilityType/', $value)) $qualifiedforclean=0;
  283. if (preg_match('/CardProduct/', $value)) $qualifiedforclean=0;
  284. if (preg_match('/sms/i', $value)) $qualifiedforclean=0;
  285. if (preg_match('/TF_/i', $value)) $qualifiedforclean=0;
  286. if (preg_match('/WithBankUsing/i', $value)) $qualifiedforclean=0;
  287. if (preg_match('/descWORKFLOW_/i', $value)) $qualifiedforclean=0;
  288. if (! $qualifiedforclean)
  289. {
  290. continue;
  291. }
  292. //$search = '\'trans("'.$value.'")\'';
  293. $search = '-e "\''.$value.'\'" -e \'"'.$value.'"\' -e "('.$value.')"';
  294. $string = 'grep -R -m 1 -F --exclude=includes/* --include=*.php '.$search.' '.$htdocs.'* '.$scripts.'*';
  295. //print $string."<br>\n";
  296. exec($string,$output);
  297. if (empty($output)) {
  298. $unused[$value] = $line;
  299. echo $line; // $trad contains the \n
  300. }
  301. else
  302. {
  303. unset($output);
  304. //print 'X'.$output.'Y';
  305. }
  306. }
  307. if (empty($unused)) print "No string not used found.\n";
  308. else
  309. {
  310. $filetosave='/tmp/'.($argv[2]?$argv[2]:"").'notused.lang';
  311. print "Strings in en_US that are never used are saved into file ".$filetosave.":\n";
  312. file_put_contents($filetosave, join("",$unused));
  313. print "To remove from original file, run command :\n";
  314. if (($argv[2]?$argv[2]:"")) print 'cd htdocs/langs/en_US; mv '.($argv[2]?$argv[2]:"")." ".($argv[2]?$argv[2]:"").".tmp; ";
  315. print "diff ".($argv[2]?$argv[2]:"").".tmp ".$filetosave." | grep \< | cut -b 3- > ".($argv[2]?$argv[2]:"");
  316. if (($argv[2]?$argv[2]:"")) print "; rm ".($argv[2]?$argv[2]:"").".tmp;\n";
  317. }
  318. }
  319. echo "\n";
  320. if ($web)
  321. {
  322. echo "</body>\n";
  323. echo "</html>\n";
  324. }
  325. exit;