From 251b77c959af37fa0da6739ea978ca4f198414cb Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Wed, 28 Apr 2021 11:46:52 +0000 Subject: [FIX] *: bunch of mismarked translation specifiers `_(xyz)` will wrap them in an underscore.js object, which when used in a string context will just return the string. So it's basically a no-op, but it certainly doesn't translate the terms. closes odoo/odoo#70000 Related: odoo/enterprise#18001 Signed-off-by: Xavier Morel (xmo) --- odoo/addons/test_lint/tests/test_jstranslate.py | 68 ++++++++++++++++++------- 1 file changed, 50 insertions(+), 18 deletions(-) (limited to 'odoo') diff --git a/odoo/addons/test_lint/tests/test_jstranslate.py b/odoo/addons/test_lint/tests/test_jstranslate.py index 696b8bef62d..64a73a3d474 100644 --- a/odoo/addons/test_lint/tests/test_jstranslate.py +++ b/odoo/addons/test_lint/tests/test_jstranslate.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. +# pylint: disable=unbalanced-tuple-unpacking import logging import re @@ -13,13 +14,16 @@ _logger = logging.getLogger(__name__) TSTRING_RE = re.compile(r'_l?t\(\s*`.*?\s*`\s*\)', re.DOTALL) EXPRESSION_RE = re.compile(r'\$\{.+?\}') +UNDERSCORE_RE = re.compile(r'\b_\(\s*[\'"]') class TestJsTranslations(lint_case.LintCase): def check_text(self, text): - """ Search for translated template strings that contains an expression - :param text: The js text to search - :return: A list of tuple with line number and invalid template string or an empty list + """ Search for translation errors in the text + + :param text: The js text to search + :return: A list of tuple with line number and invalid template string, + or None for underscore errors """ error_list = list() for m in TSTRING_RE.finditer(text): @@ -27,6 +31,11 @@ class TestJsTranslations(lint_case.LintCase): if EXPRESSION_RE.search(template_string): line_nb = text[:m.start()].count('\n') + 1 error_list.append((line_nb, template_string)) + + for m in UNDERSCORE_RE.finditer(text): + lineno = text[:m.start()].count('\n') + 1 + error_list.append((lineno, None)) + return error_list def test_regular_expression(self): @@ -39,11 +48,10 @@ class TestJsTranslations(lint_case.LintCase): """ error_list = self.check_text(bad_js) self.assertEqual(len(error_list), 1) - for line, template_string in error_list: - template_string = error_list[0][1] - self.assertIn('invalid template-string', template_string) - self.assertNotIn('but valid template-string', template_string) - self.assertEqual(line, 4) + [(line, template_string)] = error_list + self.assertEqual(line, 4) + self.assertIn('invalid template-string', template_string) + self.assertNotIn('but valid template-string', template_string) def test_regular_expression_long(self): bad_js = """ @@ -54,25 +62,49 @@ class TestJsTranslations(lint_case.LintCase): error_list = self.check_text(bad_js) self.assertEqual(len(error_list), 1) - for line, template_string in error_list: - template_string = error_list[0][1] - self.assertIn('foo ${this + is(a, very) - long == expression}', template_string) - self.assertEqual(line, 2) + [(line, template_string)] = error_list + self.assertEqual(line, 2) + self.assertIn('foo ${this + is(a, very) - long == expression}', template_string) + + def test_matches_underscore(self): + bad_js = """ + const thing1 = _('literal0'); + const thing0 = _([]); + const thing2 = _("literal1"); + """ + self.assertEqual( + self.check_text(bad_js), + [(2, None), (4, None)] + ) def test_js_translations(self): - """ Test that there are no translation of JS template strings """ + """ Test that there are no translation of JS template strings or underscore + calls misused as translation markers + """ counter = 0 failures = 0 for js_file in self.iter_module_files('*.js'): + # lodash has string methods and occurrences of `_('text')` in its comments + if js_file.endswith('/lodash.js'): + continue + counter += 1 with tools.file_open(js_file, 'r') as f: js_txt = f.read() - error_list = self.check_text(js_txt) - for line_number, template_string in error_list: - failures += 1 - mod, relative_path, _ = get_resource_from_path(js_file) - _logger.error("Translation of a template string found in `%s/%s` at line %s: %s", mod, relative_path, line_number, template_string) + + error_list = self.check_text(js_txt) + for line_number, template_string in error_list: + failures += 1 + mod, relative_path, _ = get_resource_from_path(js_file) + if template_string: + prefix = "Translation of a template string" + suffix = template_string + else: + prefix = "underscore.js used as translation function" + suffix = "_t and _lt are the JS translation functions" + + _logger.error("%s found in `%s/%s` at line %s: %s", prefix, mod, relative_path, line_number, suffix) _logger.info('%s files tested', counter) if failures > 0: -- cgit v1.2.3