#!/usr/bin/php <?php /******************************************************************************* * Copyright (C) 2007 Easter-eggs * http://ldapsaisie.labs.libre-entreprise.org * * Author: See AUTHORS file in top-level directory. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ******************************************************************************/ error_reporting(E_ERROR); // Change directory $curdir=getcwd(); chdir(dirname(__FILE__).'/../'); require_once('core.php'); require_once('conf/config.inc.php'); $available_onlys = array("config", "templates", "addons"); $only = null; $available_withouts = array_merge($available_onlys, array("select-list")); $withouts = array(); $copyoriginalvalue=False; $interactive=False; $output=False; $additionalfileformat=False; $lang=False; $encoding=False; $available_formats=array('php', 'pot'); $format=$available_formats[0]; $translations=array(); $debug = false; $load_files = array(); function usage($error, $exit_code=0) { global $argv, $available_withouts, $available_onlys; if ($error) echo "$error\n\n"; echo "Usage : ".$argv[0]." [file1] [file2] [-h] [options]\n"; echo " -W/--without Disable specified messages. Must be one of the following values :\n"; echo " '".implode("','", $available_withouts)."'\n"; echo " -O/--only Only handle specified messages. Must be one of the following values :\n"; echo " '".implode("','", $available_onlys)."'\n"; echo " -c/--copy-original-value Copy original value as translated value when no translated value exists\n"; echo " -i/--interactive Interactive mode : ask user to enter translated on each translation needed\n"; echo " -a/--additional-file-format Additional file format output\n"; echo " -l/--lang Load this specify lang (format : [lang].[encoding])\n"; echo " -o/--output Output file (default : stdout)\n"; echo " -f/--format Output file format : php or pot (default : php)\n"; echo " -d/--debug Enable debug mode\n"; exit($exit_code); } function realtive_path($path) { if ($path[0] == '/') return $path; global $curdir; return realpath($curdir)."/".$path; } if ($argc > 1) { for ($i=1;$i<$argc;$i++) { if($argv[$i]=='--without' || $argv[$i]=='-W') { $i++; $without = strtolower($argv[$i]); if (!in_array($without, $available_withouts)) die("Invalid -W/--without parameter. Must be one of the following values : '".implode("','", $available_withouts)."'.\n"); elseif ($only) die("You could not use only -W/--without parameter combined with -O/--only parameter.\n"); $withouts[] = $without; } elseif($argv[$i]=='--only' || $argv[$i]=='-O') { $i++; if ($only) die("You could specify only on -O/--only parameter.\n"); $only = strtolower($argv[$i]); if (!in_array($only, $available_onlys)) die("Invalid -O/--only parameter. Must be one of the following values : '".implode("','", $available_onlys)."'.\n"); elseif ($without) die("You could not use only -O/--only parameter combined with -W/--without parameter.\n"); } elseif($argv[$i]=='--copy-original-value' || $argv[$i]=='-c') { $copyoriginalvalue=True; } elseif($argv[$i]=='--interactive' || $argv[$i]=='-i') { $interactive=True; } elseif($argv[$i]=='--additional-file-format' || $argv[$i]=='-a') { $additionalfileformat=True; } elseif($argv[$i]=='--lang' || $argv[$i]=='-l') { $i++; $parse_lang=explode('.',$argv[$i]); if (count($parse_lang)==2) { $lang=$parse_lang[0]; $encoding=$parse_lang[1]; } else { die("Invalid --lang parameter. Must be compose in format : [lang].[encoding]\n"); } } elseif($argv[$i]=='--output' || $argv[$i]=='-o') { $i++; $output = $argv[$i]; } elseif($argv[$i]=='--format' || $argv[$i]=='-f') { $i++; $format = strtolower($argv[$i]); if (!in_array($format, $available_formats)) { die("Invalid -f/--format parameter. Must be one of the following values : '".implode("','", $available_formats)."'.\n"); } } elseif($argv[$i]=='--debug' || $argv[$i]=='-d') { $debug = true; } elseif($argv[$i]=='-h') { usage(); } else { $path = realtive_path($argv[$i]); if (is_file($path)) $load_files[] = $path; else usage($argv[$i]." : Invalid lang file to load.", 1); } } } $data=array(); function debug($msg) { global $debug, $output; if (!$debug) return true; $fd = ($output?STDOUT: STDERR); fwrite($fd, "$msg\n"); } function add($msg, $context=null) { debug("add($msg, $context)"); if ($msg!='' && _($msg) == "$msg") { global $data, $translations, $interactive, $copyoriginalvalue, $format; // Message already exists ? if (array_key_exists($msg, $data)) { if ($context && !in_array($context, $data[$msg]['contexts'])) $data[$msg]['contexts'][] = $context; return True; } // Handle translation $translation = ""; if (array_key_exists($msg, $translations)) { $translation = $translations[$msg]; } elseif (_($msg) != $msg) { $translation = _($msg); } elseif ($interactive && $format != 'pot') { if ($context) fwrite(STDERR, "\n# $context\n"); if ($copyoriginalvalue) { fwrite(STDERR, "\"$msg\"\n\n => Please enter translated string (or leave empty to copy original string) : "); $in = trim(fgets(STDIN)); if ($in) $translation = $in; else $translation = $msg; } else { fwrite(STDERR, "\"$msg\"\n\n => Please enter translated string (or 'c' to copy original message, leave empty to pass) : "); $in = trim(fgets(STDIN)); if ($in) { if ($in=="c") $translation = $msg; else $translation = $in; } } } $data[$msg] = array ( 'translation' => $translation, 'contexts' => ($context?array($context):array()), ); } } function addFromLSconfig($pattern, $value='value', $excludes=array()) { debug("addFromLSconfig($pattern, array(".implode(',', $excludes)."))"); $keys = LSconfig :: getMatchingKeys($pattern); debug("addFromLSconfig : ".count($keys)." matching key(s)"); foreach ($keys as $key => $value) { debug("addFromLSconfig : $key = $value"); if ($value == 'key') { // Get the last key parts as value and all other as key $key_parts = explode('.', $key); $value = $key_parts[count($key_parts)-1]; $key = implode('.', array_slice($key_parts, 0, count($key_parts)-1)); } if (!in_array($value, $excludes) && is_string($value)) add($value, $key); } } // Load translation files foreach($load_files as $path) { debug("Load $path lang file"); @include($path); foreach($GLOBALS['LSlang'] as $msg => $trans) { $translations[$msg]=$trans; } } // Initialize session LSsession :: initialize($lang,$encoding); // Load lang string if lang was specify if ($lang && $encoding) { foreach($GLOBALS['LSlang'] as $msg => $trans) { $translations[$msg]=$trans; } } /* * Manage configuration parameters */ if (!in_array('config', $withouts) && (!$only || $only == 'config')) { // LDAP Servers $objects = array(); foreach(LSconfig :: keys('ldap_servers') as $ldap_server_id) { addFromLSconfig("ldap_servers.$ldap_server_id.name"); addFromLSconfig("ldap_servers.$ldap_server_id.subDnLabel"); addFromLSconfig("ldap_servers.$ldap_server_id.recoverPassword.recoveryHashMail.subject"); addFromLSconfig("ldap_servers.$ldap_server_id.recoverPassword.recoveryHashMail.msg"); addFromLSconfig("ldap_servers.$ldap_server_id.recoverPassword.newPasswordMail.subject"); addFromLSconfig("ldap_servers.$ldap_server_id.recoverPassword.newPasswordMail.msg"); addFromLSconfig("ldap_servers.$ldap_server_id.subDn.*", 'key', array("LSobject")); // LSaccess foreach (LSconfig :: get("ldap_servers.$ldap_server_id.LSaccess", array()) as $LSobject) { if (is_string($LSobject) && !in_array($LSobject, $objects) && LSsession :: loadLSobject($LSobject)) { $objects[] = $LSobject; } } // Sub DN LSobjects foreach (LSconfig :: getMatchingKeys("ldap_servers.$ldap_server_id.subDn.*.LSobjects.*") as $LSobject) if (is_string($LSobject) && !in_array($LSobject, $objects) && LSsession :: loadLSobject($LSobject)) $objects[] = $LSobject; } debug('LSobjects list : '.implode(', ', $objects)); // LSobject foreach($objects as $obj) { addFromLSconfig("LSobjects.$obj.label"); // LSrelation addFromLSconfig("LSobjects.$obj.LSrelation.*.label"); addFromLSconfig("LSobjects.$obj.LSrelation.*.emptyText"); // Custom Actions addFromLSconfig("LSobjects.$obj.customActions.*.label"); addFromLSconfig("LSobjects.$obj.customActions.*.helpInfo"); addFromLSconfig("LSobjects.$obj.customActions.*.question_format"); addFromLSconfig("LSobjects.$obj.customActions.*.onSuccessMsgFormat"); // LSform addFromLSconfig("LSobjects.$obj.LSform.layout.*.label"); addFromLSconfig("LSobjects.$obj.LSform.dataEntryForm.*.label"); // LSsearch addFromLSconfig("LSobjects.$obj.LSsearch.predefinedFilters.*"); addFromLSconfig("LSobjects.$obj.LSsearch.extraDisplayedColumns.*.label"); addFromLSconfig("LSobjects.$obj.LSsearch.customActions.*.label"); addFromLSconfig("LSobjects.$obj.LSsearch.customActions.*.question_format"); addFromLSconfig("LSobjects.$obj.LSsearch.customActions.*.onSuccessMsgFormat"); // Attributes foreach(LSconfig :: keys("LSobjects.$obj.attrs") as $attr) { addFromLSconfig("LSobjects.$obj.attrs.$attr.label"); addFromLSconfig("LSobjects.$obj.attrs.$attr.help_info"); addFromLSconfig("LSobjects.$obj.attrs.$attr.no_value_label"); addFromLSconfig("LSobjects.$obj.attrs.$attr.check_data.*.msg"); addFromLSconfig("LSobjects.$obj.attrs.$attr.validation.*.msg"); // HTML Options $html_type = LSconfig :: get("LSobjects.$obj.attrs.$attr.html_type"); switch($html_type) { case 'boolean': addFromLSconfig("LSobjects.$obj.attrs.$attr.html_options.true_label"); addFromLSconfig("LSobjects.$obj.attrs.$attr.html_options.false_label"); break; case 'jsonCompositeAttribute': $components = LSconfig :: keys("LSobjects.$obj.attrs.$attr.html_options.components"); foreach($components as $c) { addFromLSconfig("LSobjects.$obj.attrs.$attr.html_options.$c.label"); addFromLSconfig("LSobjects.$obj.attrs.$attr.html_options.$c.help_info"); addFromLSconfig("LSobjects.$obj.attrs.$attr.html_options.$c.check_data.*.msg"); if ( LSconfig :: get("LSobjects.$obj.attrs.$attr.html_options.$c.type") == 'select_list' && LSconfig :: get("LSobjects.$obj.attrs.$attr.html_options.$c.options.translate_labels", "True", "bool") && !in_array('select-list', $withouts) ) { foreach(LSconfig :: get("LSobjects.$obj.attrs.$attr.html_options.$c.options.possible_values", array()) as $pkey => $plabel) { if ($pkey == 'OTHER_OBJECT') continue; elseif ($pkey == 'OTHER_ATTRIBUTE') { if (is_string($plabel)) continue; elseif (is_array($plabel)) { if (isset($plabel['json_component_key'])) addFromLSconfig("LSobjects.$obj.attrs.$attr.html_options.$c.options.possible_values.OTHER_ATTRIBUTE.json_component_label"); else addFromLSconfig("LSobjects.$obj.attrs.$attr.html_options.$c.options.possible_values.OTHER_ATTRIBUTE.*"); } } elseif(is_string($plabel)) { add($plabel, "LSobjects.$obj.attrs.$attr.html_options.$c.options.possible_values.$pkey"); } elseif (is_array($plabel)) { // Sub possible values addFromLSconfig("LSobjects.$obj.attrs.$attr.html_options.$c.options.possible_values.$pkey.label"); foreach(LSconfig :: get("LSobjects.$obj.attrs.$attr.html_options.$c.options.possible_values.$pkey.possible_values", array()) as $ppkey => $pplabel) { if ($ppkey == 'OTHER_OBJECT') continue; elseif ($ppkey == 'OTHER_ATTRIBUTE') { if (is_string($pplabel)) continue; elseif (is_array($pplabel)) { if (isset($pplabel['json_component_key'])) addFromLSconfig("LSobjects.$obj.attrs.$attr.html_options.$c.options.possible_values.OTHER_ATTRIBUTE.json_component_label"); else addFromLSconfig("LSobjects.$obj.attrs.$attr.html_options.$c.options.possible_values.OTHER_ATTRIBUTE.*"); } } elseif(is_string($pplabel)) { add($pplabel, "LSobjects.$obj.attrs.$attr.html_options.$c.options.possible_values.$pkey.possible_values.$ppkey"); } } } } } } break; case 'labeledValue': addFromLSconfig("LSobjects.$obj.attrs.$attr.html_options.labels.*"); break; case 'password': addFromLSconfig("LSobjects.$obj.attrs.$attr.html_options.mail.subject"); addFromLSconfig("LSobjects.$obj.attrs.$attr.html_options.mail.msg"); break; case 'select_list': case 'select_box': if (LSconfig :: get("LSobjects.$obj.attrs.$attr.html_options.translate_labels", "True", "bool") && !in_array('select-list', $withouts)) { foreach(LSconfig :: get("LSobjects.$obj.attrs.$attr.html_options.possible_values", array()) as $pkey => $plabel) { if ($pkey == 'OTHER_OBJECT') continue; elseif ($pkey == 'OTHER_ATTRIBUTE') { if (is_string($plabel)) continue; elseif (is_array($plabel)) { if (isset($plabel['json_component_key'])) addFromLSconfig("LSobjects.$obj.attrs.$attr.html_options.possible_values.OTHER_ATTRIBUTE.json_component_label"); else addFromLSconfig("LSobjects.$obj.attrs.$attr.html_options.possible_values.OTHER_ATTRIBUTE.*"); } } elseif(is_string($plabel)) { add($plabel, "LSobjects.$obj.attrs.$attr.html_options.possible_values.$pkey"); } elseif (is_array($plabel)) { // Sub possible values addFromLSconfig("LSobjects.$obj.attrs.$attr.html_options.possible_values.$pkey.label"); foreach(LSconfig :: get("LSobjects.$obj.attrs.$attr.html_options.possible_values.$pkey.possible_values", array()) as $ppkey => $pplabel) { if ($ppkey == 'OTHER_OBJECT') continue; elseif ($ppkey == 'OTHER_ATTRIBUTE') { if (is_string($pplabel)) continue; elseif (is_array($pplabel)) { if (isset($pplabel['json_component_key'])) addFromLSconfig("LSobjects.$obj.attrs.$attr.html_options.possible_values.OTHER_ATTRIBUTE.json_component_label"); else addFromLSconfig("LSobjects.$obj.attrs.$attr.html_options.possible_values.OTHER_ATTRIBUTE.*"); } } elseif(is_string($pplabel)) { add($pplabel, "LSobjects.$obj.attrs.$attr.html_options.possible_values.$pkey.possible_values.$ppkey"); } } } } } break; case 'valueWithUnit': addFromLSconfig("LSobjects.$obj.attrs.$attr.html_options.units.*"); break; } } } } /* * Manage template file */ if (!in_array('templates', $withouts) && (!$only || $only == 'templates')) { function parse_template_file($file) { debug("parse_template_file($file) : start ..."); $count = 0; foreach(file($file) as $line) { $count ++; if (preg_match_all('/\{ *tr +msg=["\']([^\}]+)["\'] *\}/',$line,$matches)) { foreach($matches[1] as $t) { debug(" - \"$t\" # Line $count"); add($t, "$file:$count"); } } } debug("parse_template_file($file) : done."); } function find_and_parse_template_file($dir) { if (is_dir($dir)) { if ($dh = opendir($dir)) { while (($file = readdir($dh)) !== false) { if ($file=='.' || $file=='..') continue; if (is_dir($dir.'/'.$file)) { find_and_parse_template_file($dir.'/'.$file); } elseif (is_file($dir."/".$file) && preg_match('/\.tpl$/',$file)) { parse_template_file($dir.'/'.$file); } } closedir($dh); } } } find_and_parse_template_file(LS_TEMPLATES_DIR); find_and_parse_template_file(LS_LOCAL_DIR.LS_TEMPLATES_DIR); } /* * Manage addons files */ if (!in_array('addons', $withouts) && (!$only || $only == 'addons')) { function parse_addon_file($file) { $count = 0; foreach(file($file) as $line) { $count++; $offset=0; while ($pos = strpos($line,'__(',$offset)) { $quote=''; $res=''; for ($i=$pos+3;$i<strlen($line);$i++) { if (empty($quote)) { // Quote char not detected : try to detect it if ($line[$i]=='\\' || $line[$i]==" " || $line[$i]=="\t") { // Space or escape char : pass $i++; } elseif ($line[$i]=='"' || $line[$i]=="'") { // Quote detected $quote=$line[$i]; } elseif ($line[$i]=='$' || $line[$i]==')') { // Variable translation not possible or end function call detected $offset=$i; break; } else { // Unknown case : continue $i++; } } elseif (!empty($quote)) { // Quote char already detected : try to detect end quote char if ($line[$i]=='\\') { // Escape char detected : pass this char and the following one $res.=$line[$i]; $i++; $res.=$line[$i]; } elseif ($line[$i]==$quote) { // End quote char detected : set offset for next detection and break this one $offset=$i; break; } else { // End quote char not detected : append current char to result $res.=$line[$i]; } } } if (!empty($res)) add($res, "$file:$count"); } } } function find_and_parse_addon_file($dir) { if (is_dir($dir)) { if ($dh = opendir($dir)) { while (($file = readdir($dh)) !== false) { if (preg_match('/^LSaddons\.(.+)\.php$/',$file)) { parse_addon_file($dir.'/'.$file); } } closedir($dh); } } } find_and_parse_addon_file(LS_ADDONS_DIR); find_and_parse_addon_file(LS_LOCAL_DIR.LS_ADDONS_DIR); } // Sort resulting strings ksort($data); /* * Handle output file format */ function output_php($fd) { global $additionalfileformat, $data, $copyoriginalvalue; fwrite($fd, "<?php\n\n"); if (!$additionalfileformat) fwrite($fd, "\$GLOBALS['LSlang'] = array (\n"); foreach($data as $key => $key_data) { if ($copyoriginalvalue && $key_data['translation'] == "") { $val = $key; } else $val = $key_data['translation']; $key=str_replace('"','\\"',$key); $val=str_replace('"','\\"',$val); foreach ($key_data['contexts'] as $context) fwrite($fd, "\n# $context"); if ($additionalfileformat) { fwrite($fd, "\n\$GLOBALS['LSlang'][\"$key\"] = \"$val\";\n"); } else { fwrite($fd, "\n\"$key\" =>\n \"$val\",\n"); } } if (!$additionalfileformat) fwrite($fd, "\n);\n"); } function clean_for_pot_file($val) { $val = str_replace('"', '\\"', $val); return str_replace("\n", "\\n", $val); } function output_pot($fd) { global $data, $copyoriginalvalue; foreach($data as $key => $key_data) { if ($copyoriginalvalue && $key_data['translation'] == "") { $val = $key; } else $val = $key_data['translation']; foreach ($key_data['contexts'] as $context) fwrite($fd, "#: $context\n"); $key = clean_for_pot_file($key); $val = clean_for_pot_file($val); fwrite($fd, "msgid \"$key\"\nmsgstr \"$val\"\n\n"); } } // Determine where to write result if ($output) { $output = realtive_path($output); try { debug("Open output file ($output)"); $fd = fopen($output, 'w'); } catch(Exception $e) { fwrite(STDERR, 'Error occured opening output file : '.$e->getMessage(), "\n"); } if (!$fd) { fwrite(STDERR, "Use stdout out instead.\n"); $fd = STDOUT; $output = false; } } else $fd = STDOUT; // Generate output debug("Output format : $format"); switch($format) { case 'pot': output_pot($fd); break; case 'php': default: output_php($fd); break; } // Close output file (is specified) if ($output) { debug("Close output file ($output)"); fclose($fd); } exit(0);