Your IP : 3.145.166.108


Current Path : /var/www/www-root/data/www/monolith-realty.ru/bitrix/components/bitrix/translate.edit/
Upload File :
Current File : /var/www/www-root/data/www/monolith-realty.ru/bitrix/components/bitrix/translate.edit/class.php

<?php
if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true)
{
	die();
}
if (!\Bitrix\Main\Loader::includeModule('translate'))
{
	return;
}

use Bitrix\Main;
use Bitrix\Main\Error;
use Bitrix\Main\Localization;
use Bitrix\Main\Localization\Loc;
use Bitrix\Translate;

Main\Loader::includeModule('translate');

class TranslateEditComponent extends Translate\ComponentBase
{
	public const VIEW_MODE_UNTRANSLATED = 'Untranslated';
	public const VIEW_MODE_SHOW_ALL = 'ShowAll';
	public const VIEW_MODE_SOURCE_EDIT = 'SourceEdit';
	public const VIEW_MODE_SOURCE_VIEW = 'SourceView';

	public const TEMPLATE_SOURCE_EDIT = 'source_edit';
	public const TEMPLATE_SOURCE_VIEW = 'source_view';

	/** @var string */
	private $filePath = '';

	/** @var string */
	private $viewMode;

	/** @var array */
	private $langSettings = [];

	/** @var string */
	private $highlightPhraseId;


	/**
	 * @return void
	 */
	protected function prepareParams()
	{
		parent::prepareParams();
		$paramsIn =& $this->getParams();

		$paramsIn['TAB_ID'] = $this->detectTabId();

		// highlight phrase
		$highlightPhraseId = $this->request->get('highlight');
		if (!empty($highlightPhraseId))
		{
			$this->highlightPhraseId = preg_replace("/[^a-z1-9_]+/i", '', $highlightPhraseId);
			if (!empty($this->highlightPhraseId))
			{
				$paramsIn['HIGHLIGHT_PHRASE_ID'] = $this->highlightPhraseId;
			}
		}


		// view mode
		if (!empty($this->highlightPhraseId))
		{
			$paramsIn['VIEW_MODE'] = self::VIEW_MODE_SHOW_ALL;
			$paramsIn['SHOW_ALL'] = true;
			$paramsIn['SHOW_UNTRANSLATED'] = false;
		}
		else
		{
			$paramsIn['VIEW_MODE'] = $this->detectViewMode();
			$paramsIn['SHOW_ALL'] = (self::VIEW_MODE_SHOW_ALL === $this->viewMode);
			$paramsIn['SHOW_UNTRANSLATED'] = (self::VIEW_MODE_UNTRANSLATED === $this->viewMode);
		}
	}

	/**
	 * @return string
	 */
	protected function detectTabId()
	{
		$tabId = $this->request->get('tabId');
		if (!empty($tabId) && (int)$tabId > 0)
		{
			$this->tabId = (int)$tabId;
		}
		else
		{
			$this->tabId = Translate\Filter::getTabId(true);
		}

		return $this->tabId;
	}

	/**
	 * @return void
	 */
	public function executeComponent()
	{
		if (!$this->checkModuleAvailability() || !$this->checkPermissionEdit())
		{
			return;
		}

		$this->prepareParams();

		if (in_array($this->viewMode, array(self::VIEW_MODE_SOURCE_EDIT, self::VIEW_MODE_SOURCE_VIEW)))
		{
			if (!$this->checkPermissionEditPhp())
			{
				return;
			}
		}

		$paramsIn =& $this->getParams();

		// path
		$this->path = $this->detectPath('path');
		$this->filePath = $this->detectPath('file');
		if (empty($this->filePath))
		{
			$this->addError(new Error(Loc::getMessage('TR_EDIT_FILE_PATH_ERROR'), self::STATUS_DENIED));
			$this->includeComponentTemplate(self::TEMPLATE_ERROR);
			return;
		}
		if (!Translate\IO\Path::isLangDir($this->filePath) || !Translate\IO\Path::isPhpFile($this->filePath))
		{
			$this->addError(new Error(Loc::getMessage('TR_EDIT_FILE_NOT_LANG', array('#FILE#' => $this->filePath)), self::STATUS_DENIED));
			$this->includeComponentTemplate(self::TEMPLATE_ERROR);
			return;
		}
		if (!Translate\Permission::isAllowPath($this->filePath))
		{
			$this->addError(new Error(Loc::getMessage('TR_EDIT_FILE_WRONG_NAME'), self::STATUS_DENIED));
			$this->includeComponentTemplate(self::TEMPLATE_ERROR);
			return;
		}

		$this->arResult['FILE_PATH'] = Translate\IO\Path::replaceLangId($this->filePath, Loc::getCurrentLang());
		$this->arResult['PATH'] = Translate\IO\Path::replaceLangId($this->path, Loc::getCurrentLang());

		$this->arResult['CHAIN'] = $this->generateChainLinks($this->arResult['FILE_PATH']);

		$this->arResult['LINK_BACK'] =
			$paramsIn['LIST_PATH'].
			'?lang='.Loc::getCurrentLang().
			'&tabId='.$this->tabId.
			'&path='. htmlspecialcharsbx($this->arResult['PATH']);

		$this->arResult['LINK_EDIT'] =
			$paramsIn['EDIT_PATH'].
			'?lang='.$paramsIn['CURRENT_LANG'].
			'&tabId='.$this->tabId.
			'&file='. htmlspecialcharsbx($this->arResult['FILE_PATH']).
			'&path='. htmlspecialcharsbx($this->arResult['PATH']);

		if ($this->arResult['ALLOW_EDIT_SOURCE'])
		{
			$this->arResult['LINK_SHOW_SOURCE'] =
				$paramsIn['SHOW_SOURCE_PATH'].
				'?lang='.$paramsIn['CURRENT_LANG'].
				'&tabId='.$this->tabId.
				'&file='.htmlspecialcharsbx($this->arResult['FILE_PATH']).
				'&path='.htmlspecialcharsbx($this->arResult['PATH']);

			$this->arResult['LINK_EDIT_SOURCE'] =
				$paramsIn['EDIT_SOURCE_PATH'].
				'?lang='.$paramsIn['CURRENT_LANG'].
				'&tabId='.$this->tabId.
				'&file='.htmlspecialcharsbx($this->arResult['FILE_PATH']).
				'&path='.htmlspecialcharsbx($this->arResult['PATH']);
		}

		// languages
		$this->arResult['LANGUAGES'] = $this->getLanguages();
		$this->arResult['COMPATIBLE_LANGUAGES'] = $this->getCompatibleLanguages();
		$this->arResult['LANGUAGES_TITLE'] = $this->getLanguagesTitle($this->arResult['LANGUAGES']);

		$documentRoot = Main\Application::getDocumentRoot();
		$encodingOut = Localization\Translation::getCurrentEncoding();

		// settings
		$settingsFile = Translate\Settings::instantiateByPath($documentRoot. '/'. $this->filePath);
		if (($settingsFile instanceof Translate\Settings) && $settingsFile->load())
		{
			$this->langSettings = $settingsFile->getOptions($this->filePath);
			$this->arResult['LANG_SETTINGS'] = $settingsFile->getOption($this->filePath, Translate\Settings::OPTION_LANGUAGES);
		}

		if ($this->viewMode === self::VIEW_MODE_SOURCE_VIEW || $this->viewMode === self::VIEW_MODE_SOURCE_EDIT)
		{
			$langRelPath = Translate\IO\Path::replaceLangId($this->filePath, $paramsIn['CURRENT_LANG']);
			$langFullPath = Translate\IO\Path::tidy($documentRoot.'/'.$langRelPath);
			$langFullPath = Main\Localization\Translation::convertLangPath($langFullPath, $paramsIn['CURRENT_LANG']);

			$langFile = new Translate\File($langFullPath);
			$langFile
				->setLangId($paramsIn['CURRENT_LANG'])
				->setOperatingEncoding($encodingOut);

			if ($langFile->isExists())
			{
				$this->arResult['FILE_SOURCE'] = $langFile->getContents();
				$this->arResult['FILE_PHRASE_COUNT'] = $langFile->count(true);
				$this->arResult['FILE_LANGUAGE_ID'] = $langFile->getLangId();
				$this->arResult['FILE_LANGUAGE'] = $this->arResult['LANGUAGES_TITLE'][$langFile->getLangId()];
			}

			if ($this->viewMode === self::VIEW_MODE_SOURCE_VIEW)
			{
				$this->includeComponentTemplate(self::TEMPLATE_SOURCE_VIEW);
			}
			else
			{
				$this->includeComponentTemplate(self::TEMPLATE_SOURCE_EDIT);
			}
		}
		else
		{
			$fullPaths = [];
			foreach ($this->arResult['LANGUAGES'] as $langId)
			{
				$langRelPath = Translate\IO\Path::replaceLangId($this->filePath, $langId);
				$langFullPath = Translate\IO\Path::tidy($documentRoot.'/'.$langRelPath);
				$langFullPath = Main\Localization\Translation::convertLangPath($langFullPath, $langId);
				$fullPaths[$langId] = $langFullPath;
			}

			// lets get phrases
			[$this->arResult['MESSAGES'], $this->arResult['DIFFERENCES']] = $this->mergeLangFiles(
				$fullPaths,
				$this->arResult['LANGUAGES'],
				$encodingOut,
				($this->viewMode == self::VIEW_MODE_UNTRANSLATED)
			);

			if ($paramsIn['SET_TITLE'])
			{
				$this->getApplication()->setTitle(Loc::getMessage('TR_EDIT_TITLE'));
			}

			$this->includeComponentTemplate();
		}
	}


	/**
	 * Generates name for form field.
	 *
	 * @param string $phraseId Phrase code.
	 * @param string $suffix Append name with.
	 * @param string $prefix Start name with.
	 *
	 * @return string
	 */
	public function generateFieldName($phraseId, $suffix = '', $prefix = '')
	{
		return
			(!empty($prefix) ? $prefix. '_' : '').
			str_replace(['.', '-', ' '], '_', $phraseId).
			(!empty($suffix) ? '_'.$suffix : '');
	}


	/**
	 * Merges all language files into one array.
	 *
	 * @param string[] $fullLangFilePaths Array of full paths to lang files.
	 * @param string[] $languages Array of languages to merge.
	 * @param string $encodingOut Output encoding.
	 * @param boolean $collectUntranslated Leave only untranslated phrases.
	 *
	 * @return array
	 */
	private function mergeLangFiles($fullLangFilePaths, $languages, $encodingOut = null, $collectUntranslated = false)
	{
		$mergedContent = [];
		$langCodes = [];

		$rowLang0 = [];
		foreach ($languages as $langId)
		{
			$rowLang0[$langId] = '';
		}

		foreach ($languages as $langId)
		{
			if (empty($fullLangFilePaths[$langId]))
			{
				continue;
			}

			$fullPath = $fullLangFilePaths[$langId];
			$langFile = new Translate\File($fullPath);
			$langFile->setLangId($langId);

			if (!empty($encodingOut))
			{
				$langFile->setOperatingEncoding($encodingOut);
			}

			if (!$langFile->loadTokens())
			{
				if (!$langFile->load())
				{
					continue;
				}
			}

			$langCodes[$langId] = [];
			foreach ($langFile as $code => $phrase)
			{
				if (!isset($mergedContent[$code]))
				{
					$mergedContent[$code] = $rowLang0;
				}
				$mergedContent[$code][$langId] = $phrase;
				$langCodes[$langId][] = $code;
			}
		}

		if ($collectUntranslated)
		{
			foreach ($mergedContent as $code => $row)
			{
				foreach ($row as $langId => $phr)
				{
					$isObligatory = true;
					if (!empty($this->langSettings[Translate\Settings::OPTION_LANGUAGES]))
					{
						$isObligatory = in_array($langId, $this->langSettings[Translate\Settings::OPTION_LANGUAGES], true);
					}
					if (!isset($phr) || !is_string($phr) || (empty($phr) && $phr !== '0'))
					{
						if ($isObligatory)
						{
							continue 2;
						}
					}
				}
				unset($mergedContent[$code]);
			}
		}

		// calculate the sum and difference of files
		$differences = [];
		$currentLang = Loc::getCurrentLang();
		$ethalonCodes = $langCodes[$currentLang] ?: [];
		foreach ($languages as $langId)
		{
			$isObligatory = true;
			if (!empty($this->langSettings[Translate\Settings::OPTION_LANGUAGES]))
			{
				$isObligatory = in_array($langId, $this->langSettings[Translate\Settings::OPTION_LANGUAGES], true);
			}

			if ($langId === $currentLang)
			{
				$differences[$currentLang] = array(
					'TOTAL' => count($ethalonCodes),
					'LESS' => 0,
					'MORE' => $isObligatory ? 0 : count($ethalonCodes),
					'CODES' => $ethalonCodes,
				);
			}
			elseif (!isset($langCodes[$langId]))
			{
				$differences[$langId] = array(
					'TOTAL' => 0,
					'LESS' => $isObligatory ? count($ethalonCodes) : 0,
					'MORE' => 0,
					'CODES' => [],
				);
			}
			else
			{
				$differences[$langId] = array(
					'TOTAL' => count($langCodes[$langId]),
					'LESS' => $isObligatory ? count(array_diff($ethalonCodes, $langCodes[$langId])) : 0,
					'MORE' => $isObligatory ? count(array_diff($langCodes[$langId], $ethalonCodes)) : count($langCodes[$langId]),
					'CODES' => $langCodes[$langId],
				);
			}
		}

		return [$mergedContent, $differences];
	}

	/**
	 * Finds requested path from.
	 *
	 * @param string $inpName Input parameter name.
	 * @return string
	 */
	private function detectPath($inpName = 'file')
	{
		// from request
		$path = $this->request->get($inpName) ?? '';

		if (!empty($path) && !preg_match("#\.\.[\\/]#u", $path))
		{
			$path = Translate\IO\Path::normalize($path);
			if (Translate\Permission::isAllowPath($path))
			{
				$path = Translate\IO\Path::replaceLangId($path, '#LANG_ID#');
			}
		}

		return $path;
	}

	/**
	 *  Restores current view mode.
	 *
	 * @return string
	 */
	private function detectViewMode()
	{
		$paramsIn =& $this->getParams();

		if (!empty($paramsIn['VIEW_MODE']) && in_array($paramsIn['VIEW_MODE'], array(self::VIEW_MODE_SOURCE_EDIT, self::VIEW_MODE_SOURCE_VIEW), true))
		{
			$this->viewMode = $paramsIn['VIEW_MODE'];

			return $this->viewMode;
		}

		if ($this->request->get('viewMode') !== null)
		{
			$viewMode = $this->request->get('viewMode');
		}
		else
		{
			$viewMode = \CUserOptions::getOption('translate', 'edit_mode', '');
		}
		if (!empty($viewMode) && in_array($viewMode, array(self::VIEW_MODE_UNTRANSLATED, self::VIEW_MODE_SHOW_ALL), true))
		{
			$this->viewMode = $viewMode;
			\CUserOptions::setOption('translate', 'edit_mode', $this->viewMode);
		}
		if (empty($this->viewMode))
		{
			$this->viewMode = self::VIEW_MODE_SHOW_ALL;
		}

		return $this->viewMode;
	}
}