Skip to content

Commit e3d6a44

Browse files
ENGCOM-8694: Fix #11175 - i18n:collect-phrases -m can't find many important Magento phrases - added parsing of the attr translations via \$t('Text')\ #31804
- Merge Pull Request #31804 from maksymz/magento2:2.4-develop - Merged commits: 1. 754ea5f 2. 77daafd 3. f847294
2 parents f6e06ec + f847294 commit e3d6a44

File tree

6 files changed

+130
-31
lines changed

6 files changed

+130
-31
lines changed

setup/src/Magento/Setup/Module/I18n/Parser/Adapter/Html.php

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,24 @@ class Html extends AbstractAdapter
1919
* Covers
2020
* <span><!-- ko i18n: 'Next'--><!-- /ko --></span>
2121
* <th class="col col-method" data-bind="i18n: 'Select Method'"></th>
22-
* @deprecated Not used anymore because of newly introduced constant
23-
* @see self::HTML_REGEX_LIST
22+
* @deprecated Not used anymore because of newly introduced constants
23+
* @see self::REGEX_I18N_BINDING and self::REGEX_TRANSLATE_TAG_OR_ATTR
2424
*/
25-
const HTML_FILTER = "/i18n:\s?'(?<value>[^'\\\\]*(?:\\\\.[^'\\\\]*)*)'/i";
25+
const HTML_FILTER = "/i18n:\s?'(?<value>[^'\\\\]*(?:\\\\.[^'\\\\]*)*)'/";
2626

27-
private const HTML_REGEX_LIST = [
28-
// <span><!-- ko i18n: 'Next'--><!-- /ko --></span>
29-
// <th class="col col-method" data-bind="i18n: 'Select Method'"></th>
30-
"/i18n:\s?'(?<value>[^'\\\\]*(?:\\\\.[^'\\\\]*)*)'/i",
31-
// <translate args="'System Messages'"/>
32-
// <span translate="'Examples'"></span>
33-
"/translate( args|)=\"'(?<value>[^\"\\\\]*(?:\\\\.[^\"\\\\]*)*)'\"/i"
34-
];
27+
/**
28+
* Covers
29+
* <span><!-- ko i18n: 'Next'--><!-- /ko --></span>
30+
* <th class="col col-method" data-bind="i18n: 'Select Method'"></th>
31+
*/
32+
public const REGEX_I18N_BINDING = '/i18n:\s?\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\'/';
33+
34+
/**
35+
* Covers
36+
* <translate args="'System Messages'"/>
37+
* <span translate="'Examples'"></span>
38+
*/
39+
public const REGEX_TRANSLATE_TAG_OR_ATTR = '/translate( args|)=\"\'([^\"\\\\]*(?:\\\\.[^\"\\\\]*)*)\'\"/';
3540

3641
/**
3742
* @inheritdoc
@@ -59,13 +64,24 @@ protected function _parse()
5964
}
6065
}
6166

62-
foreach (self::HTML_REGEX_LIST as $regex) {
63-
preg_match_all($regex, $data, $results, PREG_SET_ORDER);
67+
$this->extractPhrases(self::REGEX_I18N_BINDING, $data, 2, 1);
68+
$this->extractPhrases(self::REGEX_TRANSLATE_TAG_OR_ATTR, $data, 3, 2);
69+
$this->extractPhrases(Js::REGEX_TRANSLATE_FUNCTION, $data, 3, 2);
70+
}
6471

65-
for ($i = 0, $count = count($results); $i < $count; $i++) {
66-
if (!empty($results[$i]['value'])) {
67-
$this->_addPhrase($results[$i]['value']);
68-
}
72+
/**
73+
* @param string $regex
74+
* @param string $data
75+
* @param int $expectedGroupsCount
76+
* @param int $valueGroupIndex
77+
*/
78+
protected function extractPhrases(string $regex, string $data, int $expectedGroupsCount, int $valueGroupIndex): void
79+
{
80+
preg_match_all($regex, $data, $results, PREG_SET_ORDER);
81+
82+
for ($i = 0, $count = count($results); $i < $count; $i++) {
83+
if (count($results[$i]) === $expectedGroupsCount && !empty($results[$i][$valueGroupIndex])) {
84+
$this->_addPhrase($results[$i][$valueGroupIndex]);
6985
}
7086
}
7187
}

setup/src/Magento/Setup/Module/I18n/Parser/Adapter/Js.php

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,23 @@
1010
*/
1111
class Js extends AbstractAdapter
1212
{
13+
/**
14+
* Covers
15+
* $.mage.__('Example text')
16+
*/
17+
public const REGEX_MAGE_TRANSLATE = '/mage\.__\(\s*([\'"])(.*?[^\\\])\1.*?[),]/';
18+
19+
/**
20+
* Covers in JS
21+
* $t(' Example: ')
22+
*
23+
* Covers in HTML
24+
* <a data-bind="attr: { title: $t('Title'), href: '#'} "></a>
25+
* <input type="text" data-bind="attr: { placeholder: $t('Placeholder'), title: $t('Title') }" />
26+
* Double quotes are not handled correctly in the `attr` binding. Move phrase to the UI component property if needed
27+
*/
28+
public const REGEX_TRANSLATE_FUNCTION = '/\\$t\(\s*([\'"])(.*?[^\\\])\1.*?[),]/';
29+
1330
/**
1431
* @inheritdoc
1532
*/
@@ -21,19 +38,18 @@ protected function _parse()
2138
$lineNumber++;
2239
$fileRow = fgets($fileHandle, 4096);
2340
$results = [];
24-
preg_match_all('/mage\.__\(\s*([\'"])(.*?[^\\\])\1.*?[),]/', $fileRow, $results, PREG_SET_ORDER);
25-
for ($i = 0, $count = count($results); $i < $count; $i++) {
26-
if (isset($results[$i][2])) {
27-
$quote = $results[$i][1];
28-
$this->_addPhrase($quote . $results[$i][2] . $quote, $lineNumber);
29-
}
30-
}
41+
$regexes = [
42+
static::REGEX_MAGE_TRANSLATE,
43+
static::REGEX_TRANSLATE_FUNCTION
44+
];
3145

32-
preg_match_all('/\\$t\(\s*([\'"])(.*?[^\\\])\1.*?[),]/', $fileRow, $results, PREG_SET_ORDER);
33-
for ($i = 0, $count = count($results); $i < $count; $i++) {
34-
if (isset($results[$i][2])) {
35-
$quote = $results[$i][1];
36-
$this->_addPhrase($quote . $results[$i][2] . $quote, $lineNumber);
46+
foreach ($regexes as $regex) {
47+
preg_match_all($regex, $fileRow, $results, PREG_SET_ORDER);
48+
for ($i = 0, $count = count($results); $i < $count; $i++) {
49+
if (isset($results[$i][2])) {
50+
$quote = $results[$i][1];
51+
$this->_addPhrase($quote . $results[$i][2] . $quote, $lineNumber);
52+
}
3753
}
3854
}
3955
}

setup/src/Magento/Setup/Test/Unit/Module/I18n/Parser/Adapter/HtmlTest.php

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ public function testParse()
4949
'line' => '',
5050
'quote' => '',
5151
],
52+
// `I18N` is not parsed - bindings are case-sensitive
5253
[
5354
'phrase' => 'This is test data at right side of attr',
5455
'file' => $this->testFile,
@@ -97,12 +98,50 @@ public function testParse()
9798
'line' => '',
9899
'quote' => '',
99100
],
101+
// `<TRANSLATE>` tag is not parsed - only lowercase tags are accepted
100102
[
101103
'phrase' => 'This is test content in translate attribute',
102104
'file' => $this->testFile,
103105
'line' => '',
104106
'quote' => '',
105107
],
108+
// `TRANSLATE` attribute is not parsed - only lowercase attribute names are accepted
109+
// `$T()` is not parsed - function names in JS are case-sensitive
110+
[
111+
// en_US.csv: "This is ' test ' data for attribute translation with single quotes","This is ' test ' data for attribute translation with single quotes"
112+
'phrase' => 'This is \\\' test \\\' data for attribute translation with single quotes',
113+
'file' => $this->testFile,
114+
'line' => '',
115+
'quote' => '',
116+
],
117+
[
118+
// en_US.csv: "This is test data for attribute translation with a quote after''","This is test data for attribute translation with a quote after''"
119+
'phrase' => 'This is test data for attribute translation with a quote after\\\'\\\'',
120+
'file' => $this->testFile,
121+
'line' => '',
122+
'quote' => '',
123+
],
124+
[
125+
// en_US.csv: "This is test data for attribute translation with a quote after' ' ","This is test data for attribute translation with a quote after' ' "
126+
'phrase' => 'This is test data for attribute translation with a quote after\\\' \\\' ',
127+
'file' => $this->testFile,
128+
'line' => '',
129+
'quote' => '',
130+
],
131+
[
132+
// en_US.csv: "Attribute translation - Placeholder","Attribute translation - Placeholder"
133+
'phrase' => 'Attribute translation - Placeholder',
134+
'file' => $this->testFile,
135+
'line' => '',
136+
'quote' => '',
137+
],
138+
[
139+
// en_US.csv: "Attribute translation - Title","Attribute translation - Title"
140+
'phrase' => 'Attribute translation - Title',
141+
'file' => $this->testFile,
142+
'line' => '',
143+
'quote' => '',
144+
]
106145
];
107146

108147
$this->model->parse($this->testFile);

setup/src/Magento/Setup/Test/Unit/Module/I18n/Parser/Adapter/JsTest.php

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,33 @@ public function testParse()
4343
[
4444
'phrase' => 'Phrase 1',
4545
'file' => $this->_testFile,
46-
'line' => $this->_stringsCount - 2,
46+
'line' => $this->_stringsCount - 4,
4747
'quote' => Phrase::QUOTE_SINGLE,
4848
],
4949
[
5050
'phrase' => 'Phrase 2 %1',
5151
'file' => $this->_testFile,
52-
'line' => $this->_stringsCount - 1,
52+
'line' => $this->_stringsCount - 3,
5353
'quote' => Phrase::QUOTE_DOUBLE
5454
],
55+
[
56+
'phrase' => 'Field ',
57+
'file' => $this->_testFile,
58+
'line' => $this->_stringsCount - 2,
59+
'quote' => Phrase::QUOTE_SINGLE
60+
],
61+
[
62+
'phrase' => ' is required.',
63+
'file' => $this->_testFile,
64+
'line' => $this->_stringsCount - 2,
65+
'quote' => Phrase::QUOTE_SINGLE
66+
],
67+
[
68+
'phrase' => 'Welcome, %1!',
69+
'file' => $this->_testFile,
70+
'line' => $this->_stringsCount - 1,
71+
'quote' => Phrase::QUOTE_SINGLE
72+
]
5573
];
5674

5775
$this->_adapter->parse($this->_testFile);

setup/src/Magento/Setup/Test/Unit/Module/I18n/Parser/Adapter/_files/email.html

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
}}
2222
</span>
2323
<label data-bind="i18n: 'This is test data', attr: {for: 'more-test-data-'}"></label>
24+
<label data-bind="I18N: 'This is test data with uppercase binding', attr: {for: 'more-test-data-'}"></label>
2425
<label data-bind="attr: {for: 'more-test-data-' + $parent.getCode()}"><span data-bind="i18n: 'This is test data at right side of attr'"></span></label>
2526
<label data-bind="i18n: 'This is \' test \' data', attr: {for: 'more-test-data-' + $parent.getCode()}"></label>
2627
<label data-bind="i18n: 'This is \" test \" data', attr: {for: 'more-test-data-' + $parent.getCode()}"></label>
@@ -30,6 +31,13 @@
3031
<label data-bind="i18n: '\''"></label>
3132
<label data-bind="i18n: '\\\\ '"></label>
3233
<span><translate args="'This is test content in translate tag'" /></span>
34+
<span><TRANSLATE args="'This is test content in the uppercase translate tag'" /></span>
3335
<span translate="'This is test content in translate attribute'"></span>
36+
<span TRANSLATE="'This is test content in uppercase translate attribute'"></span>
37+
<a data-bind="attr: { title: $T('This is test data for invalid attribute translation'), href: '#'} "></a>
38+
<a data-bind="attr: { title: $t('This is \' test \' data for attribute translation with single quotes'), href: '#'} "></a>
39+
<a data-bind="attr: { title: $t('This is test data for attribute translation with a quote after\'\''), href: '#'} "></a>
40+
<a data-bind="attr: { title: $t('This is test data for attribute translation with a quote after\' \' '), href: '#'} "></a>
41+
<input type="text" data-bind="attr: { placeholder: $t('Attribute translation - Placeholder'), title: $t('Attribute translation - Title') }" />
3442
</body>
3543
</html>

setup/src/Magento/Setup/Test/Unit/Module/I18n/Parser/Adapter/_files/file.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,6 @@
77
$.mage.__('Phrase 1');
88
$.mage.__('Phrase 1');
99
$.mage.__("Phrase 2 %1");
10+
let message = $t('Field ') + field + $t(' is required.');
11+
let html = $t('Welcome, %1!').replace('%1', 'John Doe');
1012
});

0 commit comments

Comments
 (0)