diff --git a/emhttp/locale/LC_MESSAGES/en_US-helptext.txt b/emhttp/languages/en_US/helptext.txt similarity index 100% rename from emhttp/locale/LC_MESSAGES/en_US-helptext.txt rename to emhttp/languages/en_US/helptext.txt diff --git a/emhttp/plugins/dynamix.plugin.manager/scripts/language b/emhttp/plugins/dynamix.plugin.manager/scripts/language index 731a82ff5..91f1f8400 100755 --- a/emhttp/plugins/dynamix.plugin.manager/scripts/language +++ b/emhttp/plugins/dynamix.plugin.manager/scripts/language @@ -8,8 +8,6 @@ $docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp'); require_once "$docroot/webGui/include/Wrappers.php"; -require_once "$docroot/webGui/include/Translations.php"; - $logger = 'language-manager'; $usage = << 1) { @unlink($save); @@ -196,11 +195,8 @@ function language($method, $xml_file, &$error) { case 'remove': $name = $xml->LanguagePack; if ($name) { - $path = "$docroot/locale/en_US/LC_MESSAGES"; - @unlink("$path/$name.mo"); - @unlink("$path/$name-helptext.txt"); - @unlink("$path/$name-helptext.dot"); - @unlink("$path/$name-javascript*.txt"); + $path = "$docroot/languages/$name"; + exec("rm -rf $path"); @unlink("$docroot/webGui/javascript/translate.$name.js"); @unlink("$boot/lang-$name.xml"); @unlink("$plugins/lang-$name.xml"); @@ -398,19 +394,6 @@ if ($method == 'update') { copy($xml_file, $lang_file); symlink($lang_file, $link_file); write("language: $lang language pack updated\n"); - - // if the language pack is the same as the current language, force gettext to drop the cache - $dynamixSettings = parse_ini_file("/boot/config/plugins/dynamix/dynamix.cfg",true); - if ( ($dynamixSettings['Display']['locale']??false) && ( ($dynamixSettings['Display']['locale']??false) == $lang ) ) { - my_logger("Flushing language cache for $lang", $logger); - bindtextdomain('en_US', '/usr/local/emhttp/locale'); - bind_textdomain_codeset('en_US', 'UTF-8'); - textdomain('en_US'); - $flushCache = gettext("OK"); - bindtextdomain($lang, '/usr/local/emhttp/locale'); - bind_textdomain_codeset($lang, 'UTF-8'); - textdomain($lang); - } my_logger("$lang language pack updated", $logger); // run hook scripts for post processing post_hooks(); diff --git a/emhttp/plugins/dynamix/include/Translations.php b/emhttp/plugins/dynamix/include/Translations.php old mode 100755 new mode 100644 index 415ca2f7b..c3bd47382 --- a/emhttp/plugins/dynamix/include/Translations.php +++ b/emhttp/plugins/dynamix/include/Translations.php @@ -13,9 +13,6 @@ _('Monday'),'Tuesday'=>_('Tuesday'),'Wednesday'=>_('Wednesday'),'Thursday'=>_('Thursday'),'Friday'=>_('Friday'),'Saturday'=>_('Saturday'),'Sunday'=>_('Sunday'),'Mon'=>_('Mon'),'Tue'=>_('Tue'),'Wed'=>_('Wed'),'Thu'=>_('Thu'),'Fri'=>_('Fri'),'Sat'=>_('Sat'),'Sun'=>_('Sun'),'January'=>_('January'),'February'=>_('February'),'March'=>_('March'),'April'=>_('April'),'May'=>_('May'),'June'=>_('June'),'July'=>_('July'),'August'=>_('August'),'September'=>_('September'),'October'=>_('October'),'November'=>_('November'),'December'=>_('December'),'Jan'=>_('Jan'),'Feb'=>_('Feb'),'Mar'=>_('Mar'),'Apr'=>_('Apr'),'May'=>_('May'),'Jun'=>_('Jun'),'Jul'=>_('Jul'),'Aug'=>_('Aug'),'Sep'=>_('Sep'),'Oct'=>_('Oct'),'Nov'=>_('Nov'),'Dec'=>_('Dec')]; - foreach ($language_date as $word => $that) if (strpos($text,$word)!==false) {$text = str_replace($word,$that,$text); break;} + parse_array($language['Months_array'] ?? '',$months); + parse_array($language['Days_array'] ?? '',$days); + foreach ($months as $word => $that) if (strpos($text,$word)!==false) {$text = str_replace($word,$that,$text); break;} + foreach ($days as $word => $that) if (strpos($text,$word)!==false) {$text = str_replace($word,$that,$text); break;} return $text; case 1: // number translation - static $language_numbers = ['thirty'=>_('thirty'),'twenty-nine'=>_('twenty-nine'),'twenty-eight'=>_('twenty-eight'),'twenty-seven'=>_('twenty-seven'),'twenty-six'=>_('twenty-six'),'twenty-five'=>_('twenty-five'),'twenty-four'=>_('twenty-four'),'twenty-three'=>_('twenty-three'),'twenty-two'=>_('twenty-two'),'twenty-one'=>_('twenty-one'),'twenty'=>_('twenty'),'nineteen'=>_('nineteen'),'eighteen'=>_('eighteen'),'seventeen'=>_('seventeen'),'sixteen'=>_('sixteen'),'fifteen'=>_('fifteen'),'fourteen'=>_('fourteen'),'thirteen'=>_('thirteen'),'twelve'=>_('twelve'),'eleven'=>_('eleven'),'ten'=>_('ten'),'nine'=>_('nine'),'eight'=>_('eight'),'seven'=>_('seven'),'six'=>_('six'),'five'=>_('five'),'four'=>_('four'),'three'=>_('three'),'two'=>_('two'),'one'=>_('one'),'zero'=>_('zero')]; - return $language_numbers[$text] ?? $text; + parse_array($language['Numbers_array'] ?? '',$numbers); + return $numbers[$text] ?? $text; case 2: // time translation - static $language_time = ['days'=>_('days'),'hours'=>_('hours'),'minutes'=>_('minutes'),'seconds'=>_('seconds'),'day'=>_('day'),'hour'=>_('hour'),'minute'=>_('minute'),'second'=>_('second')]; - foreach ($language_time as $word => $that) if (strpos($text,$word)!==false) {$text = str_replace($word,$that,$text); break;} + $keys = ['days','hours','minutes','seconds','day','hour','minute','second']; + foreach ($keys as $key) if (isset($language[$key])) $text = preg_replace("/\b$key\b/",$language[$key],$text); return $text; case 3: // device translation [$p1,$p2] = array_pad(preg_split('/(?<=[a-z])(?= ?[0-9]+)/i',$text),2,''); return _($p1).$p2; default: // regular translation - return preg_replace(['/\*\*(.+?)\*\*/','/\*(.+?)\*/',"/'/"],['$1','$1','''],gettext($text)); + $text = $language[preg_replace(['/\&|[\?\{\}\|\&\~\!\[\]\(\)\/\\:\*^\.\"\']|<.+?\/?>/','/^(null|yes|no|true|false|on|off|none)$/i','/ +/'],['','$1.',' '],$text)] ?? $text; + return preg_replace(['/\*\*(.+?)\*\*/','/\*(.+?)\*/',"/'/"],['$1','$1','''],$text); } } - +function parse_lang_file($file) { + // parser for translation files, includes some trickery to handle PHP quirks. + return array_safe((array)parse_ini_string(preg_replace(['/^\s*?(null|yes|no|true|false|on|off|none)\s*?=/mi','/^\s*?([^>].*?)\s*?=\s*?(.*)\s*?$/m','/^:(.+_(help|plug)):$/m','/^:end$/m'],['$1.=','$1="$2"','_$1="','"'],escapeQuotes(file_get_contents($file))))); +} function parse_help_file($file) { // parser for help text files, includes some trickery to handle PHP quirks. $text = array_tags((array)parse_ini_string(preg_replace(['/^$/m','/^([^:;].+)$/m','/^:(.+_help(_\d{8})?):$/m','/^:end$/m'],['>','>$1','_$1="','"'],escapeQuotes(file_get_contents($file))))); return array_help($text); } +function parse_text($text) { + // inline text parser + return preg_replace_callback('/_\((.+?)\)_/m',function($m){return _($m[1]);},preg_replace(["/^:(.+_help):$/m","/^:(.+_plug):$/m","/^:end$/m"],["","",""],$text)); +} +function parse_file($file,$markdown=true) { + // replacement of PHP include function + return $markdown ? Markdown(parse_text(file_get_contents($file))) : parse_text(file_get_contents($file)); +} +function parse_plugin($plugin) { + // parse and add plugin related translations + global $docroot,$language,$locale; + $plugin = strtolower($plugin); + $text = "$docroot/languages/$locale/$plugin.txt"; + if (file_exists($text)) { + $store = "$docroot/languages/$locale/$plugin.dot"; + if (!file_exists($store)) file_put_contents($store,serialize(parse_lang_file($text))); + $language = array_merge($language,unserialize(file_get_contents($store))); + } +} +// internal helper functions +function parse_array($text,&$array) { + // multi keyword parser + parse_str(str_replace([' ',':'],['&','='],$text),$array); +} +function array_safe($array) { + // remove potential dangerous tags + return array_filter($array,function($v,$k){ + return strlen($v) && !preg_match('#<(script|iframe)(.*?)>(.+?)|<(link|meta)\s(.+?)/?>#is',html_entity_decode($v)); + },ARRAY_FILTER_USE_BOTH); +} function array_tags($array) { // filter outdated help tags return array_filter($array,function($v,$k){ @@ -90,25 +109,6 @@ function array_help(&$array) { } return $array; } -// internal helper functions -function parse_array($text,&$array) { - // multi keyword parser - parse_str(str_replace([' ',':'],['&','='],$text),$array); -} -function array_safe($array) { - // remove potential dangerous tags - return array_filter($array,function($v,$k){ - return strlen($v) && !preg_match('#<(script|iframe)(.*?)>(.+?)|<(link|meta)\s(.+?)/?>#is',html_entity_decode($v)); - },ARRAY_FILTER_USE_BOTH); -} -function parse_lang_file($file) { - // parser for translation files, includes some trickery to handle PHP quirks. - return array_safe((array)parse_ini_string(preg_replace(['/^\s*?(null|yes|no|true|false|on|off|none)\s*?=/mi','/^\s*?([^>].*?)\s*?=\s*?(.*)\s*?$/m','/^:(.+_(help|plug)):$/m','/^:end$/m'],['$1.=','$1="$2"','_$1="','"'],escapeQuotes(file_get_contents($file))))); -} -function parse_text($text) { - // inline text parser - return preg_replace_callback('/_\((.+?)\)_/m',function($m){return _($m[1]);},preg_replace(["/^:(.+_help):$/m","/^:(.+_plug):$/m","/^:end$/m"],["","",""],$text)); -} function escapeQuotes($text) { // escape double quotes return str_replace(["\"\n",'"'],["\" \n",'\"'],$text); @@ -125,39 +125,26 @@ $language = []; $locale = $_SESSION['locale'] ?? $login_locale ?? ''; $return = "function _(t){return t;}"; $jscript = "$docroot/webGui/javascript/translate.en_US.js"; -$root = "$docroot/locale/en_US/LC_MESSAGES/en_US-helptext.txt"; -$help = "$docroot/locale/en_US/LC_MESSAGES/en_US-helptext.dot"; -$languageDir = "$docroot/locale/en_US/LC_MESSAGES"; +$root = "$docroot/languages/en_US/helptext.txt"; +$help = "$docroot/languages/en_US/helptext.dot"; -putenv("LC_ALL=en_US.UTF-8"); -setlocale(LC_ALL, 'en_US.UTF-8'); - -$domain = $locale ?: 'en_US'; -if ( !is_file("$languageDir/$locale.mo")) { - $locale = 'en_US'; -} - -bindtextdomain($domain, '/usr/local/emhttp/locale'); -bind_textdomain_codeset($domain, 'UTF-8'); -textdomain($domain); - -if ($locale && $locale != 'en_US') { - $text = "$languageDir/$locale-helptext.txt"; +if ($locale) { + $text = "$docroot/languages/$locale/translations.txt"; if (file_exists($text)) { - $store = "$languageDir/$locale-helptext.dot"; + $store = "$docroot/languages/$locale/translations.dot"; // global translations if (!file_exists($store)) file_put_contents($store,serialize(parse_lang_file($text))); $language = unserialize(file_get_contents($store)); } - if (file_exists("$languageDir/$locale-helptext.txt")) { - $root = "$languageDir/$locale-helptext.txt"; - $help = "$languageDir/$locale-helptext.dot"; + if (file_exists("$docroot/languages/$locale/helptext.txt")) { + $root = "$docroot/languages/$locale/helptext.txt"; + $help = "$docroot/languages/$locale/helptext.dot"; } $jscript = "$docroot/webGui/javascript/translate.$locale.js"; if (!file_exists($jscript)) { // create javascript file with translations $source = []; - $files = glob("$languageDir/$locale-javascript*.txt",GLOB_NOSORT); + $files = glob("$docroot/languages/$locale/javascript*.txt",GLOB_NOSORT); foreach ($files as $js) $source = array_merge($source,parse_lang_file($js)); if (count($source)) { $script = ['function _(t){var l=[];']; @@ -170,9 +157,21 @@ if ($locale && $locale != 'en_US') { } } // split URI into translation levels +$uri = array_filter(explode('/',strtolower(strtok($_SERVER['REQUEST_URI']??'','?')))); +foreach($uri as $more) { + $text = "$docroot/languages/$locale/$more.txt"; + if (file_exists($text)) { + // additional translations + $store = "$docroot/languages/$locale/$more.dot"; + if (!file_exists($store)) file_put_contents($store,serialize(parse_lang_file($text))); + $language = array_merge($language,unserialize(file_get_contents($store))); + } +} +// help text if (($_SERVER['REQUEST_URI'][0]??'')=='/') { if (!file_exists($help)) file_put_contents($help,serialize(parse_help_file($root))); $language = array_merge($language,unserialize(file_get_contents($help))); } +// remove unused variables unset($return,$jscript,$root,$help,$store,$uri,$more,$text); ?>