Skip to content

Commit

Permalink
avoid duplicated CSS and JavaScript files
Browse files Browse the repository at this point in the history
  • Loading branch information
vasiljevic committed May 20, 2018
1 parent 6018d7d commit 09bcfc6
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 49 deletions.
39 changes: 25 additions & 14 deletions I18N.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,39 +3,50 @@ Internationalization

RunestoneComponents uses Wikimedia'a [jQuery.i18n](https://github.com/wikimedia/jquery.i18n) Javascript internationalization library.

Configuration and message loading
---------------------------------
Message loading scripts
-----------------------

In the `js` subfolder of a component's source folder you should create javascript files for i18n message loading. File names shoud folow the structure:
In the `js` subfolder of your component's source folder you should create javascript files for i18n message loading. A mesage loading script file name shoud folow the pattern:

_resoruce-name_`.`_language-code_`.js`
_message-bunlde-name_`.`_language-code_`.js`

where _resource-name_ should start with the component's name and ends wit `-i18n`. For examle, the english message loading script for the ActiveCode componet is `activecode-i18n.en.js`.
where _message-bunlde-name_ should start with the component's name and ends with `-i18n`. For examle, the english message loading script for the ActiveCode componet is `activecode-i18n.en.js`.

Read more about message loading at [https://github.com/wikimedia/jquery.i18n#message-loading](https://github.com/wikimedia/jquery.i18n#message-loading)

Since messages for different components may be loaded in the same web page context, to avoid name conflicts, message keys should start with `msg_`_component-name_`_` like in this sample mesaage key: `msg_activecode_play_audio`
Since messages for different components may be loaded in the same web page context, to avoid name conflicts, message keys should folow the pattern:

English is the default language. For each _resource-name_ english JavaScript file is mandatory and must define all message keys you need. For other languages you may define subset of message keys defined in the english version.
`msg_`_component-name_`_`_given-name_

Then in your component's main script file (_component-name_`.js`) import `add_i18n_javascript` from `runestone.common.runestonedirective` and in the `setup()` function add the line
`add_i18n_javascript(app,`_supported-languages_`,`_resource-name_`)`
For exemple: `msg_activecode_play_audio`

The default language is English. For each _message-bunlde-name_ there should be English message loading script with all message keys defines. For any other language you may define just a subset of those message keys.

Configure I18N
--------------

In your component's main script file (_component-name_`.py`):
- import `add_i18n_javascript` from `runestone.common.runestonedirective`
- in the `setup()` function add the call
`add_i18n_javascript(app,`_supported-languages_`,`_message-bunlde-name_`)`
before adding any other JavaScript that use i18n messages. For instance:
`add_i18n_javascript(app, {"sr-Cyrl"}, "activecode-i18n")`

Since English language support is mandatory, it is not necessary to specify it in _supported-languages_.

You may group your messages in more files, and use:
`add_i18n_javascript(app,`_supported-languages_`,`_resource-name1_`,`_resource-name2_ ...`)`
You may group your messages in different message bundles:
`add_i18n_javascript(app,`_supported-languages_`,`_message-bunlde-name1_`,`_message-bunlde-name2_ ...`)`
for instance:
`add_i18n_javascript(app, {"sr-Cyrl"}, "activecode-UI-i18n","activecode-compiler-i18n")`
`add_i18n_javascript(app, {"sr-Cyrl"}, "mycomponent-UI-i18n","mycomponent-compiler-i18n")`

Use message keys instead of hard coded messages
-----------------------------------------------

See [https://github.com/wikimedia/jquery.i18n#jqueryi18n-plugin](https://github.com/wikimedia/jquery.i18n#jqueryi18n-plugin)
Now you may use defined message keys in your component's front-end code (JavaScript and HTML). For more details see [https://github.com/wikimedia/jquery.i18n#jqueryi18n-plugin](https://github.com/wikimedia/jquery.i18n#jqueryi18n-plugin).



For book authors
----------------

To select language, you should assign `language` value in `conf.py` to contain apropriate language code.
In `conf.py` of your book project, you should just set the `language` variable to an apropriate language code.
16 changes: 5 additions & 11 deletions runestone/activecode/activecode.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
from .textfield import *
from sqlalchemy import Table
from runestone.server.componentdb import addQuestionToDB, addHTMLToDB, engine, meta
from runestone.common.runestonedirective import RunestoneIdDirective, RunestoneNode, add_i18n_javascript
from runestone.common.runestonedirective import (RunestoneIdDirective, RunestoneNode,
add_i18n_js, add_codemirror_css_and_js, add_skulpt_js)

try:
from html import escape # py3
Expand All @@ -36,21 +37,14 @@ def setup(app):
app.add_directive('activecode', ActiveCode)
app.add_directive('actex', ActiveExercise)
app.add_role('textfield',textfield_role)
app.add_stylesheet('codemirror.css')
app.add_stylesheet('activecode.css')

app.add_javascript('jquery.highlight.js')
app.add_javascript('bookfuncs.js')
app.add_javascript('codemirror.js')
app.add_javascript('xml.js')
app.add_javascript('css.js')
app.add_javascript('htmlmixed.js')
app.add_javascript('python.js')
app.add_javascript('javascript.js')
add_i18n_javascript(app, {"en","sr-Cyrl"},"activecode-i18n")
add_codemirror_css_and_js(app,'xml','css','python','htmlmixex','javascript')
add_i18n_js(app, {"en","sr-Cyrl"},"activecode-i18n")
add_skulpt_js(app)
app.add_javascript('activecode.js')
app.add_javascript('skulpt.min.js')
app.add_javascript('skulpt-stdlib.js')
app.add_javascript('clike.js')
app.add_javascript('timed_activecode.js')

Expand Down
53 changes: 39 additions & 14 deletions runestone/common/runestonedirective.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,22 +141,47 @@ def run(self):
id_to_page[id_] = Struct(docname=env.docname, lineno=self.lineno)
page_to_id[env.docname].add(id_)

# returns True when called first time with particular parameters' values
def first_time(app, *keys):
key = '$'.join(keys)
if not hasattr(app,'runestone_flags'):
app.runestone_flags = set()
if not key in app.runestone_flags:
app.runestone_flags.add(key)
return True
return False

# An internationalized component should call add_i18n_javascript() from its setup() function
def add_i18n_javascript(app, supported_langs, *i18n_resources):
app.add_javascript('jquery_i18n/CLDRPluralRuleParser.js')
app.add_javascript('jquery_i18n/jquery.i18n.js')
app.add_javascript('jquery_i18n/jquery.i18n.messagestore.js')
app.add_javascript('jquery_i18n/jquery.i18n.fallbacks.js')
app.add_javascript('jquery_i18n/jquery.i18n.language.js')
app.add_javascript('jquery_i18n/jquery.i18n.parser.js')
app.add_javascript('jquery_i18n/jquery.i18n.emitter.js')
app.add_javascript('jquery_i18n/jquery.i18n.emitter.bidi.js')
def add_i18n_js(app, supported_langs, *i18n_resources):
if first_time(app, 'add_i18n_js'):
app.add_javascript('jquery_i18n/CLDRPluralRuleParser.js')
app.add_javascript('jquery_i18n/jquery.i18n.js')
app.add_javascript('jquery_i18n/jquery.i18n.messagestore.js')
app.add_javascript('jquery_i18n/jquery.i18n.fallbacks.js')
app.add_javascript('jquery_i18n/jquery.i18n.language.js')
app.add_javascript('jquery_i18n/jquery.i18n.parser.js')
app.add_javascript('jquery_i18n/jquery.i18n.emitter.js')
app.add_javascript('jquery_i18n/jquery.i18n.emitter.bidi.js')
for res in i18n_resources:
app.add_javascript(res + ".en.js")
if app.config.language and app.config.language != "en" and app.config.language in supported_langs:
app.add_javascript(res + "." + app.config.language + ".js")


if(first_time(app,'add_i18n_js','key')):
app.add_javascript(res + ".en.js")
if app.config.language and app.config.language != "en" and app.config.language in supported_langs:
app.add_javascript(res + "." + app.config.language + ".js")

# Adds CSS and JavaScript for the CodeMirror text editor
def add_codemirror_css_and_js(app, *mods):
if first_time(app, 'add_codemirror_css_and_js'):
app.add_stylesheet('codemirror.css')
app.add_javascript('codemirror.js')
for mod in mods:
if first_time(app, 'add_codemirror_css_and_js',mod):
app.add_javascript(mod + '.js')

# Adds JavaScript for the Sculpt in-browser implementation of Python
def add_skulpt_js(app):
if first_time(app, 'add_skulpt_js'):
app.add_javascript('skulpt.min.js')
app.add_javascript('skulpt-stdlib.js')

# Some nodes have a line number of None. Look through their children to find the node's line number.
def get_node_line(node):
Expand Down
6 changes: 3 additions & 3 deletions runestone/datafile/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@
from docutils.parsers.rst import directives
from sqlalchemy import Table
from runestone.server.componentdb import engine, meta
from runestone.common.runestonedirective import RunestoneIdDirective, RunestoneNode
from runestone.common.runestonedirective import RunestoneIdDirective, RunestoneNode, add_skulpt_js

def setup(app):
app.add_directive('datafile',DataFile)
app.add_javascript('skulpt.min.js')
app.add_javascript('skulpt-stdlib.js')
add_skulpt_js(app)

app.add_javascript('datafile.js')

app.add_stylesheet('datafile.css')
Expand Down
9 changes: 2 additions & 7 deletions runestone/webgldemo/webgldemo.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import string
import re
import os
from runestone.common.runestonedirective import add_codemirror_css_and_js

__author__ = 'wayne brown'

Expand All @@ -43,16 +44,10 @@ def setup(app):
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
app.add_directive('webglinteractive', WebglInteractive)

app.add_stylesheet('codemirror.css')
app.add_stylesheet('webglinteractive.css')

# CodeMirror syntax highlighting for various types of code
app.add_javascript('codemirror.js')
app.add_javascript('xml.js')
app.add_javascript('css.js')
app.add_javascript('htmlmixed.js')
app.add_javascript('python.js')
app.add_javascript('javascript.js')
add_codemirror_css_and_js(app,'xml','css','htmlmixex','javascript')

app.add_javascript('webglinteractive.js')

Expand Down

0 comments on commit 09bcfc6

Please sign in to comment.