bfojcapell: Renaming of functions and new function prototype of the translator function

(merged from branches/gsoc)


git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@41835 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
Ingo Schommer 2007-09-15 00:21:51 +00:00
parent 3444cf28e8
commit 0872f87358
4 changed files with 254 additions and 247 deletions

View File

@ -56,5 +56,5 @@ Authenticator::registerAuthenticator('OpenIDAuthenticator');
/** /**
* Define a default language different than english * Define a default language different than english
*/ */
//LocaleAPI::setLocale('ca_AD'); //LocaleAPI::set_locale('ca_AD');
?> ?>

View File

@ -86,8 +86,8 @@ function stripslashes_recursively(&$array) {
/** /**
* This is the main translator function. Returns the string defined by $class and $entity according to the currently set locale * This is the main translator function. Returns the string defined by $class and $entity according to the currently set locale
* *
* @param string $class Class where the entity was defined. It acts as a namespace. * @param string $entity Entity that identifies the string. It must be in the form "Namespace.Entity" where Namespace will be usually
* @param string $entity Entity that identifies the string inside the namespace. * the class name where this string is used and Entity identifies the string inside the namespace.
* @param string $string The original string itself. In a usual call this is a mandatory parameter, but if you are reusing a string which * @param string $string The original string itself. In a usual call this is a mandatory parameter, but if you are reusing a string which
* has already been "declared" (using another call to this function, with the same class and entity), you can omit it. * has already been "declared" (using another call to this function, with the same class and entity), you can omit it.
* @param string $priority Optional parameter to set a translation priority. If a string is widely used, should have a high priority (PR_HIGH), * @param string $priority Optional parameter to set a translation priority. If a string is widely used, should have a high priority (PR_HIGH),
@ -95,19 +95,16 @@ function stripslashes_recursively(&$array) {
* You can use PR_MEDIUM as well. Leaving this field blank will be interpretated as a "normal" priority (less than PR_MEDIUM). * You can use PR_MEDIUM as well. Leaving this field blank will be interpretated as a "normal" priority (less than PR_MEDIUM).
* @param string $context If the string can be difficult to translate by any reason, you can help translators with some more info using this param * @param string $context If the string can be difficult to translate by any reason, you can help translators with some more info using this param
* *
* @return string The translated string, according to the currently set locale {@link i18n::setLocale()} * @return string The translated string, according to the currently set locale {@link i18n::set_locale()}
*/ */
function _($class, $entity, $string = "", $priority = 40, $context = "") { function _t($entity, $string = "", $priority = 40, $context = "") {
global $lang; global $lang;
$locale = i18n::getLocale(); $locale = i18n::get_locale();
$class = ereg_replace('.*([/\\]+)', "", $class); $entityParts = explode('.',$entity);
if(substr($class, -4) == '.php') $realEntity = array_pop($entityParts);
$class = substr($class, 0, -4); $class = implode('.',$entityParts);
if(!isset($lang[$locale][$class])) i18n::include_by_class($class);
if(isset($lang[$locale][$class]) == false) $transEntity = $lang[i18n::get_locale()][$class][$realEntity];
i18n::includeByClass($class);
$transEntity = $lang[i18n::getLocale()][$class][$entity];
return (is_array($transEntity) ? $transEntity[0] : $transEntity); return (is_array($transEntity) ? $transEntity[0] : $transEntity);
} }

View File

@ -154,7 +154,7 @@ class SSViewer extends Object {
if(isset($_GET['debug_profile'])) Profiler::mark("SSViewer::process - compile", " for $template"); if(isset($_GET['debug_profile'])) Profiler::mark("SSViewer::process - compile", " for $template");
$content = file_get_contents($template); $content = file_get_contents($template);
$content = SSViewer::parseTemplateContent($content, $template); $content = SSViewer::parseTemplateContent($content);
$fh = fopen($cacheFile,'w'); $fh = fopen($cacheFile,'w');
fwrite($fh, $content); fwrite($fh, $content);
@ -199,7 +199,7 @@ class SSViewer extends Object {
return $output; return $output;
} }
static function parseTemplateContent($content, $template="") { static function parseTemplateContent($content) {
while(true) { while(true) {
$oldContent = $content; $oldContent = $content;
$content = preg_replace_callback('/<' . '% include +([A-Za-z0-9_]+) +%' . '>/', create_function( $content = preg_replace_callback('/<' . '% include +([A-Za-z0-9_]+) +%' . '>/', create_function(
@ -282,8 +282,7 @@ class SSViewer extends Object {
$content = ereg_replace('<' . '% +end_if +%' . '>', '<? } ?>', $content); $content = ereg_replace('<' . '% +end_if +%' . '>', '<? } ?>', $content);
// i18n // i18n
ereg('.*[\/](.*)',$template,$path); $content = ereg_replace('<' . '% +_t\((([^)]|\)[^;])*)\); +%' . '>', '<?= _t(\\1) ?>', $content);
$content = ereg_replace('<' . '% +_\(([^)]*)\) +%' . '>', '<?= _(\''.$path[1].'\',\\1) ?>', $content);
// </base> isnt valid html? !? // </base> isnt valid html? !?
$content = ereg_replace('<' . '% +base_tag +%' . '>', '<base href="<?= Director::absoluteBaseURL(); ?>" />', $content); $content = ereg_replace('<' . '% +base_tag +%' . '>', '<base href="<?= Director::absoluteBaseURL(); ?>" />', $content);

View File

@ -1,230 +1,241 @@
<?php <?php
/** /**
* Silverstripe i18n API * Silverstripe i18n API
* *
* @author Bernat Foj Capell <bernat@silverstripe.com> * @author Bernat Foj Capell <bernat@silverstripe.com>
*/ */
/** /**
* Priorities definition. These constants are used in calls to _() as an optional argument * Priorities definition. These constants are used in calls to _() as an optional argument
*/ */
define('PR_HIGH',100); define('PR_HIGH',100);
define('PR_MEDIUM',50); define('PR_MEDIUM',50);
define('PR_LOW',10); define('PR_LOW',10);
class i18n extends Controller { class i18n extends Controller {
/** /**
* This static variable is used to store the current defined locale. Default value is 'en' * This static variable is used to store the current defined locale. Default value is 'en_US'
*/ */
static $currentlocale = 'en'; static $currentlocale = 'en_US';
/** /**
* This is the main method to build the master string tables with the original strings. * This is the main method to build the master string tables with the original strings.
* It will search for existent modules that use the i18n feature, parse the _() calls * It will search for existent modules that use the i18n feature, parse the _() calls
* and write the resultant files in the lang folder of each module. * and write the resultant files in the lang folder of each module.
*/ */
static function textCollector() { static function text_collector() {
if (!Permission::check("ADMIN")) die("You must be an admin to enable text collector mode"); if (!Permission::check("ADMIN")) die("You must be an admin to enable text collector mode");
echo "Collecting text...<br /><br />"; echo "Collecting text...<br /><br />";
//Calculate base directory //Calculate base directory
$baseDir = Director::baseFolder(); $baseDir = Director::baseFolder();
//Search for and process existent modules, or use the passed one instead //Search for and process existent modules, or use the passed one instead
if (!isset($_GET['module'])) { if (!isset($_GET['module'])) {
$topLevel = scandir($baseDir); $topLevel = scandir($baseDir);
foreach($topLevel as $module) { foreach($topLevel as $module) {
i18n::processModule($baseDir, $module); i18n::process_module($baseDir, $module);
} }
} else { } else {
i18n::processModule($baseDir, $_GET['module']); i18n::process_module($baseDir, $_GET['module']);
} }
echo "Done!"; echo "Done!";
} }
/** /**
* Searches for all the files in a given module * Searches for all the files in a given module
* *
* @param string $baseDir Silverstripe's base directory * @param string $baseDir Silverstripe's base directory
* @param string $module Module's name * @param string $module Module's name
*/ */
private static function processModule($baseDir, $module) { private static function process_module($baseDir, $module) {
if(is_dir("$baseDir/$module") && !in_array($module, array('sapphire','jsparty','assets')) && substr($module,0,1) != '.') { if(is_dir("$baseDir/$module") && !in_array($module, array('sapphire','jsparty','assets')) && substr($module,0,1) != '.') {
i18n::getFilesRec("$baseDir/$module/code", $fileList); i18n::get_files_rec("$baseDir/$module/code", $fileList);
foreach($fileList as $index => $file) { $mst = '';
$mst .= i18n::reportCallsCode($index, $file); foreach($fileList as $file) {
} $mst .= i18n::report_calls_code($file);
$fileList = NULL; }
i18n::getFilesRec("$baseDir/$module/templates", $fileList); $fileList = NULL;
foreach($fileList as $index => $file) { i18n::get_files_rec("$baseDir/$module/templates", $fileList);
$mst .= i18n::reportCallsTpl($index, $file); foreach($fileList as $index => $file) {
} $mst .= i18n::report_calls_tpl($index, $file);
if ($mst) { }
// Create folder for lang files if ($mst) {
$langFolder = $baseDir . '/' . $module . '/lang'; // Create folder for lang files
if(!file_exists($baseDir. '/' . $module . '/lang')) { $langFolder = $baseDir . '/' . $module . '/lang';
mkdir($langFolder); if(!file_exists($baseDir. '/' . $module . '/lang')) {
} mkdir($langFolder);
}
// Open the English file and write the Master String Table
if($fh = fopen($langFolder . '/en.php', "w")) { // Open the English file and write the Master String Table
fwrite($fh, "<?php\n\nglobal \$lang;\n\n" . $mst . "\n?>"); if($fh = fopen($langFolder . '/en_US.php', "w")) {
fclose($fh); fwrite($fh, "<?php\n\nglobal \$lang;\n\n" . $mst . "\n?>");
echo "Created file: $langFolder/en.php<br />"; fclose($fh);
echo "Created file: $langFolder/en_US.php<br />";
} else {
die("Cannot write language file! Please check permissions of $langFolder/en.php"); } else {
} die("Cannot write language file! Please check permissions of $langFolder/en_US.php");
} }
} }
} }
}
/**
* Helper function that searches for potential files to be parsed /**
* * Helper function that searches for potential files to be parsed
* @param string $folder base directory to scan (will scan recursively) *
* @param array $fileList Array where potential files will be added to * @param string $folder base directory to scan (will scan recursively)
*/ * @param array $fileList Array where potential files will be added to
private static function getFilesRec($folder, &$fileList) { */
$items = scandir($folder); private static function get_files_rec($folder, &$fileList) {
if($items) foreach($items as $item) { $items = scandir($folder);
if(substr($item,0,1) == '.') continue; if($items) foreach($items as $item) {
if(substr($item,-4) == '.php') $fileList[substr($item,0,-4)] = "$folder/$item"; if(substr($item,0,1) == '.') continue;
else if(substr($item,-3) == '.ss') $fileList[$item] = "$folder/$item"; if(substr($item,-4) == '.php') $fileList[substr($item,0,-4)] = "$folder/$item";
else if(is_dir("$folder/$item")) i18n::getFilesRec("$folder/$item", $fileList); else if(substr($item,-3) == '.ss') $fileList[$item] = "$folder/$item";
} else if(is_dir("$folder/$item")) i18n::get_files_rec("$folder/$item", $fileList);
} }
}
/**
* Look for calls to the underscore function in php files and build our MST /**
* * Look for calls to the underscore function in php files and build our MST
* @param string $index Classname used to namespace strings *
* @param string $file Path to the file to be parsed * @param string $file Path to the file to be parsed
* @return string Built Master String Table from this file * @return string Built Master String Table from this file
*/ */
private static function reportCallsCode($index, $file) { private static function report_calls_code($file) {
static $callMap; static $callMap;
$content = file_get_contents($file); $content = file_get_contents($file);
while (ereg('_\(([^$][^,"\']*|"[^,]*"|\'[^,]*\')(,[^$][^,]*)(,[^$][^,)]*)(,[^,)]*)?(,[^)]*)?\)',$content,$regs)) { $mst = '';
while (ereg('_t[[:space:]]*\([[:space:]]*("[^,]*"|\\\'[^,]*\\\')[[:space:]]*,[[:space:]]*("([^"]|\\\")*"|\'([^\']|\\\\\')*\')([[:space:]]*,[[:space:]]*[^,)]*)?([[:space:]]*,[[:space:]]*("([^"]|\\\")*"|\'([^\']|\\\\\')*\'))?[[:space:]]*\)', $content, $regs)) {
$class = ($regs[1] == '__FILE__' ? $index : $regs[1]); $entityParts = explode('.',substr($regs[1],1,-1));
$entity = substr($regs[2],2,-1); $entity = array_pop($entityParts);
$class = implode('.',$entityParts);
if ($callMap[$class.'--'.$entity]) echo "Warning! Redeclaring entity $entity in file $file<br>";
if (isset($callMap[$class.'--'.$entity])) echo "Warning! Redeclaring entity $entity in file $file<br>";
$mst .= '$lang[\'en\'][\'' . $class . '\'][\'' . substr($regs[2],2,-1) . '\'] = ';
if ($regs[4]) { $mst .= '$lang[\'en_US\'][\'' . $class . '\'][\'' . $entity . '\'] = ';
$mst .= "array(\n\t'" . substr($regs[3],2,-1) . "',\n\t" . substr($regs[4],1); if ($regs[5]) {
if ($regs[5]) $mst .= ",\n\t'" . substr($regs[5],2,-1) . '\''; $mst .= "array(\n\t'" . substr($regs[2],1,-1) . "',\n\t" . substr($regs[5],1);
$mst .= "\n);"; if ($regs[6]) {
} else $mst .= '\'' . substr($regs[3],2,-1) . '\';'; if (substr($regs[6],1,1) == '"') $regs[6] = addcslashes($regs[6],'\'');
$mst .= "\n"; $mst .= ",\n\t'" . substr($regs[6],2,-1) . '\'';
$content = str_replace($regs[0],"",$content); }
$mst .= "\n);";
$callMap[$class.'--'.$entity] = $regs[3]; } else $mst .= '\'' . substr($regs[2],1,-1) . '\';';
} $mst .= "\n";
$content = str_replace($regs[0],"",$content);
return $mst;
} $callMap[$class.'--'.$entity] = $regs[2];
}
/**
* Look for calls to the underscore function in template files and build our MST return $mst;
* Template version - no "class" argument }
*
* @param string $index Index used to namespace strings /**
* @param string $file Path to the file to be parsed * Look for calls to the underscore function in template files and build our MST
* @return string Built Master String Table from this file * Template version - no "class" argument
*/ *
private static function reportCallsTpl($index, $file) { * @param string $index Index used to namespace strings
static $callMap; * @param string $file Path to the file to be parsed
$content = file_get_contents($file); * @return string Built Master String Table from this file
while (ereg('_\(([^$][^,"\']*|"[^,]*"|\'[^,]*\')(,[^$][^,)]*)(,[^,)]*)?(,[^)]*)?\)',$content,$regs)) { */
private static function report_calls_tpl($index, $file) {
$entity = substr($regs[1],2,-1); static $callMap;
$content = file_get_contents($file);
if ($callMap[$index.'--'.$entity]) echo "Warning! Redeclaring entity $entity in file $file<br>"; $mst = '';
while (ereg('_t[[:space:]]*\([[:space:]]*("[^,]*"|\\\'[^,]*\\\')[[:space:]]*,[[:space:]]*("([^"]|\\\")*"|\'([^\']|\\\\\')*\')([[:space:]]*,[[:space:]]*[^,)]*)?([[:space:]]*,[[:space:]]*("([^"]|\\\")*"|\'([^\']|\\\\\')*\'))?[[:space:]]*\)',$content,$regs)) {
$mst .= '$lang[\'en\'][\'' . $index . '\'][\'' . substr($regs[1],1,-1) . '\'] = ';
if ($regs[3]) { $entityParts = explode('.',substr($regs[1],1,-1));
$mst .= "array(\n\t'" . substr($regs[2],2,-1) . "',\n\t" . substr($regs[3],1); $entity = array_pop($entityParts);
if ($regs[4]) $mst .= ",\n\t'" . substr($regs[4],2,-1) . '\'';
$mst .= "\n);"; // Entity redeclaration check
} else $mst .= '\'' . substr($regs[2],2,-1) . '\';'; if (isset($callMap[$index.'--'.$entity])) echo "Warning! Redeclaring entity $entity in file $file<br>";
$mst .= "\n";
$content = str_replace($regs[0],"",$content); if (substr($regs[2],0,1) == '"') $regs[2] = addcslashes($regs[2],'\'');
$mst .= '$lang[\'en_US\'][\'' . $index . '\'][\'' . $entity . '\'] = ';
$callMap[$index.'--'.$entity] = $regs[3]; if ($regs[5]) {
} $mst .= "array(\n\t'" . substr($regs[2],1,-1) . "',\n\t" . substr($regs[5],1);
if ($regs[6]) {
return $mst; if (substr($regs[6],1,1) == '"') $regs[6] = addcslashes($regs[6],'\'\\');
} $mst .= ",\n\t'" . substr($regs[6],2,-1) . '\'';
}
/** $mst .= "\n);";
* Set the current locale } else $mst .= '\'' . substr($regs[2],2,-1) . '\';';
* See http://unicode.org/cldr/data/diff/supplemental/languages_and_territories.html for a list of possible locales $mst .= "\n";
* $content = str_replace($regs[0],"",$content);
* @param string $locale Locale to be set
*/ $callMap[$index.'--'.$entity] = $regs[3];
static function setLocale($locale) { }
if ($locale) i18n::$currentlocale = $locale;
} return $mst;
}
/**
* Get the current locale /**
* * Set the current locale
* @return string Current locale in the system * See http://unicode.org/cldr/data/diff/supplemental/languages_and_territories.html for a list of possible locales
*/ *
static function getLocale() { * @param string $locale Locale to be set
return i18n::$currentlocale; */
} static function set_locale($locale) {
if ($locale) i18n::$currentlocale = $locale;
/** }
* Includes all available language files for a certain defined locale
* /**
* @param string $locale All resources from any module in locale $locale will be loaded * Get the current locale
*/ *
static function includeByLocale($locale) { * @return string Current locale in the system
if (file_exists($file = Director::getAbsFile("cms/lang/$locale.php"))) include_once($file); */
$topLevel = array_diff(scandir(Director::baseFolder()),array('cms')); static function get_locale() {
foreach($topLevel as $module) { return i18n::$currentlocale;
if (file_exists($file = Director::getAbsFile("$module/lang/$locale.php"))) { }
include_once($file);
} /**
} * Includes all available language files for a certain defined locale
} *
* @param string $locale All resources from any module in locale $locale will be loaded
/** */
* Given a class name (a "locale namespace"), will search for its module and, if available, static function include_by_locale($locale) {
* will load the resources for the currently defined locale. if (file_exists($file = Director::getAbsFile("cms/lang/$locale.php"))) include_once($file);
* If not available, the original English resource will be loaded instead (to avoid blanks) $topLevel = array_diff(scandir(Director::baseFolder()),array('cms'));
* foreach($topLevel as $module) {
* @param string $class Resources for this class will be included, according to the set locale. if (file_exists($file = Director::getAbsFile("$module/lang/$locale.php"))) {
*/ include_once($file);
static function includeByClass($class) { }
if (substr($class,-3) == '.ss') { }
global $_TEMPLATE_MANIFEST; }
$path = current($_TEMPLATE_MANIFEST[substr($class,0,-3)]);
ereg('.*/([^/]+)/templates/',$path,$module); /**
} * Given a class name (a "locale namespace"), will search for its module and, if available,
else { * will load the resources for the currently defined locale.
global $_CLASS_MANIFEST; * If not available, the original English resource will be loaded instead (to avoid blanks)
$path = $_CLASS_MANIFEST[$class]; *
ereg('.*/([^/]+)/code/',$path,$module); * @param string $class Resources for this class will be included, according to the set locale.
} */
if (file_exists($file = Director::getAbsFile("{$module[1]}/lang/". i18n::getLocale() . '.php'))) { static function include_by_class($class) {
include_once($file); if (substr($class,-3) == '.ss') {
} else if (i18n::getLocale() != 'en') { global $_TEMPLATE_MANIFEST;
i18n::setLocale('en'); $path = current($_TEMPLATE_MANIFEST[substr($class,0,-3)]);
i18n::includeByClass($class); ereg('.*/([^/]+)/templates/',$path,$module);
} else { }
user_error("Locale file $file should exist", E_USER_WARNING); else {
} global $_CLASS_MANIFEST;
} $path = $_CLASS_MANIFEST[$class];
} ereg('.*/([^/]+)/code/',$path,$module);
}
if (file_exists($file = Director::getAbsFile("{$module[1]}/lang/". i18n::get_locale() . '.php'))) {
include_once($file);
} else if (i18n::get_locale() != 'en_US') {
i18n::set_locale('en_US');
i18n::include_by_class($class);
} else {
user_error("Locale file $file should exist", E_USER_WARNING);
}
}
}
?> ?>