languages
[ class tree: languages ] [ index: languages ] [ all elements ]

Source for file get_strings.php

Documentation is available at get_strings.php

  1. <?php
  2. /**
  3.  * @package languages
  4.  * @subpackage functions
  5.  * @version $Header$
  6.  *
  7.  *  Copyright (c) 2005 bitweaver.org
  8.  *  Tiki is copyright (c) 2002-2003, Luis Argerich, Garland Foster, Eduardo Polidor, et. al.
  9.  *  All Rights Reserved. See below for details and a complete list of authors.
  10.  *  Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See http://www.gnu.org/copyleft/lesser.html for details.
  11.  */
  12.  
  13. /**
  14.  * Initialization
  15.  */
  16.  
  17. /**
  18.  * Update the language.php files
  19.  * call example: get_strings.php?lang=fr&close
  20.  * @param lang=xx    : only translate lang 'xx' - if the parameter is not given all languages are translated
  21.  * @param comments   : generate all comments (equal to close&module)
  22.  * @param close      : look for similar strings that are allready translated and generate a commet if a 'match' is made
  23.  * @param module     : generate comments that describes in which .php and/or .tpl\n module(s) a certain string was found (useful for checking translations in context)
  24.  * @param patch      : looks for the file 'language.patch' in the same directory as the corresponding language.php and overrides any strings in language.php - good if a user does not agree with some translations or if only changes are sent to the maintaner
  25.  * @param spelling   : generate a file spellcheck_me.txt in the applicable languages directory that contains all the words used in the translated text. This makes it simple to use a spellchecker on the resulting file
  26.  * @param groupwrite : Sets the generated files permissions to allow the generated language.php also be group writable. This is good for translators if they do not have root access to tiki but are in the same group as the webserver. Please remember to have write access removed when translation is finished for security reasons. (Run script again whithout this parameter)
  27.  */
  28.  
  29.  
  30.  
  31. ////////////////////////////////////////////////////////////////////////////
  32. /// functions
  33.  
  34. $addPHPslashes Array ("\n" => '\n',
  35.             "\r" => '\r',
  36.             "\t" => '\t',
  37.             '\\' => '\\\\',
  38.             '$'  => '\$',
  39.             '"'  => '\"');
  40.  
  41. function addphpslashes ($string{
  42.   // Translate as in "Table 7-1 Escaped characters" in the PHP manual
  43.   // $string = str_replace ("\n", '\n',   $string);
  44.   // $string = str_replace ("\r", '\r',   $string);
  45.   // $string = str_replace ("\t", '\t',   $string);
  46.   // $string = str_replace ('\\', '\\\\', $string);
  47.   // $string = str_replace ('$',  '\$',   $string);
  48.   // $string = str_replace ('"',  '\"',   $string);
  49.   // We skip the exotic regexps for octal an hexadecimal
  50.   // notation - \{0-7]{1,3} and \x[0-9A-Fa-f]{1,2} -
  51.   // since they should not apper in english strings.
  52.   // return $string;
  53.   global $addPHPslashes;
  54.   return strtr ($string$addPHPslashes);
  55. }
  56.  
  57.  
  58. $removePHPslashes Array ('\n'   => "\n",
  59.                '\r'   => "\r",
  60.                '\t'   => "\t",
  61.                '\\\\' => '\\',
  62.                '\$'   => '$',
  63.                '\"'   => '"');
  64.  
  65. function removephpslashes ($string{
  66.   // $string = str_replace ('\n',   "\n", $string); 
  67.   // $string = str_replace ('\r',   "\r", $string);
  68.   // $string = str_replace ('\t',   "\t", $string);
  69.   // $string = str_replace ('\\\\', '\\', $string);
  70.   // $string = str_replace ('\$',   '$',  $string);
  71.   // $string = str_replace ('\"',   '"',  $string);
  72.   // We skip the exotic regexps for octal an hexadecimal
  73.   // notation - \{0-7]{1,3} and \x[0-9A-Fa-f]{1,2} - since they 
  74.   // should not apper in english strings.
  75.   if (preg_match ('/\{0-7]{1,3}|\x[0-9A-Fa-f]{1,2}/'$string$match)) {
  76.     trigger_error ("Octal or hexadecimal string '".$match[1]."' not supported",
  77.            E_WARNING);
  78.  
  79.   }
  80.   // return $string;
  81.   global $removePHPslashes;
  82.   return strtr ($string$removePHPslashes);
  83. }
  84.  
  85. function hardwire_file ($file)
  86. {
  87.   global $files;
  88.   $files[$file;
  89.   print "File (hardwired): $file<br />";
  90. }
  91.  
  92. function collect_files ($dir)
  93. {
  94.   global $files;
  95.   $handle opendir ($dir);
  96.   while (false !== ($file readdir ($handle))) {
  97.     // Skip current and parent directory
  98.     // also skip other directories which may contain source code
  99.     // that should not be translated (the directories normally contain
  100.     // temporary results etc.)
  101.     // Please note that these directories will be skipped on all levels
  102.     if ('.'   == $file || '..'          == $file || 
  103.        'lang' == $file || 'templates_c' == $file || 'dump'  == $file ||
  104.        'util' == $file || 'gallery2' == $file || 'shopping' == $file ||
  105.        'temp' == $file || 'img'         == $file || 'cache' == $file{
  106.       continue;
  107.     }
  108.  
  109.     $filepath $dir '/' $file;
  110.     if (preg_match ("/.*\.(tpl|php)$/"$file)) {
  111.       print("File: $filepath<br />");
  112.       $files[$filepath
  113.     }
  114.     else {
  115.       if (is_dir ($filepath)) {
  116.     collect_files ($filepath);
  117.       }
  118.     }
  119.   }
  120.   closedir ($handle);
  121. }
  122.  
  123. function addToWordlist (&$wordlist$sentence{
  124.   global $spelling;
  125.   if ($spelling{
  126.     // Perhapps regexphandling must be improved?!
  127.     // Spellcheckers seems to handle special chars quite OK however.
  128.     $words preg_split  ("/[\s]+/"$sentence);
  129.     
  130.     foreach ($words as $dummy => $word{
  131.       $wordlist[strtolower($word)1;
  132.     }
  133.   }
  134. }
  135.  
  136.  
  137. function writeFile_and_User ($fd$outstring{
  138.   print (nl2br ($outstring));
  139.   fwrite ($fd$outstring);
  140. }
  141.  
  142. function writeTranslationPair ($fd$key$val{
  143.   writeFile_and_User ($fd
  144.               '"' addphpslashes ($key'"' " => " .
  145.               '"' addphpslashes ($val'",');
  146. }
  147.  
  148. ////////////////////////////////////////////////////////////////////////////
  149.  
  150. require_once'../kernel/setup_inc.php' );
  151.  
  152. if(!$gBitUser->isAdmin()) {
  153.   die("You need to be admin to run this script");
  154. }
  155.  
  156. $comments = isset ($_REQUEST['comments']);
  157. $close    = isset ($_REQUEST['close'])  || $comments;
  158. $module   = isset ($_REQUEST['module']|| $comments;
  159. $patch    = isset ($_REQUEST['patch']);
  160. $spelling = isset ($_REQUEST['spelling']);
  161. $group_w  = isset ($_REQUEST['groupwrite']);
  162.  
  163. $nohelp     = isset ($_REQUEST['nohelp']);
  164. $nosections = isset ($_REQUEST['nosections']);
  165.  
  166.  
  167. // Get the language(s)
  168. $languages Array();
  169. print("Languages: ");
  170. if (isset ($_REQUEST["lang"])) {
  171.   $lang $_REQUEST["lang"];
  172.   $languages[$lang;
  173.   print ("$lang");  
  174. }
  175. else {
  176.   $handle=opendir ('lang');
  177.   while (false !== ($lang readdir ($handle))) {
  178.     if($lang == '.' || $lang == '..'
  179.       continue;
  180.     print("$lang ");  
  181.     $languages[$lang;
  182.   }
  183.   closedir ($handle);
  184. }        
  185. print("<br />");  
  186.  
  187.  
  188. $files Array();
  189.  
  190. $wordlist Array ();
  191.  
  192. ## When collecting files we need to add a file since the directory which it
  193. ## is placed in is excluded. We should keep hardwiring to a minimum.
  194. ## In a normal case a file that should be translated shuold not exist in
  195. ## a (sub)directory that is excluded. In this (unfortunate) case it seems that
  196. ## the file is placed in a logical location.
  197. hardwire_file LANGUAGES_PKG_PATH.'lang_mapping_inc.php');
  198.  
  199.  
  200.  
  201. $oldEndMarker '##end###';
  202. $endMarker '###end###';
  203. foreach ($languages as $sel{
  204.   unset ($lang);
  205.   unset ($to_translate);
  206.   unset ($translated)
  207.   unset ($modulename);
  208.   unset ($unused);
  209.   unset ($dictionary);
  210.   $to_translate Array ();
  211.   $modulename   Array ();
  212.   $translated   Array ();
  213.  
  214.   if ($patch{
  215.     $origPatch "lang/$sel/language.patch";
  216.     if (!file_exists ($origPatch)) {
  217.       die ("No patch file .../$origPatch exisits");
  218.     }
  219.     require ($origPatch);
  220.     $patchLang $lang;
  221.     unset ($lang);
  222.   }
  223.  
  224.   require("lang/$sel/language.php");
  225.  
  226.   if (isset ($lang[$oldEndMarker])) {
  227.     unset ($lang[$oldEndMarker]);
  228.   }
  229.   if (isset ($lang[$endMarker])) {
  230.     unset ($lang[$endMarker]);
  231.   }
  232.  
  233.   $unused     $lang;
  234.   $dictionary $lang;
  235.  
  236.  
  237.   if ($group_w{
  238.     // We set umask to zero value to allow proper chmod later
  239.     // (Is this really nesserary? Does not chmod work independently of umask?)
  240.     $old_umask umask (0)
  241.   }
  242.  
  243.   $fw fopenLANGUAGES_PKG_PATH."lang/$sel/new_language.php",'w');
  244.   
  245.   print("&lt;");
  246.   fwrite($fw,"<");
  247.   writeFile_and_User ($fw"?php");
  248.   // The comment coding:utf-8 is for the benefit of emacs
  249.   // and must be on the very first line in the file
  250.   // we leave this comment in even if comments are off since
  251.   // editing files with the wrong encoding causes commical effects at best.
  252.   writeFile_and_User ($fw" // -*- coding:utf-8 -*-\n");
  253.  
  254.   if (!$nohelp{
  255.     // Good to have instructions for translators in the release file.
  256.     // The comments get filtered away by Smarty anyway
  257.     writeFile_and_User ($fw"// parameters:\n");
  258.     writeFile_and_User ($fw"// lang=xx    : only tranlates language 'xx',\n");
  259.     writeFile_and_User ($fw"//              if not given all languages are translated\n");
  260.     writeFile_and_User ($fw"// comments   : generate all comments (equal to close&module)\n");
  261.     writeFile_and_User ($fw"// close      : look for similar strings that are allready translated and\n");
  262.     writeFile_and_User ($fw"//              generate a commet if a 'match' is made\n");
  263.     writeFile_and_User ($fw"// module     : generate comments that describes in which .php and/or .tpl\n");
  264.     writeFile_and_User ($fw"//              module(s) a certain string was found (useful for checking\n");
  265.     writeFile_and_User ($fw"//              translations in context)\n");
  266.  
  267.     writeFile_and_User ($fw"// patch      : looks for the file 'language.patch' in the same directory\n");
  268.     writeFile_and_User ($fw"//              as the corresponding language.php and overrides any strings\n");
  269.     writeFile_and_User ($fw"//              in language.php - good if a user does not agree with\n");
  270.     writeFile_and_User ($fw"//              some translations or if only changes are sent to the maintaner\n");
  271.  
  272.     writeFile_and_User ($fw"// spelling   : generates a file 'spellcheck_me.txt' that contains the\n");
  273.     writeFile_and_User ($fw"//              words used in the translation.It is then easy to check this\n");
  274.     writeFile_and_User ($fw"//              file for spelling errors (corrections must be done in\n ");
  275.     writeFile_and_User ($fw"//              'language.php, however)\n");
  276.  
  277.  
  278.     writeFile_and_User ($fw"// groupwrite : Sets the generated files permissions to allow the generated\n");
  279.     writeFile_and_User ($fw"//              language.php also be group writable. This is good for\n");
  280.     writeFile_and_User ($fw"//              translators if they do not have root access to tiki but\n");
  281.     writeFile_and_User ($fw"//              are in the same group as the webserver. Please remember\n");
  282.     writeFile_and_User ($fw"//              to have write access removed when translation is finished\n");
  283.     writeFile_and_User ($fw"//              for security reasons. (Run script again without this\n");
  284.     writeFile_and_User ($fw"//              parameter)\n");
  285.  
  286.  
  287.  
  288.  
  289.     writeFile_and_User ($fw"// Examples:\n");
  290.     writeFile_and_User ($fw"// http://www.neonchart.com/get_strings.php?lang=sv\n");
  291.     writeFile_and_User ($fw"// Will translate langauage 'sv' and (almost) avoiding comment generation\n\n");
  292.  
  293.     writeFile_and_User ($fw"// http://www.neonchart.com/get_strings.php?lang=sv&comments\n");
  294.     writeFile_and_User ($fw"// Will translate langauage 'sv' and generate all possible comments.\n");
  295.     writeFile_and_User ($fw"// This is the most usefull mode when working on a translation.\n\n");
  296.     writeFile_and_User ($fw"// http://www.neonchart.com/get_strings.php?lang=sv&nohelp&nosections\n");
  297.     writeFile_and_User ($fw"// These options will only provide the minimal amout of comments.\n");
  298.     writeFile_and_User ($fw"// Usefull mode when preparing a translation for distribution.\n\n");
  299.     writeFile_and_User ($fw"// http://www.neonchart.com/get_strings.php?nohelp&nosections\n");
  300.     writeFile_and_User ($fw"// Prepare all languages for release \n\n");
  301.   }
  302.  
  303.  
  304.   // Start generating the lang array
  305.   writeFile_and_User ($fw"\n\$lang=Array(\n");  
  306.   
  307.   foreach ($files as $file{
  308.     $fp fopen ($file"r");
  309.     $data fread ($fpfilesize ($file));
  310.     fclose ($fp);
  311.  
  312.     unset ($words);   $words   Array ();
  313.     unset ($uqwords)$uqwords Array ();
  314.     unset ($sqwords)$sqwords Array ();
  315.     unset ($dqwords)$dqwords Array ();
  316.  
  317.  
  318.     // PM for unusual regexps
  319.     // (?m) sets PCRE_MULTILINE which makes '^' and '$' ignore '\n'
  320.     // (?s) sets PCRE_DOTALL which makes that '.' also matches '\n'
  321.     // ?: below makes that the pharentesis is not extracted int the outarray
  322.     // +? below is the nongreedy version of the ? operator
  323.  
  324.  
  325.     if (preg_match ("/\.php$/"$file)) {
  326.       // Do not translate PHP comments (we only filter the "safe" cases)
  327.       // Calling php -w <filename> would take care of all comments,
  328.       // but that does not go well with safe-mode.
  329.       $data preg_replace ("/(?s)\/\*.*?\*\//"""$data);  // C comments
  330.       $data preg_replace ("/(?m)^\s*\/\/.*\$/"""$data)// C++ comments
  331.       $data preg_replace ("/(?m)^\s*\#.*\$/",   ""$data)// shell comments
  332.  
  333.       // Only extract tra () and hawtra () in .php-files
  334.  
  335.       // Extract from SINGLE qouted strings
  336.       preg_match_all ('/(?s)[^a-zA-Z0-9_\x7f-\xff](?:haw)?tra\s*\(\s*\'(.+?)\'\s*\)/'$data$sqwords);
  337.  
  338.       // Extract from DOUBLE quoted strings
  339.       preg_match_all ('/(?s)[^a-zA-Z0-9_\x7f-\xff](?:haw)?tra\s*\(\s*"(.+?)"\s*\)/'$data$dqwords);
  340.     }
  341.  
  342.     if (preg_match ("/\.tpl$/"$file)) {
  343.       // Do not translate text in Smarty comments: {* Smarty comment *}
  344.       $data preg_replace ('/(?s)\{\*.*?\*\}/'''$data)// Smarty comment 
  345.  
  346.       // Strings of the type {tr}{$perms[user].type}{/tr} need (should)
  347.       // not be translated
  348.       $data preg_replace ('/(?s)\{tr\}\s*\{[$][^\}]*?\}\s*\{\/tr\}/','',$data);
  349.  
  350.       // Only extract {tr} ... {/tr} in .tpl-files
  351.       preg_match_all ('/(?s)\{tr\}(.+?)\{\/tr\}/'$data$uqwords);
  352.     }
  353.  
  354.     // Transfer UNqouted words (if any) to the words array
  355.     if (count ($uqwords0{
  356.       $words $uqwords[1];
  357.     }
  358.  
  359.     // Transfer SINGLEqouted words (if any) to the words array
  360.     if (count ($sqwords0{
  361.       foreach (array_unique ($sqwords[1]as $sqword{
  362.     // Strip the extracted strings from escapes
  363.     // (these will not be reinserted during generation, since ' need
  364.     // not be escaped when string delimeters are double quotes)
  365.     $word preg_replace ("/\\'/""'"$sqword);
  366.     $words[$word$word;                               
  367.       }
  368.     }
  369.  
  370.     // Transfer DOUBLEqouted words (if any) to the words array
  371.     if (count ($dqwords0{
  372.       foreach (array_unique ($dqwords[1]as $dqword{
  373.     // Strip the extracted strings from escapes
  374.     // (these will be reinserted during generation)
  375.     
  376.     $word removephpslashes ($dqword);
  377.     $words["$word""$word";                               
  378.       }
  379.     }
  380.  
  381.     foreach (array_unique ($wordsas $word{
  382.       if (isset ($lang[$word])) {
  383.     if (!isset ($translated[$word])) {
  384.       $translated[$word$lang[$word];
  385.     }
  386.     unset ($unused[$word]);
  387.       }
  388.       else {
  389.     if (!isset ($to_translate[$word])) {
  390.       $to_translate[$word]=$word;
  391.     }
  392.       }
  393.       
  394.       if (isset ($modulename[$word])) {
  395.     if (!strpos ($modulename[$word]$file)) {
  396.       $modulename[$word$modulename[$word.', '$file;
  397.     }
  398.       }
  399.       else {
  400.     $modulename[$word$file;
  401.       }
  402.     }
  403.   // foreach ($files as $file)
  404.  
  405.  
  406.   //////////////////////////////////////////////
  407.   if ($patch{
  408.     foreach ($unused as $key => $val{
  409.       if (isset ($patchLang[$key])) {
  410.     $unused[$key$patchLang[$key];
  411.       }
  412.     }
  413.     
  414.     foreach ($to_translate as $key => $val{
  415.       if (isset ($patchLang[$key])) {
  416.     // $to_translate[$key] = $patchLang[$key];
  417.     // We are removing words from the to_translate list,
  418.     // since they are provided by the patch
  419.     unset ($to_translate[$key]);
  420.       }
  421.     }
  422.     
  423.     foreach ($translated as $key=>$val{
  424.       if (isset ($patchLang[$key])) {
  425.     $translated[$key$patchLang[$key];
  426.       }
  427.     }
  428.   }
  429.  
  430.   unset ($unused['']);
  431.   if (count ($unused0{
  432.     writeFile_and_User ($fw"// ### Start of unused words\n");
  433.     writeFile_and_User ($fw"// ### Please remove manually!\n");
  434.     writeFile_and_User ($fw"// ### N.B. Legitimate strings may be marked");
  435.     writeFile_and_User ($fw"// ### as unused!\n");
  436.     writeFile_and_User ($fw"// ### Please see http://doc.bitweaver.org/wiki/index.php?page=UnusedWords for furhter info.\n");
  437.     foreach ($unused as $key => $val{
  438.       writeTranslationPair ($fw$key$val);
  439.       addToWordlist ($wordlist$val);
  440.       writeFile_and_User ($fw"\n");
  441.     }
  442.     writeFile_and_User ($fw"// ### end of unused words\n\n");
  443.   }
  444.  
  445.   unset ($to_translate['']);
  446.   if (count ($to_translate0{
  447.     if ('en' != $sel && !$nosections{
  448.       writeFile_and_User ($fw"// ### start of untranslated words\n");
  449.       writeFile_and_User ($fw,
  450.               "// ### uncomment value pairs as you translate\n");
  451.     }
  452.     foreach ($to_translate as $key => $val{
  453.       writeFile_and_User ($fw"// ");
  454.       writeTranslationPair ($fw$key$val);
  455.       addToWordlist ($wordlist$val);
  456.       if ($module || $close{
  457.     $closeText  "";
  458.     $moduleText "";
  459.     if ($close{
  460.       $dist 256;
  461.       foreach ($dictionary as $english=>$trans{
  462.         $d levenshtein (strtolower (substr ($key0255)),
  463.                   strtolower (substr ($english0255)));
  464.         if ($d $dist{
  465.           $dist $d;
  466.           $closeTrans   $trans;
  467.           $closeEnglish $english;
  468.         }
  469.       }
  470.       
  471.       if ($dist strlen ($key)/5{
  472.         $closeText ' // ## CLOSE: "' addphpslashes ($closeEnglish.
  473.                      '" => "' addphpslashes ($closeTrans'"';
  474.       }
  475.     }
  476.  
  477.     if ($module{
  478.       $moduleText " // ## MODULES " $modulename[$key];
  479.     }
  480.  
  481.     writeFile_and_User ($fw"${closeText}${moduleText}");
  482.       }
  483.       writeFile_and_User ($fw"\n");
  484.     }
  485.     if ('en' != $sel && !$nosections{
  486.       writeFile_and_User ($fw"// ### end of untranslated words\n");
  487.       writeFile_and_User ($fw"// ###\n\n");
  488.     }
  489.   }
  490.  
  491.   if ('en' != $sel && !$nosections{
  492.     writeFile_and_User($fw"// ###\n");
  493.     writeFile_and_User ($fw,"// ### start of possibly untranslated words\n");
  494.     writeFile_and_User($fw"// ###\n\n");
  495.   }
  496.   foreach ($translated as $key => $val{
  497.     if ($key == $val{
  498.       writeTranslationPair ($fw$key$val);
  499.       addToWordlist ($wordlist$val);
  500.       if ($module{
  501.     writeFile_and_User ($fw' // '$modulename[$key]);
  502.       }
  503.       writeFile_and_User ($fw"\n");
  504.     }
  505.   }
  506.   if ('en' != $sel && !$nosections{
  507.     writeFile_and_User($fw"// ###\n");
  508.     writeFile_and_User($fw"// ### end of possibly untranslated words\n");
  509.     writeFile_and_User($fw"// ###\n\n");
  510.   }
  511.  
  512.   foreach($translated as $key => $val{
  513.     if ($key != $val{
  514.       writeTranslationPair ($fw$key$val);
  515.       addToWordlist ($wordlist$val);
  516.       if ($module
  517.     writeFile_and_User ($fw' // '$modulename[$key]);
  518.       }
  519.       writeFile_and_User ($fw"\n");
  520.     }
  521.   }
  522.   writeFile_and_User ($fw'"'.$endMarker.'"=>"'.$endMarker.'");'."\n");
  523.   print ("?&gt;<br />\n");  
  524.   fwrite ($fw'?>'."\n");  
  525.   fclose ($fw);
  526.  
  527.   if ($spelling{
  528.     $fw fopen("lang/$sel/spellcheck_me.txt"'w');
  529.     ksort ($wordlist);
  530.     reset ($wordlist);
  531.     foreach ($wordlist as $word => $dummy{
  532.       fwrite ($fw"$word\n");
  533.     }
  534.  
  535.     fclose ($fw);
  536.   }
  537.  
  538.   @unlink ("lang/$sel/old.php");
  539.   rename ("lang/$sel/language.php","lang/$sel/old.php");
  540.   rename ("lang/$sel/new_language.php","lang/$sel/language.php");
  541.  
  542.   if ($group_w{
  543.     // chmod the file to be writeable also by group for users that do not
  544.     // have root acces
  545.     chmod ("lang/$sel/language.php"0664)
  546.  
  547.     umask($old_umask)// Reset umask back to original value
  548.   }
  549. }
  550. ?>

Documentation generated on Wed, 29 Jul 2015 13:56:41 +0000 by phpDocumentor 1.5.0-lsces