diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..03211e4
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+vendor
+var
+bin
+.idea
\ No newline at end of file
diff --git a/README.md b/README.md
index 5a2c409..72a760f 100755
--- a/README.md
+++ b/README.md
@@ -34,4 +34,9 @@ The highest quality of translation is ensured by artificial intelligence.
Extension uses [Open AI API](https://openai.com/product) - ChatGPT v3.5
### Requirements:
-* Akeneo PIM >= 6.x
\ No newline at end of file
+* Akeneo PIM >= 6.x
+
+## Contact
+`Akeneo OpenAI translator` is brought to you by [Macopedia](https://macopedia.com/).
+
+[Contact us](https://macopedia.com/contact)
\ No newline at end of file
diff --git a/composer.json b/composer.json
index cfc2834..78d4a7c 100755
--- a/composer.json
+++ b/composer.json
@@ -21,7 +21,8 @@
}
},
"require": {
- "orhanerday/open-ai": "^4.7"
+ "orhanerday/open-ai": "^4.7",
+ "akeneo/pim-community-dev": "^6.0.0||^7.0.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.15",
@@ -30,19 +31,20 @@
},
"scripts": {
"phpstan": [
- "vendor/bin/phpstan --configuration=phpstan.neon"
+ "vendor/bin/phpstan analyse --configuration=\"config/phpstan.neon\""
],
"phpunit": [
- "vendor/bin/phpunit --colors=always"
+ "vendor/bin/phpunit --colors=always --configuration=\"config/phpunit.xml.dist\""
+ ],
+ "cs:fix": [
+ "vendor/bin/php-cs-fixer fix --config=\"config/.php-cs-fixer.php\" --using-cache no --allow-risky=yes"
],
"test": [
- "vendor/bin/php-cs-fixer fix --dry-run",
+ "@cs:fix",
"@phpstan",
"@phpunit"
- ],
- "cs:fix": [
- "vendor/bin/php-cs-fixer fix"
]
+
},
"minimum-stability": "stable",
"config": {
diff --git a/config/.php-cs-fixer.php b/config/.php-cs-fixer.php
new file mode 100644
index 0000000..338b1ce
--- /dev/null
+++ b/config/.php-cs-fixer.php
@@ -0,0 +1,45 @@
+in(__DIR__ . '/../')
+ ->exclude(
+ [
+ 'var',
+ 'node_modules',
+ 'upgrades',
+ ]
+ )->notPath(
+ [
+ 'public/index.php',
+ 'public/api.php',
+ 'config/bootstrap.php',
+ 'src/Kernel.php',
+ ]
+ );
+
+return (new PhpCsFixer\Config())
+ ->setCacheFile(__DIR__ . '/../var/.php_cs.cache')
+ ->setRules(
+ [
+ '@PSR12' => true,
+ 'blank_line_after_opening_tag' => true,
+ 'braces' => ['allow_single_line_closure' => true],
+ 'compact_nullable_typehint' => true,
+ 'single_quote' => true,
+ 'concat_space' => ['spacing' => 'one'],
+ 'declare_equal_normalize' => ['space' => 'none'],
+ 'function_typehint_space' => true,
+ 'new_with_braces' => true,
+ 'method_argument_space' => ['on_multiline' => 'ensure_fully_multiline'],
+ 'no_empty_statement' => true,
+ 'no_leading_import_slash' => true,
+ 'no_leading_namespace_whitespace' => true,
+ 'no_whitespace_in_blank_line' => true,
+ 'return_type_declaration' => ['space_before' => 'none'],
+ 'single_trait_insert_per_statement' => true,
+ 'array_syntax' => ['syntax' => 'short'],
+ 'global_namespace_import' => ['import_classes' => true, 'import_constants' => true, 'import_functions' => true],
+ 'declare_strict_types' => true
+ ]
+ )
+ ->setFinder($finder);
diff --git a/config/phpstan.neon b/config/phpstan.neon
new file mode 100644
index 0000000..8e20c9c
--- /dev/null
+++ b/config/phpstan.neon
@@ -0,0 +1,6 @@
+parameters:
+ level: 6
+ paths:
+ - ../src
+ #- ../tests
+ tmpDir: ../var/phpstan
diff --git a/config/phpunit.xml.dist b/config/phpunit.xml.dist
new file mode 100644
index 0000000..4899693
--- /dev/null
+++ b/config/phpunit.xml.dist
@@ -0,0 +1,19 @@
+
+
+
+
+
+ src
+
+
+
+
+
+
+
+
+
+ ../tests
+
+
+
diff --git a/src/Macopedia/Translator/Client/OpenAiClient.php b/src/Macopedia/Translator/Client/OpenAiClient.php
index f68f6ad..c484c98 100644
--- a/src/Macopedia/Translator/Client/OpenAiClient.php
+++ b/src/Macopedia/Translator/Client/OpenAiClient.php
@@ -1,7 +1,10 @@
client->chat($message);
if ($response === false) {
- throw new InvalidOpenAiResponseException();
+ throw new InvalidOpenAiResponseException($message);
}
$response = Response::fromArray(json_decode($response, true));
@@ -50,6 +53,8 @@ public function ask(string $role, string $content): ?Response
return $response;
}
+
+ #[ArrayShape(['model' => "string", 'messages' => "\string[][]"])]
private function generateMessage(string $role, string $content): array
{
return [
@@ -61,4 +66,4 @@ private function generateMessage(string $role, string $content): array
]
];
}
-}
\ No newline at end of file
+}
diff --git a/src/Macopedia/Translator/Client/OpenAiClient/Choice.php b/src/Macopedia/Translator/Client/OpenAiClient/Choice.php
index 5ed8575..b35755d 100644
--- a/src/Macopedia/Translator/Client/OpenAiClient/Choice.php
+++ b/src/Macopedia/Translator/Client/OpenAiClient/Choice.php
@@ -1,5 +1,7 @@
message;
}
-}
\ No newline at end of file
+}
diff --git a/src/Macopedia/Translator/Client/OpenAiClient/Choices.php b/src/Macopedia/Translator/Client/OpenAiClient/Choices.php
index beadff1..9d3d5f6 100644
--- a/src/Macopedia/Translator/Client/OpenAiClient/Choices.php
+++ b/src/Macopedia/Translator/Client/OpenAiClient/Choices.php
@@ -1,5 +1,7 @@
answers;
}
-}
\ No newline at end of file
+}
diff --git a/src/Macopedia/Translator/Client/OpenAiClient/Message.php b/src/Macopedia/Translator/Client/OpenAiClient/Message.php
index d0adc69..ad4448b 100644
--- a/src/Macopedia/Translator/Client/OpenAiClient/Message.php
+++ b/src/Macopedia/Translator/Client/OpenAiClient/Message.php
@@ -1,5 +1,7 @@
content;
}
-}
\ No newline at end of file
+}
diff --git a/src/Macopedia/Translator/Client/OpenAiClient/Response.php b/src/Macopedia/Translator/Client/OpenAiClient/Response.php
index d068263..b089f20 100644
--- a/src/Macopedia/Translator/Client/OpenAiClient/Response.php
+++ b/src/Macopedia/Translator/Client/OpenAiClient/Response.php
@@ -1,21 +1,23 @@
setTimestamp($data['created']),
+ (new DateTime())->setTimestamp($data['created']),
$data['model'],
new Choices($data['choices']),
$data['usage']
@@ -54,4 +56,4 @@ public function getFirstChoiceMessage(): ?string
}
return $firstMessage->getMessage()->getContent();
}
-}
\ No newline at end of file
+}
diff --git a/src/Macopedia/Translator/Connector/Processor/MassEdit/TranslateAttributesProcessor.php b/src/Macopedia/Translator/Connector/Processor/MassEdit/TranslateAttributesProcessor.php
index bd8e5ff..ac730d8 100644
--- a/src/Macopedia/Translator/Connector/Processor/MassEdit/TranslateAttributesProcessor.php
+++ b/src/Macopedia/Translator/Connector/Processor/MassEdit/TranslateAttributesProcessor.php
@@ -1,30 +1,21 @@
'ecommerce',
* 'sourceLocale' => 'pl_PL',
* 'targetLocale' => 'en_US',
- * 'translatedAttributes' => [
+ * 'attributesToTranslate' => [
* 'name',
* 'description',
* ]
@@ -54,44 +45,6 @@ public function process(mixed $item): ProductInterface|ProductModelInterface
*/
private function translateAttributes(mixed $product, array $action): ProductInterface|ProductModelInterface
{
- $sourceScope = $action['sourceChannel'];
- $targetScope = $action['targetChannel'];
- $sourceLocaleAkeneo = $action['sourceLocale'];
- $targetLocaleAkeneo = $action['targetLocale'];
- //$sourceLocale = Language::fromCode(explode('_', $sourceLocaleAkeneo)[0]);
- $targetLocale = Language::fromCode(explode('_', $targetLocaleAkeneo)[0]);
- $attributeCodes = $action['translatedAttributes'];
-
- foreach ($attributeCodes as $attributeCode) {
- /** @var AttributeInterface|null $attribute */
- $attribute = $this->attributeRepository->findOneByIdentifier($attributeCode);
- if (!$this->checkAttributeEditable->isEditable($product, $attribute)) {
- continue;
- }
-
- if (!$attribute->isScopable()) {
- $sourceScope = null;
- $targetScope = null;
- }
- /** @var ValueInterface|null $attributeValue */
- $attributeValue = $product->getValue($attributeCode, $sourceLocaleAkeneo, $sourceScope);
- if ($attributeValue === null) {
- continue;
- }
-
- $sourceText = $attributeValue->getData();
-
- $translatedText = $this->translator->translate(
- $sourceText,
- $targetLocale
- );
-
- $this->propertySetter->setData($product, $attributeCode, $translatedText, [
- 'locale' => $targetLocaleAkeneo,
- 'scope' => $targetScope,
- ]);
- }
-
- return $product;
+ return $this->translateAttributesService->translateAttributes($product, $action);
}
}
diff --git a/src/Macopedia/Translator/DependencyInjection/MacopediaTranslatorExtension.php b/src/Macopedia/Translator/DependencyInjection/MacopediaTranslatorExtension.php
index a642208..1ef4b02 100644
--- a/src/Macopedia/Translator/DependencyInjection/MacopediaTranslatorExtension.php
+++ b/src/Macopedia/Translator/DependencyInjection/MacopediaTranslatorExtension.php
@@ -1,5 +1,7 @@
load('connector.yml');
$loader->load('services.yml');
}
}
diff --git a/src/Macopedia/Translator/Exception/InvalidOpenAiResponseException.php b/src/Macopedia/Translator/Exception/InvalidOpenAiResponseException.php
index 187407a..ed975a0 100644
--- a/src/Macopedia/Translator/Exception/InvalidOpenAiResponseException.php
+++ b/src/Macopedia/Translator/Exception/InvalidOpenAiResponseException.php
@@ -1,11 +1,15 @@
-
- 0){ %> readonly="true"<% } %>>
+ 0){ %> readonly="true"<% } %>>
<% _.each(channels, function (channel, key){ %>
<% }); %>
@@ -36,7 +36,7 @@
- 0){ %> readonly="true"<% } %>>
+ 0){ %> readonly="true"<% } %>>
<% _.each(locales, function (locale, key){ %>
<% }); %>
@@ -50,7 +50,7 @@
- 0){ %> readonly="true"<% } %>>
+ 0){ %> readonly="true"<% } %>>
<% _.each(channels, function (channel, key){ %>
<% }); %>
@@ -64,7 +64,7 @@
- 0){ %> readonly="true"<% } %>>
+ 0){ %> readonly="true"<% } %>>
<% _.each(locales, function (locale, key){ %>
<% }); %>
diff --git a/src/Macopedia/Translator/Resources/translations/messages.fr.yml b/src/Macopedia/Translator/Resources/translations/messages.fr.yml
new file mode 100644
index 0000000..362e68f
--- /dev/null
+++ b/src/Macopedia/Translator/Resources/translations/messages.fr.yml
@@ -0,0 +1,3 @@
+macopedia:
+ acl:
+ label: "Originaux d'attributs groupés"
\ No newline at end of file
diff --git a/src/Macopedia/Translator/Service/TranslateAttributesService.php b/src/Macopedia/Translator/Service/TranslateAttributesService.php
new file mode 100644
index 0000000..292bbb3
--- /dev/null
+++ b/src/Macopedia/Translator/Service/TranslateAttributesService.php
@@ -0,0 +1,86 @@
+> $action
+ */
+ public function translateAttributes(mixed $product, array $action): ProductInterface|ProductModelInterface
+ {
+ [$sourceScope, $targetScope, $sourceLocaleAkeneo, $targetLocaleAkeneo, $targetLocale, $attributesToTranslate] = $this->extractVariables($action);
+
+ foreach ($attributesToTranslate as $attributeCode) {
+ $attribute = $this->attributeRepository->findOneByIdentifier($attributeCode);
+ if (!$this->checkAttributeEditable->isEditable($product, $attribute)) {
+ continue;
+ }
+
+ if (!($attribute instanceof ScalarValue)) {
+ continue;
+ }
+
+ if (!$attribute->isScopable()) {
+ $sourceScope = null;
+ $targetScope = null;
+ }
+
+ $attributeValue = $product->getValue($attributeCode, $sourceLocaleAkeneo, $sourceScope);
+ if ($attributeValue === null) {
+ continue;
+ }
+
+ $translatedText = $this->translator->translate(
+ $attributeValue->getData(),
+ $targetLocale
+ );
+
+ $this->propertySetter->setData($product, $attributeCode, $translatedText, [
+ 'locale' => $targetLocaleAkeneo,
+ 'scope' => $targetScope,
+ ]);
+ }
+
+ return $product;
+ }
+
+ private function extractVariables(array $action): array
+ {
+ Assert::keyExists($action, 'sourceChannel');
+ Assert::keyExists($action, 'targetChannel');
+ Assert::keyExists($action, 'sourceLocale');
+ Assert::keyExists($action, 'targetLocale');
+ Assert::keyExists($action, 'attributesToTranslate');
+
+ return [
+ 'sourceScope' => $action['sourceChannel'],
+ 'targetScope' => $action['targetChannel'],
+ 'sourceLocaleAkeneo' => $action['sourceLocale'],
+ 'targetLocaleAkeneo' => $action['targetLocale'],
+ 'targetLocale' => Language::fromCode(explode('_', $action['targetLocale'])[0]),
+ 'attributesToTranslate' => $action['attributesToTranslate']
+ ];
+ }
+}
diff --git a/src/Macopedia/Translator/Translator/Language.php b/src/Macopedia/Translator/Translator/Language.php
index 9d0fc1e..9bf3fd9 100644
--- a/src/Macopedia/Translator/Translator/Language.php
+++ b/src/Macopedia/Translator/Translator/Language.php
@@ -1,5 +1,6 @@