mirror of
https://gitlab.easter-eggs.com/ee/ldapsaisie.git
synced 2024-11-16 15:33:02 +01:00
1264 lines
45 KiB
PHP
1264 lines
45 KiB
PHP
<?php
|
|
/*******************************************************************************
|
|
* Copyright (C) 2007 Easter-eggs
|
|
* https://ldapsaisie.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.
|
|
|
|
******************************************************************************/
|
|
|
|
LSsession :: loadLSclass('LSlog_staticLoggerClass');
|
|
|
|
class LSlang extends LSlog_staticLoggerClass {
|
|
|
|
|
|
/**
|
|
* Current lang
|
|
* @see LSlang::setLocale()
|
|
* @see LSlang::getLang()
|
|
* @var string|null
|
|
*/
|
|
private static $lang = NULL;
|
|
|
|
/**
|
|
* Current encoding
|
|
* @see LSlang::setLocale()
|
|
* @see LSlang::getEncoding()
|
|
* @var string|null
|
|
*/
|
|
private static $encoding = NULL;
|
|
|
|
/**
|
|
* Define current locale (and encoding)
|
|
*
|
|
* @param string|null $lang The lang (optional, default: default current LDAP
|
|
* server lang, or default lang)
|
|
* @param string|null $encoding The encoding (optional, default: default current LDAP
|
|
* server encoding, or default encoding)
|
|
*
|
|
* @return void
|
|
*/
|
|
public static function setLocale($lang=null, $encoding=null) {
|
|
// Handle $lang parameter
|
|
if (is_null($lang)) {
|
|
if (isset($_REQUEST['lang'])) {
|
|
$lang = $_REQUEST['lang'];
|
|
}
|
|
elseif (isset($_SESSION['LSlang'])) {
|
|
$lang = $_SESSION['LSlang'];
|
|
}
|
|
elseif (isset(LSsession :: $ldapServer['lang'])) {
|
|
$lang = LSsession :: $ldapServer['lang'];
|
|
}
|
|
else {
|
|
$lang = LSconfig :: get('lang');
|
|
}
|
|
}
|
|
|
|
// Handle $encoding parameter
|
|
if (is_null($encoding)) {
|
|
if (isset($_REQUEST['encoding'])) {
|
|
$encoding = $_REQUEST['encoding'];
|
|
}
|
|
elseif (isset($_SESSION['LSencoding'])) {
|
|
$encoding = $_SESSION['LSencoding'];
|
|
}
|
|
elseif (isset(LSsession :: $ldapServer['encoding'])) {
|
|
$encoding = LSsession :: $ldapServer['encoding'];
|
|
}
|
|
else {
|
|
$encoding = LSconfig :: get('encoding');
|
|
}
|
|
}
|
|
|
|
// Set session and self variables
|
|
$_SESSION['LSlang'] = self :: $lang = $lang;
|
|
$_SESSION['LSencoding'] = self :: $encoding = $encoding;
|
|
|
|
// Check
|
|
if (self :: localeExist($lang, $encoding)) {
|
|
self :: log_trace("setLocale($lang, $encoding): local '$lang.$encoding' exist, use it");
|
|
if ($encoding) {
|
|
$lang .= '.'.$encoding;
|
|
}
|
|
// Gettext firstly look the LANGUAGE env variable, so set it
|
|
putenv("LANGUAGE=$lang");
|
|
|
|
// Set the locale
|
|
if (setlocale(LC_ALL, $lang) === false)
|
|
self :: log_error("An error occured setting locale to '$lang'");
|
|
|
|
// Configure and set the text domain
|
|
$fullpath = bindtextdomain(LS_TEXT_DOMAIN, LS_I18N_DIR_PATH);
|
|
self :: log_trace("setLocale($lang, $encoding): Text domain fullpath is '$fullpath'.");
|
|
self :: log_trace("setLocale($lang, $encoding): Text domain is : ".textdomain(LS_TEXT_DOMAIN));
|
|
|
|
// Include local translation file
|
|
$lang_file = LS_I18N_DIR.'/'.$lang.'/lang.php';
|
|
if (LSsession :: includeFile($lang_file, false, false))
|
|
self :: log_trace("setLocale($lang, $encoding): lang file '$lang_file' loaded.");
|
|
else
|
|
self :: log_trace("setLocale($lang, $encoding): no lang file found ($lang_file).");
|
|
|
|
// Include other local translation file(s)
|
|
foreach(array(LS_I18N_DIR_PATH.'/'.$lang, LS_ROOT_DIR.'/'.LS_LOCAL_DIR.'/'.LS_I18N_DIR.'/'.$lang) as $lang_dir) {
|
|
self :: log_trace("setLocale($lang, $encoding): lookup for translation file in '$lang_dir'");
|
|
if (is_dir($lang_dir)) {
|
|
foreach (listFiles($lang_dir, '/^lang\..+\.php$/') as $file) {
|
|
$path = "$lang_dir/$file";
|
|
self :: log_trace("setLocale($lang, $encoding): load translation file '$path'");
|
|
include($path);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if ($encoding && $lang) $lang .= '.'.$encoding;
|
|
self :: log_error("The local '$lang' does not exists, use default one.");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Return list of available languages
|
|
*
|
|
* @param string|null $encoding Specify encoding for lang selection. If null, use self :: encoding value,
|
|
* if false, do not filter on encoding, otherwise filter available lang for
|
|
* specified encoding (optional, default: null)
|
|
* @param bool $with_encoding Return available lang list with encoding (optional, default: false)
|
|
*
|
|
* @return array List of available languages.
|
|
**/
|
|
public static function getLangList($encoding=null, $with_encoding=false) {
|
|
if (is_null($encoding))
|
|
$encoding = self :: $encoding;
|
|
if ($with_encoding)
|
|
$list = array('en_US.UTF8');
|
|
else
|
|
$list = array('en_US');
|
|
if ($encoding) {
|
|
if ($with_encoding)
|
|
$regex = '/^([a-zA-Z_]*\.'.$encoding.')$/';
|
|
else
|
|
$regex = '/^([a-zA-Z_]*)\.'.$encoding.'$/';
|
|
}
|
|
else {
|
|
if ($with_encoding)
|
|
$regex = '/^([a-zA-Z_]+\.[a-zA-Z0-9\-]+)$/';
|
|
else
|
|
$regex = '/^([a-zA-Z_]+)\.[a-zA-Z0-9\-]+$/';
|
|
}
|
|
self :: log_trace("getLangList(".varDump($encoding).", $with_encoding) : regex='$regex'");
|
|
foreach(array(LS_I18N_DIR_PATH, LS_ROOT_DIR.'/'.LS_LOCAL_DIR.'/'.LS_I18N_DIR) as $lang_dir) {
|
|
if (!is_dir($lang_dir))
|
|
continue;
|
|
if ($handle = opendir($lang_dir)) {
|
|
while (false !== ($file = readdir($handle))) {
|
|
if(is_dir("$lang_dir/$file")) {
|
|
if (preg_match($regex, $file, $regs)) {
|
|
if (!in_array($regs[1], $list)) {
|
|
$list[]=$regs[1];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return $list;
|
|
}
|
|
|
|
/**
|
|
* Return current language
|
|
*
|
|
* @param boolean $short If true, only return the two first characters of the language
|
|
* (For instance, 'fr' for 'fr_FR')
|
|
*
|
|
* @return string The current language (ex: fr_FR, or fr if $short==true)
|
|
**/
|
|
public static function getLang($short=false) {
|
|
if ($short) {
|
|
return strtolower(substr(self :: $lang, 0, 2));
|
|
}
|
|
return self :: $lang;
|
|
}
|
|
|
|
/**
|
|
* Return current encoding
|
|
*
|
|
* @return string The current encoding (ex: UTF8)
|
|
**/
|
|
public static function getEncoding() {
|
|
return self :: $encoding;
|
|
}
|
|
|
|
/**
|
|
* Check a locale exists
|
|
*
|
|
* @param string $lang The language (ex: fr_FR)
|
|
* @param string $encoding The encoding (ex: UTF8)
|
|
*
|
|
* @return boolean True if the locale is available, False otherwise
|
|
**/
|
|
public static function localeExist($lang, $encoding) {
|
|
if ( !$lang && !$encoding ) {
|
|
return false;
|
|
}
|
|
$locale=$lang.(($encoding)?'.'.$encoding:'');
|
|
if ($locale == 'en_US.UTF8') {
|
|
return true;
|
|
}
|
|
foreach(array(LS_I18N_DIR_PATH, LS_ROOT_DIR.'/'.LS_LOCAL_DIR.'/'.LS_I18N_DIR) as $lang_dir)
|
|
if (is_dir("$lang_dir/$locale"))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
***********************************************
|
|
* Generate translation file CLI methods
|
|
*
|
|
* Only load in CLI context
|
|
***********************************************
|
|
*/
|
|
if (php_sapi_name() != "cli") return true;
|
|
|
|
global $LSlang_cli_logger, $available_onlys, $available_withouts;
|
|
|
|
/**
|
|
* Convert relative path to absolute
|
|
* @param string $path The path to convert
|
|
* @return string The converted absolute path
|
|
*/
|
|
function _cli_relative2absolute_path($path) {
|
|
if ($path[0] == '/')
|
|
return $path;
|
|
global $curdir;
|
|
return realpath($curdir)."/".$path;
|
|
}
|
|
|
|
/**
|
|
* Convert absolute path to relative
|
|
* @param string $path The path to convert
|
|
* @return string The converted relative path
|
|
*/
|
|
function _cli_absolute2relative_path($path) {
|
|
if ($path[0] == '/')
|
|
$path = realpath($path);
|
|
if (substr($path, 0, strlen(LS_ROOT_DIR)) == LS_ROOT_DIR)
|
|
return substr($path, strlen(LS_ROOT_DIR)+1);
|
|
return $path;
|
|
}
|
|
|
|
/**
|
|
* CLI Helper to ask user to translate a string
|
|
* @param string $context The context of the string to translate
|
|
* @param string $msg The string to convert
|
|
* @return string|true The translated message string, true if $interactive_exit enabled
|
|
*/
|
|
function _cli_interactive_ask($context, $msg) {
|
|
global $copyoriginalvalue, $interactive_exit;
|
|
|
|
if ($interactive_exit) {
|
|
if ($copyoriginalvalue)
|
|
return $msg;
|
|
return true;
|
|
}
|
|
|
|
// Format question
|
|
$question ="\"$msg\"\n\n => "._("Please enter translated string");
|
|
$empty_action = (
|
|
$copyoriginalvalue?
|
|
_("or leave empty to copy original message"):
|
|
_("or leave empty to pass")
|
|
);
|
|
$question .= " (i";
|
|
if (!$copyoriginalvalue)
|
|
$question .= "/c";
|
|
$question .= "/e/q/? $empty_action): ";
|
|
|
|
while (true) {
|
|
if ($context)
|
|
fwrite(STDERR, "\n# $context\n");
|
|
fwrite(STDERR, $question);
|
|
$in = trim(fgets(STDIN));
|
|
switch($in) {
|
|
case 'q': // Exit interactive mode
|
|
case 'Q':
|
|
$interactive_exit = true;
|
|
return True;
|
|
case 'i': // Ignore
|
|
case 'I':
|
|
return True;
|
|
case 'c':
|
|
case 'C': // Copy
|
|
if (!$copyoriginalvalue)
|
|
return $msg;
|
|
case 'e':
|
|
case 'E': // Open editor
|
|
$tmp_file = tempnam(sys_get_temp_dir(), 'ldapsaisie_translation');
|
|
if ($tmp_file === false) {
|
|
fwrite(STDERR, _('Fail to create temporary file.'));
|
|
break;
|
|
}
|
|
$fd = fopen($tmp_file, 'w');
|
|
if ($fd === false) {
|
|
fwrite(STDERR, _('Fail to open temporary file.'));
|
|
break;
|
|
}
|
|
$nb_lines = 1;
|
|
if ($context) {
|
|
fwrite($fd, "# $context\n");
|
|
$nb_lines++;
|
|
}
|
|
$lines = explode("\n", $msg);
|
|
$nb_lines += count($lines);
|
|
fwrite($fd, "# ".implode("\n# ", $lines)."\n\n");
|
|
fclose($fd);
|
|
system("editor +$nb_lines $tmp_file > `tty`", $exit_code);
|
|
$result = array();
|
|
foreach(file($tmp_file) as $line)
|
|
if (!preg_match('/^# /', $line) || $result)
|
|
$result[] = preg_replace("/\n$/", "", $line);
|
|
unlink($tmp_file);
|
|
return implode("\n", $result);
|
|
case '?': // Help message
|
|
fwrite(STDERR, _("Available choices:\n"));
|
|
fwrite(STDERR, _(" - i: ignore this message\n"));
|
|
if (!$copyoriginalvalue)
|
|
fwrite(STDERR, _(" - c: copy original message\n"));
|
|
fwrite(STDERR, _(" - e: translate message in text editor\n"));
|
|
fwrite(STDERR, _(" - q: quit interactive mode and ignore all following untranslated messages\n"));
|
|
fwrite(STDERR, _(" - ?: Show this message\n"));
|
|
if ($copyoriginalvalue)
|
|
fwrite(STDERR, _("Or leave empty to copy original message.\n"));
|
|
else
|
|
fwrite(STDERR, _("Or leave empty to pass.\n"));
|
|
break;
|
|
case "": // Empty
|
|
// On copy orignal value mode, return $msg
|
|
if ($copyoriginalvalue)
|
|
return $msg;
|
|
// Otherwise, leave translation empty
|
|
return "";
|
|
default:
|
|
// Return user input
|
|
return $in;
|
|
}
|
|
}
|
|
// Supposed to never happen
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* CLI helper to add string to translate
|
|
* @param string $msg The string to translate
|
|
* @param string|null $context The context of the string to translate
|
|
* @return void
|
|
*/
|
|
function _cli_add_str_to_translate($msg, $context=null) {
|
|
global $LSlang_cli_logger, $lang, $data, $translations, $interactive, $interactive_exit, $copyoriginalvalue, $format;
|
|
$LSlang_cli_logger -> trace("_cli_add_str_to_translate($msg, $context)");
|
|
if ($msg == '')
|
|
return;
|
|
if (!is_null($lang) && _($msg) != "$msg")
|
|
return;
|
|
|
|
// Message already exists ?
|
|
if (array_key_exists($msg, $data)) {
|
|
if ($context && !in_array($context, $data[$msg]['contexts']))
|
|
$data[$msg]['contexts'][] = $context;
|
|
return;
|
|
}
|
|
|
|
// Handle translation
|
|
$translation = "";
|
|
if (array_key_exists($msg, $translations)) {
|
|
$translation = $translations[$msg];
|
|
}
|
|
elseif (!is_null($lang) && _($msg) != $msg) {
|
|
$translation = _($msg);
|
|
}
|
|
elseif ($interactive && $format != 'pot') {
|
|
$translation = _cli_interactive_ask($context, $msg);
|
|
if (!is_string($translation))
|
|
return;
|
|
}
|
|
$data[$msg] = array (
|
|
'translation' => $translation,
|
|
'contexts' => ($context?array($context):array()),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* CLI helper to add string to translate from LSconfig
|
|
* @param string $pattern The LSconfig parameter pattern used to find strings to translate
|
|
* @param string $what Where to find string to translate. Possible values:
|
|
* - key : The LSconfig parameter key
|
|
* - value : The LSconfig parameter value
|
|
* @param array $excludes Array of string to exclude
|
|
* @return void
|
|
*/
|
|
function _cli_add_str_to_translate_from_LSconfig($pattern, $what='value', $excludes=array()) {
|
|
global $LSlang_cli_logger;
|
|
$LSlang_cli_logger -> trace("_cli_add_str_to_translate_from_LSconfig($pattern, array(".implode(',', $excludes)."))");
|
|
$keys = LSconfig :: getMatchingKeys($pattern);
|
|
$LSlang_cli_logger -> trace("addFromLSconfig : ".count($keys)." matching key(s)");
|
|
foreach ($keys as $key => $value) {
|
|
$LSlang_cli_logger -> trace("addFromLSconfig : $key = ".varDump($value));
|
|
if ($what == '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))
|
|
_cli_add_str_to_translate($value, $key);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* CLI helper to add string to translate from list of possible values retreive from LSconfig
|
|
* @param string $context The context == prefix of the LSconfig parameter key to retreive possible values
|
|
* @param array<string> $withouts FIXME
|
|
* @param integer $level The level of the possible value (used to identify recursion level)
|
|
* @return void
|
|
*/
|
|
function _cli_add_possible_values_from_LSconfig($context, $withouts, $level=0) {
|
|
global $LSlang_cli_logger;
|
|
$LSlang_cli_logger -> trace("_cli_add_possible_values_from_LSconfig($context)");
|
|
if (in_array('select-list', $withouts))
|
|
return;
|
|
if (!LSconfig :: get("$context.translate_labels", True, "bool"))
|
|
return;
|
|
foreach(LSconfig :: get("$context.possible_values", array()) as $pkey => $plabel) {
|
|
if (is_array($plabel)) {
|
|
// Sub possible values
|
|
// Check level
|
|
if ($level > 1) {
|
|
$LSlang_cli_logger -> warning(
|
|
"_cli_add_possible_values_from_LSconfig($context): Level to hight to handle sub possible values of $context.possible_values.$pkey"
|
|
);
|
|
return;
|
|
}
|
|
_cli_add_str_to_translate_from_LSconfig("$context.possible_values.$pkey.label");
|
|
$LSlang_cli_logger -> trace("_cli_add_possible_values_from_LSconfig($context): handle sub possible values of $context.possible_values.$pkey");
|
|
_cli_add_possible_values_from_LSconfig("$context.possible_values.$pkey", $withouts, $level+1);
|
|
}
|
|
else {
|
|
switch ($pkey) {
|
|
case 'OTHER_OBJECT':
|
|
$LSlang_cli_logger -> trace("_cli_add_possible_values_from_LSconfig($context): ignore $context.possible_values.$pkey (OTHER_OBJECT)");
|
|
break;
|
|
case 'OTHER_ATTRIBUTE':
|
|
if (is_array($plabel)) {
|
|
if (isset($plabel['json_component_key']))
|
|
_cli_add_str_to_translate_from_LSconfig("$context.possible_values.OTHER_ATTRIBUTE.json_component_label");
|
|
else
|
|
_cli_add_str_to_translate_from_LSconfig("$context.possible_values.OTHER_ATTRIBUTE.*");
|
|
}
|
|
else {
|
|
$LSlang_cli_logger -> warning("_cli_add_possible_values_from_LSconfig($context): invalid $context.possible_values.OTHER_ATTRIBUTE config => Must be an array.");
|
|
}
|
|
break;
|
|
default:
|
|
_cli_add_str_to_translate($plabel, "$context.possible_values.$pkey");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* CLI helper to parse a template file to locate strings to translate
|
|
* @param string $file The file path
|
|
* @return void
|
|
*/
|
|
function _cli_parse_template_file($file) {
|
|
global $LSlang_cli_logger;
|
|
$LSlang_cli_logger -> debug("Looking for string to translate in '$file' template file");
|
|
$count = 0;
|
|
foreach(file($file) as $line) {
|
|
$count ++;
|
|
if (preg_match_all('/\{ *tr +msg=["\']([^\}]+)["\'] *\}/',$line,$matches)) {
|
|
foreach($matches[1] as $t) {
|
|
$t = preg_replace('/[\'"]\|escape\:.*$/', '', $t);
|
|
$LSlang_cli_logger -> trace(" - \"$t\" # Line $count");
|
|
_cli_add_str_to_translate($t, _cli_absolute2relative_path($file).":$count");
|
|
}
|
|
}
|
|
}
|
|
$LSlang_cli_logger -> trace("_cli_parse_template_file($file) : done.");
|
|
}
|
|
|
|
/**
|
|
* CLI helper to find and parse all template files of the specified directory
|
|
* to locate strings to translate
|
|
* @param string $dir The directory path
|
|
* @return void
|
|
*/
|
|
function _cli_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)) {
|
|
_cli_find_and_parse_template_file($dir.'/'.$file);
|
|
}
|
|
elseif (is_file($dir."/".$file) && preg_match('/\.tpl$/',$file)) {
|
|
_cli_parse_template_file($dir.'/'.$file);
|
|
}
|
|
}
|
|
closedir($dh);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* CLI helper to parse a PHP file to locate strings to translate
|
|
* @param string $file The file path
|
|
* @return void
|
|
*/
|
|
function _cli_parse_php_file($file) {
|
|
global $LSlang_cli_logger;
|
|
$LSlang_cli_logger -> debug("Looking for string to translate in '$file' PHP file");
|
|
$count = 0;
|
|
$quote='';
|
|
$res='';
|
|
foreach(file($file) as $line) {
|
|
$count++;
|
|
$LSlang_cli_logger -> trace("Handle line #$count of '$file' PHP file");
|
|
$offset=0;
|
|
while ($pos = strpos($line,'__(',$offset)) {
|
|
$LSlang_cli_logger -> trace("$file:$count: detect keyword at position #$pos ('$line')");
|
|
for ($i=$pos+3;$i<strlen($line);$i++) {
|
|
$offset=$i; // Always increase offset to avoid infinity-loop
|
|
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
|
|
break;
|
|
}
|
|
else {
|
|
// Unknown case : continue
|
|
$i++;
|
|
}
|
|
}
|
|
elseif ($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 : reset quote char detection and break detection
|
|
$quote='';
|
|
break;
|
|
}
|
|
else {
|
|
// End quote char not detected : append current char to result
|
|
$res.=$line[$i];
|
|
}
|
|
}
|
|
}
|
|
// Include detected string if not empty and quote char was detected and reseted
|
|
if (!empty($res) && empty($quote)) {
|
|
_cli_add_str_to_translate($res, _cli_absolute2relative_path($file).":$count");
|
|
$res='';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* CLI helper to find and parse all PHP files of the specified directory
|
|
* to locate strings to translate
|
|
* @param string $dir The directory path
|
|
* @return void
|
|
*/
|
|
function _cli_find_and_parse_php_file($dir, $filename_regex) {
|
|
if (is_dir($dir)) {
|
|
if ($dh = opendir($dir)) {
|
|
while (($file = readdir($dh)) !== false) {
|
|
if (preg_match($filename_regex, $file)) {
|
|
_cli_parse_php_file($dir.'/'.$file);
|
|
}
|
|
}
|
|
closedir($dh);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* CLI helper to generate output PHP translation file
|
|
* @param resource $fd The file descriptor where to write to generated output
|
|
* @return void
|
|
*/
|
|
function _cli_output_php($fd) {
|
|
global $LSlang_cli_logger, $additionalfileformat, $data, $copyoriginalvalue, $keep_unused, $translations;
|
|
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");
|
|
}
|
|
}
|
|
|
|
// Handle keep unused mode
|
|
if ($keep_unused) {
|
|
$unused_msgs = array();
|
|
foreach ($translations as $msg => $trans)
|
|
if (!array_key_exists($msg, $data))
|
|
$unused_msgs[$msg] = $trans;
|
|
if ($unused_msgs) {
|
|
fwrite($fd, "\n\n");
|
|
fwrite($fd, "######################################################################\n");
|
|
fwrite($fd, "# Unused translations keeped #\n");
|
|
fwrite($fd, "######################################################################\n");
|
|
foreach($unused_msgs as $key => $val) {
|
|
$key=str_replace('"','\\"',$key);
|
|
$val=str_replace('"','\\"',$val);
|
|
if ($additionalfileformat) {
|
|
fwrite($fd, "\n\$GLOBALS['LSlang'][\"$key\"] = \"$val\";\n");
|
|
}
|
|
else {
|
|
fwrite($fd, "\n\"$key\" =>\n \"$val\",\n");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!$additionalfileformat) fwrite($fd, "\n);\n");
|
|
}
|
|
|
|
/**
|
|
* CLI helper to clean a orignal or translated message before writing it in a POT file
|
|
* @param string $val The string to clean
|
|
* @return string The cleaned string
|
|
*/
|
|
function _cli_clean_for_pot_file($val) {
|
|
$val = str_replace('"', '\\"', $val);
|
|
return str_replace("\n", "\\n", $val);
|
|
}
|
|
|
|
/**
|
|
* CLI helper to generate output POT translation file
|
|
* @param resource $fd The file descriptor where to write to generated output
|
|
* @return void
|
|
*/
|
|
function _cli_output_pot($fd) {
|
|
global $LSlang_cli_logger, $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 = _cli_clean_for_pot_file($key);
|
|
$val = _cli_clean_for_pot_file($val);
|
|
fwrite($fd, "msgid \"$key\"\nmsgstr \"$val\"\n\n");
|
|
}
|
|
}
|
|
|
|
$available_onlys = array("config", "templates", "addons", "auth_methods", "includes");
|
|
$available_withouts = array_merge($available_onlys, array("select-list"));
|
|
|
|
|
|
/**
|
|
* CLI generate_lang_file command
|
|
*
|
|
* @param string $command_args Command arguments
|
|
*
|
|
* @return boolean True on success, false otherwise
|
|
**/
|
|
function cli_generate_lang_file($command_args) {
|
|
// Use global variables to share it with sub-functions
|
|
global $LSlang_cli_logger, $available_onlys, $available_withouts, $data, $translations, $interactive,
|
|
$interactive_exit, $copyoriginalvalue, $format, $curdir, $additionalfileformat, $copyoriginalvalue,
|
|
$keep_unused, $lang;
|
|
|
|
// Initialize logger (if not already initialized by another CLI command)
|
|
if (!isset($LSlang_cli_logger))
|
|
$LSlang_cli_logger = LSlog :: get_logger('generate_lang_file');
|
|
|
|
// Store existing translations
|
|
$translations = array();
|
|
// Store output translations
|
|
$data = array();
|
|
|
|
// Parameters
|
|
$only = null;
|
|
$withouts = array();
|
|
$include_upstream = false;
|
|
$copyoriginalvalue = False;
|
|
$interactive = False;
|
|
$interactive_exit = False; // Exit flag set when user type 'q'
|
|
$output = False;
|
|
$additionalfileformat = False;
|
|
$keep_unused = False;
|
|
$fix_utf8 = False;
|
|
$lang = null;
|
|
$encoding = null;
|
|
$available_formats = array('php', 'pot');
|
|
$format=$available_formats[0];
|
|
|
|
$debug = false;
|
|
$load_files = array();
|
|
|
|
// Change directory
|
|
$curdir = getcwd();
|
|
chdir(dirname(__FILE__).'/../');
|
|
|
|
for ($i=0; $i < count($command_args); $i++) {
|
|
switch ($command_args[$i]) {
|
|
case '--without':
|
|
case '-W':
|
|
$i++;
|
|
$without = strtolower($command_args[$i]);
|
|
if (!in_array($without, $available_withouts))
|
|
LScli :: usage(_("Invalid -W/--without parameter. Must be one of the following values: %s.'"), implode("','", $available_withouts));
|
|
elseif ($only)
|
|
LScli :: usage(_("You could not use -W/--without parameter combined with -O/--only parameter."));
|
|
$withouts[] = $without;
|
|
break;
|
|
|
|
case '--only':
|
|
case '-O':
|
|
$i++;
|
|
if ($only)
|
|
LScli :: usage(_("You could specify only one -O/--only parameter."));
|
|
$only = strtolower($command_args[$i]);
|
|
if (!in_array($only, $available_onlys))
|
|
LScli :: usage(_("Invalid -O/--only parameter. Must be one of the following values: %s.'"), implode("','", $available_onlys));
|
|
elseif ($withouts)
|
|
LScli :: usage(_("You could not use -W/--without parameter combined with -O/--only parameter."));
|
|
break;
|
|
|
|
case '-I':
|
|
case '--include-upstream':
|
|
$include_upstream=True;
|
|
break;
|
|
|
|
case '--copy-original-value':
|
|
case '-c':
|
|
$copyoriginalvalue=True;
|
|
break;
|
|
|
|
case '--interactive':
|
|
case '-i':
|
|
$interactive=True;
|
|
break;
|
|
|
|
case '--additional-file-format':
|
|
case '-a':
|
|
$additionalfileformat=True;
|
|
break;
|
|
|
|
case '--lang':
|
|
case '-l':
|
|
$i++;
|
|
$parse_lang = explode('.', $command_args[$i]);
|
|
if (count($parse_lang) == 2) {
|
|
$lang = $parse_lang[0];
|
|
$encoding = $parse_lang[1];
|
|
}
|
|
else {
|
|
LScli :: usage(_("Invalid -l/--lang parameter. Must be compose in format : [lang].[encoding]"));
|
|
}
|
|
break;
|
|
|
|
case '--output':
|
|
case '-o':
|
|
$i++;
|
|
$output = $command_args[$i];
|
|
break;
|
|
|
|
case '--format':
|
|
case '-f':
|
|
$i++;
|
|
$format = strtolower($command_args[$i]);
|
|
if (!in_array($format, $available_formats)) {
|
|
LScli :: usage(_("Invalid -f/--format parameter. Must be one of the following values: %s.'"), implode("','", $available_formats));
|
|
}
|
|
break;
|
|
|
|
case '--debug':
|
|
case '-d':
|
|
$debug = true;
|
|
break;
|
|
|
|
case '--keep-unused':
|
|
case '-K':
|
|
$keep_unused = true;
|
|
break;
|
|
|
|
case '--fix-utf8':
|
|
case '-F':
|
|
$fix_utf8 = true;
|
|
break;
|
|
|
|
default:
|
|
$path = _cli_relative2absolute_path($command_args[$i]);
|
|
if (is_file($path))
|
|
$load_files[] = $path;
|
|
else
|
|
LScli :: usage(_("%s: Invalid parameter or lang file to load."), $command_args[$i]);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// In fix-utf8 mode, load ForceUT8/Encoding lib
|
|
if ($fix_utf8)
|
|
LSsession :: includeFile(LS_LIB_DIR . "ForceUTF8/Encoding.php");
|
|
|
|
// Load translation files
|
|
foreach($load_files as $path) {
|
|
$LSlang_cli_logger -> debug("Load $path lang file");
|
|
@include($path);
|
|
foreach($GLOBALS['LSlang'] as $msg => $trans) {
|
|
if ($fix_utf8)
|
|
$translations[\ForceUTF8\Encoding::fixUTF8($msg)] = \ForceUTF8\Encoding::fixUTF8($trans);
|
|
else
|
|
$translations[$msg] = $trans;
|
|
}
|
|
}
|
|
|
|
// Initialize session
|
|
LSlang :: setLocale($lang, $encoding);
|
|
|
|
// Load lang string if lang was specify
|
|
if ($lang && $encoding && isset($GLOBALS['LSlang']) && is_array($GLOBALS['LSlang'])) {
|
|
foreach($GLOBALS['LSlang'] as $msg => $trans) {
|
|
if ($fix_utf8)
|
|
$translations[\ForceUTF8\Encoding::fixUTF8($msg)] = \ForceUTF8\Encoding::fixUTF8($trans);
|
|
else
|
|
$translations[$msg] = $trans;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Manage configuration parameters
|
|
*/
|
|
if (!in_array('config', $withouts) && (!$only || $only == 'config')) {
|
|
// LDAP Servers
|
|
$objects = array();
|
|
$LSlang_cli_logger -> info("Looking for string to translate configuration of LDAP servers");
|
|
foreach(LSconfig :: keys('ldap_servers') as $ldap_server_id) {
|
|
$LSlang_cli_logger -> debug("Looking for string to translate configuration of LDAP server #$ldap_server_id");
|
|
_cli_add_str_to_translate_from_LSconfig("ldap_servers.$ldap_server_id.name");
|
|
_cli_add_str_to_translate_from_LSconfig("ldap_servers.$ldap_server_id.subDnLabel");
|
|
_cli_add_str_to_translate_from_LSconfig("ldap_servers.$ldap_server_id.recoverPassword.recoveryHashMail.subject");
|
|
_cli_add_str_to_translate_from_LSconfig("ldap_servers.$ldap_server_id.recoverPassword.recoveryHashMail.msg");
|
|
_cli_add_str_to_translate_from_LSconfig("ldap_servers.$ldap_server_id.recoverPassword.newPasswordMail.subject");
|
|
_cli_add_str_to_translate_from_LSconfig("ldap_servers.$ldap_server_id.recoverPassword.newPasswordMail.msg");
|
|
_cli_add_str_to_translate_from_LSconfig("ldap_servers.$ldap_server_id.subDn.*", 'key', array("LSobject"));
|
|
_cli_add_str_to_translate_from_LSconfig("ldap_servers.$ldap_server_id.LSprofiles.*.label");
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
$LSlang_cli_logger -> debug('LSobjects list : '.implode(', ', $objects));
|
|
|
|
// LSobject
|
|
foreach($objects as $obj) {
|
|
$LSlang_cli_logger -> info("Looking for string to translate configuration of object type $obj");
|
|
_cli_add_str_to_translate_from_LSconfig("LSobjects.$obj.label");
|
|
|
|
// LSrelation
|
|
_cli_add_str_to_translate_from_LSconfig("LSobjects.$obj.LSrelation.*.label");
|
|
_cli_add_str_to_translate_from_LSconfig("LSobjects.$obj.LSrelation.*.emptyText");
|
|
|
|
// Custom Actions
|
|
_cli_add_str_to_translate_from_LSconfig("LSobjects.$obj.customActions.*.label");
|
|
_cli_add_str_to_translate_from_LSconfig("LSobjects.$obj.customActions.*.helpInfo");
|
|
_cli_add_str_to_translate_from_LSconfig("LSobjects.$obj.customActions.*.question_format");
|
|
_cli_add_str_to_translate_from_LSconfig("LSobjects.$obj.customActions.*.onSuccessMsgFormat");
|
|
|
|
// LSform
|
|
_cli_add_str_to_translate_from_LSconfig("LSobjects.$obj.LSform.layout.*.label");
|
|
_cli_add_str_to_translate_from_LSconfig("LSobjects.$obj.LSform.dataEntryForm.*.label");
|
|
|
|
// LSsearch
|
|
_cli_add_str_to_translate_from_LSconfig("LSobjects.$obj.LSsearch.predefinedFilters.*");
|
|
_cli_add_str_to_translate_from_LSconfig("LSobjects.$obj.LSsearch.extraDisplayedColumns.*.label");
|
|
_cli_add_str_to_translate_from_LSconfig("LSobjects.$obj.LSsearch.extraDisplayedColumns.*.LSformat");
|
|
_cli_add_str_to_translate_from_LSconfig("LSobjects.$obj.LSsearch.extraDisplayedColumns.*.alternativeLSformats.*");
|
|
_cli_add_str_to_translate_from_LSconfig("LSobjects.$obj.LSsearch.extraDisplayedColumns.*.formaterLSformat");
|
|
_cli_add_str_to_translate_from_LSconfig("LSobjects.$obj.LSsearch.customActions.*.label");
|
|
_cli_add_str_to_translate_from_LSconfig("LSobjects.$obj.LSsearch.customActions.*.question_format");
|
|
_cli_add_str_to_translate_from_LSconfig("LSobjects.$obj.LSsearch.customActions.*.onSuccessMsgFormat");
|
|
|
|
// Attributes
|
|
foreach(LSconfig :: keys("LSobjects.$obj.attrs") as $attr) {
|
|
_cli_add_str_to_translate_from_LSconfig("LSobjects.$obj.attrs.$attr.label");
|
|
_cli_add_str_to_translate_from_LSconfig("LSobjects.$obj.attrs.$attr.help_info");
|
|
_cli_add_str_to_translate_from_LSconfig("LSobjects.$obj.attrs.$attr.no_value_label");
|
|
_cli_add_str_to_translate_from_LSconfig("LSobjects.$obj.attrs.$attr.check_data.*.msg");
|
|
_cli_add_str_to_translate_from_LSconfig("LSobjects.$obj.attrs.$attr.validation.*.msg");
|
|
|
|
// HTML Options
|
|
$html_type = LSconfig :: get("LSobjects.$obj.attrs.$attr.html_type");
|
|
switch($html_type) {
|
|
case 'boolean':
|
|
_cli_add_str_to_translate_from_LSconfig("LSobjects.$obj.attrs.$attr.html_options.true_label");
|
|
_cli_add_str_to_translate_from_LSconfig("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) {
|
|
_cli_add_str_to_translate_from_LSconfig("LSobjects.$obj.attrs.$attr.html_options.components.$c.label");
|
|
_cli_add_str_to_translate_from_LSconfig("LSobjects.$obj.attrs.$attr.html_options.components.$c.help_info");
|
|
_cli_add_str_to_translate_from_LSconfig("LSobjects.$obj.attrs.$attr.html_options.components.$c.check_data.*.msg");
|
|
|
|
if (LSconfig :: get("LSobjects.$obj.attrs.$attr.html_options.components.$c.type") == 'select_list')
|
|
_cli_add_possible_values_from_LSconfig("LSobjects.$obj.attrs.$attr.html_options.components.$c.options", $withouts);
|
|
}
|
|
break;
|
|
case 'labeledValue':
|
|
if (LSconfig :: get("LSobjects.$obj.attrs.$attr.html_options.translate_labels", True, "bool"))
|
|
_cli_add_str_to_translate_from_LSconfig("LSobjects.$obj.attrs.$attr.html_options.labels.*");
|
|
break;
|
|
case 'password':
|
|
_cli_add_str_to_translate_from_LSconfig("LSobjects.$obj.attrs.$attr.html_options.mail.subject");
|
|
_cli_add_str_to_translate_from_LSconfig("LSobjects.$obj.attrs.$attr.html_options.mail.msg");
|
|
_cli_add_str_to_translate_from_LSconfig("LSobjects.$obj.attrs.$attr.html_options.confirmChangeQuestion");
|
|
break;
|
|
case 'select_list':
|
|
case 'select_box':
|
|
_cli_add_possible_values_from_LSconfig("LSobjects.$obj.attrs.$attr.html_options", $withouts);
|
|
break;
|
|
case 'valueWithUnit':
|
|
_cli_add_str_to_translate_from_LSconfig("LSobjects.$obj.attrs.$attr.html_options.units.*");
|
|
break;
|
|
case 'date':
|
|
_cli_add_str_to_translate_from_LSconfig("LSobjects.$obj.attrs.$attr.html_options.special_values.*");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Manage template file
|
|
*/
|
|
if (!in_array('templates', $withouts) && (!$only || $only == 'templates')) {
|
|
$LSlang_cli_logger -> info("Looking for string to translate in templates file");
|
|
if ($include_upstream) _cli_find_and_parse_template_file(LS_ROOT_DIR.'/'.LS_TEMPLATES_DIR);
|
|
_cli_find_and_parse_template_file(LS_ROOT_DIR.'/'.LS_LOCAL_DIR.LS_TEMPLATES_DIR);
|
|
}
|
|
|
|
/*
|
|
* Manage custom PHP code/config files
|
|
*/
|
|
|
|
// Manage includes files
|
|
if (!in_array('includes', $withouts) && (!$only || $only == 'includes')) {
|
|
// Note: Upstream code most only use gettext translation, do not handle it here
|
|
if ($include_upstream) _cli_find_and_parse_php_file(LS_ROOT_DIR.'/'.LS_INCLUDE_DIR, '/^(.+)\.php$/');
|
|
_cli_find_and_parse_php_file(LS_ROOT_DIR.'/'.LS_LOCAL_DIR.LS_INCLUDE_DIR, '/^(.+)\.php$/');
|
|
if ($include_upstream) _cli_find_and_parse_php_file(LS_ROOT_DIR.'/'.LS_CLASS_DIR, '/^class\.(.+)\.php$/');
|
|
_cli_find_and_parse_php_file(LS_ROOT_DIR.'/'.LS_LOCAL_DIR.LS_CLASS_DIR, '/^class\.(.+)\.php$/');
|
|
}
|
|
|
|
// Manage addons files
|
|
if (!in_array('addons', $withouts) && (!$only || $only == 'addons')) {
|
|
$LSlang_cli_logger -> info("Looking for string to translate in LSaddons PHP code");
|
|
if ($include_upstream) _cli_find_and_parse_php_file(LS_ROOT_DIR.'/'.LS_ADDONS_DIR, '/^LSaddons\.(.+)\.php$/');
|
|
_cli_find_and_parse_php_file(LS_ROOT_DIR.'/'.LS_LOCAL_DIR.LS_ADDONS_DIR, '/^LSaddons\.(.+)\.php$/');
|
|
$LSlang_cli_logger -> info("Looking for string to translate in LSaddons configuration files");
|
|
if ($include_upstream) _cli_find_and_parse_php_file(LS_ROOT_DIR.'/'.LS_CONF_DIR.'/LSaddons', '/^config\.LSaddons\.(.+)\.php$$/');
|
|
_cli_find_and_parse_php_file(LS_ROOT_DIR.'/'.LS_LOCAL_DIR.LS_CONF_DIR.'/LSaddons', '/^config\.LSaddons\.(.+)\.php$$/');
|
|
}
|
|
|
|
// Manage auth methods files
|
|
if (!in_array('auth_methods', $withouts) && (!$only || $only == 'auth_methods')) {
|
|
$LSlang_cli_logger -> info("Looking for string to translate in LSauthMethods configuration files");
|
|
if ($include_upstream) _cli_find_and_parse_php_file(LS_ROOT_DIR.'/'.LS_CONF_DIR.'/LSauth', '/^config\.(.+)\.php$$/');
|
|
_cli_find_and_parse_php_file(LS_ROOT_DIR.'/'.LS_LOCAL_DIR.LS_CONF_DIR.'/LSauth', '/^config\.(.+)\.php$$/');
|
|
}
|
|
|
|
// Sort resulting strings
|
|
ksort($data);
|
|
|
|
/*
|
|
* Handle output file format
|
|
*/
|
|
|
|
// Determine where to write result
|
|
if ($output) {
|
|
$output = _cli_relative2absolute_path($output);
|
|
$LSlang_cli_logger -> info("Write result in output file ($output)");
|
|
$fd = null;
|
|
try {
|
|
$LSlang_cli_logger -> debug("Open output file ($output)");
|
|
$fd = fopen($output, 'w');
|
|
}
|
|
catch(Exception $e) {
|
|
$LSlang_cli_logger -> error('Error occured opening output file : '.$e->getMessage(), "\n");
|
|
}
|
|
if (!$fd) {
|
|
$LSlang_cli_logger -> error("Use stdout out instead.\n");
|
|
$fd = STDOUT;
|
|
$output = false;
|
|
}
|
|
}
|
|
else
|
|
$fd = STDOUT;
|
|
|
|
// Generate output
|
|
$LSlang_cli_logger -> debug("Output format : $format");
|
|
switch($format) {
|
|
case 'pot':
|
|
_cli_output_pot($fd);
|
|
break;
|
|
case 'php':
|
|
default:
|
|
_cli_output_php($fd);
|
|
break;
|
|
}
|
|
|
|
// Close output file (is specified)
|
|
if ($output && $fd != STDOUT) {
|
|
$LSlang_cli_logger -> debug("Close output file ($output)");
|
|
fclose($fd);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Args autocompleter for CLI command generate_lang_file
|
|
*
|
|
* @param array $comp_words List of already typed words of the command
|
|
* @param int $comp_word_num The command word number to autocomplete
|
|
* @param string $comp_word The command word to autocomplete
|
|
* @param array<string> $opts List of global available options
|
|
*
|
|
* @return array<string> List of available options for the word to autocomplete
|
|
**/
|
|
function cli_generate_lang_file_args_autocompleter($comp_words, $comp_word_num, $comp_word, $opts) {
|
|
global $available_withouts, $available_onlys;
|
|
switch ($comp_words[$comp_word_num-1]) {
|
|
case '-W':
|
|
case '--without':
|
|
return LScli :: autocomplete_opts($available_withouts, $comp_word);
|
|
break;
|
|
case '-O':
|
|
case '--only':
|
|
return LScli :: autocomplete_opts($available_onlys, $comp_word);
|
|
break;
|
|
case '-l':
|
|
case '--lang':
|
|
return LScli :: autocomplete_opts(LSlang :: getLangList(false, true), $comp_word);
|
|
break;
|
|
case '-o':
|
|
case '--output':
|
|
return array();
|
|
break;
|
|
case '-f':
|
|
case '--format':
|
|
return LScli :: autocomplete_opts(array('php', 'pot'), $comp_word);
|
|
break;
|
|
}
|
|
$opts = array_merge(
|
|
$opts,
|
|
array (
|
|
'-W', '--without',
|
|
'-O', '--only',
|
|
'-c', '--copy-original-value',
|
|
'-i', '--interactive',
|
|
'-a', '--additional-file-format',
|
|
'-l', '--lang',
|
|
'-o', '--output',
|
|
'-f', '--format',
|
|
'-I', '--include-upstream',
|
|
'-K', '--keep-unused',
|
|
'-F', '--fix-utf8',
|
|
)
|
|
);
|
|
return LScli :: autocomplete_opts($opts, $comp_word);
|
|
}
|
|
|
|
LScli :: add_command(
|
|
'generate_lang_file',
|
|
'cli_generate_lang_file',
|
|
___('Generate lang.php file'),
|
|
'-l [lang] [-o output.file] [file1] [file2] [-h] [options]',
|
|
array(
|
|
___(
|
|
" -W/--without Disable specified messages. Must be one of
|
|
the following values:"),
|
|
" - ".implode("\n - ", $available_withouts),
|
|
___(
|
|
" -O/--only Only handle specified messages. Must be one
|
|
of the following values :"),
|
|
" - ".implode("\n - ", $available_onlys),
|
|
___(
|
|
" -I/--include-upstream Include upstream code to message lookup
|
|
-c/--copy-original-value Copy original value as translated value when
|
|
no translated value exists
|
|
-i/--interactive Interactive mode : ask user to enter
|
|
translated on each translation needed
|
|
-a/--additional-file-format Additional file format output
|
|
-l/--lang Language of the translation
|
|
Format: [lang].[encoding]
|
|
-o/--output Output file (default: stdout)
|
|
-f/--format Output file format : php or pot
|
|
(default: php)
|
|
-K/--keep-unused Keep unused translations in resulting file
|
|
-F/--fix-utf8 Try to load and fix broken UTF-8 characters
|
|
in existing lang files.")
|
|
),
|
|
false, // This command does not need LDAP connection
|
|
'cli_generate_lang_file_args_autocompleter'
|
|
);
|
|
|
|
/**
|
|
* CLI generate_ldapsaisie_pot command
|
|
*
|
|
* @param string $command_args Command arguments
|
|
*
|
|
* @return boolean True on success, false otherwise
|
|
**/
|
|
function cli_generate_ldapsaisie_pot($command_args) {
|
|
global $LSlang_cli_logger;
|
|
// Initialize logger (if not already initialized by another CLI command)
|
|
if (!isset($LSlang_cli_logger))
|
|
$LSlang_cli_logger = LSlog :: get_logger('generate_ldapsaisie_pot');
|
|
|
|
// Clean php file in tmp directory
|
|
if (is_dir(LS_TMP_DIR_PATH)) {
|
|
foreach(listFiles(LS_TMP_DIR_PATH, '/\.php$/') as $file) {
|
|
$tmp_file = LS_TMP_DIR_PATH.$file;
|
|
$LSlang_cli_logger -> debug("Remove temporary file '$tmp_file'");
|
|
if (!unlink($tmp_file)) {
|
|
$LSlang_cli_logger -> fatal("Fail to delete temporary file '$tmp_file'.");
|
|
}
|
|
}
|
|
}
|
|
|
|
// List PHP files to parse
|
|
$php_files = LScli :: run_external_command(
|
|
array('find', '-name', "'*.php'"),
|
|
null, // no STDIN data
|
|
false, // do not escape command args (already done)
|
|
LS_ROOT_DIR // run in LdapSaisie root directory to retreive relative paths
|
|
);
|
|
if (!is_array($php_files) || $php_files[0] != 0) {
|
|
$LSlang_cli_logger -> fatal("Fail to list PHP files.");
|
|
return false;
|
|
}
|
|
|
|
// Extract messages from LdapSaisie PHP files using xgettext
|
|
$result = LScli :: run_external_command(
|
|
array(
|
|
"xgettext",
|
|
"--from-code utf-8",
|
|
"--language=PHP",
|
|
"-o", LS_I18N_DIR_PATH."/ldapsaisie-main.pot", // Output
|
|
"--omit-header", // No POT header
|
|
"--keyword=__", // Handle custom __() translation function
|
|
"--keyword=___", // Handle custom ___() translation function
|
|
"--files=-" // Read files to parse from STDIN
|
|
),
|
|
$php_files[1], // Pass PHP files list via STDIN
|
|
true, // Escape parameters
|
|
LS_ROOT_DIR // Run in LdapSaisie root directory
|
|
);
|
|
if (!is_array($result) || $result[0] != 0)
|
|
$LSlang_cli_logger -> fatal("Fail to extract messages from PHP files using xgettext.");
|
|
|
|
|
|
// Extract other messages from LdapSaisie templates files
|
|
$result = LScli :: run_command(
|
|
'generate_lang_file',
|
|
array (
|
|
"-o", LS_I18N_DIR_PATH."/ldapsaisie-templates.pot",
|
|
"-f", "pot",
|
|
"--only", "templates",
|
|
"--include-upstream",
|
|
),
|
|
false // do not exit
|
|
);
|
|
if (!$result)
|
|
$LSlang_cli_logger -> fatal("Fail to extract messages from template files using generate_lang_file command.");
|
|
|
|
// Merge previous results in ldapsaisie.pot file using msgcat
|
|
$result = LScli :: run_external_command(array(
|
|
'msgcat',
|
|
LS_I18N_DIR_PATH."/ldapsaisie-main.pot",
|
|
LS_I18N_DIR_PATH."/ldapsaisie-templates.pot",
|
|
"-o", LS_I18N_DIR_PATH."/ldapsaisie.pot",
|
|
));
|
|
if (!is_array($result) || $result[0] != 0)
|
|
$LSlang_cli_logger -> fatal("Fail to merge messages using msgcat.");
|
|
|
|
return true;
|
|
}
|
|
LScli :: add_command(
|
|
'generate_ldapsaisie_pot',
|
|
'cli_generate_ldapsaisie_pot',
|
|
___('Generate POT files:'),
|
|
null,
|
|
array(
|
|
___("This command generate 3 POT files:"),
|
|
" - ".LS_I18N_DIR_PATH."/ldapsaisie-main.pot",
|
|
___(" => contains messages from PHP files"),
|
|
" - ".LS_I18N_DIR_PATH."/ldapsaisie-templates.pot",
|
|
___(" => contains messages from templates files"),
|
|
" - ".LS_I18N_DIR_PATH."/ldapsaisie.pot",
|
|
___(" => contains all messages"),
|
|
),
|
|
false // This command does not need LDAP connection
|
|
);
|