├── LICENSE.txt
├── README.md
├── composer.json
└── src
├── Console
└── Command
│ ├── I18nCsvDiffCommand.php
│ └── I18nCsvTranslateCommand.php
├── etc
├── acl.xml
├── adminhtml
│ └── system.xml
├── config.xml
├── di.xml
└── module.xml
└── registration.php
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2022, Hyvä Themes B.V.
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | 1. Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | 2. Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | 3. Neither the name of the copyright holder nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Hyvä Themes - Magento translation CSV comparison command
2 |
3 | [](https://hyva.io/)
4 |
5 | ## hyva-themes/magento2-i18n-csv-diff
6 |
7 | ![Supported Magento Versions][ico-compatibility]
8 |
9 | This module adds the `bin/magento i18n:diff-csv` and `i18n:translate-csv` commands.
10 |
11 | ### i18n:diff-csv
12 |
13 | The command takes two CSV files as arguments.
14 | It displays all translations that are present in the first CSV file but not in the second, based on the first colum in the files.
15 |
16 | ### i18n:translate
17 |
18 | The command takes a target language 2-letter ISO code as the argument.
19 | It reads a Magento localization CSV dictionary from stdin, translates it using the DeepL API, and writes it to stdout.
20 | Be sure to check the automatic translations afterwards!
21 |
22 | ## Usage Examples:
23 |
24 | * Collect all Magento and Hyvä strings:
25 | ```sh
26 | bin/magento i18n:collect-phrases vendor/magento/ > magento-strings.csv
27 | bin/magento i18n:collect-phrases vendor/hyva-themes/magento2-default-theme/ > hyva-strings.csv
28 | bin/magento i18n:collect-phrases vendor/hyva-themes/magento2-theme-module/ >> hyva-strings.csv
29 | ```
30 | * Find all Hyvä specific translations that are not part of native Magento:
31 | ```sh
32 | bin/magento i18n:diff-csv hyva-strings.csv magento-strings.csv
33 | ```
34 |
35 | * Find all translations that are missing in a Hyvä translation file:
36 | ```sh
37 | bin/magento i18n:diff-csv hyva-strings.csv i18n/de_DE.csv
38 | ```
39 | * Find all translations that are in a translation file but are not used in Hyvä:
40 | ```sh
41 | bin/magento i18n:diff-csv i18n/de_DE.csv hyva-strings.csv
42 | ```
43 | * Add new translations to an existing dictionary file.
44 | ```sh
45 | bin/magento i18n:diff-csv hyva-strings.csv i18n/de_DE.csv | bin/magento i18n:translate-csv DE >> i18n/de_DE.csv
46 | ```
47 |
48 | ## Installation
49 |
50 | 1. Install via composer
51 | ```
52 | composer require hyva-themes/magento2-i18n-csv-diff
53 | ```
54 | 2. Enable module
55 | ```
56 | bin/magento setup:upgrade
57 | ```
58 |
59 | ## Configuration
60 |
61 | To use the Deep`i18n:translate-csv` command, configure your [API key](https://www.deepl.com/pro-api?cta=header-pro-api/) in the system configuration at *Hyva Themes > Localization CLI > Translation > DeepL API Key*.
62 |
63 | ## License
64 |
65 | The BSD-3-Clause License. Please see [License File](LICENSE.txt) for more information.
66 |
67 | [ico-compatibility]: https://img.shields.io/badge/magento-%202.3%20|%202.4-brightgreen.svg?logo=magento&longCache=true&style=flat-square
68 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hyva-themes/magento2-i18n-csv-diff",
3 | "description": "Magento command to display all translations that are present in the first CSV file but not in the second.",
4 | "require": {
5 | "php": ">=7.4.0"
6 | },
7 | "type": "magento2-module",
8 | "license": [
9 | "BSD-3-Clause"
10 | ],
11 | "autoload": {
12 | "files": [
13 | "src/registration.php"
14 | ],
15 | "psr-4": {
16 | "Hyva\\I18nCsvDiff\\": "src/"
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/Console/Command/I18nCsvDiffCommand.php:
--------------------------------------------------------------------------------
1 | ignoreStrings = $ignoreStrings;
36 | parent::__construct();
37 | }
38 |
39 | protected function configure()
40 | {
41 | $this->setName('i18n:diff-csv');
42 | $this->setDescription('Display all translations that are present in the first CSV file but not in the second.');
43 | $this->addArgument('file-a', InputArgument::REQUIRED, 'First i18n CSV file');
44 | $this->addArgument('file-b', InputArgument::REQUIRED, 'Second i18n CSV file');
45 | }
46 |
47 | protected function execute(InputInterface $input, OutputInterface $output)
48 | {
49 | setlocale(LC_ALL, "en_US.UTF-8");
50 | $fileA = $input->getArgument('file-a');
51 | $fileB = $input->getArgument('file-b');
52 |
53 | $recordsA = $this->readFirstCol($fileA);
54 | sort($recordsA);
55 |
56 | $recordsB = $this->readFirstCol($fileB);
57 | sort($recordsB);
58 |
59 | $diff = diff($recordsA, $recordsB);
60 |
61 | foreach ($diff as $r) {
62 | // display the record twice so the output can be copy&pasted into a translation CSV file
63 | fputcsv(STDOUT, [$r, $r]);
64 | }
65 | return 0;
66 | }
67 |
68 | private function readFirstCol(string $file): array
69 | {
70 | $fileHandle = fopen($file, 'r');
71 | $records = [];
72 | while (!feof($fileHandle)) {
73 | $row = fgetcsv($fileHandle);
74 |
75 | // ignore empty lines and known invalid record
76 | if ($row && $row[0] !== null && false === search($row[0], $this->ignoreStrings)) {
77 | $records[] = $row[0];
78 | }
79 | }
80 | return $records;
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/src/Console/Command/I18nCsvTranslateCommand.php:
--------------------------------------------------------------------------------
1 | httpClientFactory = $httpClientFactory;
41 | $this->scopeConfig = $scopeConfig;
42 | parent::__construct();
43 | }
44 |
45 | protected function configure()
46 | {
47 | $this->setName('i18n:translate-csv');
48 | $this->setDescription(
49 | 'Translate a Magento2 localization CSV to a language using DeepL. ' .
50 | 'Be sure to check the translation afterwards!'
51 | );
52 | $this->addOption('in', null, InputOption::VALUE_OPTIONAL, 'Input CSV', 'stdin');
53 | $this->addOption('out', null, InputOption::VALUE_OPTIONAL, 'Input CSV', 'stdout');
54 | $this->addArgument('target-lang', InputArgument::REQUIRED, 'The target language code (for example NL or DE)');
55 | }
56 |
57 | protected function execute(InputInterface $input, OutputInterface $output)
58 | {
59 | $inFileHandle = $input->getOption('in') === 'stdin'
60 | ? STDIN
61 | : fopen($input->getOption('in'), 'r');
62 | $outFileHandle = $input->getOption('out') === 'stdout'
63 | ? STDOUT
64 | : fopen($input->getOption('out'), 'r');
65 |
66 | $lang = strtoupper($input->getArgument('target-lang'));
67 |
68 | while (!feof($inFileHandle)) {
69 | $row = fgetcsv($inFileHandle);
70 |
71 | // ignore empty lines and known invalid record
72 | if (!$row || $row[0] === null) {
73 | continue;
74 | }
75 | fputcsv($outFileHandle, [$row[0], $this->translate($lang, $row[0])]);
76 | }
77 |
78 | return 0;
79 | }
80 |
81 | private function translate(string $lang, string $phrase): string
82 | {
83 | $key = $this->scopeConfig->getValue('hyva_themes_i18n/translation/deepl_api_key');
84 |
85 | $client = $this->httpClientFactory->create();
86 | $client->post('https://api-free.deepl.com/v2/translate', [
87 | 'tag_handling' => 'xml',
88 | 'split_sentences' => 'nonewlines',
89 | 'source_lang' => 'EN',
90 | 'auth_key' => $key,
91 | 'text' => $phrase,
92 | 'target_lang' => $lang,
93 | ]);
94 | $result = json_decode($client->getBody(), true);
95 | return $result['translations'][0]['text'] ?? $phrase;
96 | }
97 |
98 | }
99 |
--------------------------------------------------------------------------------
/src/etc/acl.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/src/etc/adminhtml/system.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
12 |
13 |
14 |
15 |
16 |
18 |
19 | hyva_themes
20 | Hyvy_I18nCsvDiff::config_hyva_i18n
21 |
23 |
24 |
26 |
27 | Magento\Config\Model\Config\Backend\Encrypted
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/src/etc/config.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/etc/di.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
12 |
13 |
14 |
15 | - Hyva\I18nCsvDiff\Console\Command\I18nCsvDiffCommand
16 | - Hyva\I18nCsvDiff\Console\Command\I18nCsvTranslateCommand
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/src/etc/module.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/registration.php:
--------------------------------------------------------------------------------
1 |