ENHANCEMENT Allowing i18nTextCollector to discover entities in templates stored in themes/ directory (thanks nlou)

git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@113918 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
Ingo Schommer 2010-11-18 19:00:13 +00:00
parent 854cbe79c8
commit ab92919b27
11 changed files with 180 additions and 14 deletions

View File

@ -0,0 +1,4 @@
<% _t("i18nTestTheme1Include.WITHNAMESPACE", 'Theme1 Include Entity with Namespace') %>
<% _t("NONAMESPACE", 'Theme1 Include Entity without Namespace') %>
<% sprintf(_t('i18nTestTheme1Include.SPRINTFINCLUDENAMESPACE','Theme1 My include replacement: %s'),$TestProperty) %>
<% sprintf(_t('SPRINTFINCLUDENONAMESPACE','Theme1 My include replacement no namespace: %s'),$TestProperty) %>

View File

@ -0,0 +1,5 @@
<% _t('i18nTestTheme1.LAYOUTTEMPLATE',"Theme1 Layout Template") %>
<% _t('LAYOUTTEMPLATENONAMESPACE',"Theme1 Layout Template no namespace") %>
<% sprintf(_t('i18nTestTheme1.SPRINTFNAMESPACE','Theme1 My replacement: %s'),$TestProperty) %>
<% sprintf(_t('SPRINTFNONAMESPACE','Theme1 My replacement no namespace: %s'),$TestProperty) %>
<% include i18nTestTheme1Include %>

View File

@ -0,0 +1,3 @@
<% _t('i18nTestTheme1.MAINTEMPLATE',"Theme1 Main Template") %>
$Layout
lonely _t() call that should be ignored

View File

@ -0,0 +1,3 @@
<% _t('i18nTestTheme2.MAINTEMPLATE',"Theme2 Main Template") %>
$Layout
lonely _t() call that should be ignored

View File

@ -13,7 +13,7 @@
* The collector needs to be run whenever you make new translatable * The collector needs to be run whenever you make new translatable
* entities available. Please don't alter the arrays in language tables manually. * entities available. Please don't alter the arrays in language tables manually.
* *
* Usage through URL: http://localhost/dev/tasks/i18nTextCollectorTast * Usage through URL: http://localhost/dev/tasks/i18nTextCollectorTask
* Usage through URL (module-specific): http://localhost/dev/tasks/i18nTextCollectorTask/?module=mymodule * Usage through URL (module-specific): http://localhost/dev/tasks/i18nTextCollectorTask/?module=mymodule
* Usage on CLI: sake dev/tasks/i18nTextCollectorTask * Usage on CLI: sake dev/tasks/i18nTextCollectorTask
* Usage on CLI (module-specific): sake dev/tasks/i18nTextCollectorTask module=mymodule * Usage on CLI (module-specific): sake dev/tasks/i18nTextCollectorTask module=mymodule
@ -39,10 +39,10 @@ class i18nTextCollector extends Object {
public $basePath; public $basePath;
/** /**
* @var string $basePath The directory base on which the collector should create new lang folders and files. * @var string $baseSavePath The directory base on which the collector should create new lang folders and files.
* Usually the webroot set through {@link Director::baseFolder()}. * Usually the webroot set through {@link Director::baseFolder()}.
* Can be overwritten for testing or export purposes. * Can be overwritten for testing or export purposes.
* @todo Fully support changing of basePath through {@link SSViewer} and {@link ManifestBuilder} * @todo Fully support changing of baseSavePath through {@link SSViewer} and {@link ManifestBuilder}
*/ */
public $baseSavePath; public $baseSavePath;
@ -70,6 +70,7 @@ class i18nTextCollector extends Object {
//Debug::message("Collecting text...", false); //Debug::message("Collecting text...", false);
$modules = array(); $modules = array();
$themeFolders = array();
// A master string tables array (one mst per module) // A master string tables array (one mst per module)
$entitiesByModule = array(); $entitiesByModule = array();
@ -83,13 +84,38 @@ class i18nTextCollector extends Object {
$modules = scandir($this->basePath); $modules = scandir($this->basePath);
} }
foreach($modules as $index => $module){
if($module != 'themes') continue;
else {
$themes = scandir($this->basePath."/themes");
if(count($themes)){
foreach($themes as $theme) {
if(is_dir($this->basePath."/themes/".$theme) && substr($theme,0,1) != '.' && is_dir($this->basePath."/themes/".$theme."/templates")){
$themeFolders[] = 'themes/'.$theme;
}
}
}
$themesInd = $index;
}
}
if(isset($themesInd)) {
unset($modules[$themesInd]);
}
$modules = array_merge($modules, $themeFolders);
foreach($modules as $module) { foreach($modules as $module) {
// Only search for calls in folder with a _config.php file (which means they are modules) // Only search for calls in folder with a _config.php file (which means they are modules, including themes folder)
$isValidModuleFolder = ( $isValidModuleFolder = (
is_dir("$this->basePath/$module") is_dir("$this->basePath/$module")
&& is_file("$this->basePath/$module/_config.php") && is_file("$this->basePath/$module/_config.php")
&& substr($module,0,1) != '.' && substr($module,0,1) != '.'
) || (
substr($module,0,7) == 'themes/'
&& is_dir("$this->basePath/$module")
); );
if(!$isValidModuleFolder) continue; if(!$isValidModuleFolder) continue;
// we store the master string tables // we store the master string tables
@ -122,7 +148,7 @@ class i18nTextCollector extends Object {
/** /**
* Build the module's master string table * Build the module's master string table
* *
* @param string $module Module's name * @param string $module Module's name or 'themes'
*/ */
protected function processModule($module) { protected function processModule($module) {
$entitiesArr = array(); $entitiesArr = array();
@ -132,7 +158,7 @@ class i18nTextCollector extends Object {
// Search for calls in code files if these exists // Search for calls in code files if these exists
if(is_dir("$this->basePath/$module/code")) { if(is_dir("$this->basePath/$module/code")) {
$fileList = $this->getFilesRecursive("$this->basePath/$module/code"); $fileList = $this->getFilesRecursive("$this->basePath/$module/code");
} else if($module == 'sapphire') { } else if($module == 'sapphire' || substr($module, 0, 7) == 'themes/') {
// sapphire doesn't have the usual module structure, so we'll scan all subfolders // sapphire doesn't have the usual module structure, so we'll scan all subfolders
$fileList = $this->getFilesRecursive("$this->basePath/$module"); $fileList = $this->getFilesRecursive("$this->basePath/$module");
} }

View File

@ -0,0 +1,4 @@
<% _t("i18nTestTheme1Include.WITHNAMESPACE", 'Theme1 Include Entity with Namespace') %>
<% _t("NONAMESPACE", 'Theme1 Include Entity without Namespace') %>
<% sprintf(_t('i18nTestTheme1Include.SPRINTFINCLUDENAMESPACE','Theme1 My include replacement: %s'),$TestProperty) %>
<% sprintf(_t('SPRINTFINCLUDENONAMESPACE','Theme1 My include replacement no namespace: %s'),$TestProperty) %>

View File

@ -0,0 +1,5 @@
<% _t('i18nTestTheme1.LAYOUTTEMPLATE',"Theme1 Layout Template") %>
<% _t('LAYOUTTEMPLATENONAMESPACE',"Theme1 Layout Template no namespace") %>
<% sprintf(_t('i18nTestTheme1.SPRINTFNAMESPACE','Theme1 My replacement: %s'),$TestProperty) %>
<% sprintf(_t('SPRINTFNONAMESPACE','Theme1 My replacement no namespace: %s'),$TestProperty) %>
<% include i18nTestTheme1Include %>

View File

@ -0,0 +1,3 @@
<% _t('i18nTestTheme1.MAINTEMPLATE',"Theme1 Main Template") %>
$Layout
lonely _t() call that should be ignored

View File

@ -0,0 +1,3 @@
<% _t('i18nTestTheme2.MAINTEMPLATE',"Theme2 Main Template") %>
$Layout
lonely _t() call that should be ignored

View File

@ -49,10 +49,6 @@ class i18nTest extends SapphireTest {
$_TEMPLATE_MANIFEST['i18nTestModuleInclude.ss'] = array( $_TEMPLATE_MANIFEST['i18nTestModuleInclude.ss'] = array(
'Includes' => $this->alternateBasePath . '/i18ntestmodule/templates/Includes/i18nTestModuleInclude.ss', 'Includes' => $this->alternateBasePath . '/i18ntestmodule/templates/Includes/i18nTestModuleInclude.ss',
); );
$_TEMPLATE_MANIFEST['i18nTestModule.ss'] = array(
'main' => $this->alternateBasePath . '/i18ntestmodule/templates/i18nTestModule.ss',
'Layout' => $this->alternateBasePath . '/i18ntestmodule/templates/Layout/i18nTestModule.ss',
);
$this->originalLocale = i18n::get_locale(); $this->originalLocale = i18n::get_locale();
} }

View File

@ -44,9 +44,13 @@ class i18nTextCollectorTest extends SapphireTest {
$_TEMPLATE_MANIFEST['i18nTestModuleInclude.ss'] = array( $_TEMPLATE_MANIFEST['i18nTestModuleInclude.ss'] = array(
'Includes' => $this->alternateBasePath . '/i18ntestmodule/templates/Includes/i18nTestModuleInclude.ss', 'Includes' => $this->alternateBasePath . '/i18ntestmodule/templates/Includes/i18nTestModuleInclude.ss',
); );
$_TEMPLATE_MANIFEST['i18nTestModule.ss'] = array(
'main' => $this->alternateBasePath . '/i18ntestmodule/templates/i18nTestModule.ss', $_TEMPLATE_MANIFEST['i18nTestTheme1.ss'] = array(
'Layout' => $this->alternateBasePath . '/i18ntestmodule/templates/Layout/i18nTestModule.ss', 'main' => $this->alternateBasePath . '/themes/testtheme1/templates/i18nTestTheme1.ss',
'Layout' => $this->alternateBasePath . '/themes/testtheme1/templates/Layout/i18nTestTheme1.ss',
);
$_TEMPLATE_MANIFEST['i18nTestTheme1Include.ss'] = array(
'Includes' => $this->alternateBasePath . '/themes/testtheme1/templates/Includes/i18nTestTheme1Include.ss',
); );
} }
@ -406,6 +410,60 @@ PHP;
); );
} }
function testCollectFromThemesTemplates() {
$c = new i18nTextCollector();
$templateFilePath = $this->alternateBasePath . '/themes/testtheme1/templates/Layout/i18nTestTheme1.ss';
$html = file_get_contents($templateFilePath);
$matches = $c->collectFromTemplate($html, 'themes/testtheme1', 'i18nTestTheme1.ss');
// all entities from i18nTestTheme1.ss
$this->assertEquals(
$matches['i18nTestTheme1.LAYOUTTEMPLATE'],
array('Theme1 Layout Template', null, null)
);
$this->assertArrayHasKey('i18nTestTheme1.ss.LAYOUTTEMPLATENONAMESPACE', $matches);
$this->assertEquals(
$matches['i18nTestTheme1.ss.LAYOUTTEMPLATENONAMESPACE'],
array('Theme1 Layout Template no namespace', null, null)
);
$this->assertEquals(
$matches['i18nTestTheme1.SPRINTFNAMESPACE'],
array('Theme1 My replacement: %s', null, null)
);
$this->assertArrayHasKey('i18nTestTheme1.ss.SPRINTFNONAMESPACE', $matches);
$this->assertEquals(
$matches['i18nTestTheme1.ss.SPRINTFNONAMESPACE'],
array('Theme1 My replacement no namespace: %s', null, null)
);
// all entities from i18nTestTheme1Include.ss
$this->assertEquals(
$matches['i18nTestTheme1Include.WITHNAMESPACE'],
array('Theme1 Include Entity with Namespace', null, null)
);
$this->assertArrayHasKey('i18nTestTheme1Include.ss.NONAMESPACE', $matches);
$this->assertEquals(
$matches['i18nTestTheme1Include.ss.NONAMESPACE'],
array('Theme1 Include Entity without Namespace', null, null)
);
$this->assertEquals(
$matches['i18nTestTheme1Include.SPRINTFINCLUDENAMESPACE'],
array('Theme1 My include replacement: %s', null, null)
);
$this->assertArrayHasKey('i18nTestTheme1Include.ss.SPRINTFINCLUDENONAMESPACE', $matches);
$this->assertEquals(
$matches['i18nTestTheme1Include.ss.SPRINTFINCLUDENONAMESPACE'],
array('Theme1 My include replacement no namespace: %s', null, null)
);
}
function testCollectFromFilesystemAndWriteMasterTables() { function testCollectFromFilesystemAndWriteMasterTables() {
$defaultlocal = i18n::default_locale(); $defaultlocal = i18n::default_locale();
$local = i18n::get_locale(); $local = i18n::get_locale();
@ -426,7 +484,6 @@ PHP;
); );
$moduleLangFileContent = file_get_contents($moduleLangFile); $moduleLangFileContent = file_get_contents($moduleLangFile);
$this->assertContains( $this->assertContains(
"\$lang['en_US']['i18nTestModule']['ADDITION'] = 'Addition';", "\$lang['en_US']['i18nTestModule']['ADDITION'] = 'Addition';",
$moduleLangFileContent $moduleLangFileContent
@ -472,6 +529,63 @@ PHP;
$otherModuleLangFileContent $otherModuleLangFileContent
); );
// testtheme1
$theme1LangFile = "{$this->alternateBaseSavePath}/themes/testtheme1/lang/" . $c->getDefaultLocale() . '.php';
$this->assertTrue(
file_exists($theme1LangFile),
'Master theme language file can be written to themes/testtheme1 /lang folder'
);
$theme1LangFileContent = file_get_contents($theme1LangFile);
$this->assertContains(
"\$lang['en_US']['i18nTestTheme1']['MAINTEMPLATE'] = 'Theme1 Main Template';",
$theme1LangFileContent
);
$this->assertContains(
"\$lang['en_US']['i18nTestTheme1']['LAYOUTTEMPLATE'] = 'Theme1 Layout Template';",
$theme1LangFileContent
);
$this->assertContains(
"\$lang['en_US']['i18nTestTheme1']['SPRINTFNAMESPACE'] = 'Theme1 My replacement: %s';",
$theme1LangFileContent
);
$this->assertContains(
"\$lang['en_US']['i18nTestTheme1.ss']['LAYOUTTEMPLATENONAMESPACE'] = 'Theme1 Layout Template no namespace';",
$theme1LangFileContent
);
$this->assertContains(
"\$lang['en_US']['i18nTestTheme1.ss']['SPRINTFNONAMESPACE'] = 'Theme1 My replacement no namespace: %s';",
$theme1LangFileContent
);
$this->assertContains(
"\$lang['en_US']['i18nTestTheme1Include']['SPRINTFINCLUDENAMESPACE'] = 'Theme1 My include replacement: %s';",
$theme1LangFileContent
);
$this->assertContains(
"\$lang['en_US']['i18nTestTheme1Include']['WITHNAMESPACE'] = 'Theme1 Include Entity with Namespace';",
$theme1LangFileContent
);
$this->assertContains(
"\$lang['en_US']['i18nTestTheme1Include.ss']['NONAMESPACE'] = 'Theme1 Include Entity without Namespace';",
$theme1LangFileContent
);
$this->assertContains(
"\$lang['en_US']['i18nTestTheme1Include.ss']['SPRINTFINCLUDENONAMESPACE'] = 'Theme1 My include replacement no namespace: %s';",
$theme1LangFileContent
);
// testtheme2
$theme2LangFile = "{$this->alternateBaseSavePath}/themes/testtheme2/lang/" . $c->getDefaultLocale() . '.php';
$this->assertTrue(
file_exists($theme2LangFile),
'Master theme language file can be written to themes/testtheme2 /lang folder'
);
$theme2LangFileContent = file_get_contents($theme2LangFile);
$this->assertContains(
"\$lang['en_US']['i18nTestTheme2']['MAINTEMPLATE'] = 'Theme2 Main Template';",
$theme2LangFileContent
);
i18n::set_locale($local); //set the locale to the US locale expected in the asserts i18n::set_locale($local); //set the locale to the US locale expected in the asserts
+ i18n::set_default_locale($defaultlocal); + i18n::set_default_locale($defaultlocal);
} }