public function exportTranslations($group, $recursing = 0) { // TODO: clean up this recursion crap if (!$recursing) { $this->clearErrors(); } if ($group && $group !== '*') { $this->translation->getConnection()->affectingStatement("DELETE FROM ltm_translations WHERE is_deleted = 1"); } elseif (!$recursing) { $this->translation->getConnection()->affectingStatement("DELETE FROM ltm_translations WHERE is_deleted = 1 AND `group` = ?", [$group]); } $inDatabasePublishing = $this->inDatabasePublishing(); if ($inDatabasePublishing < 3 && $inDatabasePublishing && ($inDatabasePublishing < 2 || !$recursing)) { if ($group && $group !== '*') { $this->translation->getConnection()->affectingStatement(<<<SQL UPDATE ltm_translations SET saved_value = value, status = ? WHERE (saved_value <> value || status <> ?) AND `group` = ? SQL , [Translation::STATUS_SAVED_CACHED, Translation::STATUS_SAVED, $group]); $translations = $this->translation->query()->where('status', '<>', Translation::STATUS_SAVED)->where('group', '=', $group)->get(['group', 'key', 'locale', 'saved_value']); } else { $this->translation->getConnection()->affectingStatement(<<<SQL UPDATE ltm_translations SET saved_value = value, status = ? WHERE (saved_value <> value || status <> ?) SQL , [Translation::STATUS_SAVED_CACHED, Translation::STATUS_SAVED]); $translations = $this->translation->query()->where('status', '<>', Translation::STATUS_SAVED)->get(['group', 'key', 'locale', 'saved_value']); } /* @var $translations Collection */ $this->clearCache($group); $translations->each(function ($tr) { $this->cacheTranslation($tr->group . '.' . $tr->key, $tr->saved_value, $tr->locale); }); } if (!$inDatabasePublishing || $inDatabasePublishing === 2 || $inDatabasePublishing === 3) { if (!in_array($group, $this->config()['exclude_groups'])) { if ($group == '*') { $this->exportAllTranslations(1); } if ($inDatabasePublishing !== 3) { $this->clearCache($group); } $tree = $this->makeTree(Translation::where('group', $group)->whereNotNull('value')->orderby('key')->get()); $configRewriter = new TranslationFileRewriter(); $exportOptions = array_key_exists('export_format', $this->config()) ? TranslationFileRewriter::optionFlags($this->config()['export_format']) : null; // Laravel 5.1 $base_path = $this->app->basePath(); $pathTemplateResolver = new PathTemplateResolver($this->files, $base_path, $this->config()['language_dirs'], '5'); $zipRoot = $base_path . $this->config('zip_root', mb_substr($this->app->langPath(), 0, -4)); // Laravel 4.2 //$base_path = base_path(); //$pathTemplateResolver = new PathTemplateResolver($this->files, $base_path, $this->config()['language_dirs'], '4'); //$zipRoot = $base_path . $this->config('zip_root', mb_substr($this->app->make('path').'/lang', 0, -4)); if (mb_substr($zipRoot, -1) === '/') { $zipRoot = substr($zipRoot, 0, -1); } foreach ($tree as $locale => $groups) { if (isset($groups[$group])) { $translations = $groups[$group]; // use the new path mapping $computedPath = $base_path . $pathTemplateResolver->groupFilePath($group, $locale); $path = $computedPath; if ($path) { $configRewriter->parseSource($this->files->exists($path) ? $this->files->get($path) : ''); $output = $configRewriter->formatForExport($translations, $exportOptions); if ($this->zipExporting) { $pathPrefix = mb_substr($path, 0, mb_strlen($zipRoot)); $filePathName = $pathPrefix === $zipRoot ? mb_substr($path, mb_strlen($zipRoot)) : $path; //$this->makeDirPath($filePathName); $this->zipExporting->addFromString($filePathName, $output); } else { try { $this->makeDirPath($path); if (($result = $this->files->put($path, $output)) === false) { $this->errors[] = "Failed to write to {$path}"; } } catch (Exception $e) { $this->errors[] = $e->getMessage(); } } } } } if (!$inDatabasePublishing) { Translation::where('group', $group)->update(array('status' => Translation::STATUS_SAVED, 'saved_value' => new Expression('value'))); } } } }
public function getIndex($group = null) { $locales = $this->locales; $currentLocale = \Lang::getLocale(); $primaryLocale = $this->primaryLocale; $translatingLocale = $this->translatingLocale; $groups = Translation::groupBy('group'); $excludedGroups = $this->manager->getConfig('exclude_groups'); if ($excludedGroups) { $groups->whereNotIn('group', $excludedGroups); } $groups = array('' => noEditTrans($this->packagePrefix . 'messages.choose-group')) + $groups->lists('group', 'group')->all(); $numChanged = Translation::where('group', $group)->where('status', Translation::STATUS_CHANGED)->count(); // to allow proper handling of nested directory structure we need to copy the keys for the group for all missing // translations, otherwise we don't know what the group and key looks like. //$allTranslations = Translation::where('group', $group)->orderBy('key', 'asc')->get(); $displayWhere = $this->displayLocales ? ' AND locale IN (\'' . implode("','", explode(',', $this->displayLocales)) . "')" : ''; $allTranslations = Translation::hydrateRaw($sql = <<<SQL SELECT * FROM ltm_translations WHERE `group` = ? {$displayWhere} UNION ALL SELECT DISTINCT NULL id, NULL status, locale, `group`, `key`, NULL value, NULL created_at, NULL updated_at, NULL source, NULL saved_value, NULL is_deleted FROM (SELECT * FROM (SELECT DISTINCT locale FROM ltm_translations WHERE 1=1 {$displayWhere}) lcs CROSS JOIN (SELECT DISTINCT `group`, `key` FROM ltm_translations WHERE `group` = ? {$displayWhere}) grp) m WHERE NOT EXISTS(SELECT * FROM ltm_translations t WHERE t.locale = m.locale AND t.`group` = m.`group` AND t.`key` = m.`key`) ORDER BY `key` ASC SQL , [$group, $group]); if (!count($allTranslations) && $group) { $pos = strrpos($url = Request::url(), '/index'); if ($pos !== false) { $url = substr($url, 0, $pos); return Redirect::to($url); } } $numTranslations = count($allTranslations); $translations = array(); foreach ($allTranslations as $translation) { $translations[$translation->key][$translation->locale] = $translation; } $stats = DB::select(<<<SQL SELECT (mx.total_keys - lcs.total) missing, lcs.changed, lcs.deleted, lcs.locale, lcs.`group` FROM (SELECT sum(total) total, sum(changed) changed, sum(deleted) deleted, `group`, locale FROM (SELECT count(value) total, sum(status) changed, sum(is_deleted) deleted, `group`, locale FROM ltm_translations lt WHERE 1=1 {$displayWhere} GROUP BY `group`, locale UNION ALL SELECT DISTINCT 0, 0, 0, `group`, locale FROM (SELECT DISTINCT locale FROM ltm_translations WHERE 1=1 {$displayWhere}) lc CROSS JOIN (SELECT DISTINCT `group` FROM ltm_translations) lg) a GROUP BY `group`, locale) lcs JOIN (SELECT count(DISTINCT `key`) total_keys, `group` FROM ltm_translations WHERE 1=1 {$displayWhere} GROUP BY `group`) mx ON lcs.`group` = mx.`group` WHERE lcs.total < mx.total_keys OR lcs.changed > 0 OR lcs.deleted > 0 SQL ); // returned result set lists mising, changed, group, locale $summary = []; foreach ($stats as $stat) { if (!isset($summary[$stat->group])) { $item = $summary[$stat->group] = new \stdClass(); $item->missing = ''; $item->changed = ''; $item->deleted = ''; $item->group = $stat->group; } $item = $summary[$stat->group]; if ($stat->missing) { $item->missing .= $stat->locale . ":" . $stat->missing . " "; } if ($stat->changed) { $item->changed .= $stat->locale . ":" . $stat->changed . " "; } if ($stat->deleted) { $item->deleted .= $stat->locale . ":" . $stat->deleted . " "; } } $mismatches = null; $mismatchEnabled = $this->manager->getConfig('mismatch_enabled'); if ($mismatchEnabled) { // get mismatches $mismatches = DB::select(<<<SQL SELECT DISTINCT lt.*, ft.ru, ft.en FROM (SELECT * FROM ltm_translations WHERE 1=1 {$displayWhere}) lt JOIN (SELECT DISTINCT mt.`key`, BINARY mt.ru ru, BINARY mt.en en FROM (SELECT lt.`group`, lt.`key`, group_concat(CASE lt.locale WHEN '{$primaryLocale}' THEN VALUE ELSE NULL END) en, group_concat(CASE lt.locale WHEN '{$translatingLocale}' THEN VALUE ELSE NULL END) ru FROM (SELECT value, `group`, `key`, locale FROM ltm_translations WHERE 1=1 {$displayWhere} UNION ALL SELECT NULL, `group`, `key`, locale FROM ((SELECT DISTINCT locale FROM ltm_translations WHERE 1=1 {$displayWhere}) lc CROSS JOIN (SELECT DISTINCT `group`, `key` FROM ltm_translations WHERE 1=1 {$displayWhere}) lg) ) lt GROUP BY `group`, `key`) mt JOIN (SELECT lt.`group`, lt.`key`, group_concat(CASE lt.locale WHEN '{$primaryLocale}' THEN VALUE ELSE NULL END) en, group_concat(CASE lt.locale WHEN '{$translatingLocale}' THEN VALUE ELSE NULL END) ru FROM (SELECT value, `group`, `key`, locale FROM ltm_translations WHERE 1=1 {$displayWhere} UNION ALL SELECT NULL, `group`, `key`, locale FROM ((SELECT DISTINCT locale FROM ltm_translations WHERE 1=1 {$displayWhere}) lc CROSS JOIN (SELECT DISTINCT `group`, `key` FROM ltm_translations WHERE 1=1 {$displayWhere}) lg) ) lt GROUP BY `group`, `key`) ht ON mt.`key` = ht.`key` WHERE (mt.ru NOT LIKE BINARY ht.ru AND mt.en LIKE BINARY ht.en) OR (mt.ru LIKE BINARY ht.ru AND mt.en NOT LIKE BINARY ht.en) ) ft ON (lt.locale = '{$translatingLocale}' AND lt.value LIKE BINARY ft.ru) AND lt.`key` = ft.key ORDER BY `key`, `group` SQL ); $key = ''; $rus = []; $ens = []; $rubases = []; // by key $enbases = []; // by key $extra = new \stdClass(); $extra->key = ''; $mismatches[] = $extra; foreach ($mismatches as $mismatch) { if ($mismatch->key !== $key) { if ($key) { // process diff for key $txtru = ''; $txten = ''; if (count($ens) > 1) { $maxen = 0; foreach ($ens as $en => $cnt) { if ($maxen < $cnt) { $maxen = $cnt; $txten = $en; } } $enbases[$key] = $txten; } else { $txten = array_keys($ens)[0]; $enbases[$key] = $txten; } if (count($rus) > 1) { $maxru = 0; foreach ($rus as $ru => $cnt) { if ($maxru < $cnt) { $maxru = $cnt; $txtru = $ru; } } $rubases[$key] = $txtru; } else { $txtru = array_keys($rus)[0]; $rubases[$key] = $txtru; } } $key = $mismatch->key; $rus = []; $ens = []; } if ($mismatch->key === '') { break; } if (!isset($ens[$mismatch->en])) { $ens[$mismatch->en] = 1; } else { $ens[$mismatch->en]++; } if (!isset($rus[$mismatch->ru])) { $rus[$mismatch->ru] = 1; } else { $rus[$mismatch->ru]++; } } array_splice($mismatches, count($mismatches) - 1, 1); foreach ($mismatches as $mismatch) { $mismatch->en_value = $mismatch->ru; $mismatch->en = mb_renderDiffHtml($enbases[$mismatch->key], $mismatch->en); $mismatch->ru_value = $mismatch->ru; $mismatch->ru = mb_renderDiffHtml($rubases[$mismatch->key], $mismatch->ru); } } // returned result set lists group key ru, en columns for the locale translations, ru has different values for same values in en $displayLocales = explode(',', $this->displayLocales); $displayLocales = array_combine($displayLocales, $displayLocales); return \View::make($this->packagePrefix . 'index')->with('controller', '\\' . get_class($this))->with('package', $this->package)->with('public_prefix', '/vendor/')->with('translations', $translations)->with('yandex_key', !!$this->manager->getConfig('yandex_translator_key'))->with('locales', $locales)->with('primaryLocale', $primaryLocale)->with('currentLocale', $currentLocale)->with('translatingLocale', $translatingLocale)->with('displayLocales', $displayLocales)->with('groups', $groups)->with('group', $group)->with('numTranslations', $numTranslations)->with('numChanged', $numChanged)->with('adminEnabled', $this->manager->getConfig('admin_enabled') && UserCan::admin_translations())->with('mismatchEnabled', $mismatchEnabled)->with('stats', $summary)->with('mismatches', $mismatches); }