languageFilePath = resource_path()."/lang/";
$this->languages = array('de','en','fr','es','nd');
}
public function createOverview(Request $request)
{
$languageFolders = scandir($this->languageFilePath);
$dirs = [];
foreach ($languageFolders as $folder) {
if (is_dir($this->languageFilePath . $folder) && $folder !== "." && $folder !== "..") {
$dirs[] = $folder;
}
}
# Im Array "$dirs" haben wir nun alle Verzeichnisse mit dem entsprechenden Sprachkürzel
# Alle von uns bislang unterstützen Sprachen sind hier eingetragen.
$langTexts = [];
$sum = [];
foreach ($dirs as $dir) {
# Wir überprüfen nun für jede Datei die Anzahl der vorhandenen Übersetzungen
$di = new RecursiveDirectoryIterator($this->languageFilePath . $dir);
$langTexts[$dir]["textCount"] = 0;
$langTexts[$dir]["fileCount"] = 0;
foreach (new RecursiveIteratorIterator($di) as $filename => $file) {
if (!$this->endsWith($filename, ".")) {
$langTexts[$dir]["fileCount"] += 1;
$tmp = include $filename;
foreach ($tmp as $key => $value) {
$sum = array_merge($sum, $this->getValues([$key => $value], basename($filename)));
$langTexts[$dir]["textCount"] += count($this->getValues([$key => $value]));
}
}
}
}
$deComplete = $langTexts["de"]["textCount"] === count($sum) ? true : false;
return view('languages.overview')
->with('title', trans('titles.languages'))
->with('langTexts', $langTexts)
->with('sum', $sum)
->with('deComplete', $deComplete);
}
public function createEditPage($from, $to, $exclude = "", $email = "")
{
$languageFolders = scandir($this->languageFilePath);
$dirs = [];
foreach ($languageFolders as $folder) {
if (is_dir($this->languageFilePath . $folder) && $folder !== "." && $folder !== "..") {
$dirs[$folder] = $folder;
}
}
# Abbruchbedingungen:
if (!in_array($to, $this->languages) || $from === "" || $to === "" || ($from !== "de" && $from !== "all") || ($from === "all" && $to !== "de") && !array_has($dirs, $to)) {
return redirect(url('languages'));
}
$texts = [];
$langTexts = [];
$sum = [];
$filePath = [];
foreach ($dirs as $dir) {
if ($from !== "all" && $dir !== $to && $dir !== $from) {
continue;
}
# Wir überprüfen nun für jede Datei die Anzahl der vorhandenen Übersetzungen
$di = new RecursiveDirectoryIterator($this->languageFilePath . $dir);
$langTexts[$dir] = 0;
foreach (new RecursiveIteratorIterator($di) as $filename => $file) {
if (!$this->endsWith($filename, ".")) {
$tmp = include $filename;
foreach ($tmp as $key => $value) {
$sum = array_merge($sum, $this->getValues([$key => $value], basename($filename)));
$texts[basename($filename)][$key][$dir] = $value;
$langTexts[$dir] += count($this->getValues([$key => $value]));
}
$filePath[basename($filename)] = preg_replace("/lang\/.*?\//si", "lang/$to/", substr($filename, strpos($filename, "lang")));
}
}
}
$langs = [];
$fn = "";
$t = [];
$ex = $this->decodeExcludedFiles($exclude);
foreach ($texts as $filename => $text) {
foreach ($ex['files'] as $file) {
if ($file === $filename) {
continue 2;
}
}
while ($this->hasToMuchDimensions($text)) {
$text = $this->deMultidimensionalizeArray($text);
}
# Hier können wir später die bereits bearbeiteten Dateien ausschließen.
foreach ($text as $textname => $languages) {
if ($languages === "") {
continue;
}
foreach ($languages as $lang => $value) {
if ($lang !== $to) {
$langs = array_add($langs, $lang, $lang);
}
}
if (!isset($languages[$to])) {
$fn = $filePath[$filename];
$t = $text;
break 2;
}
}
}
$t = $this->htmlEscape($t, $to);
$t = $this->createHints($t, $to);
return view('languages.edit')
->with('texts', $t) //Array mit vorhandenen Übersetzungen der Datei $fn in beiden Sprachen
->with('filename', $fn) //Pfad zur angezeigten Datei
->with('title', trans('titles.languages.edit'))
->with('langs', $langs) //Ausgangssprache (1 Element)
->with('to', $to) //zu bearbeitende Sprache
->with('langTexts', $langTexts) //Anzahl der vorhandenen Übersetzungen
->with('sum', $sum) //Alle vorhandenen Texte (in allen Dateien) in beiden Sprachen in einem Array
->with('new', $ex["new"]) //
->with('email', $email); //Email-Adresse des Benutzers
}
public function createSynopticEditPage(Request $request, $exclude = '', $chosenFile = '')
{
$languageFolders = scandir($this->languageFilePath);
# Enthält zu jeder Sprache ein Objekt mit allen Daten
$languageObjects = [];
# Alle vorhandenen Sprachen
$to = [];
# Dekodieren ausgeschlossener Dateien anhand des URL-Parameters
$ex = $this->decodeExcludedFiles($exclude);
# Instanziiere LanguageObject
foreach ($languageFolders as $folder) {
if (is_dir($this->languageFilePath . $folder) && $folder !== "." && $folder !== "..") {
$languageObjects[$folder] = new LanguageObject($folder, $this->languageFilePath.$folder);
}
}
$fileNames = [];
# Speichere Daten in LanguageObject, überspringe ausgeschlossene Dateien
foreach ($languageObjects as $folder => $languageObject) {
$to[] = $folder;
$di = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($languageObject->filePath));
foreach($di as $filename => $file) {
if(!$this->endsWith($filename, ".") && !in_array(basename($filename), $fileNames)) {
$fileNames[] = basename($filename);
}
if(!$this->endsWith($filename, ".")) {
$tmp = include $filename;
foreach ($tmp as $key => $value) {
$languageObject->saveData(basename($filename), $key, $value);
}
}
}
}
$fn = "";
# Wähle die erste, unbearbeitete Datei aus, überspringe bereits bearbeitete Dateien
if($chosenFile !== "") {
$fn = $chosenFile;
} else {
foreach($languageObjects as $folder => $languageObject) {
foreach($languageObject->stringMap as $languageFileName => $languageFile) {
foreach($ex['files'] as $file) {
if($file === basename($languageFileName)) {
continue 2;
}
}
$fn = $languageFileName;
break 2;
}
}
}
$snippets = [];
$changeTime = 0;
$recentlyChangedFiles = [];
# Speichere den Inhalt der ausgewählten Datei in allen Sprachen in $snippets ab
foreach($languageObjects as $folder => $languageObject) {
foreach($languageObject->stringMap as $languageFileName => $languageFile) {
if($languageFileName === $fn) {
if($changeTime < filemtime($languageObject->filePath."/".$languageFileName)) {
unset($recentlyChangedFiles);
$changeTime = filemtime($languageObject->filePath."/".$languageFileName);
$recentlyChangedFiles[] = $languageObject->language;
} else if($changeTime === filemtime($languageObject->filePath."/".$languageFileName)) {
$recentlyChangedFiles[] = $languageObject->language;
}
foreach($languageFile as $key => $value) {
$snippets[$key][$languageObject->language] = $value;
}
continue 2;
}
}
}
# Fülle $snippets auf mit leeren Einträgen für die restlichen Sprachen
foreach($to as $t) {
foreach($snippets as $key => $langArray) {
if(!isset($langArray[$t])) {
$snippets[$key][$t] = "";
}
}
}
return view('languages.synoptic')
->with('to', $to) # Alle vorhandenen Sprachen
->with('texts', $snippets) # Array mit Sprachsnippets
->with('filename', $fn) # Name der Datei
->with('recentlyChangedFiles', $recentlyChangedFiles)
->with('otherFiles', $fileNames) # Namen der restlichen Sprachdateien
->with('title', trans('titles.languages.edit'));
}
private function htmlEscape($t, $to)
{
foreach ($t as $key => $langTexts) {
if ($langTexts !== "") {
foreach ($langTexts as $lang => $text) {
if ($lang !== $to) {
$t[$key][$lang] = htmlspecialchars($text);
}
}
}
}
return $t;
}
public function processSynopticPageInput(Request $request, $exclude = '', $chosenFile = '') {
$filename = $request->input('filename');
# Identifizieren des gedrückten Buttons
if(isset($request['download'])) {
# Auslesen, zippen und herunterladen der veränderten Dateien
$data = [];
$new = 0;
$editedFiles = [];
foreach ($request->all() as $key => $value) {
if ($key === "filename" || $value === "") {
continue;
}
$key = base64_decode($key);
# Pfad zur Datei anhand des Schlüsselnamens rekonstruieren (Schlüssel enthält Sprachkürzel)
$langdir = $this->extractLanguage($key);
$filepath = "lang/".$langdir."/".$filename;
if (strpos($key, "_new_") === 0 && $value !== "" || MailController::isEdited($this->processKey($key), $value, $filepath)) {
$new++;
$editedFiles[$langdir] = $filepath;
}
}
# Erneute Iteration über Request, damit Dateien mitsamt vorherigen Einträgen abgespeichert werden
foreach($request->all() as $key => $value) {
if ($key === "filename" || $value === "") {
continue;
}
$key = base64_decode($key);
# Pfad zur Datei anhand des Schlüsselnamens rekonstruieren (Schlüssel enthält Sprachkürzel)
$langdir = $this->extractLanguage($key);
# Überspringe Datei, falls diese nicht bearbeitet worden ist
if(!isset($editedFiles[$langdir])) {
continue;
}
# Key kuerzen, sodass er nur den eigentlichen Keynamen enthält
$key = $this->processKey($key);
if (!strpos($key, "#")) {
$data[$langdir][$key] = $value;
# Aufdröseln von 2D-Arrays
} else {
$ref = &$data;
do {
$ref = &$ref[$langdir][substr($key, 0, strpos($key, "#"))];
$key = substr($key, strpos($key, "#") + 1);
} while (strpos($key, "#"));
$ref = &$ref[$key];
$ref = $value;
}
}
if(file_exists("/tmp/langfiles.zip"))
unlink("/tmp/langfiles.zip");
$zip = new ZipArchive();
if (empty($data) || $zip->open("/tmp/langfiles.zip", ZipArchive::CREATE) !== TRUE) {
return redirect(url('synoptic', ['exclude' => $exclude]));
}
try{
# Erstelle Ausgabedateien
foreach($data as $lang => $entries) {
$output = json_encode($entries, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$output = preg_replace("/\{/si", "[", $output);
$output = preg_replace("/\}/si", "]", $output);
$output = preg_replace("/\": ([\"\[])/si", "\"\t=>\t$1", $output);
$output = "addEmptyDir($lang);
$zip->addFromString($lang."/".$filename, $output);
}
$zip->close();
return response()->download("/tmp/langfiles.zip", $filename.".zip");
} catch(ErrorException $e) {
echo("Failed to write ".$filename);
}
# Andernfalls weiterleiten zur nächsten Seite
} else {
$ex = [];
if ($exclude !== "") {
try {
$ex = unserialize(base64_decode($exclude));
} catch (\ErrorException $e) {
$ex = [];
}
if (!isset($ex["files"])) {
$ex["files"] = [];
}
}
if (!isset($ex["new"])) {
$ex["new"] = 0;
}
$ex['files'][] = basename($filename);
$ex = base64_encode(serialize($ex));
if(isset($request['nextpage'])) {
return redirect(url('synoptic', ['exclude' => $ex]));
} elseif(isset($request['chosenFile'])) {
return redirect(url('synoptic', ['exclude' => $ex, 'chosenFile' => $request['chosenFile']]));
}
}
}
private function createHints($t, $to)
{
foreach ($t as $key => $langTexts) {
if ($langTexts !== "") {
foreach ($langTexts as $lang => $text) {
if ($lang !== $to) {
if (preg_match("/:\w+/si", $text)) {
$t[$key][$lang] = preg_replace("/(:\w+)/si", "$1", $text);
}
if (preg_match("/<.*?>/si", $text)) {
$t[$key][$lang] = preg_replace("/(<.*?>)/si", "$1", $text);
}
}
}
}
}
return $t;
}
private function decodeExcludedFiles($exclude)
{
$ex = ['files' => [], 'new' => 0];
if ($exclude !== "") {
try {
$ex = unserialize(base64_decode($exclude));
} catch (ErrorException $e) {
$ex = ['files' => [], 'new' => 0];
}
}
return $ex;
}
private function getValues($values, $prefix = "")
{
$return = [];
if (!is_array($values)) {
return $return;
} else {
foreach ($values as $key => $value) {
if (is_array($value)) {
$return = array_merge($return, $this->getValues($value, $prefix . $key));
} elseif (is_string($value)) {
$return[$prefix . $key] = $value;
}
}
}
return $return;
}
private function hasToMuchDimensions($t)
{
foreach ($t as $key => $value) {
if (is_array($value)) {
foreach ($value as $lang => $val) {
if (is_array($val)) {
return true;
}
}
}
}
return false;
}
private function deMultidimensionalizeArray($t)
{
# Es gibt noch Besonderheiten in den Texten
# Es kann sein, dass statt einem String ein Array aus Strings als Werte existieren.
# Diese müssen aufgelöst werden:
$tmp = [];
foreach ($t as $key => $value) {
$isArray = false;
if (is_array($value)) {
foreach ($value as $lang => $val) {
if (is_array($val)) {
$isArray = true;
}
}
} else {
$tmp[$key] = $value;
continue;
}
if (!$isArray) {
$tmp[$key] = $value;
} else {
$tmp[$key] = "";
foreach ($value as $lang => $val) {
if (is_array($val)) {
foreach ($val as $key2 => $val) {
$tmp["\t" . $key . "#" . $key2][$lang] = $val;
}
}
}
}
}
return $tmp;
}
public function startsWith($haystack, $needle)
{
// search backwards starting from haystack length characters from the end
return $needle === "" || strrpos($haystack, $needle, -strlen($haystack)) !== false;
}
public function endsWith($haystack, $needle)
{
// search forward starting from end minus needle length characters
return $needle === "" || (($temp = strlen($haystack) - strlen($needle)) >= 0 && strpos($haystack, $needle, $temp) !== false);
}
private function extractLanguage($key)
{
# Kürzt bspw. "_new_de_redirect bzw. "de_redirect" zu "de"
preg_match("/^(?:_new_)?([^_]*)/", $key, $matches);
foreach($matches as $dir) {
if(strlen($dir) == 2)
return $dir;
}
}
private function processKey($key)
{
$key = trim($key);
# Kürzt bspw. "_new_de_redirect bzw. "de_redirect" zu "redirect"
preg_match("/^(?:_new_)?(?:[^_]*)_(\w*.?\w*#?.?\w*)/", $key, $matches);
foreach($matches as $processedKey) {
if(strpos($processedKey, "_") === FALSE) {
return $processedKey;
}
}
return $key;
}
}