You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

328 lines
9.1 KiB

<?php
// (c) Copyright by authors of the Tiki Wiki CMS Groupware Project
//
// All Rights Reserved. See copyright.txt for details and a complete list of authors.
// Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details.
// $Id$
/**
* @package Tiki
* @subpackage Language
*/
class Language_GetStrings
{
/**
* Array of file types objects.
*
* @var array
*/
protected $fileTypes = [];
/**
* Array of valid extensions. Extracted
* from $this->fileTypes.
*
* @var array
*/
protected $extensions = [];
/**
* List of languages whose language.php
* files will be updated. If empty all
* language.php files are updated.
*
* @var array
*/
protected $languages = [];
/**
* Name of the file that contain the
* translations.
* @var string
*/
protected $fileName = 'language.php';
/**
* @var Language_CollectFiles
*/
public $collectFiles;
/**
* @var Language_WriteFile_Factory
*/
public $writeFileFactory;
/**
* Whether file paths where the string was found
* is included or not in langauge.php files. Default
* is false.
*
* @var bool
*/
protected $outputFiles = false;
/**
* Directory used as base to search for strings
* and to construct paths to language.php files.
* @var string
*/
protected $baseDir;
/**
* Class construct.
*
* The following are valid $options:
* - 'outputFiles' => true: will write to language.php file the path
* to the files where the string was found. Default is false.
* - 'lang' => 'langCode' or 'lang' => array(list of lang codes):
* language code or list of language codes whose language.php will be
* updated. If empty, all language.php files are updated.
*
* @param Language_CollectFiles $collectFiles
* @param Language_WriteFile_Factory $writeFileFactory factory to create Language_WriteFile objects
* @param array $options list of options to control object behavior (see above)
* @return null
*/
public function __construct(Language_CollectFiles $collectFiles, Language_WriteFile_Factory $writeFileFactory, array $options = null)
{
$this->collectFiles = $collectFiles;
$this->writeFileFactory = $writeFileFactory;
if (isset($options['outputFiles'])) {
$this->outputFiles = true;
}
if (isset($options['baseDir'])) {
if (! is_dir($options['baseDir'])) {
throw new Language_Exception("Invalid directory {$options['baseDir']}.");
}
$this->baseDir = $options['baseDir'];
} else {
$this->baseDir = getcwd();
}
if (isset($options['fileName'])) {
$this->fileName = $options['fileName'];
}
if (isset($options['lang'])) {
$this->setLanguages($options['lang']);
} else {
$this->setLanguages();
}
}
/**
* Getter for $this->extensions
* @return array
*/
public function getExtensions()
{
return $this->extensions;
}
/**
* Getter for $this->fileTypes
* @return array
*/
public function getFileTypes()
{
return $this->fileTypes;
}
/**
* Add a file type object to $this->fileTypes
* and update $this->extensions.
*
* @param $fileType Language_FileType
* @return null
* @throws Language_Exception if type being added already exists
*/
public function addFileType(Language_FileType $fileType)
{
if (in_array($fileType, $this->fileTypes)) {
$className = get_class($fileType);
throw new Language_Exception("Type $className already added.");
}
$this->fileTypes[] = $fileType;
$this->extensions = array_merge($this->extensions, $fileType->getExtensions());
}
/**
* Setter method $this->languages
* property.
*
* @param array|string $languages
* @return null
*/
public function setLanguages($languages = null)
{
if (is_null($languages)) {
$languages = $this->getAllLanguages();
} else {
if (is_string($languages)) {
$languages = [$languages];
}
foreach ($languages as $lang) {
if (! file_exists($this->baseDir . '/lang/' . $lang)) {
throw new Language_Exception('Invalid language code.');
}
}
}
$this->languages = $languages;
}
/**
* Getter method for $this->languages.
*
* @return array
*/
public function getLanguages()
{
return $this->languages;
}
/**
* Get English strings from a given file.
*
* @param string $filePath path to file
* @return array collected strings
*/
public function collectStrings($filePath)
{
if (empty($this->fileTypes)) {
throw new Language_Exception('No Language_FileType found.');
}
$strings = [];
$fileExtension = strrchr($filePath, '.');
if (! $fileExtension || $fileExtension == '.') {
throw new Language_Exception('Could not determine file extension.');
}
foreach ($this->fileTypes as $fileType) {
if (in_array($fileExtension, $fileType->getExtensions())) {
$file = file_get_contents($filePath);
foreach ($fileType->getCleanupRegexes() as $regex => $replacement) {
$file = preg_replace($regex, $replacement, $file);
}
foreach ($fileType->getRegexes() as $postProcess => $regex) {
$matches = [];
preg_match_all($regex, $file, $matches);
$newStrings = $matches[1];
// $postProcess can be used to call a file type specific method for each regular expression
// used for PHP file type to perform different clean up for single quoted and double quoted strings
if (method_exists($fileType, $postProcess)) {
$newStrings = $fileType->$postProcess($newStrings);
}
$strings = array_merge($strings, $newStrings);
}
break;
}
}
return array_values(array_unique($strings));
}
/**
* Loop through a list of files and
* calls $this->collectStrings() for each
* file. Return a list of translatable strings
* found.
*
* @param array $files
* @return array $strings translatable strings found in scanned files
*/
public function scanFiles($files)
{
$strings = [];
// strings collected per file
$filesStrings = [];
if (! empty($files)) {
foreach ($files as $file) {
$filesStrings[$file] = $this->collectStrings($file);
}
}
// join strings collected per file into a single array
// and remove duplicated strings
foreach ($filesStrings as $file => $fileStrings) {
foreach ($fileStrings as $str) {
if (! isset($strings[$str])) {
$string = ['name' => $str];
if ($this->outputFiles) {
// $string['files'] is an array with all the files where the string was found
$string['files'] = [$file];
}
$strings[$str] = $string;
} else {
if ($this->outputFiles) {
$strings[$str]['files'][] = $file;
}
}
}
}
return $strings;
}
public function writeToFiles($strings)
{
foreach ($this->languages as $lang) {
$filePath = $this->baseDir . '/lang/' . $lang . '/' . $this->fileName;
$writeFile = $this->writeFileFactory->factory($filePath);
$writeFile->writeStringsToFile($strings, $this->outputFiles, $lang);
}
}
/**
* Return all available languages (check for the
* existence of a language file).
* @return array all language codes
*/
protected function getAllLanguages()
{
$dirs = dir($this->baseDir . '/lang');
while (false !== ($entry = $dirs->read())) {
if ($entry == '.' || $entry == '..') {
continue;
}
$path = $dirs->path . '/' . $entry;
if (is_dir($path) && file_exists($path . '/' . $this->fileName)) {
$languages[] = $entry;
}
}
return $languages;
}
public function run()
{
if (empty($this->fileTypes)) {
throw new Language_Exception('No Language_FileType found.');
}
$this->collectFiles->setExtensions($this->extensions);
$files = $this->collectFiles->run($this->baseDir);
$strings = $this->scanFiles($files);
$this->writeToFiles($strings);
}
}