qcubed/framework

View on GitHub
includes/framework/QTranslationPoParser.class.php

Summary

Maintainability
F
5 days
Test Coverage
<?php

class QPoParserException extends QCallerException {}

class QTranslationPoParser implements QTranslationBase {
    public static function Initialize() {
        return self::Load(QApplication::$LanguageCode, QApplication::$CountryCode);
    }

    public static function Load($strLanguageCode = null, $strCountryCode = null) {
        $objLanguageObject = null;
        if ($strLanguageCode) {
            if ($strCountryCode) {
                $strCode = sprintf('%s_%s', $strLanguageCode, $strCountryCode);
                $strLanguageFiles = array(
                __QCUBED_CORE__ . '/i18n/' . $strLanguageCode . '.po',
                __QCUBED_CORE__ . '/i18n/' . $strCode . '.po',
                __QI18N_PO_PATH__ . '/' . $strLanguageCode . '.po',
                __QI18N_PO_PATH__ . '/' . $strCode . '.po'
                );
            } else {
                $strCode = $strLanguageCode;
                $strLanguageFiles = array(
                __QCUBED_CORE__ . '/i18n/' . $strLanguageCode . '.po',
                __QI18N_PO_PATH__ . '/' . $strLanguageCode . '.po'
                );
            }

            // Setup the LanguageFileObject cache mechanism
            $objCache = new QCache('i18n.po', $strCode, 'i18n', $strLanguageFiles);

            // If cached data exists and is valid, use it
            $strData = $objCache->GetData();
            if ($strData) {
                $objLanguageObject = unserialize($strData);

                // Otherwise, reload all langauge files and update the cache
            } else {
                $objLanguage = new QTranslationPoParser();
                    
                foreach ($strLanguageFiles as $strLanguageFile) {
                    if (file_exists($strLanguageFile)) {
                        try {
                            //print($strLanguageFile.'<BR>');
                            $objLanguage->ParsePoData(file_get_contents($strLanguageFile));
                        } catch (QPoParserException $objExc) {
                            $objExc->setMessage('Invalid Language File: ' . $strLanguageFile . ': ' . $objExc->getMessage());
                            $objExc->IncrementOffset();
                            throw $objExc;
                        }
                    }
                }
                $objLanguageObject = $objLanguage;
                $objCache->SaveData(serialize($objLanguage));
            }
        }
        return $objLanguageObject;

    }

    const PoParseStateNone = 0;
    const PoParseStateMessageIdStart = 1;
    const PoParseStateMessageId = 2;
    const PoParseStateMessageStringStart = 3;
    const PoParseStateMessageString = 4;

    protected static function UnescapeContent($strContent) {
        $intLength = strlen($strContent);
        $strToReturn = '';
        $blnEscape = false;

        for ($intIndex = 0; $intIndex < $intLength; $intIndex++) {
            if ($blnEscape) {
                switch ($strContent[$intIndex]) {
                    case 'n':
                        $blnEscape = false;
                        $strToReturn .= "\n";
                        break;
                    case 'r':
                        $blnEscape = false;
                        $strToReturn .= "\r";
                        break;
                    case 't':
                        $blnEscape = false;
                        $strToReturn .= "    ";
                        break;
                    case '\\':
                        $blnEscape = false;
                        $strToReturn .= '\\';
                        break;
                    case '"':
                        $blnEscape = false;
                        $strToReturn .= '"';
                        break;
                    case "'":
                        $blnEscape = false;
                        $strToReturn .= "'";
                        break;
                    default:
                        $blnEscape = false;
                        $strToReturn .= '\\' . $strContent[$intIndex];
                        break;
                }
            } else {
                if ($strContent[$intIndex] == '\\')
                $blnEscape = true;
                else
                $strToReturn .= $strContent[$intIndex];
            }
        }

        if ($blnEscape)
        return false;

        $strToReturn = str_replace("\r", '', $strToReturn);
        return $strToReturn;
    }

    protected function ParsePoData($strPoData) {
        $strPoData = str_replace("\r", '', trim($strPoData));
        $strPoLines = explode("\n", $strPoData);

        $strMatches = array();

        $intState = QTranslationPoParser::PoParseStateNone;
        $intLineCount = count($strPoLines);

        if (strlen($strPoLines[0]) == 0)
        return;

        for ($intLineNumber = 0; $intLineNumber < $intLineCount; $intLineNumber++) {
            $strPoLine = $strPoLines[$intLineNumber] = trim($strPoLines[$intLineNumber]);

            if (strlen($strPoLine) && (QString::FirstCharacter($strPoLine) != '#')) {
                switch ($intState) {
                    case QTranslationPoParser::PoParseStateNone:
                        $intCount = preg_match_all('/msgid(_[a-z0-9]+)?[\s]+"([\S     ]*)"/i', $strPoLine, $strMatches);
                        if ($intCount && ($strMatches[0][0] == $strPoLine)) {
                            $intLineNumber--;
                            $intState = QTranslationPoParser::PoParseStateMessageIdStart;
                        } else
                        throw new QPoParserException('Invalid content for PoParseStateNone on Line ' . ($intLineNumber + 1) . ': ' . $strPoLine);
                        break;

                    case QTranslationPoParser::PoParseStateMessageIdStart:
                        $intCount = preg_match_all('/msgid(_[a-z0-9]+)?[\s]+"([\S     ]*)"/i', $strPoLine, $strMatches);
                        if ($intCount && ($strMatches[0][0] == $strPoLine)) {
                            $strMessageId = array('', '', '', '', '', '', '');
                            $strMessageString = array('', '', '', '', '', '', '');
                            $intArrayIndex = 0;

                            $strContent = QTranslationPoParser::UnescapeContent($strMatches[2][0]);
                            if ($strContent === false)
                            throw new QPoParserException('Invalid content on Line ' . ($intLineNumber + 1));
                            $strMessageId[$intArrayIndex] = $strContent;
                            $intState = QTranslationPoParser::PoParseStateMessageId;
                        } else
                        throw new QPoParserException('Invalid content for PoParseStateMessageIdStart on Line ' . ($intLineNumber + 1) . ': ' . $strPoLine);
                        break;

                    case QTranslationPoParser::PoParseStateMessageId:
                        $intCount = preg_match_all('/msgid(_[a-z0-9]+)[\s]+"([\S     ]*)"/i', $strPoLine, $strMatches);
                        if ($intCount && ($strMatches[0][0] == $strPoLine)) {
                            if (strlen(trim($strMessageId[$intArrayIndex])) == 0)
                            throw new QPoParserException('No MsgId content for current MsgId on Line ' . ($intLineNumber) . ': ' . $strPoLine);
                            $intArrayIndex++;
                            $strContent = QTranslationPoParser::UnescapeContent($strMatches[2][0]);
                            if ($strContent === false)
                            throw new QPoParserException('Invalid content on Line ' . ($intLineNumber + 1));
                            $strMessageId[$intArrayIndex] = $strContent;
                            break;
                        }

                        $intCount = preg_match_all('/"([\S     ]*)"/', $strPoLine, $strMatches);
                        if ($intCount && ($strMatches[0][0] == $strPoLine)) {
                            $strContent = QTranslationPoParser::UnescapeContent($strMatches[1][0]);
                            if ($strContent === false)
                            throw new QPoParserException('Invalid content on Line ' . ($intLineNumber + 1));
                            $strMessageId[$intArrayIndex] .= $strContent;
                            break;
                        }

                        $intCount = preg_match_all('/msgstr(\[[0-9]+\])?[\s]+"([\S     ]*)"/i', $strPoLine, $strMatches);
                        if ($intCount && ($strMatches[0][0] == $strPoLine)) {
                            if (strlen(trim($strMessageId[$intArrayIndex])) == 0)
                            throw new QPoParserException('No MsgId content for current MsgId on Line ' . ($intLineNumber) . ': ' . $strPoLine);
                            $intLineNumber--;
                            $intState = QTranslationPoParser::PoParseStateMessageStringStart;
                            break;
                        }

                        throw new QPoParserException('Invalid content for PoParseStateMessageId on Line ' . ($intLineNumber + 1) . ': ' . $strPoLine);

                    case QTranslationPoParser::PoParseStateMessageStringStart:
                        $intCount = preg_match_all('/msgstr(\[[0-9]+\])?[\s]+"([\S     ]*)"/i', $strPoLine, $strMatches);
                        if ($intCount && ($strMatches[0][0] == $strPoLine)) {
                            $intArrayIndex = 0;

                            if (strlen($strMatches[1][0]))
                            $intArrayIndex = intval(substr($strMatches[1][0], 1, strlen($strMatches[1][0]) - 2));

                            $strContent = QTranslationPoParser::UnescapeContent($strMatches[2][0]);
                            if ($strContent === false)
                            throw new QPoParserException('Invalid content on Line ' . ($intLineNumber + 1));
                            $strMessageString[$intArrayIndex] = $strContent;
                            $intState = QTranslationPoParser::PoParseStateMessageString;
                        } else
                        throw new QPoParserException('Invalid content for PoParseStateMessageStringStart on Line ' . ($intLineNumber + 1) . ': ' . $strPoLine);
                        break;


                    case QTranslationPoParser::PoParseStateMessageString:
                        $intCount = preg_match_all('/msgid(_[a-z0-9]+)?[\s]+"([\S     ]*)"/i', $strPoLine, $strMatches);
                        if ($intCount && ($strMatches[0][0] == $strPoLine)) {
                            for ($intIndex = 0; $intIndex < count($strMessageId); $intIndex++)
                            if (strlen(trim($strMessageId[$intIndex]))) {
                                if (!strlen(trim($strMessageString[$intIndex]))) {
                                    $this->SetTranslation($strMessageId[$intIndex], "");
                                }
                                $this->SetTranslation($strMessageId[$intIndex], $strMessageString[$intIndex]);
                            }

                            $intLineNumber--;
                            $intState = QTranslationPoParser::PoParseStateMessageIdStart;
                            break;
                        }

                        $intCount = preg_match_all('/"([\S     ]*)"/', $strPoLine, $strMatches);
                        if ($intCount && ($strMatches[0][0] == $strPoLine)) {
                            $strContent = QTranslationPoParser::UnescapeContent($strMatches[1][0]);
                            if ($strContent === false)
                            throw new QPoParserException('Invalid content on Line ' . ($intLineNumber + 1));
                            $strMessageString[$intArrayIndex] .= $strContent;
                            break;
                        }

                        $intCount = preg_match_all('/msgstr(\[[0-9]+\])?[\s]+"([\S     ]*)"/i', $strPoLine, $strMatches);
                        if ($intCount && ($strMatches[0][0] == $strPoLine)) {

                            if (strlen($strMatches[1][0]))
                            $intArrayIndex = intval(substr($strMatches[1][0], 1, strlen($strMatches[1][0]) - 2));
                            else
                            throw new QPoParserException('No index specified for alternate MsgStr for PoParseStateMessageString on Line ' . ($intLineNumber + 1) . ': ' . $strPoLine);

                            if (strlen(trim($strMessageId[$intArrayIndex])) == 0)
                            throw new QPoParserException('No MsgId for MsgStr' . $strMatches[1][0] . ' for PoParseStateMessageString on Line ' . ($intLineNumber + 1) . ': ' . $strPoLine);

                            $strContent = QTranslationPoParser::UnescapeContent($strMatches[2][0]);
                            if ($strContent === false)
                            throw new QPoParserException('Invalid content on Line ' . ($intLineNumber + 1));
                            $strMessageString[$intArrayIndex] = $strContent;
                            break;
                        }

                        throw new QPoParserException('Invalid content for PoParseStateMessageString on Line ' . ($intLineNumber + 1) . ': ' . $strPoLine);

                    default:
                        throw new QPoParserException('Invalid PoParseState on Line ' . ($intLineNumber + 1) . ': ' . $strPoLine);
                }
            }
        }

        for ($intIndex = 0; $intIndex < count($strMessageId); $intIndex++) {
            if (strlen(trim($strMessageId[$intIndex]))) {
                if (!strlen(trim($strMessageString[$intIndex]))) {
                    $this->SetTranslation($strMessageId[$intIndex], "");
                }
                $this->SetTranslation($strMessageId[$intIndex], $strMessageString[$intIndex]);
            }
        }
    }

    protected $strTranslationArray = array();

    protected function SetTranslation($strToken, $strTranslatedText) {
        $this->strTranslationArray[$strToken] = $strTranslatedText;
    }

    public function TranslateToken($strToken) {
        $strCleanToken = str_replace("\r", '', $strToken);
        if (array_key_exists($strCleanToken, $this->strTranslationArray)) {
            return $this->strTranslationArray[$strCleanToken];
        } else {
            return $strToken;
        }
    }

    public function VarDump() {
        $strToReturn = '';
        foreach ($this->strTranslationArray as $strKey=>$strValue) {
            $strKey = str_replace("\n", '\\n', addslashes(QApplication::HtmlEntities($strKey)));
            $strValue = str_replace("\n", '\\n', addslashes(QApplication::HtmlEntities($strValue)));
            $strToReturn .= sprintf("\"%s\"\n\"%s\"\n\n", $strKey, $strValue);
        }
        return $strToReturn;
    }
}