From f8b009fecc6ab995d1d74cd53554574892eb328d Mon Sep 17 00:00:00 2001 From: Michael Terry Date: Tue, 1 May 2018 12:25:58 -0400 Subject: [PATCH] Fix extracting i18n from jsx code React code (in jsx files) was not being extracted at all. Fixed this by updating to edx-i18n-tools 0.4.5. Also, template literals (feature of es2015) don't work well with gettext at all. So convert those instances to HtmlUtils or StringUtils interpolation calls. FEDX-505 --- .../support/static/support/jsx/.eslintrc.js | 6 +++++- .../static/support/jsx/logged_in_user.jsx | 9 ++++++++- .../static/support/jsx/logged_out_user.jsx | 20 ++++++++++++++++--- .../support/jsx/single_support_form.jsx | 9 ++++++++- .../support/static/support/jsx/success.jsx | 7 ++++++- .../commands/tests/test_cache_programs.py | 2 ++ openedx/core/lib/tests/test_edx_api_utils.py | 1 + .../features/course_experience/.eslintrc.js | 6 +++++- .../course_experience/js/CourseGoals.js | 7 ++++++- requirements/edx/base.txt | 4 ++-- requirements/edx/development.txt | 12 +++++------ requirements/edx/github.in | 2 +- requirements/edx/pip-tools.txt | 2 +- requirements/edx/testing.in | 2 +- requirements/edx/testing.txt | 10 +++++----- 15 files changed, 74 insertions(+), 25 deletions(-) diff --git a/lms/djangoapps/support/static/support/jsx/.eslintrc.js b/lms/djangoapps/support/static/support/jsx/.eslintrc.js index 2c5f18759e..23fa913be3 100644 --- a/lms/djangoapps/support/static/support/jsx/.eslintrc.js +++ b/lms/djangoapps/support/static/support/jsx/.eslintrc.js @@ -2,7 +2,11 @@ module.exports = { extends: 'eslint-config-edx', root: true, settings: { - 'import/resolver': 'webpack', + 'import/resolver': { + webpack: { + config: 'webpack.dev.config.js', + }, + }, }, rules: { 'import/prefer-default-export': 'off', diff --git a/lms/djangoapps/support/static/support/jsx/logged_in_user.jsx b/lms/djangoapps/support/static/support/jsx/logged_in_user.jsx index a4a7f3f3d3..d7ea1a10ed 100644 --- a/lms/djangoapps/support/static/support/jsx/logged_in_user.jsx +++ b/lms/djangoapps/support/static/support/jsx/logged_in_user.jsx @@ -3,6 +3,8 @@ import React from 'react'; import PropTypes from 'prop-types'; +import StringUtils from 'edx-ui-toolkit/js/utils/string-utils'; + import FileUpload from './file_upload'; function LoggedInUser({ userInformation, setErrorState, zendeskApiHost, submitForm }) { @@ -36,7 +38,12 @@ function LoggedInUser({ userInformation, setErrorState, zendeskApiHost, submitFo data-username={userInformation.username} data-email={userInformation.email} > -

{gettext(`What can we help you with, ${userInformation.username}?`)}

+

+ {StringUtils.interpolate( + gettext('What can we help you with, {username}?'), + { username: userInformation.username }, + )} +

diff --git a/lms/djangoapps/support/static/support/jsx/logged_out_user.jsx b/lms/djangoapps/support/static/support/jsx/logged_out_user.jsx index ee8fdf30f9..d9b59fbdbe 100644 --- a/lms/djangoapps/support/static/support/jsx/logged_out_user.jsx +++ b/lms/djangoapps/support/static/support/jsx/logged_out_user.jsx @@ -3,12 +3,17 @@ import React from 'react'; import PropTypes from 'prop-types'; +import StringUtils from 'edx-ui-toolkit/js/utils/string-utils'; + function LoggedOutUser({ platformName, loginQuery, supportEmail }) { return (
-

{gettext(`Sign in to ${platformName} so we can help you better.`)}

+

{StringUtils.interpolate( + gettext('Sign in to {platform} so we can help you better.'), + { platform: platformName }, + )}

@@ -20,9 +25,18 @@ function LoggedOutUser({ platformName, loginQuery, supportEmail }) {
- {gettext(`Create an ${platformName} account`)} + + {StringUtils.interpolate( + // FIXME: not all platforms start with a vowel + gettext('Create an {platform} account'), + { platform: platformName }, + )} +

- {gettext(`If you are unable to access your account contact us via email using ${supportEmail}.`)} + {StringUtils.interpolate( + gettext('If you are unable to access your account contact us via email using {email}.'), + { email: supportEmail }, + )}

diff --git a/lms/djangoapps/support/static/support/jsx/single_support_form.jsx b/lms/djangoapps/support/static/support/jsx/single_support_form.jsx index ed0c14c82c..6ad7696b12 100644 --- a/lms/djangoapps/support/static/support/jsx/single_support_form.jsx +++ b/lms/djangoapps/support/static/support/jsx/single_support_form.jsx @@ -6,6 +6,8 @@ import PropTypes from 'prop-types'; import React from 'react'; import ReactDOM from 'react-dom'; +import StringUtils from 'edx-ui-toolkit/js/utils/string-utils'; + import ShowErrors from './errors_list'; import LoggedInUser from './logged_in_user'; import LoggedOutUser from './logged_out_user'; @@ -161,7 +163,12 @@ class RenderForm extends React.Component { {gettext(`Search the ${this.props.context.platformName} Help Center`)} + > + {StringUtils.interpolate( + gettext('Search the {platform} Help Center'), + { platform: this.props.context.platformName }, + )} +
diff --git a/lms/djangoapps/support/static/support/jsx/success.jsx b/lms/djangoapps/support/static/support/jsx/success.jsx index 09828c9aff..67ce13403c 100644 --- a/lms/djangoapps/support/static/support/jsx/success.jsx +++ b/lms/djangoapps/support/static/support/jsx/success.jsx @@ -4,6 +4,8 @@ import React from 'react'; import PropTypes from 'prop-types'; +import StringUtils from 'edx-ui-toolkit/js/utils/string-utils'; + function Success({ platformName, homepageUrl, dashboardUrl, isLoggedIn }) { let btnText, btnUrl; @@ -11,7 +13,10 @@ function Success({ platformName, homepageUrl, dashboardUrl, isLoggedIn }) { btnText = gettext('Go to my Dashboard'); btnUrl = dashboardUrl; } else { - btnText = gettext(`Go to ${platformName} Home`); + btnText = StringUtils.interpolate( + gettext('Go to {platform} Home'), + { platform: platformName }, + ); btnUrl = homepageUrl; } return (
diff --git a/openedx/core/djangoapps/catalog/management/commands/tests/test_cache_programs.py b/openedx/core/djangoapps/catalog/management/commands/tests/test_cache_programs.py index 0daf776f1c..9f439e1b1e 100644 --- a/openedx/core/djangoapps/catalog/management/commands/tests/test_cache_programs.py +++ b/openedx/core/djangoapps/catalog/management/commands/tests/test_cache_programs.py @@ -23,6 +23,8 @@ class TestCachePrograms(CatalogIntegrationMixin, CacheIsolationTestCase, SiteMix def setUp(self): super(TestCachePrograms, self).setUp() + httpretty.httpretty.reset() + self.catalog_integration = self.create_catalog_integration() self.site_domain = 'testsite.com' self.set_up_site( diff --git a/openedx/core/lib/tests/test_edx_api_utils.py b/openedx/core/lib/tests/test_edx_api_utils.py index 2b0058fe5a..c70d6a8429 100644 --- a/openedx/core/lib/tests/test_edx_api_utils.py +++ b/openedx/core/lib/tests/test_edx_api_utils.py @@ -31,6 +31,7 @@ class TestGetEdxApiData(CatalogIntegrationMixin, CredentialsApiConfigMixin, Cach self.user = UserFactory() + httpretty.httpretty.reset() cache.clear() def _mock_catalog_api(self, responses, url=None): diff --git a/openedx/features/course_experience/.eslintrc.js b/openedx/features/course_experience/.eslintrc.js index 12cb26eef9..838b853a82 100644 --- a/openedx/features/course_experience/.eslintrc.js +++ b/openedx/features/course_experience/.eslintrc.js @@ -2,6 +2,10 @@ module.exports = { extends: 'eslint-config-edx', root: true, settings: { - 'import/resolver': 'webpack', + 'import/resolver': { + webpack: { + config: 'webpack.dev.config.js', + }, + }, }, }; diff --git a/openedx/features/course_experience/static/course_experience/js/CourseGoals.js b/openedx/features/course_experience/static/course_experience/js/CourseGoals.js index fac60d331d..467997b759 100644 --- a/openedx/features/course_experience/static/course_experience/js/CourseGoals.js +++ b/openedx/features/course_experience/static/course_experience/js/CourseGoals.js @@ -1,5 +1,7 @@ /* globals gettext */ +import HtmlUtils from 'edx-ui-toolkit/js/utils/html-utils'; + export class CourseGoals { // eslint-disable-line import/prefer-default-export constructor(options) { @@ -19,7 +21,10 @@ export class CourseGoals { // eslint-disable-line import/prefer-default-export $('.section-goals').slideDown(); $('.section-goals .goal .text').text(data.goal_text); $('.section-goals select').val(data.goal_key); - const successMsg = gettext(`Thank you for setting your course goal to ${data.goal_text.toLowerCase()}!`); + const successMsg = HtmlUtils.interpolateHtml( + gettext('Thank you for setting your course goal to {goal}!'), + { goal: data.goal_text.toLowerCase() }, + ); if (!data.is_unsure) { // xss-lint: disable=javascript-jquery-html $('.message-content').html(`
${successMsg}
`); diff --git a/requirements/edx/base.txt b/requirements/edx/base.txt index 295231160d..5493e61778 100644 --- a/requirements/edx/base.txt +++ b/requirements/edx/base.txt @@ -26,7 +26,7 @@ git+https://github.com/mitodl/edx-sga.git@6b2f7aa2a18206023c8407e2c46f86d4b4c3ac git+https://github.com/edx/xblock-lti-consumer.git@v1.1.7#egg=lti_consumer-xblock==1.1.7 git+https://github.com/edx/MongoDBProxy.git@25b99097615bda06bd7cdfe5669ed80dc2a7fed0#egg=MongoDBProxy==0.1.0 -e . -git+https://github.com/edx/edx-ora2.git@2.1.15#egg=ora2==2.1.15 +git+https://github.com/edx/edx-ora2.git@2.1.16#egg=ora2==2.1.16 -e git+https://github.com/dgrtwo/ParsePy.git@7949b9f754d1445eff8e8f20d0e967b9a6420639#egg=parse_rest -e git+https://github.com/appliedsec/pygeoip.git@95e69341cebf5a6a9fbf7c4f5439d458898bdc3b#egg=pygeoip -e git+https://github.com/dementrock/pystache_custom.git@776973740bdaad83a3b029f96e415a7d1e8bec2f#egg=pystache_custom-dev @@ -116,7 +116,7 @@ edx-django-release-util==0.3.1 edx-django-sites-extensions==2.3.1 edx-drf-extensions==1.2.5 edx-enterprise==0.67.7 -edx-i18n-tools==0.4.4 +edx-i18n-tools==0.4.5 edx-milestones==0.1.13 edx-oauth2-provider==1.2.2 edx-opaque-keys[django]==0.4.4 diff --git a/requirements/edx/development.txt b/requirements/edx/development.txt index 511dd35685..35b4df1492 100644 --- a/requirements/edx/development.txt +++ b/requirements/edx/development.txt @@ -29,7 +29,7 @@ git+https://github.com/edx/lettuce.git@31b0dfd865766243e9b563ec65fae9122edf7975# git+https://github.com/edx/xblock-lti-consumer.git@v1.1.7#egg=lti_consumer-xblock==1.1.7 git+https://github.com/edx/MongoDBProxy.git@25b99097615bda06bd7cdfe5669ed80dc2a7fed0#egg=MongoDBProxy==0.1.0 -e . -git+https://github.com/edx/edx-ora2.git@2.1.15#egg=ora2==2.1.15 +git+https://github.com/edx/edx-ora2.git@2.1.16#egg=ora2==2.1.16 -e git+https://github.com/dgrtwo/ParsePy.git@7949b9f754d1445eff8e8f20d0e967b9a6420639#egg=parse_rest -e git+https://github.com/appliedsec/pygeoip.git@95e69341cebf5a6a9fbf7c4f5439d458898bdc3b#egg=pygeoip -e git+https://github.com/dementrock/pystache_custom.git@776973740bdaad83a3b029f96e415a7d1e8bec2f#egg=pystache_custom-dev @@ -135,7 +135,7 @@ edx-django-release-util==0.3.1 edx-django-sites-extensions==2.3.1 edx-drf-extensions==1.2.5 edx-enterprise==0.67.7 -edx-i18n-tools==0.4.4 +edx-i18n-tools==0.4.5 edx-lint==0.5.5 edx-milestones==0.1.13 edx-oauth2-provider==1.2.2 @@ -161,7 +161,7 @@ first==2.0.1 fixtures==3.0.0 flake8-polyfill==1.0.2 flake8==3.5.0 -flask==0.12.2 +flask==1.0.1 freezegun==0.3.10 fs-s3fs==0.1.8 fs==2.0.18 @@ -175,7 +175,7 @@ hash-ring==1.3.1 help-tokens==1.0.3 html5lib==0.999 httplib2==0.11.3 -httpretty==0.8.14 +httpretty==0.9.4 idna==2.6 imagesize==1.0.0 # via sphinx incremental==17.5.0 @@ -229,7 +229,7 @@ pbr==4.0.2 pdfminer==20140328 piexif==1.0.2 pillow==3.4.0 -pip-tools==2.0.1 +pip-tools==2.0.2 pluggy==0.6.0 polib==1.1.0 psutil==1.2.1 @@ -317,7 +317,7 @@ text-unidecode==1.2 tox-battery==0.5.1 tox==3.0.0 traceback2==1.4.0 -transifex-client==0.13.2 +transifex-client==0.13.3 twisted==16.6.0 typing==3.6.4 # via sphinx unicodecsv==0.14.1 diff --git a/requirements/edx/github.in b/requirements/edx/github.in index 2b710a5ab6..f1612b4da5 100644 --- a/requirements/edx/github.in +++ b/requirements/edx/github.in @@ -92,7 +92,7 @@ # Our libraries: -e git+https://github.com/edx/codejail.git@a320d43ce6b9c93b17636b2491f724d9e433be47#egg=codejail -e git+https://github.com/edx/acid-block.git@e46f9cda8a03e121a00c7e347084d142d22ebfb7#egg=acid-xblock --e git+https://github.com/edx/edx-ora2.git@2.1.15#egg=ora2==2.1.15 +-e git+https://github.com/edx/edx-ora2.git@2.1.16#egg=ora2==2.1.16 -e git+https://github.com/edx/RecommenderXBlock.git@1.3#egg=recommender-xblock==1.3 -e git+https://github.com/solashirai/crowdsourcehinter.git@518605f0a95190949fe77bd39158450639e2e1dc#egg=crowdsourcehinter-xblock==0.1 -e git+https://github.com/edx/RateXBlock.git@367e19c0f6eac8a5f002fd0f1559555f8e74bfff#egg=rate-xblock diff --git a/requirements/edx/pip-tools.txt b/requirements/edx/pip-tools.txt index c159b1d75c..44aa65b2a3 100644 --- a/requirements/edx/pip-tools.txt +++ b/requirements/edx/pip-tools.txt @@ -7,5 +7,5 @@ click==6.7 # via pip-tools first==2.0.1 # via pip-tools -pip-tools==2.0.1 +pip-tools==2.0.2 six==1.11.0 # via pip-tools diff --git a/requirements/edx/testing.in b/requirements/edx/testing.in index 96305c91d9..9141b41484 100644 --- a/requirements/edx/testing.in +++ b/requirements/edx/testing.in @@ -20,7 +20,7 @@ before_after # Syntactic sugar for mock, only used in one test case bok-choy # Framework for browser automation tests, based on selenium cssselect # Used to extract HTML fragments via CSS selectors in 2 test cases and pyquery ddt # Run a test case multiple times with different input; used in many, many of our tests -edx-i18n-tools # Commands for developers and translators to extract, compile and validate translations +edx-i18n-tools>=0.4.5 # Commands for developers and translators to extract, compile and validate translations edx-lint # pylint extensions for Open edX repositories factory_boy==2.8.1 # Library for creating test fixtures, used in many tests freezegun # Allows tests to mock the output of assorted datetime module functions diff --git a/requirements/edx/testing.txt b/requirements/edx/testing.txt index f19def348d..0bb9666ce9 100644 --- a/requirements/edx/testing.txt +++ b/requirements/edx/testing.txt @@ -27,7 +27,7 @@ git+https://github.com/edx/lettuce.git@31b0dfd865766243e9b563ec65fae9122edf7975# git+https://github.com/edx/xblock-lti-consumer.git@v1.1.7#egg=lti_consumer-xblock==1.1.7 git+https://github.com/edx/MongoDBProxy.git@25b99097615bda06bd7cdfe5669ed80dc2a7fed0#egg=MongoDBProxy==0.1.0 -e . -git+https://github.com/edx/edx-ora2.git@2.1.15#egg=ora2==2.1.15 +git+https://github.com/edx/edx-ora2.git@2.1.16#egg=ora2==2.1.16 -e git+https://github.com/dgrtwo/ParsePy.git@7949b9f754d1445eff8e8f20d0e967b9a6420639#egg=parse_rest -e git+https://github.com/appliedsec/pygeoip.git@95e69341cebf5a6a9fbf7c4f5439d458898bdc3b#egg=pygeoip -e git+https://github.com/dementrock/pystache_custom.git@776973740bdaad83a3b029f96e415a7d1e8bec2f#egg=pystache_custom-dev @@ -130,7 +130,7 @@ edx-django-release-util==0.3.1 edx-django-sites-extensions==2.3.1 edx-drf-extensions==1.2.5 edx-enterprise==0.67.7 -edx-i18n-tools==0.4.4 +edx-i18n-tools==0.4.5 edx-lint==0.5.5 edx-milestones==0.1.13 edx-oauth2-provider==1.2.2 @@ -154,7 +154,7 @@ firebase-token-generator==1.3.2 fixtures==3.0.0 # via testtools flake8-polyfill==1.0.2 # via radon flake8==3.5.0 # via flake8-polyfill -flask==0.12.2 # via moto +flask==1.0.1 # via moto freezegun==0.3.10 fs-s3fs==0.1.8 fs==2.0.18 @@ -168,7 +168,7 @@ hash-ring==1.3.1 help-tokens==1.0.3 html5lib==0.999 httplib2==0.11.3 -httpretty==0.8.14 +httpretty==0.9.4 idna==2.6 incremental==17.5.0 # via twisted inflect==0.2.5 @@ -301,7 +301,7 @@ text-unidecode==1.2 # via faker tox-battery==0.5.1 tox==3.0.0 traceback2==1.4.0 # via testtools, unittest2 -transifex-client==0.13.2 +transifex-client==0.13.3 twisted==16.6.0 # via pa11ycrawler, scrapy unicodecsv==0.14.1 unidecode==1.0.22 # via python-slugify