tao-test/app/tao/helpers/translation/class.SourceCodeExtractor.php

254 lines
7.9 KiB
PHP

<?php
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; under version 2
* of the License (non-upgradable).
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright (c) 2008-2010 (original work) Deutsche Institut für Internationale Pädagogische Forschung (under the project TAO-TRANSFER);
* 2009-2012 (update and modification) Public Research Centre Henri Tudor (under the project TAO-SUSTAIN & TAO-DEV);
* 2013-2014 (update and modification) Open Assessment Technologies SA (under the project TAO-PRODUCT);
*/
/**
* A TranslationExtractor that focuses on the extraction of Translation Units
* source code. It searches for calls to the __() function. The generated
* units will get the first parameter of the __() function as their source.
*
* @access public
* @author Jerome Bogaerts
* @package tao
* @since 2.2
* @version 1.0
*/
class tao_helpers_translation_SourceCodeExtractor extends tao_helpers_translation_TranslationExtractor
{
// --- ASSOCIATIONS ---
// --- ATTRIBUTES ---
/**
* Short description of attribute filesTypes
*
* @var array
*/
private $filesTypes = [];
/**
*
* @var array
*/
private $bannedFileType = [ '.min.js' ];
// --- OPERATIONS ---
/**
* Short description of method extract
*
* @access public
* @author firstname and lastname of author, <author@example.org>
*/
public function extract()
{
$this->setTranslationUnits([]);
foreach ($this->getPaths() as $dir) {
// Directories should come with a trailing slash.
$d = strrev($dir);
if ($d[0] !== '/') {
$dir = $dir . '/';
}
$this->recursiveSearch($dir);
}
}
/**
* Short description of method recursiveSearch
*
* @access private
* @author firstname and lastname of author, <author@example.org>
* @param string $directory
*/
private function recursiveSearch($directory)
{
if (is_dir($directory)) {
// We get the list of files and directories.
if (($files = scandir($directory)) !== false) {
foreach ($files as $fd) {
if (!preg_match("/^\./", $fd) && $fd != "ext") {
// If it is a directory ...
if (is_dir($directory . $fd . "/")) {
$this->recursiveSearch($directory . $fd . "/");
// If it is a file ...
} else {
// Retrieve from the file ...
$this->getTranslationsInFile($directory . $fd);
}
}
}
}
}
}
/**
* Creates a SourceCodeExtractor for a given set of paths. Only file
* that matches an entry in the $fileTypes array will be processed.
*
* @access public
* @author firstname and lastname of author, <author@example.org>
* @param array $paths
* @param array $fileTypes
* @return mixed
*/
public function __construct($paths, array $fileTypes)
{
parent::__construct($paths);
$this->setFileTypes($fileTypes);
}
/**
* Gets an array of file extensions that will be processed. It acts as a
*
* @access public
* @author firstname and lastname of author, <author@example.org>
* @return array
*/
public function getFileTypes()
{
return $this->filesTypes;
}
/**
* Sets an array that contains the extensions of files that have to be
* during the invokation of the SourceCodeExtractor::extract method.
*
* @access public
* @author firstname and lastname of author, <author@example.org>
* @param array $fileTypes
*/
public function setFileTypes(array $fileTypes)
{
$this->filesTypes = $fileTypes;
}
/**
* Short description of method getTranslationsInFile
*
* @access private
* @author firstname and lastname of author, <author@example.org>
* @param string $filePath
*/
private function getTranslationsInFile($filePath)
{
// File extension ?
$extOk = in_array(\Jig\Utils\FsUtils::getFileExtension($filePath), $this->getFileTypes());
if ($extOk) {
foreach ($this->getBannedFileType() as $bannedExt) {
$extOk &= substr_compare($filePath, $bannedExt, strlen($filePath) - strlen($bannedExt), strlen($bannedExt)) !== 0;
}
}
if ($extOk) {
// We read the file.
$lines = file($filePath);
foreach ($lines as $line) {
$strings = $this->getTranslationPhrases($line);
//preg_match_all("/__(\(| )+['\"](.*?)['\"](\))?/u", $line, $string);
//lookup for __('to translate') or __ 'to translate'
// preg_match_all("/__(\(| )+(('(.*?)')|(\"(.*?)\"))(\))?/u", $line, $string);
foreach ($strings as $s) {
$tu = new tao_helpers_translation_TranslationUnit();
$tu->setSource(tao_helpers_translation_POUtils::sanitize($s));
$tus = $this->getTranslationUnits();
$found = false;
// We must add the string as a new TranslationUnit only
// if a similiar source does not exist.
foreach ($tus as $t) {
if ($tu->getSource() == $t->getSource()) {
$found = true;
break;
}
}
if (!$found) {
$tus[] = $tu;
$this->setTranslationUnits($tus);
}
}
}
}
}
/**
* @return array
*/
public function getBannedFileType()
{
return $this->bannedFileType;
}
/**
* @param array $bannedFileType
*/
public function setBannedFileType($bannedFileType)
{
$this->bannedFileType = $bannedFileType;
}
/**
* @param $line
*
* @return array
*/
protected function getTranslationPhrases($line)
{
$strings = [];
$patternMatch1 = [];
$patternMatch2 = [];
preg_match_all("/__\\(([\\\"'])(?:(?=(\\\\?))\\2.)*?\\1/u", $line, $patternMatch1); //for php and JS helper function
preg_match_all("/\{\{__ ['\"](.*?)['\"]\}\}/u", $line, $patternMatch2); //used for parsing templates
if (! empty($patternMatch1[0])) {
$strings = array_reduce(
$patternMatch1[0],
function ($m, $str) use ($patternMatch1) {
$found = preg_match(
"/([\"'])(?:(?=(\\\\?))\\2.)*?\\1/u",
$str,
$matches
); //matches first passed argument only
$m[] = $found ? trim($matches[0], '"\'') : $patternMatch1[1];
return $m;
},
[]
);
}
if (! empty($patternMatch2[1])) {
$strings = array_merge($strings, $patternMatch2[1]);
return $strings;
}
return $strings;
}
}