16 use Translate\Controller\Stepper;
17 use Translate\Controller\ProcessParams;
38 private $updateMethod;
48 private $languageList;
54 private $importedPhraseCount = 0;
67 $fields = [
'tabId',
'encodingIn',
'updateMethod',
'csvFilePath',
'seekLine',
'importedPhrasesCount'];
71 foreach ($fields as $key)
81 self::$enabledLanguages = Translate\Config::getEnabledLanguages();
83 foreach (self::$enabledLanguages as $languageId)
98 public function run($runBefore =
false)
108 ->setFieldsType(Translate\
IO\CsvFile::FIELDS_TYPE_WITH_DELIMITER)
109 ->setFirstHeader(
false)
112 if (!$this->csvFile->openLoad())
117 'STATUS' => Translate\Controller\STATUS_COMPLETED
120 if (!$this->verifyCsvFile())
123 'STATUS' => Translate\Controller\STATUS_COMPLETED
127 if ($this->csvFile->hasUtf8Bom())
129 $this->encodingIn =
'utf-8';
132 if ($this->isNewProcess)
136 $this->totalItems = 0;
137 while ($csvRow = $this->csvFile->fetch())
139 $this->totalItems ++;
142 $this->processedItems = 0;
148 'STATUS' => Translate\Controller\STATUS_PROGRESS,
149 'PROCESSED_ITEMS' => 0,
157 if (isset($progressParams[
'totalItems']))
159 $this->totalItems = $progressParams[
'totalItems'];
161 if (isset($progressParams[
'seekLine']))
163 $this->seekLine = $progressParams[
'seekLine'];
165 if (isset($progressParams[
'importedPhrasesCount']))
167 $this->importedPhraseCount = $progressParams[
'importedPhrasesCount'];
179 private function runImporting(): array
181 $fileIndex = $this->columnList[
'file'];
182 $keyIndex = $this->columnList[
'key'];
185 $maxLinePortion = 500;
186 $hasFinishedReading =
false;
193 while ($csvRow = $this->csvFile->fetch())
197 if ($this->seekLine > 0)
199 if ($currentLine <= $this->seekLine)
206 !\is_array($csvRow) ||
208 (\count($csvRow) == 1 && ($csvRow[0] ===
null || $csvRow[0] ===
''))
216 $filePath = (isset($csvRow[$fileIndex]) ? $csvRow[$fileIndex] :
'');
217 $key = (isset($csvRow[$keyIndex]) ? $csvRow[$keyIndex] :
'');
218 if ($filePath ==
'' || $key ==
'')
222 $rowErrors[] =
Loc::getMessage(
'TR_IMPORT_ERROR_DESTINATION_FILEPATH_ABSENT');
229 'TR_IMPORT_ERROR_LINE_FILE_EXT',
231 '#LINE#' => ($currentLine + 1),
232 '#ERROR#' => implode(
'; ', $rowErrors)
241 if (!isset($phraseList[$filePath]))
243 $phraseList[$filePath] = [];
245 foreach ($this->languageList as $languageId)
247 if (!isset($phraseList[$filePath][$languageId]))
249 $phraseList[$filePath][$languageId] = [];
252 $langIndex = $this->columnList[$languageId];
253 if (!isset($csvRow[$langIndex]) || (empty($csvRow[$langIndex]) && $csvRow[$langIndex] !==
'0'))
259 $phrase = $csvRow[$langIndex];
261 $encodingOut = self::$sourceEncoding[$languageId];
263 if (!empty($this->encodingIn) && $this->encodingIn !== $encodingOut)
265 $phrase = Main\Text\Encoding::convertEncoding($phrase, $this->encodingIn, $encodingOut);
269 if ($encodingOut ===
'utf-8')
271 $validPhrase = \preg_replace(
"/[^\x01-\x7F]/",
'', $phrase);
272 if ($validPhrase !== $phrase)
274 $checked = Translate\Text\StringHelper::validateUtf8OctetSequences($phrase);
281 $phraseList[$filePath][$languageId][$key] = $phrase;
285 $rowErrors[] =
Loc::getMessage(
'TR_IMPORT_ERROR_NO_VALID_UTF8_PHRASE', [
'#LANG#' => $languageId]);
288 unset($checked, $phrase);
291 if (!empty($rowErrors))
294 'TR_IMPORT_ERROR_LINE_FILE_BIG',
296 '#LINE#' => ($currentLine + 1),
297 '#FILENAME#' => $filePath,
299 '#ERROR#' => implode(
'; ', $rowErrors),
306 if ($linePortion >= $maxLinePortion)
312 if ($csvRow ===
null)
314 $hasFinishedReading =
true;
318 $this->processedItems += $linePortion;
320 foreach ($phraseList as $filePath => $translationList)
322 if (Translate\
IO\Path::isLangDir($filePath,
true) !==
true)
328 $filePath = Translate\IO\Path::normalize(
'/'.$filePath);
330 foreach ($translationList as $languageId => $fileMessages)
332 if (empty($fileMessages))
337 $langFilePath = Translate\IO\Path::replaceLangId($filePath, $languageId);
339 if (\Rel2Abs(
'/', $langFilePath) !== $langFilePath)
345 $fullPath = self::$documentRoot. $langFilePath;
346 $fullPath = Main\Localization\Translation::convertLangPath($fullPath, $languageId);
348 $langFile =
new Translate\File($fullPath);
349 $langFile->setLangId($languageId);
350 $langFile->setOperatingEncoding(self::$sourceEncoding[$languageId]);
352 if (!$langFile->loadTokens())
354 if (!$langFile->load() && $langFile->hasErrors())
356 foreach ($langFile->getErrors() as $error)
358 if ($error->getCode() !==
'EMPTY_CONTENT')
370 $hasDataToUpdate =
false;
373 foreach ($fileMessages as $key => $phrase)
375 switch ($this->updateMethod)
378 case Translate\Controller\Import\Csv::METHOD_ADD_ONLY:
379 if (!isset($langFile[$key]) || (empty($langFile[$key]) && $langFile[$key] !==
'0'))
381 $langFile[$key] = $phrase;
382 $hasDataToUpdate =
true;
383 $this->importedPhraseCount ++;
388 case Translate\Controller\Import\Csv::METHOD_UPDATE_ONLY:
389 if (isset($langFile[$key]) && $langFile[$key] !== $phrase)
391 $langFile[$key] = $phrase;
392 $hasDataToUpdate =
true;
393 $this->importedPhraseCount ++;
399 case Translate\Controller\Import\Csv::METHOD_ADD_UPDATE:
400 if ($langFile[$key] !== $phrase)
402 $langFile[$key] = $phrase;
403 $hasDataToUpdate =
true;
404 $this->importedPhraseCount ++;
410 if ($hasDataToUpdate)
413 if ($langFile->isExists() && Translate\Config::needToBackUpFiles())
415 if (!$langFile->backup())
418 Loc::getMessage(
'TR_IMPORT_ERROR_CREATE_BACKUP', [
'#FILE#' => $langFilePath])
424 if (Translate\Config::needToSortPhrases())
426 if (\in_array($languageId, Translate\Config::getNonSortPhraseLanguages()) ===
false)
428 $langFile->sortPhrases();
434 if (!$langFile->save())
436 if ($langFile->hasErrors())
438 $this->
addErrors($langFile->getErrors());
442 catch (Main\
IO\IoException $exception)
444 if (!$langFile->isExists())
447 Loc::getMessage(
'TR_IMPORT_ERROR_WRITE_CREATE', [
'#FILE#' => $langFilePath])
453 Loc::getMessage(
'TR_IMPORT_ERROR_WRITE_UPDATE', [
'#FILE#' => $langFilePath])
463 $this->seekLine = $currentLine;
467 if ($hasFinishedReading)
475 $this->csvFile->close();
486 'TOTAL_PHRASES' => $this->importedPhraseCount,
496 private function verifyCsvFile(): bool
499 Translate\IO\CsvFile::DELIMITER_TZP,
500 Translate\IO\CsvFile::DELIMITER_TAB,
501 Translate\IO\CsvFile::DELIMITER_ZPT,
503 foreach ($testDelimiters as $delimiter)
505 $this->csvFile->setFieldDelimiter($delimiter);
507 $this->csvFile->moveFirst();
508 $rowHead = $this->csvFile->fetch();
512 || empty($rowHead[0])
513 || (\count($rowHead) < 3)
525 || empty($rowHead[0])
526 || (count($rowHead) < 3)
535 $this->columnList = array_flip($rowHead);
536 foreach ($this->languageList as $keyLang => $langID)
538 if (!isset($this->columnList[$langID]))
540 unset($this->languageList[$keyLang]);
543 if (!isset($this->columnList[
'file']))
547 if (!isset($this->columnList[
'key']))
551 if (empty($this->languageList))
static getMessage($code, $replace=null, $language=null)