Вход Регистрация
Файл: library/XenForo/Model/Language.php
Строк: 761
<?php

class XenForo_Model_Language extends XenForo_Model
{
    public function 
getLanguageById($id, $fetchMaster = false)
    {
        if (
strval($id) === '0')
        {
            if (
$fetchMaster)
            {
                return array(
                    
'language_id' => 0,
                    
'title' => new XenForo_Phrase('master_language'),
                    
'parent_id' => 0
                
);
            }
            else
            {
                return 
false;
            }
        }

        
$localCacheKey = 'language_' . $id;
        if ((
$data = $this->_getLocalCacheData($localCacheKey)) === false)
        {
            
$data = $this->_getDb()->fetchRow('
                SELECT *
                FROM xf_language
                WHERE language_id = ?
            '
, $id);

            
$this->setLocalCacheData($localCacheKey, $data);
        }

        return 
$data;
    }

    public function 
getAllLanguages()
    {
        if ((
$languages = $this->_getLocalCacheData('allLanguages')) === false)
        {
            
$languages = $this->fetchAllKeyed('
                SELECT *
                FROM xf_language
                ORDER BY title
            '
, 'language_id');

            
$this->setLocalCacheData('allLanguages', $languages);
        }

        return 
$languages;
    }

    
/**
     * Return results for admin quick search
     *
     * @param string Keywords for which to search
     *
     * @return array
     */
    
public function getLanguagesForAdminQuickSearch($searchText)
    {
        return 
$this->fetchAllKeyed('
            SELECT *
            FROM xf_language
            WHERE title LIKE ' 
. XenForo_Db::quoteLike($searchText, 'lr', $this->_getDb()) . '
            ORDER BY title
        '
, 'language_id');
    }

    
/**
     * Gets the parent => language associations from a flat list of language info.
     *
     * @param array $languageList
     *
     * @return array [parent id][] => language id
     */
    
public function getLanguageTreeAssociations(array $languageList)
    {
        
$parents = array();
        foreach (
$languageList AS $language)
        {
            
$parents[$language['parent_id']][] = $language['language_id'];
        }

        return 
$parents;
    }

    
/**
     * Gets a list of child language IDs that are direct children of the specified language.
     *
     * @param integer $languageId
     *
     * @return array Array of language IDs
     */
    
public function getDirectChildLanguageIds($languageId)
    {
        
$languages = $this->getAllLanguages();
        
$languageTree = $this->getLanguageTreeAssociations($languages);

        if (isset(
$languageTree[$languageId]))
        {
            return 
$languageTree[$languageId];
        }
        else
        {
            return array();
        }
    }

    
/**
     * Gets all children of a language ID, no matter how many levels below.
     *
     * @param integer $languageId
     *
     * @return array Array of language IDs
     */
    
public function getAllChildLanguageIds($languageId)
    {
        
$languages = $this->getAllLanguages();
        
$languageTree = $this->getLanguageTreeAssociations($languages);

        if (isset(
$languageTree[$languageId]))
        {
            return 
$this->_getAllChildLanguageIds($languageId, $languageTree);
        }
        else
        {
            return array();
        }
    }

    
/**
     * Internal handler to get call child language IDs.
     *
     * @param integer $parentId Parent language ID
     * @param array $languageTree Tree of languages ([parent id][] => language id)
     *
     * @return array
     */
    
protected function _getAllChildLanguageIds($parentId, array $languageTree)
    {
        if (!isset(
$languageTree[$parentId]))
        {
            return array();
        }

        
$children = array();
        foreach (
$languageTree[$parentId] AS $childId)
        {
            
$children[] = $childId;
            
$children = array_merge($children, $this->_getAllChildLanguageIds($childId, $languageTree));
        }

        return 
$children;
    }

    
/**
     * Gets a list of languages in the form of a flattened tree. The return
     * is an array containing all languages and their related info. Each language
     * additionally includes a "depth" element that repesents the depth from
     * the (implicit) master. Children of the master have a depth 0, unless
     * $baseDepth is overridden.
     *
     * @param integer $baseDepth Starting depth value.
     *
     * @return array Format: [language id] => (array) language info, including depth
     */
    
public function getAllLanguagesAsFlattenedTree($baseDepth = 0)
    {
        
$languages = $this->getAllLanguages();
        
$tree = $this->getLanguageTreeAssociations($languages);

        return 
$this->_buildFlattenedLanguageTree($languages, $tree, 0, $baseDepth);
    }

    
/**
     * Returns an array of all languages, suitable for use in ACP template syntax as options source.
     *
     * @param array $languageTree
     *
     * @return array
     */
    
public function getLanguagesForOptionsTag($selectedId = null, $languageTree = null)
    {
        if (
$languageTree === null)
        {
            
$languageTree = $this->getAllLanguagesAsFlattenedTree();
        }

        
$languages = array();
        foreach (
$languageTree AS $id => $language)
        {
            
$languages[$id] = array(
                
'value' => $id,
                
'label' => $language['title'],
                
'selected' => ($selectedId == $id),
                
'depth' => $language['depth']
            );
        }

        return 
$languages;
    }

    
/**
     * Builds the flattened tree recursively, incrementing the depth each time.
     *
     * @param array $languageList List of languages and their information
     * @param array $tree Tree structure of languages ([parent id][] => language id)
     * @param integer $root Where to start in the tree
     * @param integer $depth Current/starting depth
     *
     * @return array List of languages with additional depth key
     */
    
protected function _buildFlattenedLanguageTree(array $languageList, array $tree, $root = 0, $depth = 0)
    {
        if (!isset(
$tree[$root]) || !is_array($tree[$root]))
        {
            return array();
        }

        
$output = array();

        foreach (
$tree[$root] AS $languageId)
        {
            
$output[$languageId] = $languageList[$languageId];
            
$output[$languageId]['depth'] = $depth;

            
$output += $this->_buildFlattenedLanguageTree($languageList, $tree, $languageId, $depth + 1);
        }

        return 
$output;
    }

    
/**
     * Gets the base parent list for a language. This list starts with the *parent* of the given language ID, then
     * works up the tree, eventually ending with 0.
     *
     * @param integer $languageId
     *
     * @return array List of parent language IDs (including 0)
     */
    
public function getLanguageBaseParentList($languageId)
    {
        
$languages = $this->getAllLanguages();

        
$parents = array();
        while (isset(
$languages[$languageId]) && $language = $languages[$languageId])
        {
            
$parents[] = $language['parent_id'];
            
$languageId = $language['parent_id'];
        }

        return 
$parents;
    }

    
/**
     * Recursively rebuilds the parent list in part of the language tree.
     *
     * @param integer $languageId First language to start with. All child will be rebuild.
     */
    
public function rebuildLanguageParentListRecursive($languageId)
    {
        
$languages = $this->getAllLanguages();

        if (isset(
$languages[$languageId]))
        {
            
$languageTree = $this->getLanguageTreeAssociations($languages);

            
$baseParentList = $this->getLanguageBaseParentList($languageId);
            
$this->_rebuildLanguageParentListRecursive($languageId, $baseParentList, $languages, $languageTree);
        }
    }

    
/**
     * Internal function to rebuild the language parent list recursively.
     *
     * @param integer $languageId Base lanaguage Id
     * @param array $baseParentList Base parent list for the language. Should not include this language ID in it.
     * @param array $languages List of languages
     * @param array $languageTree Language tree
     */
    
protected function _rebuildLanguageParentListRecursive($languageId, array $baseParentList, array $languages, array $languageTree)
    {
        if (isset(
$languages[$languageId]))
        {
            
$parentList = $baseParentList;
            
array_unshift($parentList, $languageId);

            
$db = $this->_getDb();
            
$db->update(
                
'xf_language',
                array(
'parent_list' => implode(',', $parentList)),
                
'language_id = ' . $db->quote($languageId)
            );

            if (isset(
$languageTree[$languageId]))
            {
                foreach (
$languageTree[$languageId] AS $childLanguageId)
                {
                    
$this->_rebuildLanguageParentListRecursive($childLanguageId, $parentList, $languages, $languageTree);
                }
            }
        }
    }

    
/**
     * Rebuilds the global phrase cache for all languages.
     *
     * @param array|null $globalPhraseTitles List of phrases that should be included. If null, uses flag from phrase table.
     */
    
public function rebuildLanguageGlobalPhraseCache(array $globalPhraseTitles = null)
    {
        
$phraseModel = $this->_getPhraseModel();

        if (
$globalPhraseTitles === null)
        {
            
$globalPhraseTitles = $phraseModel->getGlobalPhraseCacheTitles();
        }

        
$db = $this->_getDb();

        
$languages = $this->getAllLanguages();
        
$globalPhrases = $phraseModel->getEffectivePhraseValuesInAllLanguages($globalPhraseTitles);

        foreach (
$languages AS $languageId => $language)
        {
            if (isset(
$globalPhrases[$languageId]))
            {
                
$phrases = $globalPhrases[$languageId];
            }
            else
            {
                
$phrases = array();
            }

            
$db->update('xf_language',
                array(
'phrase_cache' => serialize($phrases)),
                
'language_id = ' . $db->quote($languageId)
            );
        }
    }

    
/**
    * Helper to determine whether the master language should be shown in lists.
    *
    * @return boolean
    */
    
public function showMasterLanguage()
    {
        return 
XenForo_Application::debugMode();
    }

    
/**
    * Helper to get the default language
    *
    * @return array
    */
    
public function getDefaultLanguage()
    {
        return array(
            
'language_id' => 0,
            
'parent_id' => 0,
            
'parent_list' => '',
            
'title' => '',
            
'date_format' => 'M j, Y',
            
'time_format' => 'g:i A',
            
'decimal_point' => '.',
            
'thousands_separator' => ',',
            
'text_direction' => 'LTR',
            
'language_code' => 'en-US'
        
);
    }

    
/**
     * Gets all languages in the format expected by the language cache.
     *
     * @return array Format: [language id] => info, with phrase cache as array
     */
    
public function getAllLanguagesForCache()
    {
        
$this->resetLocalCacheData('allLanguages');

        
$languages = $this->getAllLanguages();
        foreach (
$languages AS &$language)
        {
            
$language['phrase_cache'] = unserialize($language['phrase_cache']);
        }

        return 
$languages;
    }

    
/**
     * Rebuilds the full language cache.
     *
     * @return array Format: [language id] => info, with phrase cache as array
     */
    
public function rebuildLanguageCache()
    {
        
$this->resetLocalCacheData('allLanguages');

        
$languages = $this->getAllLanguagesForCache();

        
$this->_getDataRegistryModel()->set('languages', $languages);

        return 
$languages;
    }

    
/**
     * Rebuilds all language caches (including global phrase cache).
     */
    
public function rebuildLanguageCaches()
    {
        
$this->rebuildLanguageGlobalPhraseCache();
        
$this->rebuildLanguageCache();
    }

    
/**
     * Generates the date and time format examples based on the
     * current time.
     *
     * @return array [0] => date formats, [1] => time formats; keyed by format string
     */
    
public function getLanguageFormatExamples()
    {
        
$dateFormatsRaw = array(
            
'M j, Y',
            
'F j, Y',
            
'j M Y',
            
'j F Y',
            
'j/n/y',
            
'n/j/y'
        
);

        
$dateFormats = array();
        foreach (
$dateFormatsRaw AS $dateFormat)
        {
            
$dateFormats[$dateFormat] = XenForo_Locale::getFormattedDate(XenForo_Application::$time, $dateFormat);
        }

        
$timeFormatsRaw = array(
            
'g:i A',
            
'H:i'
        
);

        
$timeFormats = array();
        foreach (
$timeFormatsRaw AS $timeFormat)
        {
            
$timeFormats[$timeFormat] = XenForo_Locale::getFormattedDate(XenForo_Application::$time, $timeFormat);
        }

        return array(
$dateFormats, $timeFormats);
    }

    
/**
     * Returns the total number of phrases in the master language
     *
     * @return integer
     */
    
public function countMasterPhrases()
    {
        return 
$this->_getDb()->fetchOne('SELECT COUNT(*) FROM xf_phrase WHERE language_id = 0');
    }

    
/**
     * Counts the number of translated phrases in each non-master language
     *
     * @param array $languages Array of languages
     *
     * @return array The $languages array including a phraseCount key
     */
    
public function countTranslatedPhrasesPerLanguage(array $languages = array())
    {
        
$totals = $this->_getDb()->fetchPairs('
            SELECT language_id, COUNT(*) AS phraseCount
            FROM xf_phrase
            WHERE language_id <> 0
            GROUP BY language_id
        '
);

        foreach (
$totals AS $languageId => $phraseCount)
        {
            if (isset(
$languages[$languageId]))
            {
                
$languages[$languageId]['phraseCount'] = $phraseCount;
            }
        }

        return 
$languages;
    }

    
/**
     * Gets the DOM document that represents a language file.
     * This must be turned into XML (or HTML) by the caller.
     *
     * @param array $language
     * @param string|null $limitAddOnId If specified, only exports phrases from the specified add-on
     * @param boolean $getUntranslated If true, gets untranslated phrases in this language
     *
     * @return DOMDocument
     */
    
public function getLanguageXml(array $language, $limitAddOnId = null, $getUntranslated = false)
    {
        
$document = new DOMDocument('1.0', 'utf-8');
        
$document->formatOutput = true;

        
$rootNode = $document->createElement('language');
        
$rootNode->setAttribute('title', $language['title']);
        
$rootNode->setAttribute('date_format', $language['date_format']);
        
$rootNode->setAttribute('time_format', $language['time_format']);
        
$rootNode->setAttribute('decimal_point', $language['decimal_point']);
        
$rootNode->setAttribute('thousands_separator', $language['thousands_separator']);
        
$rootNode->setAttribute('language_code', $language['language_code']);
        
$rootNode->setAttribute('text_direction', $language['text_direction']);
        if (
$limitAddOnId !== null)
        {
            
$rootNode->setAttribute('addon_id', $limitAddOnId);
        }
        
$document->appendChild($rootNode);

        
$db = $this->_getDb();

        if (
$getUntranslated)
        {
            
$phrases = $db->fetchAll('
                SELECT phrase.*,
                    IF(master.phrase_id, master.addon_id, phrase.addon_id) AS addon_id
                FROM xf_phrase_map AS map
                INNER JOIN xf_phrase AS phrase ON (map.phrase_id = phrase.phrase_id)
                LEFT JOIN xf_phrase AS master ON (master.title = phrase.title AND master.language_id = 0)
                WHERE map.language_id = ?
                    AND ' 
. ($limitAddOnId === null ? '1=1' : 'master.addon_id = ' . $db->quote($limitAddOnId)) . '
                ORDER BY map.title
            '
, $language['language_id']);
        }
        else
        {
            
$phrases = $db->fetchAll('
                SELECT phrase.*,
                    IF(master.phrase_id, master.addon_id, phrase.addon_id) AS addon_id
                FROM xf_phrase AS phrase
                LEFT JOIN xf_phrase AS master ON (master.title = phrase.title AND master.language_id = 0)
                WHERE phrase.language_id = ?
                    AND ' 
. ($limitAddOnId === null ? '1=1' : 'master.addon_id = ' . $db->quote($limitAddOnId)) . '
                ORDER BY phrase.title
            '
, $language['language_id']);
        }

        foreach (
$phrases AS $phrase)
        {
            
$phraseNode = $document->createElement('phrase');
            
$phraseNode->setAttribute('title', $phrase['title']);
            
$phraseNode->setAttribute('addon_id', $phrase['addon_id']);
            if (
$phrase['global_cache'])
            {
                
$phraseNode->setAttribute('global_cache', $phrase['global_cache']);
            }
            
$phraseNode->setAttribute('version_id', $phrase['version_id']);
            
$phraseNode->setAttribute('version_string', $phrase['version_string']);
            
$phraseNode->appendChild($document->createCDATASection($phrase['phrase_text']));

            
$rootNode->appendChild($phraseNode);
        }

        return 
$document;
    }

    
/**
     * Imports a language XML file.
     *
     * @param SimpleXMLElement $document
     * @param integer $parentLanguageId If not overwriting, the ID of the parent lang
     * @param integer $overwriteLanguageId If non-0, parent lang is ignored
     */
    
public function importLanguageXml(SimpleXMLElement $document, $parentLanguageId = 0, $overwriteLanguageId = 0)
    {
        if (
$document->getName() != 'language')
        {
            throw new 
XenForo_Exception(new XenForo_Phrase('provided_file_is_not_valid_language_xml'), true);
        }

        
$title = (string)$document['title'];
        if (
$title === '')
        {
            throw new 
XenForo_Exception(new XenForo_Phrase('provided_file_is_not_valid_language_xml'), true);
        }

        
$db = $this->_getDb();
        
XenForo_Db::beginTransaction($db);

        
$limitAddOnId = (string)$document['addon_id'];

        if (
$overwriteLanguageId)
        {
            
$db->delete('xf_phrase',
                
'language_id = ' . $db->quote($overwriteLanguageId)
                    . (
$limitAddOnId != '' ? ' AND addon_id = ' . $db->quote($limitAddOnId) : '')
            );

            
$existingPhrases = $this->_getPhraseModel()->getAllPhrasesInLanguage($overwriteLanguageId);
        }
        else
        {
            
$existingPhrases = array();
        }

        
$writer = XenForo_DataWriter::create('XenForo_DataWriter_Language');
        if (
$overwriteLanguageId)
        {
            
$writer->setExistingData($overwriteLanguageId);
        }
        else
        {
            
$writer->set('title', (string)$document['title']);
            
$writer->set('parent_id', $parentLanguageId);

            
$textDirection = (string)$document['text_direction'];
            
$writer->bulkSet(array(
                
'date_format' => (string)$document['date_format'],
                
'time_format' => (string)$document['time_format'],
                
'decimal_point' => (string)$document['decimal_point'],
                
'thousands_separator' => (string)$document['thousands_separator'],
                
'language_code' => (string)$document['language_code'],
                
'text_direction' => ($textDirection ? $textDirection : 'LTR')
            ));
        }

        
$writer->save();

        
$languageId = $writer->get('language_id');

        
$this->_getPhraseModel()->importPhrasesXml($document, $languageId, null, $existingPhrases);

        
$this->triggerLanguageRebuildDeferred();

        
XenForo_Db::commit($db);
    }

    public function 
triggerLanguageRebuildDeferred()
    {
        
XenForo_Application::defer('Atomic',
            array(
'simple' => array('Phrase', 'Template', 'AdminTemplate', 'EmailTemplate')),
            
'languageRebuild', true
        
);
    }

    
/**
     * Fetches $languageId from cookie if it's available, or returns the default language ID.
     *
     * @return integer
     */
    
public function getLanguageIdFromCookie()
    {
        
$languageId = XenForo_Helper_Cookie::getCookie('edit_language_id');
        if (
$languageId === false)
        {
            
$languageId = (XenForo_Application::debugMode()
                ? 
0
                
: XenForo_Application::get('options')->defaultLanguageId
            
);
        }

        if (!
XenForo_Application::debugMode() && !$languageId)
        {
            
$languageId = XenForo_Application::get('options')->defaultLanguageId;
        }

        return 
$languageId;
    }

    
/**
     * @return XenForo_Model_Phrase
     */
    
protected function _getPhraseModel()
    {
        return 
$this->getModelFromCache('XenForo_Model_Phrase');
    }
}
Онлайн: 3
Реклама