From 57c8e06435d0d8ee518920d73f57a3b37a49d53a Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Mon, 22 Oct 2007 01:51:02 +0000 Subject: [PATCH] #1476 Patch for ticket #128 and a few other changes git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@43662 467b73ca-7a2a-4603-9d3b-597d59a354a9 --- core/i18n.php | 168 +++++++++++++++++++++++++++++++---------- lang/_manifest_exclude | 0 2 files changed, 130 insertions(+), 38 deletions(-) create mode 100644 lang/_manifest_exclude diff --git a/core/i18n.php b/core/i18n.php index e6e4abb75..af7b786d5 100755 --- a/core/i18n.php +++ b/core/i18n.php @@ -391,7 +391,7 @@ class i18n extends Controller { 'pt_TL' => 'Portuguese (East Timor)', 'qu_BO' => 'Quechua (Bolivia)', 'qu_PE' => 'Quechua (Peru)', - 'rcf_RE' => 'Rï¿œunion Creole French (Reunion)', + 'rcf_RE' => 'Réunion Creole French (Reunion)', 'rej_ID' => 'Rejang (Indonesia)', 'rif_MA' => 'Tarifit (Morocco)', 'rjb_IN' => 'Rajbanshi (India)', @@ -911,37 +911,116 @@ class i18n extends Controller { } return $translatableModules; } + + /** + * Given a file name (a php class name, without the .php ext, or a template name, including the .ss extension) + * this helper function determines the module where this file is located + * + * @param string $name php class name or template file name + * @return string Module where the file is located + */ + protected static function get_owner_module($name) { + if (substr($name,-3) == '.ss') { + global $_TEMPLATE_MANIFEST; + $path = current($_TEMPLATE_MANIFEST[substr($name,0,-3)]); + ereg('.*/([^/]+)/templates/',$path,$module); + } else { + global $_CLASS_MANIFEST; + $path = $_CLASS_MANIFEST[$name]; + ereg('.*/([^/]+)/code/',$path,$module); + } + return $module[1]; + + } /** - * Searches for all the files in a given module + * Build the module's master string table * * @param string $baseDir Silverstripe's base directory * @param string $module Module's name + * @return string Generated master string table */ protected static function process_module($baseDir, $module) { - if(!Translatable::is_enabled()) return false; - // Only search for text in folder with a _config.php file (which means they are modules) - if(is_dir("$baseDir/$module") && is_file("$baseDir/$module/_config.php") - && !in_array($module, array('sapphire','jsparty')) && substr($module,0,1) != '.') { + // Only search for calls in folder with a _config.php file (which means they are modules) + if(is_dir("$baseDir/$module") && is_file("$baseDir/$module/_config.php") && substr($module,0,1) != '.') { - $fileList = array(); - self::get_files_rec("$baseDir/$module/code", $fileList); $mst = ''; - foreach($fileList as $file) { - $mst .= self::report_calls_code($file); - } - $fileList = NULL; - - // Make sure the templates directory exists before trying to open it - if (is_dir("$baseDir/$module/templates")) { - self::get_files_rec("$baseDir/$module/templates", $fileList); - foreach($fileList as $index => $file) { - $mst .= self::report_calls_tpl($index, $file); + // Search for calls in code files if these exists + if(is_dir("$baseDir/$module/code")) { + $fileList = array(); + self::get_files_rec("$baseDir/$module/code", $fileList); + foreach($fileList as $file) { + $mst .= self::report_calls_code($file); + } + } else if('sapphire' == $module) { + // sapphire doesn't have the usual module structure, so we'll scan all subfolders + $fileList = array(); + self::get_files_rec("$baseDir/$module", $fileList); + foreach($fileList as $file) { + if('.ss' != substr($file,-3)) $mst .= self::report_calls_code($file); } } - if ($mst) { + // Search for calls in template files if these exists + if(is_dir("$baseDir/$module/templates")) { + $fileList = array(); + $includedtpl[$module] = array(); + self::get_files_rec("$baseDir/$module/templates", $fileList); + foreach($fileList as $index => $file) { + $mst .= self::report_calls_tpl($index, $file, $includedtpl[$module]); + } + } + + return $mst; + + } else return false; + } + + /** + * Write the master string table of every processed module + * + * @param string $baseDir Silverstripe's base directory + * @param array $allmst Module's master string tables + * @param array $includedtpl Templates included by other templates + */ + protected static function write_mst($baseDir, $allmst, $includedtpl) { + + // Evaluate the constructed mst + foreach($allmst as $mst) eval($mst); + + // Resolve template dependencies + foreach($includedtpl as $tplmodule => $includers) { + // Variable initialization + $stringsCode = ''; + $moduleCode = ''; + $modulestoinclude = array(); + + foreach($includers as $includertpl => $allincluded) + foreach($allincluded as $included) + // we will only add code if the included template has localizable strings + if(isset($lang['en_US']["$included.ss"])) { + $module = self::get_owner_module("$included.ss"); + + /* if the module of the included template is not the same as the includer's one + * we will need to load the first one in order to have these included strings in memory + */ + if ($module != $tplmodule) $modulestoinclude[$module] = $included; + + // Give the includer name to the included strings in order to be used from the includer template + $stringsCode .= "\$lang['en_US']['$includertpl'] = " . + "array_merge(\$lang['en_US']['$includertpl'], \$lang['en_US']['$included.ss']);\n"; + } + + // Include a template for every needed module (the module language file will then be autoloaded) + foreach($modulestoinclude as $tpltoinclude) $moduleCode .= "self::include_by_class('$tpltoinclude.ss');\n"; + + // Add the extra code to the existing module mst + if ($stringsCode) $allmst[$tplmodule] .= "\n$moduleCode$stringsCode"; + } + + // Write each module language file + foreach($allmst as $module => $mst) { // Create folder for lang files $langFolder = $baseDir . '/' . $module . '/lang'; if(!file_exists($baseDir. '/' . $module . '/lang')) { @@ -959,7 +1038,7 @@ class i18n extends Controller { user_error("Cannot write language file! Please check permissions of $langFolder/en_US.php", E_USER_ERROR); } } - } + } /** @@ -993,7 +1072,8 @@ class i18n extends Controller { $entity = array_pop($entityParts); $class = implode('.',$entityParts); - if (isset($callMap[$class.'--'.$entity])) user_error("Warning! Redeclaring entity $entity in file $file
", E_USER_WARNING); + if (isset($callMap["$class--$entity"])) + echo "Warning! Redeclaring entity $entity in file $file (previously declared in {$callMap["$class--$entity"]})
"; if (substr($regs[2],0,1) == '"') $regs[2] = addcslashes($regs[2],'\''); $mst .= '$lang[\'en_US\'][\'' . $class . '\'][\'' . $entity . '\'] = '; @@ -1008,7 +1088,7 @@ class i18n extends Controller { $mst .= "\n"; $content = str_replace($regs[0],"",$content); - $callMap[$class.'--'.$entity] = $regs[2]; + $callMap["$class--$entity"] = $file; } return $mst; @@ -1020,11 +1100,20 @@ class i18n extends Controller { * * @param string $index Index used to namespace strings * @param string $file Path to the file to be parsed + * @param string $included List of explicitly included templates * @return string Built Master String Table from this file */ - protected static function report_calls_tpl($index, $file) { + protected static function report_calls_tpl($index, $file, &$included) { static $callMap; $content = file_get_contents($file); + + // Search for included templates + preg_match_all('/<' . '% include +([A-Za-z0-9_]+) +%' . '>/', $content, $inc, PREG_SET_ORDER); + foreach ($inc as $template) { + if (!isset($included[$index])) $included[$index] = array(); + array_push($included[$index], $template[1]); + } + $mst = ''; while (ereg('_t[[:space:]]*\([[:space:]]*("[^"]*"|\\\'[^\']*\\\')[[:space:]]*,[[:space:]]*("([^"]|\\\")*"|\'([^\']|\\\\\')*\')([[:space:]]*,[[:space:]]*[^,)]*)?([[:space:]]*,[[:space:]]*("([^"]|\\\")*"|\'([^\']|\\\\\')*\'))?[[:space:]]*\)',$content,$regs)) { @@ -1032,7 +1121,8 @@ class i18n extends Controller { $entity = array_pop($entityParts); // Entity redeclaration check - if (isset($callMap[$index.'--'.$entity])) user_error("Warning! Redeclaring entity $entity in file $file
", E_USER_WARNING); + if (isset($callMap["$index--$entity"])) + echo "Warning! Redeclaring entity $entity in file $file (previously declared in {$callMap["$class--$entity"]})
"; if (substr($regs[2],0,1) == '"') $regs[2] = addcslashes($regs[2],'\''); $mst .= '$lang[\'en_US\'][\'' . $index . '\'][\'' . $entity . '\'] = '; @@ -1047,7 +1137,7 @@ class i18n extends Controller { $mst .= "\n"; $content = str_replace($regs[0],"",$content); - $callMap[$index.'--'.$entity] = $regs[3]; + $callMap["$index--$entity"] = $file; } return $mst; @@ -1123,17 +1213,8 @@ class i18n extends Controller { * @param string $class Resources for this class will be included, according to the set locale. */ static function include_by_class($class) { - if (substr($class,-3) == '.ss') { - global $_TEMPLATE_MANIFEST; - $path = current($_TEMPLATE_MANIFEST[substr($class,0,-3)]); - ereg('.*/([^/]+)/templates/',$path,$module); - } - else { - global $_CLASS_MANIFEST; - $path = $_CLASS_MANIFEST[$class]; - ereg(Director::baseFolder() . '/([^/]+)/',$path,$module); - } - if (file_exists($file = Director::getAbsFile("{$module[1]}/lang/". self::get_locale() . '.php'))) { + $module = self::get_owner_module($class); + if (file_exists($file = Director::getAbsFile("$module/lang/". self::get_locale() . '.php'))) { include_once($file); } else if (self::get_locale() != 'en_US') { self::set_locale('en_US'); @@ -1171,16 +1252,27 @@ class i18n extends Controller { //Calculate base directory $baseDir = Director::baseFolder(); + // A master string tables array (one mst per module) + $mst = array(); + // A list of included templates dependencies + $includedtpl = array(); + //Search for and process existent modules, or use the passed one instead if (!isset($_GET['module'])) { $topLevel = scandir($baseDir); foreach($topLevel as $module) { - self::process_module($baseDir, $module); + // we store the master string tables + $processed = self::process_module($baseDir, $module, $includedtpl); + if ($processed) $mst[$module] = $processed; } } else { - self::process_module($baseDir, $_GET['module']); + $processed = self::process_module($baseDir, $_GET['module'], $includedtpl); + if ($processed) $mst[$module] = $processed; } + // Write the generated master string tables + self::write_mst($baseDir, $mst, $includedtpl); + echo "Done!"; } diff --git a/lang/_manifest_exclude b/lang/_manifest_exclude new file mode 100644 index 000000000..e69de29bb