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 10, 2023
1 parent ed52df4 commit b6827a1
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)
92 changes: 92 additions & 0 deletions dev_settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
"""
Django settings for xblock-drag-and-drop-v2 project.
For more information on this file, see
https://docs.djangoproject.com/en/1.11/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.11/ref/settings/
"""

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
from __future__ import absolute_import
import os
BASE_DIR = os.path.dirname(os.path.dirname(__file__))


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
# This is just a container for running tests, it's okay to allow it to be
# defaulted here if not present in environment settings
SECRET_KEY = os.environ.get('SECRET_KEY', '&=@m=qyqg#l!f99ouuuinpbsv0ah001unk@q^7)bkr^^n5@q1=')

# SECURITY WARNING: don't run with debug turned on in production!
# This is just a container for running tests
DEBUG = True

TEMPLATE_DEBUG = True

ALLOWED_HOSTS = []


# Application definition

INSTALLED_APPS = (
'statici18n',
'recommender',
)

# Internationalization
# https://docs.djangoproject.com/en/1.11/topics/i18n/

LANGUAGE_CODE = 'en'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.11/howto/static-files/

STATIC_URL = '/static/'

# statici18n
# http://django-statici18n.readthedocs.io/en/latest/settings.html

LANGUAGES = [
('ar', 'Arabic'),
('de', 'German'),
('en', 'English - Source Language'),
('eo', 'Esperanto'),
('es_419', 'Spanish (Latin America)'),
('fr', 'French'),
('he', 'Hebrew'),
('hi', 'Hindi'),
('it', 'Italian'),
('ja', 'Japanese'),
('ko', 'Korean (Korea)'),
('nl', 'Dutch'),
('pl', 'Polski'),
('pt_BR', 'Portuguese (Brazil)'),
('pt_PT', 'Portuguese (Portugal)'),
('ru', 'Russian'),
('tr', 'Turkish'),
('zh_CN', 'Chinese (China)'),
]

LOCALE_PATHS = [os.path.join(BASE_DIR, "locale")]

STATICI18N_DOMAIN = 'text'
STATICI18N_NAMESPACE = 'RecommenderXBlockI18N'
STATICI18N_PACKAGES = (
'recommender',
)
STATICI18N_ROOT = 'recommender/public/js'
STATICI18N_OUTPUT_DIR = 'translations'
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",
"dev_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
Loading

0 comments on commit b6827a1

Please sign in to comment.