Spaghetticode! Kein Luxus! Code-Schnipsel vergleicht zwei Ländervarianten einer Joomla-Sprachdatei, z.B. en-GB.plg_system_example.ini (im Code die $mama) und de-DE.plg_system_example.ini (im Code das $child).

Voraussetzungen

  • Die Dateien müssen dem ini-Standard entsprechen, also 1 Zeile pro Sprachstring. PLG_EXAMPLE_OPTIONAL="(optional)". Keine Zeilenumbrüche etc.
  • Die Sprachdateien befinden sich im einzutragenden $langsPath in Unterordnern wie in Joomla üblich, z.B. en-GB/ und de-DE/.
  • Benötigt ggf. Anpassungen für Joomla 4, da dort der Dateinamen-Prefix, z.B. de-DE. , auch weggelassen werden darf.

Was es tut

  • Die Sprachstring-Platzhalter werden vom Skript alphabetisch sortiert.
  • Fehlende Sprachstring-Platzhalter, die in der $mama, existieren, aber im $child fehlen, werden ins's $child kopiert, mit einem Prefix-Kommentar ;;NOT-FOUND-IN-child;;. Der Code geht also davon aus, dass die $mama bereits vollständig ist. Natürlich kann man für einen Gegentest $mama und $child austauschen im Skript.
  • Doppelte Sprach-Platzhalter, gefunden in der selben Datei, brechen den Code ab mit einem entsprechenden Hinsweis DOPPELTER key xyz in Datei abc.
  • Wo identische Übersetzungen für den selben Sprachstringplatzhalter gefunden werden, erfolgt am Ende eine Ausgabe Folgende eventuell nicht übersetzt? In beiden Dateien gleich.
  • Veraltete Double-Quote-Platzhalter "__QQ__" werden in \" umgewandelt.
  • Erzeugt Kopien der Original-Sprachdateien, z.B. en-GB.plg_system_example-copy.ini für händische Kontrolle und Nacharbeit und ggf. Copy&Paste in die Originale.

Ausgabe und Skript

Gerenderte Ausgabe der Datei language-files-synchronize.php

$mama, $child und $xyz-copy

Original $mama: /media/php-includes_ghsvs/language/en-GB/en-GB.plg_system_example.ini
Copy $mama: /media/php-includes_ghsvs/language/en-GB/en-GB.plg_system_example-copy.ini
----------
Original $child: /media/php-includes_ghsvs/language/de-DE/de-DE.plg_system_example.ini
Copy $child: /media/php-includes_ghsvs/language/de-DE/de-DE.plg_system_example-copy.ini
----------

Folgende eventuell nicht übersetzt? In beiden Dateien gleich.
Array
(
    [PLG_A_EXAMPLE_DESC5] => Example.
    [PLG_B_EXAMPLE_DESC4] => Ding dong dang.
    [PLG_EXAMPLE_DESC] => Extremly \"reduced\" in blah.
)

Quelltext der Datei language-files-synchronize.php

<?php
\defined('_JEXEC') or die;

use Joomla\CMS\Uri\Uri;

### Konfiguration START.

// Verzeichnis mit Sprachdateien.
$langsPath = '/media/php-includes_ghsvs/language/';

// Mitteleil der Dateien. Bspw. in 'en-GB.plg_system_example ini'.
// Auch denkbar für .sys.ini-Dateien: 'plg_system_example.sys'.
$filePart  = 'plg_system_example';

// $mama ist die Referenz für $child.
$mama      = 'en-GB';
$child     = 'de-DE';

// Ich bevorzuge Leerzeilen zwischen den Einzelzeilern.
$outputLineEndings = "\n\n";

// Dateinamen-Postfix für die bearbeiteten Dateien.
$copiedFileEnding = '-copy';

### Konfiguration ENDE.

$sepa = '|-[x::SEPA-CHECKER::]-|';

$mamaFile = $langsPath . $mama . '/' . $mama . '.' . $filePart;
$mamaFileAbs = JPATH_SITE . $mamaFile;

$mamaLines   = file($mamaFileAbs . '.ini',
	FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);

$mamaStrings = parse_ini_file($mamaFileAbs . '.ini');

$mamaLinesDoubleCheck = $sepa . implode($sepa, $mamaLines);

foreach ($mamaStrings as $key => $string)
{
	if (substr_count($mamaLinesDoubleCheck, $sepa . $key . '=') > 1)
	{
		echo "DOPPELTER key in $mamaFile : " . PHP_EOL . $key . PHP_EOL . PHP_EOL;
		exit;
	}
}

$childFile = $langsPath . $child . '/' . $child . '.' . $filePart;
$childFileAbs = JPATH_SITE . $childFile;

$childLines   = file($childFileAbs . '.ini',
	FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);

$childStrings = parse_ini_file($childFileAbs . '.ini');

$childLinesDoubleCheck = $sepa . implode($sepa, $childLines);

foreach ($childStrings as $key => $string)
{
	if (substr_count($childLinesDoubleCheck, $sepa . $key . '=') > 1)
	{
		echo "DOPPELTER key in $childFile : " . PHP_EOL . $key . PHP_EOL . PHP_EOL;
		exit;
	}
}

$collectChilds = array();
ksort($mamaStrings);

foreach ($mamaStrings as $key => $string)
{
	$mamaStrings[$key] = str_replace(array('"_QQ_"', '"'), '_QQ_', $string);
}

foreach ($childStrings as $key => $string)
{
	$childStrings[$key] = str_replace(array('"_QQ_"', '"'), '_QQ_', $string);
}

$collectIdenticals = array();

foreach ($mamaStrings as $key => $string)
{
	$mamaStrings[$key] = $key . '="' . str_replace('_QQ_', '\"', $string) . '"';

	if (!isset($childStrings[$key]))
	{
		$collectChilds[] = ';;NOT-FOUND-IN-child;;' .  $key . '="'
			. str_replace('_QQ_', '\"', $string) . '"';
	}
	else
	{
		if ($string === $childStrings[$key])
		{
			$collectIdenticals[$key] = htmlspecialchars(str_replace('_QQ_', '\"',
				$string));
		}

		$collectChilds[] = $key . '="' . str_replace('_QQ_', '\"',
			$childStrings[$key]) . '"';
	}
}

file_put_contents($childFileAbs . $copiedFileEnding . '.ini',
	implode($outputLineEndings, $collectChilds));

file_put_contents($mamaFileAbs . $copiedFileEnding . '.ini',
	implode($outputLineEndings, $mamaStrings));

echo '<h5>$mama, $child und $xyz-copy</h5>' . PHP_EOL;

$version = '?v=' . time();

$dings = '<p>Original $mama: <a href="' . Uri::root()
	. ltrim($mamaFile . '.ini', '/') . '">'
	. $mamaFile . '.ini' . '</a><br>' . PHP_EOL;
$dings .= 'Copy $mama: <a href="' . Uri::root()
	. ltrim($mamaFile . $copiedFileEnding . '.ini' . $version, '/') . '">'
	. $mamaFile . $copiedFileEnding . '.ini' . '</a><br>' . PHP_EOL;
$dings .= '----------<br>' . PHP_EOL ;

$dings .= 'Original $child: <a href="' . Uri::root()
	. ltrim($childFile . '.ini', '/') . '">'
	. $childFile . '.ini' . '</a><br>' . PHP_EOL;
$dings .= 'Copy $child: <a href="' . Uri::root()
	. ltrim($childFile . $copiedFileEnding . '.ini' . $version, '/') . '">'
	. $childFile . $copiedFileEnding . '.ini' . '</a><br>' . PHP_EOL;
$dings .= '----------<br>' . PHP_EOL . '</p>' ;
echo $dings;


echo '<h5>Folgende eventuell nicht übersetzt? In beiden Dateien gleich.</h5>'
	. PHP_EOL;
echo '<pre>' . print_r($collectIdenticals, true) . '</pre>' . PHP_EOL;