Skip to content

Commit

Permalink
MCKIN-23600 Automating scorm xblock extraction process in PO file (#49)
Browse files Browse the repository at this point in the history
* MCKIN-23600 Automating scorm xblock extraction process in PO file

* Update config.yaml
  • Loading branch information
wasifarbisoft authored Sep 2, 2020
1 parent caaeb46 commit a3df336
Show file tree
Hide file tree
Showing 10 changed files with 479 additions and 8 deletions.
37 changes: 37 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
.DEFAULT_GOAL := help

WORKING_DIR := scormxblock
JS_TARGET := $(WORKING_DIR)/public/js/translations
EXTRACT_DIR := $(WORKING_DIR)/translations/en/LC_MESSAGES
EXTRACTED_DJANGO := $(EXTRACT_DIR)/django-partial.po
EXTRACTED_TEXT := $(EXTRACT_DIR)/text.po
EXTRACTED_DJANGOJS := $(EXTRACT_DIR)/djangojs-partial.po
EXTRACTED_TEXTJS := $(EXTRACT_DIR)/textjs.po


help: ## display this help message
@echo "Please use \`make <target>' where <target> is one of"
@perl -nle'print $& if m{^[a-zA-Z_-]+:.*?## .*$$}' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m %-25s\033[0m %s\n", $$1, $$2}'

extract_translations: ## extract strings to be translated, outputting .po files
cd $(WORKING_DIR) && i18n_tool extract
mv $(EXTRACTED_DJANGO) $(EXTRACTED_TEXT)
if [ -f "$(EXTRACTED_DJANGOJS)" ]; then mv $(EXTRACTED_DJANGOJS) $(EXTRACTED_TEXTJS); fi
rm -f $(EXTRACTED_DJANGO)
rm -f $(EXTRACTED_DJANGOJS)
find $(EXTRACT_DIR) -type f -name "*.po" -exec sed -i'' -e 's/nplurals=INTEGER/nplurals=2/' {} \;
find $(EXTRACT_DIR) -type f -name "*.po" -exec sed -i'' -e 's/plural=EXPRESSION/plural=\(n != 1\)/' {} \;

compile_translations: ## compile translation files, outputting .mo files for each supported language
cd $(WORKING_DIR) && i18n_tool generate
python manage.py compilejsi18n --output $(JS_TARGET)

detect_changed_source_translations:
cd $(WORKING_DIR) && i18n_tool changed

dummy_translations: ## generate dummy translation (.po) files
cd $(WORKING_DIR) && i18n_tool dummy

build_dummy_translations: dummy_translations compile_translations ## generate and compile dummy translation files

validate_translations: build_dummy_translations detect_changed_source_translations ## validate translations
36 changes: 29 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,20 @@ edx_xblock_scorm
=========================

XBlock to display SCORM content within the Open edX LMS. Editable within Open edx Studio. Will save student state and report scores to the progress tab of the course.
Currently supports SCORM 1.2 standard, but not yet SCORM 2004. It supports multi-SCO content packages.
Currently supports SCORM 1.2 standard, but not yet SCORM 2004. It supports multi-SCO content packages.


# Installation

## Using Ansible

* Add to your `server-vars.yml` file this entry underneath the `EDXAPP_EXTRA_REQUIREMENTS` key

```
- name: 'git+https://github.com/appsembler/edx_xblock_scorm@use_ssla_player#egg=scormxblock'
```

* Configure a SCORM player backend in the XBlock settings, under the `"ScormXBlock"`. Currently you must provide the SSLA player by JCA Solutions.
* Configure a SCORM player backend in the XBlock settings, under the `"ScormXBlock"`. Currently you must provide the SSLA player by JCA Solutions.

```
EDXAPP_XBLOCK_SETTINGS:
Expand All @@ -38,7 +38,7 @@ Each backend is a key under `SCORM_PLAYER_BACKENDS` and should provide a `"name"

* Configure Staff Debug Info: If you want staff debug info for SCORM XBlocks to be visible to instructors and other permitted staff, add this key to your `EDXAPP_XBLOCK_SETTINGS` key for 'ScormXBlock'. Only the 'Delete Student State' action will work; 'Reset Student Attempts' and 'Rescore Student Submission' are not yet operable, but may be in the future.

```
```
"SCORM_DISPLAY_STAFF_DEBUG_INFO": true
```

Expand All @@ -49,12 +49,34 @@ Nginx (or other front-end web server) must be configured to serve SCORM content.

# Usage
* In Studio, add `scormxblock` to the list of advanced modules in the advanced settings of a course.
* Add a 'scorm' component to your Unit.
* Specify a display name, an optional description, and choose a 'player' (IMPORTANT: currently only works using the commercial SSLA player from JCA Solutions. Contact Appsembler if you would like assistance with this).
* Add a 'scorm' component to your Unit.
* Specify a display name, an optional description, and choose a 'player' (IMPORTANT: currently only works using the commercial SSLA player from JCA Solutions. Contact Appsembler if you would like assistance with this).
* Specify a weight for your SCORM content within your Open edX course. For example, your course SCO may have an internal max. score of 100. If you give your SCORM component a weight of 10 and a student scores 50 within the SCORM course, they will receive 5 points within Open edX. SCORM components can be weighted as normal against other gradable Open edX components.
* Choose a display format (popup or iframe -- only use iframe if your SCORM content package itself creates a popup window) and display size.
* Choose a display format (popup or iframe -- only use iframe if your SCORM content package itself creates a popup window) and display size.
* Upload a zip file containint your content package. The `imsmanifest.xml` file must be at the root of the zipped package (i.e., make sure you don't have an additional directory at the root of the Zip archive which can handle if e.g., you select an entire folder and use Mac OS X's compress feature).
* Publish your content as usual.

# Translation (i18n)

This repo offers multiple make targets to automate the translation tasks.
Each make target will be explained below:

- `extract_translations`. Use [`i18n_tool` extract](https://github.com/edx/i18n-tools) to create `.po` files based on all the tagged strings in the python and javascript code.
- `compile_translations`. Use [`i18n_tool` generate](https://github.com/edx/i18n-tools) to create `.mo` compiled files.
- `detect_changed_source_translations`. Use [`i18n_tool` changed](https://github.com/edx/i18n-tools) to identify any updated translations.
- `validate_translations`. Compile translations and check the source translations haven't changed.

If you want to add a new language:
1. Add language to `scormxblock/translations/config.yaml`
2. Make sure all tagged strings have been extracted:
```bash
make extract_translations
```
3. Clone `en` directory to `scormxblock/translations/<lang_code>/` for example: `scormxblock/translations/fa_IR/`
4. Make necessary changes to translation files headers. Make sure you have proper `Language` and `Plural-Forms` lines.
5. When you finished your modification process, re-compile the translation messages.
```bash
make compile_translations
```


10 changes: 10 additions & 0 deletions manage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/usr/bin/env python
import os
import sys

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

from django.core.management import execute_from_command_line

execute_from_command_line(sys.argv)
1 change: 1 addition & 0 deletions scormxblock/conf/locale
101 changes: 101 additions & 0 deletions scormxblock/public/js/translations/en/textjs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@

(function(global){
var ScormxBlockXBlockI18N = {
init: function() {


(function (globals) {

var django = globals.django || (globals.django = {});


django.pluralidx = function (count) { return (count == 1) ? 0 : 1; };



/* gettext identity library */

django.gettext = function (msgid) { return msgid; };
django.ngettext = function (singular, plural, count) { return (count == 1) ? singular : plural; };
django.gettext_noop = function (msgid) { return msgid; };
django.pgettext = function (context, msgid) { return msgid; };
django.npgettext = function (context, singular, plural, count) { return (count == 1) ? singular : plural; };


django.interpolate = function (fmt, obj, named) {
if (named) {
return fmt.replace(/%\(\w+\)s/g, function(match){return String(obj[match.slice(2,-2)])});
} else {
return fmt.replace(/%s/g, function(match){return String(obj.shift())});
}
};


/* formatting library */

django.formats = {
"DATETIME_FORMAT": "N j, Y, P",
"DATETIME_INPUT_FORMATS": [
"%Y-%m-%d %H:%M:%S",
"%Y-%m-%d %H:%M:%S.%f",
"%Y-%m-%d %H:%M",
"%Y-%m-%d",
"%m/%d/%Y %H:%M:%S",
"%m/%d/%Y %H:%M:%S.%f",
"%m/%d/%Y %H:%M",
"%m/%d/%Y",
"%m/%d/%y %H:%M:%S",
"%m/%d/%y %H:%M:%S.%f",
"%m/%d/%y %H:%M",
"%m/%d/%y"
],
"DATE_FORMAT": "N j, Y",
"DATE_INPUT_FORMATS": [
"%Y-%m-%d",
"%m/%d/%Y",
"%m/%d/%y"
],
"DECIMAL_SEPARATOR": ".",
"FIRST_DAY_OF_WEEK": "0",
"MONTH_DAY_FORMAT": "F j",
"NUMBER_GROUPING": "3",
"SHORT_DATETIME_FORMAT": "m/d/Y P",
"SHORT_DATE_FORMAT": "m/d/Y",
"THOUSAND_SEPARATOR": ",",
"TIME_FORMAT": "P",
"TIME_INPUT_FORMATS": [
"%H:%M:%S",
"%H:%M:%S.%f",
"%H:%M"
],
"YEAR_MONTH_FORMAT": "F Y"
};

django.get_format = function (format_type) {
var value = django.formats[format_type];
if (typeof(value) == 'undefined') {
return format_type;
} else {
return value;
}
};

/* add to global namespace */
globals.pluralidx = django.pluralidx;
globals.gettext = django.gettext;
globals.ngettext = django.ngettext;
globals.gettext_noop = django.gettext_noop;
globals.pgettext = django.pgettext;
globals.npgettext = django.npgettext;
globals.interpolate = django.interpolate;
globals.get_format = django.get_format;

}(this));


}
};
ScormxBlockXBlockI18N.init();
global.ScormxBlockXBlockI18N = ScormxBlockXBlockI18N;
}(this));

83 changes: 83 additions & 0 deletions scormxblock/settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
"""
Django settings for the scormxblock 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, ...)
import os
import yaml

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', 'xydut433=!s!i(n9u&1oiyv!hu1k=(h-)nuu30d(gd(ew%7+1w')

# 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',
'scormxblock',
'django.contrib.auth',
'django.contrib.contenttypes',
)

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

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True


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

STATIC_URL = '/static/'

LOCALE_PATHS = [
os.path.join(BASE_DIR, 'scormxblock/translations'),
]

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

with open(os.path.join(BASE_DIR, 'scormxblock/translations/config.yaml'), 'r') as locale_config_file:
LOCALE_CONFIG = yaml.load(locale_config_file)

LANGUAGES = [
(code, code,)
for code in LOCALE_CONFIG['locales'] + LOCALE_CONFIG['dummy_locales']
]

STATICI18N_DOMAIN = 'textjs'

STATICI18N_NAMESPACE = 'ScormxBlockXBlockI18N'
STATICI18N_PACKAGES = (
'scormxblock',
)
STATICI18N_ROOT = 'scormxblock/public/js'
STATICI18N_OUTPUT_DIR = 'translations'
29 changes: 29 additions & 0 deletions scormxblock/translations/config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Configuration for i18n workflow.

locales:
- en # English - Source Language
- ar # Arabic
- es_419 # Spanish (Latin America)
- ja_JP # Japanese
- ko_KR # Korean
- fr # French
- pt_BR # Portuguese (Brazil)
- zh_CN # Chinese (China)
- de_DE # German
- pl # Polish

# The locales used for fake-accented English, for testing.
dummy_locales:
- eo

# Directories we don't search for strings.
ignore_dirs:
- tests
- translations

# i18n_tools produces just "django-partial.po" by default, but we need "text.po":
generate_merge:
text.po:
- django-partial.po
textjs.po:
- djangojs-partial.po
Loading

0 comments on commit a3df336

Please sign in to comment.