You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

112 lines
3.8 KiB
Python

8 months ago
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
# pylint: disable=unbalanced-tuple-unpacking
import logging
import re
from odoo import tools
from odoo.modules import get_resource_from_path
from . import lint_case
_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 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):
template_string = m.group(0)
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):
bad_js = """
const foo = {
valid: _lt(`not useful but valid template-string`),
invalid: _lt(`invalid template-string
that spans multiple lines ${expression}`)
};
"""
error_list = self.check_text(bad_js)
self.assertEqual(len(error_list), 1)
[(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 = """
thing = _t(
`foo ${this + is(a, very) - long == expression}`
);
"""
error_list = self.check_text(bad_js)
self.assertEqual(len(error_list), 1)
[(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 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)
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:
self.fail("%s invalid template strings found in js files." % failures)