Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
9 / 9
CRAP
100.00% covered (success)
100.00%
67 / 67
Translate\Service\TranslationSaver
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
9 / 9
30
100.00% covered (success)
100.00%
67 / 67
 __construct
100.00% covered (success)
100.00%
1 / 1
4
100.00% covered (success)
100.00%
4 / 4
 rationaliseFilePattern
100.00% covered (success)
100.00%
1 / 1
3
100.00% covered (success)
100.00%
4 / 4
 setTranslationManager
100.00% covered (success)
100.00%
1 / 1
3
100.00% covered (success)
100.00%
5 / 5
 getPoFileLocation
100.00% covered (success)
100.00%
1 / 1
5
100.00% covered (success)
100.00%
10 / 10
 createNewPoFile
100.00% covered (success)
100.00%
1 / 1
3
100.00% covered (success)
100.00%
19 / 19
 getTranslator
100.00% covered (success)
100.00%
1 / 1
5
100.00% covered (success)
100.00%
9 / 9
 saveMissingTranslation
100.00% covered (success)
100.00%
1 / 1
5
100.00% covered (success)
100.00%
11 / 11
 updateMoFile
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
3 / 3
 messageAlreadyExists
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
2 / 2
<?php
/**
 * Class TranslationSaver
 *
 * @package     Translate\Service
 * @author      Nigel Hurnell
 * @version     v 1.0.0
 * @license     BSD
 * @copyright   Copyright (c) 2017, Nigel Hurnell
 */
namespace Translate\Service;
use Gettext\Translations;
use Translate\Service\TranslationManager;
/**
 * Class that is responsible for saving translated messages.
 *
 * @package     Translate\Service
 * @author      Nigel Hurnell
 * @version     v 1.0.0
 * @license     BSD
 * @copyright   Copyright (c) 2017, Nigel Hurnell
 */
class TranslationSaver implements TranslationSaverInterface
{
    /**
     * Array of PO/MO file directories
     * 
     * @var array 
     */
    protected $directories = [];
    /**
     * Present text domain key = controller alias
     * 
     * @var string
     */
    protected $textDomainKey;
    /**
     * The Translation Manager
     * 
     * @var TranslationManager 
     */
    protected $translationManager;
    /**
     * 
     * 
     * @var array of Gettext\Translations
     */
    protected $translators = [];
    /**
     * Flag to show whether translation file exists
     * 
     * @var boolean
     */
    protected $translationFileExists = false;
    /**
     * Present PO location file
     * 
     * @var string the location of (present) PO file
     */
    protected $poFile;
    /**
     * 
     * 
     * @var string the location of (present) MO file
     */
    protected $moFile;
    /**
     * Instantiate TranslationSaver object injecting file patters  
     * 
     * @param array $filePatterns
     */
    public function __construct($filePatterns)
    {
        foreach ($filePatterns as $pattern) {
            if (array_key_exists('base_dir', $pattern) && array_key_exists('controllers', $pattern)) {
                $this->rationaliseFilePattern($pattern);
            }
        }
    }
    /**
     * Transform controller patterns into location array
     * Controller alias as key and directory as value
     * 
     * @param array $pattern
     */
    private function rationaliseFilePattern($pattern)
    {
        foreach ($pattern['controllers'] as $controller) {
            if (!array_key_exists($controller, $this->directories)) {
                $this->directories[$controller] = $pattern['base_dir'];
            }
        }
    }
    /**
     * Set the translation manager 
     * 
     * @param TranslationManager $translationManager
     * @throws \Exception if global 
     */
    public function setTranslationManager(TranslationManager $translationManager)
    {
        if (!array_key_exists('global', $this->directories) || false == realpath($this->directories['global'])) {
            throw new \Exception('You must specify a global (controllers array) translation save path  (usually in global.php');
        }
        $this->translationManager = $translationManager;
        $this->translationManager->setDirectories($this->directories);
    }
    /**
     * Get file location of PO file for specific text domain (controller alias) and locale
     * 
     * @param string $textDomainKey
     * @param string $locale
     * @return string
     */
    public function getPoFileLocation($textDomainKey, $locale)
    {
        $folder = $this->directories['global'];
        $this->poFile = realpath($folder) . '/' . $locale . '.po';
        if (array_key_exists($textDomainKey, $this->directories) && file_exists($this->directories[$textDomainKey])) {
            $folder = $this->directories[$textDomainKey];
            $this->poFile = realpath($folder) . '/' . $locale . '.po';
        }
        if (realpath($folder) && !file_exists($this->poFile)) {
            $this->createNewPoFile($this->poFile, $locale);
        }
        $this->moFile = realpath($folder) . '/' . $locale . '.mo';
        $this->translationFileExists = file_exists($this->poFile);
        return $this->poFile;
    }
    /**
     * Create PO file when missing
     * 
     * @param string $location
     * @param string $locale
     */
    public function createNewPoFile($location, $locale)
    {
        $allLocales = $this->translationManager->getAllLocales();
        if (in_array($locale, $allLocales) && $this->translationManager->checkLocaleIsEnabled($locale)) {
            $cleanLocation = str_replace(['\\', '/'], DIRECTORY_SEPARATOR, $location);
            $date = new \DateTime();
            $locale = $this->translationManager->getLocale();
            $text = 'msgid ""' . "\n" . 'msgstr ""' . "\n";
            $text .= '"Project-Id-Version: Hurnell User Demo"' . "\n";
            $text .= '"Report-Msgid-Bugs-To: "' . "\n";
            $text .= '"POT-Creation-Date: "' . $date->getTimestamp() . '"' . "\n";
            $text .= '"Last-Translator: "' . "\n";
            $text .= '"Language: ' . $locale . "\n";
            $text .= '"MIME-Version: 1.0"' . "\n";
            $text .= '"Content-Type: text/plain; charset=UTF-8"' . "\n";
            $text .= '"Content-Transfer-Encoding: 8bit"' . "\n";
            $text .= '"X-Poedit-KeywordsList: translate"' . "\n";
            $text .= '"X-Poedit-Basepath: ."' . "\n";
            $text .= '"X-Poedit-SearchPath-0: .."' . "\n";
            file_put_contents($cleanLocation, $text);
        }
    }
    /**
     * Get the Gettext\Translations object
     * 
     * @param string $textDomainKey
     * @param string $locale
     * @return Gettext\Translations|false
     */
    public function getTranslator($textDomainKey, $locale)
    {
        $poFileLocation = $this->getPoFileLocation($textDomainKey, $locale);
        if ($textDomainKey != $this->textDomainKey && $this->translationFileExists) {
            if (!array_key_exists($textDomainKey, $this->translators)) {
                $this->translators[$textDomainKey] = Translations::fromPoFile($poFileLocation);
            }
            $this->textDomainKey = $textDomainKey;
        }
        $result = false;
        if (array_key_exists($this->textDomainKey, $this->translators)) {
            $result = $this->translators[$this->textDomainKey];
        }
        return $result;
    }
    /**
     * Save translation for particular message if missing
     * @param string $message
     * @param string $locale
     * @param string $translation
     */
    public function saveMissingTranslation($message, $locale, $translation)
    {
        $textDomainKey = $this->translationManager->getTextDomain();
        $translator = $this->getTranslator($textDomainKey, $locale);
        if ($this->translationFileExists && $translator && !$this->messageAlreadyExists($message, $translator)) {
            $translation = ' ';
            if ('en_GB' == $locale) {
                $translation = $message;
            }
            $insertedTranslation = $translator->insert('', $message);
            $insertedTranslation->addReference('URI: ' . $this->translationManager->getUrl());
            $insertedTranslation->setTranslation($translation);
            $this->updateMoFile($translator);
        }
    }
    /**
     * Update MO file based on corresponding PO file
     * 
     * @param Translations $translator
     */
    protected function updateMoFile($translator)
    {
        $translator->toPoFile($this->poFile);
        $translator->toMoFile($this->moFile);
    }
    /**
     * Check whether message already exists in translator
     * 
     * @param string $message
     * @param Translations $translator
     * @return boolean whether message already exists in the translator
     */
    public function messageAlreadyExists($message, $translator)
    {
        $exists = $translation = $translator->find(null, $message) !== false;
        return $exists;
    }
}