Skip to content

Commit

Permalink
PISHPS-438: Add new Language PT (#934)
Browse files Browse the repository at this point in the history
* NTR: PISHPS-438: Added translation files

* NTR: added config to pipeline check, added importer

* NTR: fix config

* NTR: update config.xml

* NTR: PR fix

---------

Co-authored-by: Vitalij Mik <[email protected]>
  • Loading branch information
BlackScorp and Vitalij Mik authored Jan 30, 2025
1 parent 547cdf0 commit 74bd129
Show file tree
Hide file tree
Showing 11 changed files with 2,548 additions and 131 deletions.
27 changes: 25 additions & 2 deletions .phpunuhi.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<phpunuhi
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/boxblinkracer/phpunuhi/main/config.xsd"
xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/boxblinkracer/phpunuhi/refs/heads/main/schema/dev-main.xsd"
>
<translations>

Expand All @@ -13,6 +13,7 @@
<locale name="en-GB">./src/Resources/app/administration/src/snippet/en-GB.json</locale>
<locale name="nl-NL">./src/Resources/app/administration/src/snippet/nl-NL.json</locale>
<locale name="it-IT">./src/Resources/app/administration/src/snippet/it-IT.json</locale>
<locale name="pt-PT">./src/Resources/app/administration/src/snippet/pt-PT.json</locale>
</locales>
</set>

Expand All @@ -29,8 +30,30 @@
<locale name="en-GB">./src/Resources/snippet/en_GB/mollie-payments.en-GB.json</locale>
<locale name="nl-NL">./src/Resources/snippet/nl_NL/mollie-payments.nl-NL.json</locale>
<locale name="it-IT">./src/Resources/snippet/it_IT/mollie-payments.it-IT.json</locale>
<locale name="pt-PT">./src/Resources/snippet/pt_PT/mollie-payments.pt-PT.json</locale>
</locales>
</set>

<!--
<set name="plugin-settings">
<rules>
<emptyContent>
<key name="card.0.title">
<locale>*</locale>
</key>
</emptyContent>
</rules>
<format>
<shopware6 type="config" file="src/Resources/config/config.xml"/>
</format>
<locales>
<locale name="en-GB" base="true"></locale>
<locale name="de-DE"></locale>
<locale name="nl-NL"></locale>
<locale name="it-IT"></locale>
<locale name="pt-PT"></locale>
</locales>
</set>
-->
</translations>

</phpunuhi>
11 changes: 11 additions & 0 deletions shopware/Component/TranslationImporter/AppenderInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php
declare(strict_types=1);

namespace Mollie\Shopware\Component\TranslationImporter;

use DOMDocument;

interface AppenderInterface
{
public function append(DOMDocument $config, string $key, string $text, string $languageCode): AppenderResult;
}
29 changes: 29 additions & 0 deletions shopware/Component/TranslationImporter/AppenderResult.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php
declare(strict_types=1);

namespace Mollie\Shopware\Component\TranslationImporter;

final class AppenderResult
{
public const STATUS_SUCCESS = 'success';
public const STATUS_ERROR = 'error';
public const STATUS_WARNING = 'warning';
private string $message;
private string $status;

public function __construct(string $message, string $status = self::STATUS_SUCCESS)
{
$this->message = $message;
$this->status = $status;
}

public function getMessage(): string
{
return $this->message;
}

public function getStatus(): string
{
return $this->status;
}
}
78 changes: 78 additions & 0 deletions shopware/Component/TranslationImporter/ImportCSVCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?php
declare(strict_types=1);

namespace Mollie\Shopware\Component\TranslationImporter;

use League\Flysystem\Filesystem;
use Shopware\Core\Framework\Plugin;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

final class ImportCSVCommand extends Command
{
private Filesystem $fileSystem;
private AppenderInterface $appender;
private Plugin $plugin;
private array $keyMappings = [
'card.payments.shopwareFailedPayments.label' => 'card.payments.shopwareFailedPayment.label',
'card.payments.shopwareFailedPayments.helpText' => 'card.payments.shopwareFailedPayment.helpText',
'card.orderManagement.automaticCancelation.label' => 'card.orderManagement.automaticCancellation.label',
'card.orderManagement.automaticCancelation.helpText' => 'card.orderManagement.automaticCancellation.helpText',
'card.orderStateAutomation.ordeStateFinalState.label' => 'card.orderStateAutomation.orderStateFinalState.label',
'card.orderStateAutomation.ordeStateFinalState.helpText' => 'card.orderStateAutomation.orderStateFinalState.helpText',
'card.subscriptions.subscriptionsSkipRenewalsOnFailedPayments.label' => 'card.subscriptions.subscriptionSkipRenewalsOnFailedPayments.label',
'card.subscriptions.subscriptionsSkipRenewalsOnFailedPayments.helpText' => 'card.subscriptions.subscriptionSkipRenewalsOnFailedPayments.label',
];

public function __construct(Filesystem $fileSystem, AppenderInterface $appender, Plugin $plugin)
{
parent::__construct('mollie:translation:import');
$this->fileSystem = $fileSystem;
$this->appender = $appender;
$this->plugin = $plugin;
}

protected function configure()
{
$this->setDescription('Import translations from CSV file and stores it into config.xml');
$this->addArgument('path', InputArgument::REQUIRED, 'Path to source CSV file');
$this->addArgument('code', InputArgument::REQUIRED, 'Language to import e.g. "it-IT"');
}


protected function execute(InputInterface $input, OutputInterface $output): int
{
$path = $input->getArgument('path');
$localeCode = $input->getArgument('code');

if (! $this->fileSystem->fileExists($path)) {
$output->writeln('<error>File not found: ' . $path . '</error>');
return Command::FAILURE;
}


$pathToConfigXml = realpath($this->plugin->getPath() . '/Resources/config/config.xml');
if ($pathToConfigXml === false) {
$output->writeln('<error>Config file not found: ' . $path . '</error>');
return Command::FAILURE;
}

$stream = $this->fileSystem->readStream($path);
$domDocument = new \DOMDocument();
$domDocument->loadXML(file_get_contents($pathToConfigXml));
$row = fgetcsv($stream, null, ';');//skip header
while ($row = fgetcsv($stream, null, ';')) {
$key = $row[0];
$key = $this->keyMappings[$key] ?? $key;
$text = $row[2];
$result = $this->appender->append($domDocument, $key, $text, $localeCode);
$output->writeln('<' . $result->getStatus() . '>' . $result->getMessage() . '</' . $result->getStatus() . '>');
}
$domDocument->save($pathToConfigXml);


return Command::SUCCESS;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services
https://symfony.com/schema/dic/services/services-1.0.xsd">

<when env="dev">
<services>
<service id="Mollie\Shopware\Component\TranslationImporter\TranslationAppender"/>

<service id="Mollie\Shopware\Component\TranslationImporter\ImportCSVCommand">
<argument type="service" id="shopware.filesystem.private"/>
<argument type="service" id="Mollie\Shopware\Component\TranslationImporter\TranslationAppender"/>
<argument type="service" id="Kiener\MolliePayments\MolliePayments"/>
<tag name="console.command"/>
</service>

</services>
</when>

</container>
109 changes: 109 additions & 0 deletions shopware/Component/TranslationImporter/TranslationAppender.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
<?php
declare(strict_types=1);

namespace Mollie\Shopware\Component\TranslationImporter;

use DOMDocument;
use DOMXPath;

final class TranslationAppender implements AppenderInterface
{
public function append(DOMDocument $config, string $key, string $text, string $languageCode): AppenderResult
{
$domXpath = new DOMXPath($config);

$keyParts = explode('.', $key);
$lastKeyPart = array_pop($keyParts);


$path = '/';
foreach ($keyParts as $keyPart) {
$keyPart = mb_strtolower($keyPart);

$searchParts = [
"following-sibling::" . $keyPart, //search for the HTMLElement
"following::" . $keyPart, //search for the HTMLElement
"following::title[contains(translate(text(),'ABCDEFGHIJKLMNOPQRSTUVWXYZ ','abcdefghijklmnopqrstuvwxyz'),'" . $keyPart . "')]",//search for the title which contains the key part,
"following::name[contains(translate(text(),'ABCDEFGHIJKLMNOPQRSTUVWXYZ ','abcdefghijklmnopqrstuvwxyz'),'" . $keyPart . "')]",//search for the name which contains the key part,
"descendant::" . $keyPart, //search for the HTMLElement
"descendant::title[contains(translate(text(),'ABCDEFGHIJKLMNOPQRSTUVWXYZ ','abcdefghijklmnopqrstuvwxyz'),'" . $keyPart . "')]",//search for the title which contains the key part,
"descendant::name[contains(translate(text(),'ABCDEFGHIJKLMNOPQRSTUVWXYZ ','abcdefghijklmnopqrstuvwxyz'),'" . $keyPart . "')]",//search for the name which contains the key part,
];

if (is_numeric($keyPart)) {
//convert options.0. to options/*[0]
$searchParts = [
"*[" . $keyPart . "]"
];
}

foreach ($searchParts as $searchPart) {
$result = $domXpath->query($path . '/' . $searchPart);

if ($result->count() === 0) {
continue;
}
$path .= '/' . $searchPart;
break;
}
}

$replaceXpathQuery = $path . '/' . $lastKeyPart . '[@lang="' . $languageCode . '"]';
$domElement = $domXpath->query($replaceXpathQuery);
if ($domElement->count() === 0) {
$replaceXpathQuery = $path . '/following-sibling::' . $lastKeyPart . '[@lang="' . $languageCode . '"]';
$domElement = $domXpath->query($replaceXpathQuery);

if ($domElement->count() === 0) {
$replaceXpathQuery = $path . '/following::' . $lastKeyPart . '[@lang="' . $languageCode . '"]';
$domElement = $domXpath->query($replaceXpathQuery);
}
}

if ($domElement->count() === 1) {
$oldElement = $domElement->item(0);

if ($oldElement !== null) {
$textElement = $oldElement->firstChild;
if ($textElement instanceof \DOMText) {
$textElement->data = $text;
}
}

return new AppenderResult(sprintf('Replace "%s" with the key %s', $text, $key));
}


$domElement = $domXpath->query($path);

//we expect to find exactly one node, not multiple
if ($domElement->count() === 0) {
return new AppenderResult(sprintf('Failed to find entry for key "%s" with the path "%s"', $key, $path), AppenderResult::STATUS_ERROR);
}

$newNode = $config->createElement($lastKeyPart, $text);
$attribute = $config->createAttribute('lang');
$attribute->value = $languageCode;
$newNode->appendChild($attribute);
$targetNodePath = $path . '/descendant::' . $lastKeyPart . '[last()]';

$targetChildren = $domXpath->query($targetNodePath);

if ($targetChildren->count() === 0) {
$targetNodePath = $path . '/following-sibling::' . $lastKeyPart . '[last()]';
}

$targetChildren = $domXpath->query($targetNodePath);

if ($targetChildren->count() === 1) {
$targetNode = $targetChildren->item(0);
$targetNode->parentNode->insertBefore($newNode, $targetNode->nextSibling);
return new AppenderResult(sprintf('Appended "%s" with the key %s', $text, $key));
}

if ($targetChildren->count() === 0) {
$domElement->item(0)->appendChild($newNode);
}
return new AppenderResult(sprintf('Created new entry "%s" with the key %s', $text, $key));
}
}
Loading

0 comments on commit 74bd129

Please sign in to comment.