tao-test/app/tao/scripts/class.TaoTranslate.php

1519 lines
65 KiB
PHP

<?php
use oat\generis\model\OntologyRdfs;
use oat\tao\helpers\ApplicationHelper;
use oat\tao\model\menu\MenuService;
/**
* 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) 2002-2008 (original work) Public Research Centre Henri Tudor & University of Luxembourg (under the project TAO & TAO2);
* 2008-2010 (update and modification) 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);
*
*/
/**
* The TaoTranslate script aims at providing command line tools to manage
* of tao. It enables you to manage the i18n of the messages found in the source
* (gettext) but also i18n of RDF Models.
*
* @access public
* @author Joel Bout, <joel.bout@tudor.lu>
* @package tao
*/
class tao_scripts_TaoTranslate extends tao_scripts_Runner
{
// --- ASSOCIATIONS ---
// --- ATTRIBUTES ---
/**
* Short description of attribute DEF_INPUT_DIR
*
* @access public
* @var string
*/
const DEF_INPUT_DIR = '.';
/**
* Short description of attribute DEF_OUTPUT_DIR
*
* @access public
* @var string
*/
const DEF_OUTPUT_DIR = 'locales';
/**
* Short description of attribute DEF_PO_FILENAME
*
* @access public
* @var string
*/
const DEF_PO_FILENAME = 'messages.po';
/**
* Short description of attribute DEF_JS_FILENAME
*
* @access public
* @var string
*/
const DEF_JS_FILENAME = 'messages_po.js';
/**
* Short description of attribute options
*
* @access protected
* @var array
*/
protected $options = [];
/**
* Short description of attribute DEF_LANG_FILENAME
*
* @access public
* @var string
*/
const DEF_LANG_FILENAME = 'lang.rdf';
private static $WHITE_LIST = [
'actions',
'helpers',
'models',
'views',
'helper',
'controller',
'model',
'scripts',
];
protected $verbose = false;
// --- OPERATIONS ---
/**
* keys - action names from user input
* value - base name for method to call
* @return array
*/
protected function getAllowedActions()
{
return [
'create' => 'Create',
'update' => 'Update',
'delete' => 'Delete',
'updateall' => 'UpdateAll',
'deleteall' => 'DeleteAll',
'enable' => 'Enable',
'disable' => 'Disable',
'compile' => 'Compile',
'compileall' => 'CompileAll',
'changecode' => 'ChangeCode',
'getallextensions' => 'GetExt',
];
}
/**
* Things that must happen before script execution.
*
* @access public
* @author Joel Bout, <joel.bout@tudor.lu>
* @return void
*/
public function preRun()
{
$this->options = ['verbose' => false,
'action' => null,
'extension' => null];
$this->options = array_merge($this->options, $this->parameters);
if ($this->options['verbose'] == true) {
$this->verbose = true;
}
// The 'action' parameter is always required.
if ($this->options['action'] == null) {
$this->err("Please enter the 'action' parameter.", true);
} else {
$this->options['action'] = strtolower($this->options['action']);
if (!in_array($this->options['action'], array_keys($this->getAllowedActions()))) {
$this->err("'" . $this->options['action'] . "' is not a valid action.", true);
} else {
// The 'action' parameter is ok.
// Let's check additional inputs depending on the value of the 'action' parameter.
$this->checkInput();
}
}
}
/**
* Main script implementation.
*
* @access public
* @author Joel Bout, <joel.bout@tudor.lu>
* @return void
*/
public function run()
{
// Select the action to perform depending on the 'action' parameter.
// Verification of the value of 'action' performed in self::preRun().
$actions = $this->getAllowedActions();
$pendingActionName = 'action' . $actions[$this->options['action']];
if (method_exists($this, $pendingActionName)) {
return $this->$pendingActionName();
}
}
/**
* Things that must happen after the run() method.
*
* @access public
* @author Joel Bout, <joel.bout@tudor.lu>
* @return void
*/
public function postRun()
{
}
/**
* Checks the inputs for the current script call.
*
* @access private
* @author Joel Bout, <joel.bout@tudor.lu>
* @return void
*/
private function checkInput()
{
$actions = $this->getAllowedActions();
$pendingActionName = 'check' . $actions[$this->options['action']] . 'Input';
if (method_exists($this, $pendingActionName)) {
return $this->$pendingActionName();
}
}
/**
* Checks the inputs for the 'create' action.
*
* @access private
* @author Joel Bout, <joel.bout@tudor.lu>
* @return void
*/
private function checkCreateInput()
{
$defaults = ['language' => null,
'languageLabel' => null,
'extension' => null,
'input' => dirname(__FILE__) . '/../../' . $this->options['extension'] . '/' . self::DEF_INPUT_DIR,
'output' => dirname(__FILE__) . '/../../' . $this->options['extension'] . '/' . self::DEF_OUTPUT_DIR,
'build' => true, // Build translation files by having a look in source code, models.
'force' => false]; // Do not force rebuild if locale already exist.
$this->options = array_merge($defaults, $this->options);
if (is_null($this->options['language'])) {
$this->err("Please provide a 'language' identifier such as en-US, fr-CA, IT, ...", true);
} else {
if (is_null($this->options['extension'])) {
$this->err("Please provide an 'extension' for which the 'language' will be created", true);
} else {
// Check if the extension(s) exists.
$extensionsToCreate = explode(',', $this->options['extension']);
$extensionsToCreate = array_unique($extensionsToCreate);
foreach ($extensionsToCreate as $etc) {
$this->options['input'] = dirname(__FILE__) . '/../../' . $etc . '/' . self::DEF_INPUT_DIR;
$this->options['output'] = dirname(__FILE__) . '/../../' . $etc . '/' . self::DEF_OUTPUT_DIR;
$extensionDir = dirname(__FILE__) . '/../../' . $etc;
if (!is_dir($extensionDir)) {
$this->err("The extension '" . $etc . "' does not exist.", true);
} elseif (!is_readable($extensionDir)) {
$this->err("The '" . $etc . "' directory is not readable. Please check permissions on this directory.", true);
} elseif (!is_writable($extensionDir)) {
$this->err("The '" . $etc . "' directory is not writable. Please check permissions on this directory.", true);
}
// The input 'parameter' is optional.
// (and only used if the 'build' parameter is set to true)
$this->checkInputOption();
// The 'output' parameter is optional.
$this->checkOutputOption();
}
}
}
}
/**
* Checks the inputs for the 'update' action.
*
* @access private
* @author Joel Bout, <joel.bout@tudor.lu>
* @return void
*/
private function checkUpdateInput()
{
$defaults = ['language' => null,
'extension' => null,
'input' => dirname(__FILE__) . '/../../' . $this->options['extension'] . '/' . self::DEF_INPUT_DIR,
'output' => dirname(__FILE__) . '/../../' . $this->options['extension'] . '/' . self::DEF_OUTPUT_DIR];
$this->options = array_merge($defaults, $this->options);
if (is_null($this->options['language'])) {
$this->err("Please provide a 'language' identifier such as en-US, fr-CA, IT, ...", true);
} else {
// Check if the language folder exists and is readable/writable.
$languageDir = $this->buildLanguagePath($this->options['extension'], $this->options['language']);
if (!is_dir($languageDir)) {
$this->err("The 'language' directory ${languageDir} does not exist.", true);
} elseif (!is_readable($languageDir)) {
$this->err("The 'language' directory ${languageDir} is not readable. Please check permissions on this directory.");
} elseif (!is_writable($languageDir)) {
$this->err("The 'language' directory ${languageDir} is not writable. Please check permissions on this directory.");
} else {
if (is_null($this->options['extension'])) {
$this->err("Please provide an 'extension' for which the 'language' will be created", true);
} else {
// Check if the extension exists.
$extensionDir = dirname(__FILE__) . '/../../' . $this->options['extension'];
if (!is_dir($extensionDir)) {
$this->err("The extension '" . $this->options['extension'] . "' does not exist.", true);
} elseif (!is_readable($extensionDir)) {
$this->err("The '" . $this->options['extension'] . "' directory is not readable. Please check permissions on this directory.", true);
} elseif (!is_writable($extensionDir)) {
$this->err("The '" . $this->options['extension'] . "' directory is not writable. Please check permissions on this directory.", true);
} else {
// And can we read the messages.po file ?
if (!file_exists($languageDir . '/' . self::DEF_PO_FILENAME)) {
$this->err("Cannot find " . self::DEF_PO_FILENAME . " for extension '" . $this->options['extension'] . "' and language '" . $this->options['language'] . "'.", true);
} elseif (!is_readable($languageDir . '/' . self::DEF_PO_FILENAME)) {
$this->err(self::DEF_PO_FILENAME . " is not readable for '" . $this->options['extension'] . "' and language '" . $this->options['language'] . "'. Please check permissions for this file.", true);
} else {
// The input 'parameter' is optional.
$this->checkInputOption();
// The 'output' parameter is optional.
$this->checkOutputOption();
}
}
}
}
}
}
/**
* checks the input for the 'updateAll' action.
*
* @access private
* @author Joel Bout, <joel.bout@tudor.lu>
* @return void
*/
private function checkUpdateAllInput()
{
$defaults = ['input' => dirname(__FILE__) . '/../../' . $this->options['extension'] . '/' . self::DEF_INPUT_DIR,
'output' => dirname(__FILE__) . '/../../' . $this->options['extension'] . '/' . self::DEF_OUTPUT_DIR,
'extension' => null];
$this->options = array_merge($defaults, $this->options);
// The input 'parameter' is optional.
$this->checkInputOption();
// The 'output' parameter is optional.
$this->checkOutputOption();
}
/**
* Checks the inputs for the 'delete' action.
*
* @access private
* @author Joel Bout, <joel.bout@tudor.lu>
* @return void/
*/
private function checkDeleteInput()
{
$defaults = ['language' => null,
'input' => dirname(__FILE__) . '/../../' . $this->options['extension'] . '/' . self::DEF_INPUT_DIR,
'output' => dirname(__FILE__) . '/../../' . $this->options['extension'] . '/' . self::DEF_OUTPUT_DIR,
'extension' => null];
$this->options = array_merge($defaults, $this->options);
if (is_null($this->options['extension'])) {
$this->err("Please provide an 'extension' identifier.", true);
} else {
if (is_null($this->options['language'])) {
$this->err("Please provide a 'language' identifier such as en-US, fr-CA, IT, ...", true);
} else {
$this->checkInputOption();
}
}
}
/**
* Checks inputs for the 'deleteAll' action.
*
* @access private
* @author Joel Bout, <joel.bout@tudor.lu>
* @return void
*/
private function checkDeleteAllInput()
{
$defaults = ['input' => dirname(__FILE__) . '/../../' . $this->options['extension'] . '/' . self::DEF_INPUT_DIR,
'output' => dirname(__FILE__) . '/../../' . $this->options['extension'] . '/' . self::DEF_OUTPUT_DIR,
'extension' => null];
$this->options = array_merge($defaults, $this->options);
// The input 'parameter' is optional.
if (!is_null($this->options['extension'])) {
$this->checkInputOption();
} else {
$this->err("Please provide an 'extension' identifier.", true);
}
}
private function checkChangeCodeInput()
{
$defaults = ['input' => dirname(__FILE__) . '/../../' . $this->options['extension'] . '/' . self::DEF_INPUT_DIR,
'output' => dirname(__FILE__) . '/../../' . $this->options['extension'] . '/' . self::DEF_OUTPUT_DIR,
'extension' => null,
'language' => null,
'targetLanguage' => null];
$this->options = array_merge($defaults, $this->options);
if (empty($this->options['language'])) {
$this->err("Please provide a source 'language' identifier such as en-US, fr-CA, IT, ...", true);
} elseif (empty($this->options['targetLanguage'])) {
$this->err("Please provide a 'targetLanguage' identifier such as en-US, fr-CA, IT, ...", true);
} elseif (empty($this->options['extension'])) {
$this->err("Please provide an 'extension' identifier.", true);
} elseif (!is_readable($this->options['output'] . DIRECTORY_SEPARATOR . $this->options['language'])) {
$this->err("The '" . $this->options['language'] . "' locale directory is not readable.", true);
} elseif (!is_writable($this->options['output'])) {
$this->err("The locales directory of extension '" . $this->options['extension'] . "' is not writable.");
}
}
/**
* Implementation of the 'create' action.
*
* @access public
* @author Joel Bout, <joel.bout@tudor.lu>
* @return void
*/
public function actionCreate()
{
$extensionsToCreate = explode(',', $this->options['extension']);
$extensionsToCreate = array_unique($extensionsToCreate);
foreach ($extensionsToCreate as $etc) {
$this->options['extension'] = $etc;
$this->options['input'] = dirname(__FILE__) . '/../../' . $etc . '/' . self::DEF_INPUT_DIR;
$this->options['output'] = dirname(__FILE__) . '/../../' . $etc . '/' . self::DEF_OUTPUT_DIR;
$this->outVerbose("Creating language '" . $this->options['language'] . "' for extension '" . $this->options['extension'] . "' ...");
// We first create the directory where locale files will go.
$dir = $this->buildLanguagePath($this->options['extension'], $this->options['language']);
$dirExists = false;
if (file_exists($dir) && is_dir($dir) && $this->options['force'] == true) {
$dirExists = true;
$this->outVerbose("Language '" . $this->options['language'] . "' exists for extension '" . $this->options['extension'] . "'. Creation will be forced.");
// Clean it up.
foreach (scandir($dir) as $d) {
if ($d !== '.' && $d !== '..' && $d !== '.svn') {
if (!tao_helpers_File::remove($dir . '/' . $d, true)) {
$this->err("Unable to clean up 'language' directory '" . $dir . "'.", true);
}
}
}
} elseif (file_exists($dir) && is_dir($dir) && $this->options['force'] == false) {
$this->err("The 'language' " . $this->options['language'] . " already exists in the file system. Use the 'force' parameter to overwrite it.", true);
}
// If we are still here... it means that we have to create the language directory.
if (!$dirExists && !@mkdir($dir)) {
$this->err("Unable to create 'language' directory '" . $this->options['language'] . "'.", true);
} else {
if ($this->options['build'] == true) {
$sortingMethod = tao_helpers_translation_TranslationFile::SORT_ASC_I;
$this->outVerbose("Building language '" . $this->options['language'] . "' for extension '" . $this->options['extension'] . "' ...");
// Let's populate the language with raw PO files containing sources but no targets.
// Source code extraction.
$fileExtensions = ['php', 'tpl', 'js', 'ejs'];
$filePaths = [];
foreach (self::$WHITE_LIST as $subFolder) {
$filePaths[] = $this->options['input'] . DIRECTORY_SEPARATOR . $subFolder;
}
$sourceExtractor = new tao_helpers_translation_SourceCodeExtractor($filePaths, $fileExtensions);
$sourceExtractor->extract();
$translationFile = new tao_helpers_translation_POFile();
$translationFile->setSourceLanguage(tao_helpers_translation_Utils::getDefaultLanguage());
$translationFile->setTargetLanguage($this->options['language']);
$translationFile->addTranslationUnits($sourceExtractor->getTranslationUnits());
$file = MenuService::getStructuresFilePath($this->options['extension']);
if (!is_null($file)) {
$structureExtractor = new tao_helpers_translation_StructureExtractor([$file]);
$structureExtractor->extract();
$translationFile->addTranslationUnits($structureExtractor->getTranslationUnits());
}
$sortedTus = $translationFile->sortBySource($sortingMethod);
$sortedTranslationFile = new tao_helpers_translation_POFile();
$sortedTranslationFile->setSourceLanguage(tao_helpers_translation_Utils::getDefaultLanguage());
$sortedTranslationFile->setTargetLanguage($this->options['language']);
$sortedTranslationFile->addTranslationUnits($sortedTus);
$this->preparePOFile($sortedTranslationFile, true);
$poPath = $dir . '/' . self::DEF_PO_FILENAME;
$writer = new tao_helpers_translation_POFileWriter(
$poPath,
$sortedTranslationFile
);
$writer->write();
$this->outVerbose("PO Translation file '" . basename($poPath) . "' in '" . $this->options['language'] . "' created for extension '" . $this->options['extension'] . "'.");
$writer->write();
// Writing JS files
$jsPath = $dir . '/' . self::DEF_JS_FILENAME;
$writer = new tao_helpers_translation_JSFileWriter(
$jsPath,
$sortedTranslationFile
);
$writer->write(false);
$this->outVerbose("JavaScript Translation file '" . basename($jsPath) . "' in '" . $this->options['language'] . "' created for extension '" . $this->options['extension'] . "'.");
$writer->write();
// Now that PO files & JS files are created, we can create the translation models
// if we find RDF models to load for this extension.
$translatableProperties = [OntologyRdfs::RDFS_LABEL, OntologyRdfs::RDFS_COMMENT];
foreach ($this->getOntologyFiles() as $f) {
common_Logger::d('reading rdf ' . $f);
$translationFile = $this->extractPoFileFromRDF($f, $translatableProperties);
$writer = new tao_helpers_translation_POFileWriter($dir . '/' . $this->getOntologyPOFileName($f), $translationFile);
$writer->write();
$this->outVerbose("PO Translation file '" . $this->getOntologyPOFileName($f) . "' in '" . $this->options['language'] . "' created for extension '" . $this->options['extension'] . "'.");
}
$this->outVerbose("Language '" . $this->options['language'] . "' created for extension '" . $this->options['extension'] . "'.");
} else {
// Only build virgin files.
// (Like a virgin... woot !)
$translationFile = new tao_helpers_translation_POFile();
$translationFile->setSourceLanguage(tao_helpers_translation_Utils::getDefaultLanguage());
$translationFile->setTargetLanguage($this->options['language']);
$this->preparePOFile($translationFile, true);
foreach ($this->getOntologyFiles() as $f) {
common_Logger::d('reading rdf ' . $f);
$translationFile = new tao_helpers_translation_POFile();
$translationFile->setSourceLanguage(tao_helpers_translation_Utils::getDefaultLanguage());
$translationFile->setTargetLanguage($this->options['language']);
$translationFile->setExtensionId($this->options['extension']);
$writer = new tao_helpers_translation_POFileWriter($dir . '/' . $this->getOntologyPOFileName($f), $translationFile);
$writer->write();
}
$this->outVerbose("Language '" . $this->options['language'] . "' created for extension '" . $this->options['extension'] . "'.");
}
// Create the language manifest in RDF.
if ($this->options['extension'] == 'tao') {
$langDescription = tao_helpers_translation_RDFUtils::createLanguageDescription(
$this->options['language'],
$this->options['languageLabel']
);
$langDescription->save($dir . '/' . self::DEF_LANG_FILENAME);
}
}
}
}
/**
* Implementation of the 'update' action.
*
* @access public
* @author Joel Bout, <joel.bout@tudor.lu>
* @return void
*/
public function actionUpdate()
{
$this->outVerbose("Updating language '" . $this->options['language'] . "' for extension '" . $this->options['extension'] . "'...");
$sortingMethod = tao_helpers_translation_TranslationFile::SORT_ASC_I;
// Get virgin translations from the source code and manifest.
$filePaths = [];
foreach (self::$WHITE_LIST as $subFolder) {
$filePaths[] = $this->options['input'] . DIRECTORY_SEPARATOR . $subFolder;
}
$extensions = ['php', 'tpl', 'js', 'ejs'];
$sourceCodeExtractor = new tao_helpers_translation_SourceCodeExtractor($filePaths, $extensions);
$sourceCodeExtractor->extract();
$translationFile = new tao_helpers_translation_POFile();
$translationFile->setSourceLanguage(tao_helpers_translation_Utils::getDefaultLanguage());
$translationFile->setTargetLanguage($this->options['language']);
$translationFile->addTranslationUnits($sourceCodeExtractor->getTranslationUnits());
$file = MenuService::getStructuresFilePath($this->options['extension']);
if (!is_null($file)) {
$structureExtractor = new tao_helpers_translation_StructureExtractor([$file]);
$structureExtractor->extract();
$structureUnits = $structureExtractor->getTranslationUnits();
$this->outVerbose(count($structureUnits) . ' units extracted from structures.xml.');
$translationFile->addTranslationUnits($structureUnits);
}
// For each TU that was recovered, have a look in an older version
// of the translations.
$oldFilePath = $this->buildLanguagePath($this->options['extension'], $this->options['language']) . '/' . self::DEF_PO_FILENAME;
$translationFileReader = new tao_helpers_translation_POFileReader($oldFilePath);
$translationFileReader->read();
$oldTranslationFile = $translationFileReader->getTranslationFile();
foreach ($oldTranslationFile->getTranslationUnits() as $oldTu) {
if (($newTu = $translationFile->getBySource($oldTu)) !== null && $oldTu->getTarget() != '') {
// No duplicates in TFs so I simply add it whatever happens.
// If it already has the same one, it means we will update it.
$newTu->setTarget($oldTu->getTarget());
}
}
$sortedTranslationFile = new tao_helpers_translation_POFile();
$sortedTranslationFile->setSourceLanguage($translationFile->getSourceLanguage());
$sortedTranslationFile->setTargetLanguage($translationFile->getTargetLanguage());
$sortedTranslationFile->addTranslationUnits($translationFile->sortBySource($sortingMethod));
$this->preparePOFile($sortedTranslationFile, true);
// Write the new ones.
$poFileWriter = new tao_helpers_translation_POFileWriter($oldFilePath, $sortedTranslationFile);
$poFileWriter->write();
$this->outVerbose("PO translation file '" . basename($oldFilePath) . "' in '" . $this->options['language'] . "' updated for extension '" . $this->options['extension'] . "'.");
$translatableProperties = [OntologyRdfs::RDFS_LABEL, OntologyRdfs::RDFS_COMMENT];
// We now deal with RDF models.
foreach ($this->getOntologyFiles() as $f) {
// Loop on 'master' models.
$translationFile = $this->extractPoFileFromRDF($f, $translatableProperties);
// The slave RDF file is the translation of the ontology that we find in /extId/Locales/langCode.
$slavePOFilePath = $this->buildLanguagePath($this->options['extension'], $this->options['language']) . '/' . $this->getOntologyPOFileName($f);
if (file_exists($slavePOFilePath)) {
// Read the existing RDF Translation file for this RDF model.
$poReader = new tao_helpers_translation_POFileReader($slavePOFilePath);
$poReader->read();
$slavePOFile = $poReader->getTranslationFile();
// Try to update translation units found in the master PO file with
// targets found in the old translation of the ontology.
foreach ($slavePOFile->getTranslationUnits() as $oTu) {
$translationFile->addTranslationUnit($oTu);
}
// Remove Slave PO file. It will be overwritten by the modified Master PO file.
tao_helpers_File::remove($slavePOFilePath);
}
// Write Master PO file as the new Slave PO file.
$rdfWriter = new tao_helpers_translation_POFileWriter($slavePOFilePath, $translationFile);
$rdfWriter->write();
$this->outVerbose("Translation model {$this->getOntologyPOFileName($f)} in '" . $this->options['language'] . "' updated for extension '" . $this->options['extension'] . "'.");
}
$this->outVerbose("Language '" . $this->options['language'] . "' updated for extension '" . $this->options['extension'] . "'.");
}
/**
* Implementation of the 'updateAll' action.
*
* @access public
* @author Joel Bout, <joel.bout@tudor.lu>
* @return void
*/
public function actionUpdateAll()
{
// Scan the locales folder for languages in the wwextension and
// launch actionUpdate for each of them.
// Get the list of languages that will be updated.
$locales = $this->getLanguageList();
// We now identified locales to be updated.
$this->outVerbose("Languages '" . implode(',', $locales) . "' will be updated for extension '" . $this->options['extension'] . "'.");
foreach ($locales as $l) {
$this->options['language'] = $l;
$this->checkUpdateInput();
$this->actionUpdate();
$this->outVerbose("");
}
}
/**
* Implementation of the 'delete' action.
*
* @access public
* @author Joel Bout, <joel.bout@tudor.lu>
* @return void
*/
public function actionDelete()
{
$this->outVerbose("Deleting language '" . $this->options['language'] . "' for extension '" . $this->options['extension'] . "' ...");
$dir = $this->buildLanguagePath($this->options['extension'], $this->options['language']);
if (!tao_helpers_File::remove($dir, true)) {
$this->err("Could not delete language '" . $this->options['language'] . "' for extension '" . $this->options['extension'] . "'.", true);
}
$this->outVerbose("Language '" . $this->options['language'] . "' for extension '" . $this->options['extension'] . "' successfully deleted.");
}
/**
* Implementation of the 'deleteAll' action.
*
* @access public
* @author Joel Bout, <joel.bout@tudor.lu>
* @return void
*/
public function actionDeleteAll()
{
// Get the list of languages that will be deleted.
$this->outVerbose("Deleting all languages for extension '" . $this->options['extension'] . "'...");
$locales = $this->getLanguageList();
foreach ($locales as $l) {
$this->options['language'] = $l;
$this->checkDeleteInput();
$this->actionDelete();
$this->outVerbose("");
}
}
public function actionChangeCode()
{
$this->outVerbose("Changing code of locale '" . $this->options['language'] . "' to '" . $this->options['targetLanguage'] . "' for extension '" . $this->options['extension'] . "'...");
// First we copy the old locale to a new directory named as 'targetLanguage'.
$sourceLocaleDir = $this->options['output'] . DIRECTORY_SEPARATOR . $this->options['language'];
$destLocaleDir = $this->options['output'] . DIRECTORY_SEPARATOR . $this->options['targetLanguage'];
if (!tao_helpers_File::copy($sourceLocaleDir, $destLocaleDir, true, true)) {
$this->err("Locale '" . $this->options['language'] . "' could not be copied to locale '" . $this->options['targetLanguage'] . "'.");
}
// We now apply transformations to the new locale.
foreach (scandir($destLocaleDir) as $f) {
$sourceLang = $this->options['language'];
$destLang = $this->options['targetLanguage'];
$qSourceLang = preg_quote($sourceLang);
$qDestLang = preg_quote($destLang);
if (!is_dir($f) && $f[0] != '.') {
if ($f == 'messages.po') {
// Change the language tag in the PO file.
$pattern = "/Language: ${qSourceLang}/u";
$count = 0;
$content = file_get_contents($destLocaleDir . DIRECTORY_SEPARATOR . 'messages.po');
$newFileContent = preg_replace($pattern, "Language: ${destLang}", $content, -1, $count);
if ($count == 1) {
$this->outVerbose("Language tag '${destLang}' applied to messages.po.");
file_put_contents($destLocaleDir . DIRECTORY_SEPARATOR . 'messages.po', $newFileContent);
} else {
$this->err("Could not change language tag in messages.po.");
}
} elseif ($f == 'messages_po.js') {
// Change the language tag in comments.
// Change the langCode JS variable.
$pattern = "/var langCode = '${qSourceLang}';/u";
$count1 = 0;
$content = file_get_contents($destLocaleDir . DIRECTORY_SEPARATOR . 'messages_po.js');
$newFileContent = preg_replace($pattern, "var langCode = '${destLang}';", $content, -1, $count1);
$pattern = "|/\\* lang: ${qSourceLang} \\*/|u";
$count2 = 0;
$newFileContent = preg_replace($pattern, "/* lang: ${destLang} */", $newFileContent, -1, $count2);
if ($count1 + $count2 == 2) {
$this->outVerbose("Language tag '${destLang}' applied to messages_po.js");
file_put_contents($destLocaleDir . DIRECTORY_SEPARATOR . 'messages_po.js', $newFileContent);
} else {
$this->err("Could not change language tag in messages_po.js");
}
} elseif ($f == 'lang.rdf') {
// Change <![CDATA[XX]]>
// Change http://www.tao.lu/Ontologies/TAO.rdf#LangXX
$pattern = "/<!\\[CDATA\\[${qSourceLang}\\]\\]>/u";
$count1 = 0;
$content = file_get_contents($destLocaleDir . DIRECTORY_SEPARATOR . 'lang.rdf');
$newFileContent = preg_replace($pattern, "<![CDATA[${destLang}]]>", $content, -1, $count1);
$pattern = "|http://www.tao.lu/Ontologies/TAO.rdf#Lang${qSourceLang}|u";
$count2 = 0;
$newFileContent = preg_replace($pattern, "http://www.tao.lu/Ontologies/TAO.rdf#Lang${destLang}", $newFileContent, -1, $count2);
$pattern = '/xml:lang="EN"/u';
$count3 = 0;
$newFileContent = preg_replace($pattern, 'xml:lang="en-US"', $newFileContent, -1, $count3);
if ($count1 + $count2 + $count3 == 3) {
$this->outVerbose("Language tag '${destLang}' applied to lang.rdf");
file_put_contents($destLocaleDir . DIRECTORY_SEPARATOR . 'lang.rdf', $newFileContent);
} else {
$this->err("Could not change language tag in lang.rdf");
}
} else {
// Check for a .rdf extension.
$infos = pathinfo($destLocaleDir . DIRECTORY_SEPARATOR . $f);
if (isset($infos['extension']) && $infos['extension'] == 'rdf') {
// Change annotations @sourceLanguage and @targetLanguage
// Change xml:lang
$pattern = "/@sourceLanguage EN/u";
$content = file_get_contents($destLocaleDir . DIRECTORY_SEPARATOR . $f);
$newFileContent = preg_replace($pattern, "@sourceLanguage en-US", $content);
$pattern = "/@targetLanguage ${qSourceLang}/u";
$newFileContent = preg_replace($pattern, "@targetLanguage ${destLang}", $newFileContent);
$pattern = '/xml:lang="' . $qSourceLang . '"/u';
$newFileContent = preg_replace($pattern, 'xml:lang="' . $destLang . '"', $newFileContent);
$this->outVerbose("Language tag '${destLang}' applied to ${f}");
file_put_contents($destLocaleDir . DIRECTORY_SEPARATOR . $f, $newFileContent);
}
}
}
}
}
/**
* Builds the path to files dedicated to a given language (locale) for a
* extension ID.
*
* @access private
* @author Joel Bout, <joel.bout@tudor.lu>
* @param string extension
* @param string language
* @return string
*/
private function buildLanguagePath($extension, $language)
{
$returnValue = (string) '';
$returnValue = dirname(__FILE__) . '/../../' . $extension . '/' . self::DEF_OUTPUT_DIR . '/' . $language;
return (string) $returnValue;
}
/**
* Find a structure.xml manifest in a given directory.
*
* @access public
* @author Joel Bout, <joel.bout@tudor.lu>
* @param string directory
* @return mixed
*/
public function findStructureManifest($directory = null)
{
$returnValue = null;
if ($directory == null) {
$actionsDir = $this->options['input'] . '/actions';
} else {
$actionsDir = $directory . '/actions';
}
$dirEntries = scandir($actionsDir);
if ($dirEntries === false) {
$returnValue = false;
} else {
$structureFile = null;
foreach ($dirEntries as $f) {
if (preg_match("/(.*)structure\.xml$/", $f)) {
$structureFile = $f;
break;
}
}
if ($structureFile === null) {
$returnValue = false;
} else {
$returnValue = $structureFile;
}
}
return $returnValue;
}
/**
* Prepare a PO file before output by adding headers to it.
*
* @access public
* @author Joel Bout, <joel.bout@tudor.lu>
* @param tao_helpers_translation_POFile $poFile
* @param bool $poEditorReady
* @return void
*/
public function preparePOFile(tao_helpers_translation_POFile $poFile, $poEditorReady = false)
{
$poFile->addHeader('Project-Id-Version', PRODUCT_NAME . ' ' . ApplicationHelper::getVersionName());
$poFile->addHeader('PO-Revision-Date', date('Y-m-d') . 'T' . date('H:i:s'));
$poFile->addHeader('Last-Translator', 'TAO Translation Team <translation@tao.lu>');
$poFile->addHeader('MIME-Version', '1.0');
$poFile->addHeader('Language', $poFile->getTargetLanguage());
$poFile->addHeader('sourceLanguage', $poFile->getSourceLanguage());
$poFile->addHeader('targetLanguage', $poFile->getTargetLanguage());
$poFile->addHeader('Content-Type', 'text/plain; charset=utf-8');
$poFile->addHeader('Content-Transfer-Encoding', '8bit');
if ($poEditorReady) {
$poFile->addHeader('X-Poedit-Basepath', '../../');
$poFile->addHeader('X-Poedit-KeywordsList', '__');
$poFile->addHeader('X-Poedit-SearchPath-0', '.');
}
}
/**
* Determines if an given directory actually contains a TAO extension.
*
* @access public
* @author Joel Bout, <joel.bout@tudor.lu>
* @param string directory
* @return boolean
*/
public function isExtension($directory)
{
$returnValue = (bool) false;
$hasStructure = $this->findStructureManifest($directory) !== false;
$hasPHPManifest = false;
$files = scandir($this->options['input']);
if ($files !== false) {
foreach ($files as $f) {
if (is_file($this->options['input'] . '/' . $f) && is_readable($this->options['input'] . '/' . $f)) {
if ($f == 'manifest.php') {
$hasPHPManifest = true;
}
}
}
}
$returnValue = $hasStructure || $hasPHPManifest;
return (bool) $returnValue;
}
/**
* Add translations as translation units found in a structure.xml manifest
* a given PO file.
*
* @access public
* @author Joel Bout, <joel.bout@tudor.lu>
* @param tao_helpers_translation_POFile $poFile
* @throws Exception
* @return void
*/
public function addManifestsTranslations(tao_helpers_translation_POFile $poFile)
{
$this->outVerbose("Adding all manifests messages to extension '" . $this->options['extension'] . "'");
$rootDir = dirname(__FILE__) . '/../../';
$directories = scandir($rootDir);
$exceptions = ['generis', 'tao', '.*'];
if (false === $directories) {
$this->err("The TAO root directory is not readable. Please check permissions on this directory.", true);
} else {
foreach ($directories as $dir) {
if (is_dir($rootDir . $dir) && !in_array($dir, $exceptions)) {
// Maybe it should be read.
if (in_array('.*', $exceptions) && $dir[0] == '.') {
continue;
} else {
// Is this a TAO extension ?
$file = MenuService::getStructuresFilePath($this->options['extension']);
if (!is_null($file)) {
$structureExtractor = new tao_helpers_translation_StructureExtractor([$file]);
$structureExtractor->extract();
$poFile->addTranslationUnits($structureExtractor->getTranslationUnits());
$this->outVerbose("Manifest of extension '" . $dir . "' added to extension '" . $this->options['extension'] . "'");
}
}
}
}
}
}
/**
* Add the requested language in the ontology. It will used the parameters
* the command line for logic.
*
* @access protected
* @author Joel Bout, <joel.bout@tudor.lu>
* @return void
*/
protected function addLanguageToOntology()
{
$this->outVerbose("Importing RDF language description '" . $this->options['language'] . "' to ontology...");
// RDF Language Descriptions are stored in the tao meta-extension locales.
$expectedDescriptionPath = $this->buildLanguagePath('tao', $this->options['language']) . '/lang.rdf';
if (file_exists($expectedDescriptionPath)) {
if (is_readable($expectedDescriptionPath)) {
// Let's remove any instance of the language description before inserting the new one.
$taoNS = 'http://www.tao.lu/Ontologies/TAO.rdf#';
$expectedLangUri = $taoNS . 'Lang' . $this->options['language'];
$lgDescription = new core_kernel_classes_Resource($expectedLangUri);
if ($lgDescription->exists()) {
$lgDescription->delete();
$this->outVerbose("Existing RDF Description language '" . $this->options['language'] . "' deleted.");
}
$generisAdapterRdf = new tao_helpers_data_GenerisAdapterRdf();
if (true === $generisAdapterRdf->import($expectedDescriptionPath, null, LOCAL_NAMESPACE)) {
$this->outVerbose("RDF language description '" . $this->options['language'] . "' successfully imported.");
} else {
$this->err("An error occured while importing the RDF language description '" . $this->options['language'] . "'.", true);
}
} else {
$this->err("RDF language description (lang.rdf) cannot be read in meta-extension 'tao' for language '" . $this->options['language'] . "'.", true);
}
} else {
$this->err("RDF language description (lang.rdf) not found in meta-extension 'tao' for language '" . $this->options['language'] . "'.", true);
}
$this->outVerbose("RDF language description '" . $this->options['language'] . "' added to ontology.");
}
/**
* Removes a language from the Ontology and all triples with the related
* tag. Will use command line parameters for logic.
*
* @access protected
* @author Joel Bout, <joel.bout@tudor.lu>
* @return void
*/
protected function removeLanguageFromOntology()
{
$this->outVerbose("Removing RDF language description '" . $this->options['language'] . "' from ontology...");
$taoNS = 'http://www.tao.lu/Ontologies/TAO.rdf#';
$expectedDescriptionUri = $taoNS . 'Lang' . $this->options['language'];
$lgResource = new core_kernel_classes_Resource($expectedDescriptionUri);
if (true === $lgResource->exists()) {
$lgResource->delete();
$this->outVerbose("RDF language description '" . $this->options['language'] . "' successfully removed.");
} else {
$this->outVerbose("RDF language description '" . $this->options['language'] . "' not found but considered removed.");
}
}
/**
* Checks authentication parameters for the TAO API.
*
* @access protected
* @author Joel Bout, <joel.bout@tudor.lu>
* @return void
*/
protected function checkAuthInput()
{
$defaults = ['user' => null,
'password' => null];
$this->options = array_merge($defaults, $this->options);
if ($this->options['user'] == null) {
$this->err("Please provide a value for the 'user' parameter.", true);
} elseif ($this->options['password'] == null) {
$this->err("Please provide a value for the 'password' parameter.", true);
}
}
/**
* Get the ontology file paths for a given extension, sorted by target name
*
* @access private
* @author Joel Bout, <joel.bout@tudor.lu>
* @return array
*/
private function getOntologyFiles()
{
$returnValue = [];
$ext = common_ext_ExtensionsManager::singleton()->getExtensionById($this->options['extension']);
$returnValue = $ext->getManifest()->getInstallModelFiles();
return (array) $returnValue;
}
/**
* Check inputs for the 'enable' action.
*
* @access private
* @author Joel Bout, <joel.bout@tudor.lu>
* @return void
*/
private function checkEnableInput()
{
$this->checkAuthInput();
$defaults = ['language' => null,
'input' => dirname(__FILE__) . '/../../' . $this->options['extension'] . '/' . self::DEF_INPUT_DIR,
'output' => dirname(__FILE__) . '/../../' . $this->options['extension'] . '/' . self::DEF_OUTPUT_DIR];
$this->options = array_merge($defaults, $this->options);
if ($this->options['language'] == null) {
$this->err("Please provide the 'language' parameter.", true);
}
}
/**
* Short description of method checkDisableInput
*
* @access private
* @author Joel Bout, <joel.bout@tudor.lu>
* @return void
*/
private function checkDisableInput()
{
$this->checkAuthInput();
$defaults = ['language' => null];
$this->options = array_merge($defaults, $this->options);
if ($this->options['language'] == null) {
$this->err("Please provide the 'language' parameter.", true);
}
}
/**
* Short description of method actionEnable
*
* @access public
* @author Joel Bout, <joel.bout@tudor.lu>
* @return void
*/
public function actionEnable()
{
$userService = tao_models_classes_UserService::singleton();
$this->outVerbose("Connecting to TAO as '" . $this->options['user'] . "' ...");
if ($userService->loginUser($this->options['user'], $this->options['password'])) {
$this->outVerbose("Connected to TAO as '" . $this->options['user'] . "'.");
$this->addLanguageToOntology();
$userService->logout();
$this->outVerbose("Disconnected from TAO.");
} else {
$this->err("Unable to connect to TAO as '" . $this->options['user'] . "'. Please check user name and password.", true);
}
}
/**
* Implementation of the 'disable' action. When this action is called, a
* Language Description ('language' param) is removed from the Knowledge
* The language is at this time not available anymore to end-users. However,
* Triples that had a corresponding language tag are not remove from the
* If the language is enabled again via the 'enable' action of this script,
* having corresponding languages will be reachable again.
*
* @access public
* @author Joel Bout, <joel.bout@tudor.lu>
* @return void
*/
public function actionDisable()
{
$userService = tao_models_classes_UserService::singleton();
$this->outVerbose("Connecting to TAO as '" . $this->options['user'] . "' ...");
if ($userService->loginUser($this->options['user'], $this->options['password'])) {
$this->outVerbose("Connected to TAO as '" . $this->options['user'] . "'.");
$this->removeLanguageFromOntology();
$userService->logout();
$this->outVerbose("Disconnected from TAO.");
} else {
$this->err("Unable to connect to TAO as '" . $this->options['user'] . "'. Please check user name and password.", true);
}
}
/**
* Implementation of the 'compile' action.
*
* @access public
* @author Joel Bout, <joel.bout@tudor.lu>
* @return void
*/
public function actionCompile()
{
$extensionsToCreate = explode(',', $this->options['extension']);
$extensionsToCreate = array_unique($extensionsToCreate);
foreach ($extensionsToCreate as $extension) {
$language = $this->options['language'];
$compiledTranslationFile = new tao_helpers_translation_TranslationFile();
$compiledTranslationFile->setTargetLanguage($this->options['language']);
$this->outVerbose("Compiling language '${language}' for extension '${extension}'...");
// Get the dependencies of the target extension.
// @todo Deal with dependencies at compilation time.
$dependencies = [];
if ($extension !== 'tao') {
$dependencies[] = 'tao';
}
$this->outVerbose("Resolving Dependencies...");
foreach ($dependencies as $depExtId) {
$this->outVerbose("Adding messages from extension '${depExtId}' in '${language}'...");
// Does the locale exist for $depExtId?
$depPath = $this->buildLanguagePath($depExtId, $language) . '/' . self::DEF_PO_FILENAME;
if (!file_exists($depPath) || !is_readable($depPath)) {
$this->outVerbose("Dependency on extension '${depExtId}' in '${language}' does not exist. Trying to resolve default language...");
$depPath = $this->buildLanguagePath($depExtId, tao_helpers_translation_Utils::getDefaultLanguage() . '/' . self::DEF_PO_FILENAME);
if (!file_exists($depPath) || !is_readable($depPath)) {
$this->outVerbose("Dependency on extension '${depExtId}' in '${language}' does not exist.");
continue;
}
}
// Recompile the dependent extension (for the moment 'tao' meta-extension only).
$oldVerbose = $this->options['verbose'];
$this->parameters['verbose'] = false;
$this->options['extension'] = $depExtId;
$this->actionCompile();
$this->options['extension'] = $extension;
$this->parameters['verbose'] = $oldVerbose;
$poFileReader = new tao_helpers_translation_POFileReader($depPath);
$poFileReader->read();
$poFile = $poFileReader->getTranslationFile();
$poCount = $poFile->count();
$compiledTranslationFile->addTranslationUnits($poFile->getTranslationUnits());
$this->outVerbose("${poCount} messages added.");
}
if (($extDirectories = scandir(ROOT_PATH)) !== false) {
// Get all public messages accross extensions.
foreach ($extDirectories as $extDir) {
$extPath = ROOT_PATH . '/' . $extDir;
if (is_dir($extPath) && is_readable($extPath) && $extDir[0] != '.' && !in_array($extDir, $dependencies) && $extDir != $extension && $extDir != 'generis') {
$this->outVerbose("Adding public messages from extension '${extDir}' in '${language}'...");
$poPath = $this->buildLanguagePath($extDir, $language) . '/' . self::DEF_PO_FILENAME;
if (!file_exists($poPath) || !is_readable($poPath)) {
$this->outVerbose("Extension '${extDir}' is not translated in language '${language}'. Trying to retrieve default language...");
$poPath = $this->buildLanguagePath($extDir, tao_helpers_translation_Utils::getDefaultLanguage()) . '/' . self::DEF_PO_FILENAME;
if (!file_exists($poPath) || !is_readable($poPath)) {
$this->outVerbose("Extension '${extDir}' in '${language}' does not exist.");
continue;
}
}
$poFileReader = new tao_helpers_translation_POFileReader($poPath);
$poFileReader->read();
$poFile = $poFileReader->getTranslationFile();
$poUnits = $poFile->getByFlag('tao-public');
$poCount = count($poUnits);
$compiledTranslationFile->addTranslationUnits($poUnits);
$this->outVerbose("${poCount} public messages added.");
}
}
// Finally, add the translation units related to the target extension.
$path = $this->buildLanguagePath($extension, $language) . '/' . self::DEF_PO_FILENAME;
if (file_exists($path) && is_readable($path)) {
$poFileReader = new tao_helpers_translation_POFileReader($path);
$poFileReader->read();
$poFile = $poFileReader->getTranslationFile();
$compiledTranslationFile->addTranslationUnits($poFile->getTranslationUnits());
// Sort the TranslationUnits.
$sortingMethod = tao_helpers_translation_TranslationFile::SORT_ASC_I;
$compiledTranslationFile->setTranslationUnits($compiledTranslationFile->sortBySource($sortingMethod));
$jsPath = $this->buildLanguagePath($extension, $language) . '/' . self::DEF_JS_FILENAME;
$jsFileWriter = new tao_helpers_translation_JSFileWriter($jsPath, $compiledTranslationFile);
$jsFileWriter->write();
$this->outVerbose("JavaScript compiled translations for extension '${extension}' with '${language}' written.");
} else {
$this->err("PO file '${path}' for extension '${extension}' with language '${language}' cannot be read.", true);
}
} else {
$this->err("Cannot list TAO Extensions from root path. Check your system rights.", true);
}
$this->outVerbose("Translations for '${extension}' with language '${language}' gracefully compiled.");
}
}
/**
* Checks the input for the 'compile' action.
*
* @access public
* @author Joel Bout, <joel.bout@tudor.lu>
* @return void
*/
private function checkCompileInput()
{
$defaults = ['extension' => null,
'language' => null,
'input' => dirname(__FILE__) . '/../../' . $this->options['extension'] . '/' . self::DEF_INPUT_DIR,
'output' => dirname(__FILE__) . '/../../' . $this->options['extension'] . '/' . self::DEF_OUTPUT_DIR];
$this->options = array_merge($defaults, $this->options);
if ($this->options['extension'] == null) {
$this->err("Please provide the 'extension' parameter.", true);
} elseif ($this->options['language'] == null) {
$this->err("Please provide the 'language' parameter.", true);
}
}
/**
* Implementation of the 'compileAll' action.
*
* @access public
* @author Joel Bout, <joel.bout@tudor.lu>
* @return void
*/
public function actionCompileAll()
{
// Get the list of languages that will be compiled.
$this->outVerbose("Compiling all languages for extension '" . $this->options['extension'] . "'...");
$rootDir = ROOT_PATH;
$extensionDir = $rootDir . '/' . $this->options['extension'];
$localesDir = $extensionDir . '/locales';
$locales = [];
$directories = scandir($localesDir);
if ($directories === false) {
$this->err("The locales directory of extension '" . $this->options['extension'] . "' cannot be read.", true);
} else {
foreach ($directories as $dir) {
if ($dir[0] !== '.') {
// It is a language directory.
$locales[] = $dir;
}
}
}
foreach ($locales as $l) {
$this->options['language'] = $l;
$this->checkCompileInput();
$this->actionCompile();
$this->outVerbose("");
}
}
/**
* Checks the input of the 'compileAll' action.
*
* @access public
* @author Joel Bout, <joel.bout@tudor.lu>
* @return void
*/
private function checkCompileAllInput()
{
$defaults = ['extension' => null,
'input' => dirname(__FILE__) . '/../../' . $this->options['extension'] . '/' . self::DEF_INPUT_DIR,
'output' => dirname(__FILE__) . '/../../' . $this->options['extension'] . '/' . self::DEF_OUTPUT_DIR];
$this->options = array_merge($defaults, $this->options);
if ($this->options['extension'] == null) {
$this->err("Please provide the 'extension' parameter.", true);
}
}
private function actionGetExt()
{
$rootDir = ROOT_PATH;
$extensions = [];
$extensionsList = '';
$language = $this->options['language'];
// create initial folders array
if ($dir = opendir($rootDir)) {
$j = 0;
while (($file = readdir($dir)) !== false) {
if ($file[0] !== '.' && $file != '.' && $file != '..' && is_dir($rootDir . $file)) {
$j++;
$directories[$j] = $file;
}
}
}
if ($directories === false) {
$this->err("The locales directory of extension '" . $this->options['extension'] . "' cannot be read.", true);
} else {
foreach ($directories as $dir) {
// folder where these .po files should be
$extensionLocalesDir = $dir . '/' . self::DEF_OUTPUT_DIR . '/' . $language;
$poFile = $rootDir . $extensionLocalesDir . '/' . self::DEF_PO_FILENAME;
// check .po file existency
if (file_exists($poFile) && is_readable($poFile)) {
$extensions[] = $dir;
$extensionsList .= (!$extensionsList ? "" : ",") . $dir;
}
}
sort($extensions);
print_r($extensions);
echo ( count($extensions) . ' extensions with translations: ' . $extensionsList . "\n");
}
}
/**
* @param $f
* @param $translatableProperties
* @return tao_helpers_translation_POFile
* @throws tao_helpers_translation_TranslationException
*/
protected function extractPoFileFromRDF($f, $translatableProperties)
{
$modelExtractor = new tao_helpers_translation_POExtractor([$f]);
$modelExtractor->setTranslatableProperties($translatableProperties);
$modelExtractor->extract();
$translationFile = new tao_helpers_translation_POFile();
$translationFile->setSourceLanguage(tao_helpers_translation_Utils::getDefaultLanguage());
$translationFile->setTargetLanguage($this->options['language']);
$translationFile->addTranslationUnits($modelExtractor->getTranslationUnits());
$translationFile->setExtensionId($this->options['extension']);
$this->preparePOFile($translationFile);
return $translationFile;
}
protected function checkInputOption()
{
if (!is_null($this->options['input'])) {
if (!is_dir($this->options['input'])) {
$this->err("The 'input' parameter you provided is not a directory.", true);
} else {
if (!is_readable($this->options['input'])) {
$this->err("The 'input' directory is not readable.", true);
}
}
}
}
protected function checkOutputOption()
{
if (!is_null($this->options['output'])) {
if (!is_dir($this->options['output'])) {
$this->err("The 'output' parameter you provided is not a directory.", true);
} else {
if (!is_writable($this->options['output'])) {
$this->err("The 'output' directory is not writable.", true);
}
}
}
}
/**
* @return array
* @throws Exception
*/
protected function getLanguageList()
{
$rootDir = dirname(__FILE__) . '/../..';
$extensionDir = $rootDir . '/' . $this->options['extension'];
$localesDir = $extensionDir . '/locales';
$locales = [];
$directories = scandir($localesDir);
if ($directories === false) {
$this->err("The locales directory of extension '" . $this->options['extension'] . "' cannot be read.", true);
return $locales;
} else {
foreach ($directories as $dir) {
if ($dir[0] !== '.') {
// It is a language directory.
$locales[] = $dir;
}
}
return $locales;
}
}
/**
*
* @param $f filename
* @return string
*/
protected function getOntologyPOFileName($f)
{
return basename($f) . '.po';
}
}