Skip to content

Commit

Permalink
feat: Add gettext for JS translation
Browse files Browse the repository at this point in the history
JS translations will not be shown fetched without directing (gettext) to the
correct javascript file

Refs: FC-0012 OEP-58
  • Loading branch information
shadinaif committed Oct 18, 2023
1 parent ed52df4 commit dc013ff
Show file tree
Hide file tree
Showing 17 changed files with 346 additions and 104 deletions.
19 changes: 6 additions & 13 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
WORKING_DIR := recommender
EXTRACT_DIR := $(WORKING_DIR)/conf/locale/en/LC_MESSAGES
EXTRACTED_DJANGO_PARTIAL := $(EXTRACT_DIR)/django-partial.po
EXTRACTED_DJANGOJS_PARTIAL := $(EXTRACT_DIR)/djangojs-partial.po
EXTRACTED_DJANGO := $(EXTRACT_DIR)/django.po
JS_TARGET := $(WORKING_DIR)/public/js/translations

COMMON_CONSTRAINTS_TXT=requirements/common_constraints.txt
.PHONY: $(COMMON_CONSTRAINTS_TXT)
Expand All @@ -22,12 +19,8 @@ upgrade: $(COMMON_CONSTRAINTS_TXT) ## update the requirements/*.txt files with
pip-compile --upgrade -o requirements/ci.txt requirements/ci.in

extract_translations: ## extract strings to be translated, outputting .po files
cd $(WORKING_DIR) && i18n_tool extract
mv $(EXTRACTED_DJANGO_PARTIAL) $(EXTRACTED_DJANGO)
# Safely concatenate djangojs if it exists
if test -f $(EXTRACTED_DJANGOJS_PARTIAL); then \
msgcat $(EXTRACTED_DJANGO) $(EXTRACTED_DJANGOJS_PARTIAL) -o $(EXTRACTED_DJANGO) && \
rm $(EXTRACTED_DJANGOJS_PARTIAL); \
fi
sed -i'' -e 's/nplurals=INTEGER/nplurals=2/' $(EXTRACTED_DJANGO)
sed -i'' -e 's/plural=EXPRESSION/plural=\(n != 1\)/' $(EXTRACTED_DJANGO)
cd $(WORKING_DIR) && i18n_tool extract --no-segment --merge-po-files

compile_translations: ## compile translation files, outputting .mo files for each supported language
cd $(WORKING_DIR) && i18n_tool generate -v
python manage.py compilejsi18n --namespace RecommenderXBlockI18N --output $(JS_TARGET)
12 changes: 12 additions & 0 deletions manage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/usr/bin/env python
import os
import sys
from django.core.management import execute_from_command_line

if __name__ == "__main__":
os.environ.setdefault(
"DJANGO_SETTINGS_MODULE",
"translation_settings"
)

execute_from_command_line(sys.argv)
4 changes: 3 additions & 1 deletion recommender/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
This XBlock will show a set of recommended resources which may be helpful to
students solving a given problem.
"""
from .recommender import RecommenderXBlock
# We avoid importing RecommenderXBlock here, because it's importing Filesystem from xblock.reference.plugins
# which is not loaded when running `manage.py` commands (which is used by `make compile_translations`)
# from .recommender import RecommenderXBlock

__version__ = '2.1.0'
3 changes: 3 additions & 0 deletions recommender/conf/locale/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,6 @@

locales:
- en # English - Source Language

ignore_dirs:
- public
54 changes: 0 additions & 54 deletions recommender/conf/locale/en/LC_MESSAGES/django.po

This file was deleted.

1 change: 0 additions & 1 deletion recommender/conf/locale/en/LC_MESSAGES/text.po

This file was deleted.

54 changes: 54 additions & 0 deletions recommender/conf/locale/en/LC_MESSAGES/text.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
"POT-Creation-Date: 2016-05-27 11:04+0500\n"
"PO-Revision-Date: 2016-05-27 11:04+0500\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: en\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#: recommender.py
msgid "The resource you are attempting to provide already exists"
msgstr ""

#: recommender.py
msgid ""
"The resource you are attempting to provide has been disallowed by the staff. "
"Reason: "
msgstr ""

#: recommender.py
msgid "The selected resource does not exist"
msgstr ""

#: recommender.py
msgid "Size of uploaded file exceeds threshold"
msgstr ""

#: recommender.py
msgid "The configuration of pyfs is not properly set"
msgstr ""

#: recommender.py:729
msgid "Endorse resource without permission"
msgstr ""

#: recommender.py
msgid "You don't have the permission to remove this resource"
msgstr ""

#: recommender.py
msgid "Only staff can import resources"
msgstr ""

#: recommender.py
msgid "Please submit the JSON file obtained with the download resources button"
msgstr ""

#: recommender.py
msgid "Tried to access flagged resources without staff permission"
msgstr ""
22 changes: 22 additions & 0 deletions recommender/recommender.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import bleach
from webob.response import Response
from django.utils import translation

from xblock.core import XBlock
from xblock.exceptions import JsonHandlerError
Expand Down Expand Up @@ -944,6 +945,21 @@ def _construct_view_resource(self, resource):

return result

@staticmethod
def _get_statici18n_js_url(): # pragma: no cover
"""
Returns the Javascript translation file for the currently selected language, if any found by `pkg_resources`
"""
lang_code = translation.get_language()
if not lang_code:
return None
text_js = 'public/js/translations/{lang_code}/text.js'
country_code = lang_code.split('-')[0]
for code in (translation.to_locale(lang_code), lang_code, country_code):
if pkg_resources.resource_exists(resource_loader.module_name, text_js.format(lang_code=code)):
return text_js.format(lang_code=code)
return None

def student_view(self, _context=None): # pylint: disable=unused-argument
"""
The primary view of the RecommenderXBlock, shown to students
Expand Down Expand Up @@ -990,6 +1006,9 @@ def student_view(self, _context=None): # pylint: disable=unused-argument
frag.add_css(self.resource_string("static/css/recommender.css"))
frag.add_css(self.resource_string("static/css/introjs.css"))
frag.add_javascript(self.resource_string("static/js/src/jquery.tooltipster.min.js"))
statici18n_js_url = self._get_statici18n_js_url()
if statici18n_js_url:
frag.add_javascript(self.resource_string(statici18n_js_url))
frag.add_javascript(self.resource_string("static/js/src/cats.js"))
frag.add_javascript(self.resource_string("static/js/src/recommender.js"))
frag.initialize_js('RecommenderXBlock', self.get_client_configuration())
Expand All @@ -1007,6 +1026,9 @@ def studio_view(self, _context=None): # pylint: disable=unused-argument
))
frag.add_css(load("static/css/recommenderstudio.css"))
frag.add_javascript_url("//ajax.googleapis.com/ajax/libs/jqueryui/1.10.4/jquery-ui.min.js")
statici18n_js_url = self._get_statici18n_js_url()
if statici18n_js_url:
frag.add_javascript(self.resource_string(statici18n_js_url))
frag.add_javascript(load("static/js/src/recommenderstudio.js"))
frag.initialize_js('RecommenderXBlock')
return frag
Expand Down
24 changes: 20 additions & 4 deletions recommender/static/js/src/cats.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,26 @@
//
// Note: The global `window.*` variables should be converted into local ones to avoid over-using global variables. This is a 2014-era legacy XBlock coding standard that should be refactored -- @OmarIthawi at Apr 4, 2023
//
var gettext = window.gettext || (function (string) {
// Shim Django's `gettext` if unavailable.
return string;
});
var gettext;
if ('RecommenderXBlockI18N' in window) {
// Use Recommender's local translations
gettext = function(string) {
var translated = window.RecommenderXBlockI18N.gettext(string);
// if Recommender's translation is the same as the input, check if global has a different value
// This is useful for overriding the XBlock's string by themes (only for English)
if (string === translated && 'gettext' in window) {
translated = window.gettext(string);
}
return translated;
};
} else if ('gettext' in window) {
// Use edxapp's global translations
gettext = window.gettext;
}
if (typeof gettext == "undefined") {
// No translations -- used by test environment
gettext = function(string) { return string; };
}

var span = function(text) {
// Surround text with a span.
Expand Down
1 change: 1 addition & 0 deletions requirements/base.in
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ mako
simplejson
webob
web_fragments
edx-i18n-tools
28 changes: 25 additions & 3 deletions requirements/base.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,43 @@
#
appdirs==1.4.4
# via fs
bleach==6.0.0
asgiref==3.7.2
# via django
bleach==6.1.0
# via -r requirements/base.in
django==3.2.22
# via
# -c requirements/common_constraints.txt
# edx-i18n-tools
edx-i18n-tools==1.3.0
# via -r requirements/base.in
fs==2.4.16
# via -r requirements/base.in
lxml==4.9.3
# via edx-i18n-tools
mako==1.2.4
# via -r requirements/base.in
markupsafe==2.1.3
# via mako
simplejson==3.19.1
path==16.7.1
# via edx-i18n-tools
polib==1.2.0
# via edx-i18n-tools
pytz==2023.3.post1
# via django
pyyaml==6.0.1
# via edx-i18n-tools
simplejson==3.19.2
# via -r requirements/base.in
six==1.16.0
# via
# bleach
# fs
web-fragments==2.0.0
sqlparse==0.4.4
# via django
typing-extensions==4.8.0
# via asgiref
web-fragments==2.1.0
# via -r requirements/base.in
webencodings==0.5.1
# via bleach
Expand Down
47 changes: 43 additions & 4 deletions requirements/ci.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,65 @@ appdirs==1.4.4
# via
# -r requirements/test.txt
# fs
bleach==6.0.0
asgiref==3.7.2
# via
# -r requirements/test.txt
# django
bleach==6.1.0
# via -r requirements/test.txt
django==3.2.22
# via
# -c requirements/common_constraints.txt
# -r requirements/test.txt
# edx-i18n-tools
edx-i18n-tools==1.3.0
# via -r requirements/test.txt
fs==2.4.16
# via -r requirements/test.txt
lxml==4.9.3
# via
# -r requirements/test.txt
# edx-i18n-tools
mako==1.2.4
# via -r requirements/test.txt
markupsafe==2.1.3
# via
# -r requirements/test.txt
# mako
pycodestyle==2.10.0
path==16.7.1
# via
# -r requirements/test.txt
# edx-i18n-tools
polib==1.2.0
# via
# -r requirements/test.txt
# edx-i18n-tools
pycodestyle==2.11.0
# via -r requirements/test.txt
simplejson==3.19.1
pytz==2023.3.post1
# via
# -r requirements/test.txt
# django
pyyaml==6.0.1
# via
# -r requirements/test.txt
# edx-i18n-tools
simplejson==3.19.2
# via -r requirements/test.txt
six==1.16.0
# via
# -r requirements/test.txt
# bleach
# fs
web-fragments==2.0.0
sqlparse==0.4.4
# via
# -r requirements/test.txt
# django
typing-extensions==4.8.0
# via
# -r requirements/test.txt
# asgiref
web-fragments==2.1.0
# via -r requirements/test.txt
webencodings==0.5.1
# via
Expand Down
5 changes: 0 additions & 5 deletions requirements/common_constraints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,3 @@ django-simple-history==3.0.0
# tox>4.0.0 isn't yet compatible with many tox plugins, causing CI failures in almost all repos.
# Details can be found in this discussion: https://github.com/tox-dev/tox/discussions/1810
tox<4.0.0

# edx-sphinx-theme is not compatible with latest Sphinx==6.0.0 version
# Pinning Sphinx version unless the compatibility issue gets resolved
# For details, see issue https://github.com/openedx/edx-sphinx-theme/issues/197
sphinx<6.0.0
Loading

0 comments on commit dc013ff

Please sign in to comment.