Commit 0c8911a4 by Tim Krones

Merge pull request #36 from open-craft/i18n

Mark user-visible strings for translation
parents 595b5fd2 7dd4efba
from .utils import _
DEFAULT_DATA = { DEFAULT_DATA = {
"zones": [ "zones": [
{ {
"index": 1, "index": 1,
"width": 200, "width": 200,
"title": "Zone 1", "title": _("Zone 1"),
"height": 100, "height": 100,
"x": "120", "x": "120",
"y": "200", "y": "200",
...@@ -12,7 +14,7 @@ DEFAULT_DATA = { ...@@ -12,7 +14,7 @@ DEFAULT_DATA = {
{ {
"index": 2, "index": 2,
"width": 200, "width": 200,
"title": "Zone 2", "title": _("Zone 2"),
"height": 100, "height": 100,
"x": "120", "x": "120",
"y": "360", "y": "360",
...@@ -23,8 +25,8 @@ DEFAULT_DATA = { ...@@ -23,8 +25,8 @@ DEFAULT_DATA = {
{ {
"displayName": "1", "displayName": "1",
"feedback": { "feedback": {
"incorrect": "No, 1 does not belong here", "incorrect": _("No, 1 does not belong here"),
"correct": "Yes, it's a 1" "correct": _("Yes, it's a 1")
}, },
"zone": "Zone 1", "zone": "Zone 1",
"backgroundImage": "", "backgroundImage": "",
...@@ -37,8 +39,8 @@ DEFAULT_DATA = { ...@@ -37,8 +39,8 @@ DEFAULT_DATA = {
{ {
"displayName": "2", "displayName": "2",
"feedback": { "feedback": {
"incorrect": "No, 2 does not belong here", "incorrect": _("No, 2 does not belong here"),
"correct": "Yes, it's a 2" "correct": _("Yes, it's a 2")
}, },
"zone": "Zone 2", "zone": "Zone 2",
"backgroundImage": "", "backgroundImage": "",
...@@ -51,7 +53,7 @@ DEFAULT_DATA = { ...@@ -51,7 +53,7 @@ DEFAULT_DATA = {
{ {
"displayName": "X", "displayName": "X",
"feedback": { "feedback": {
"incorrect": "You silly, there are no zones for X", "incorrect": _("You silly, there are no zones for X"),
"correct": "" "correct": ""
}, },
"zone": "none", "zone": "none",
...@@ -68,7 +70,7 @@ DEFAULT_DATA = { ...@@ -68,7 +70,7 @@ DEFAULT_DATA = {
"finished": True "finished": True
}, },
"feedback": { "feedback": {
"start": "Intro Feed", "start": _("Intro Feed"),
"finish": "Final Feed" "finish": _("Final Feed")
}, },
} }
...@@ -12,7 +12,7 @@ from xblock.core import XBlock ...@@ -12,7 +12,7 @@ from xblock.core import XBlock
from xblock.fields import Scope, String, Dict, Float, Boolean from xblock.fields import Scope, String, Dict, Float, Boolean
from xblock.fragment import Fragment from xblock.fragment import Fragment
from .utils import render_template, load_resource from .utils import _, render_template, load_resource
from .default_data import DEFAULT_DATA from .default_data import DEFAULT_DATA
...@@ -23,29 +23,29 @@ class DragAndDropBlock(XBlock): ...@@ -23,29 +23,29 @@ class DragAndDropBlock(XBlock):
XBlock providing a Drag and Drop question XBlock providing a Drag and Drop question
""" """
display_name = String( display_name = String(
display_name="Title", display_name=_("Title"),
help="The title of the Drag and Drop that is displayed to the user", help=_("The title of the Drag and Drop that is displayed to the user"),
scope=Scope.settings, scope=Scope.settings,
default="Drag and Drop", default=_("Drag and Drop"),
) )
show_title = Boolean( show_title = Boolean(
display_name="Show title", display_name=_("Show title"),
help="Display the title to the user?", help=_("Display the title to the user?"),
scope=Scope.settings, scope=Scope.settings,
default=True, default=True,
) )
question_text = String( question_text = String(
display_name="Question text", display_name=_("Question text"),
help="The question text that is displayed to the user", help=_("The question text that is displayed to the user"),
scope=Scope.settings, scope=Scope.settings,
default="", default="",
) )
weight = Float( weight = Float(
display_name="Weight", display_name=_("Weight"),
help="This is the maximum score that the user receives when he/she successfully completes the problem", help=_("This is the maximum score that the user receives when he/she successfully completes the problem"),
scope=Scope.settings, scope=Scope.settings,
default=1, default=1,
) )
...@@ -71,26 +71,30 @@ class DragAndDropBlock(XBlock): ...@@ -71,26 +71,30 @@ class DragAndDropBlock(XBlock):
) )
data = Dict( data = Dict(
display_name="Drag and Drop", display_name=_("Drag and Drop"),
help="JSON spec as generated by the builder", help=_("JSON spec as generated by the builder"),
scope=Scope.content, scope=Scope.content,
default=DEFAULT_DATA, default=DEFAULT_DATA,
) )
item_state = Dict( item_state = Dict(
help="How the student has interacted with the problem", help=_("How the student has interacted with the problem"),
scope=Scope.user_state, scope=Scope.user_state,
default={}, default={},
) )
completed = Boolean( completed = Boolean(
help="The student has completed the problem at least once", help=_("The student has completed the problem at least once"),
scope=Scope.user_state, scope=Scope.user_state,
default=False, default=False,
) )
has_score = True has_score = True
def _(self, text):
""" Translate text """
return self.runtime.service(self, "i18n").ugettext(text)
def student_view(self, context): def student_view(self, context):
""" """
Player view, displayed to the student Player view, displayed to the student
...@@ -124,8 +128,13 @@ class DragAndDropBlock(XBlock): ...@@ -124,8 +128,13 @@ class DragAndDropBlock(XBlock):
""" """
js_templates = load_resource('/templates/html/js_templates.html') js_templates = load_resource('/templates/html/js_templates.html')
help_texts = {
'item_background_color': self._(self.fields['item_background_color'].help),
'item_text_color': self._(self.fields['item_text_color'].help)
}
context = { context = {
'js_templates': js_templates, 'js_templates': js_templates,
'help_texts': help_texts,
'self': self, 'self': self,
'data': urllib.quote(json.dumps(self.data)), 'data': urllib.quote(json.dumps(self.data)),
} }
......
function DragAndDropBlock(runtime, element) { function DragAndDropBlock(runtime, element) {
// Set up gettext in case it isn't available in the client runtime:
if (typeof gettext == "undefined") {
window.gettext = function gettext_stub(string) { return string; };
}
var root = $(element).find('.xblock--drag-and-drop')[0]; var root = $(element).find('.xblock--drag-and-drop')[0];
var __state; var __state;
......
function DragAndDropEditBlock(runtime, element) { function DragAndDropEditBlock(runtime, element) {
// Set up gettext in case it isn't available in the client runtime:
if (typeof gettext == "undefined") {
window.gettext = function gettext_stub(string) { return string; };
}
// Make gettext available in Handlebars templates
Handlebars.registerHelper('i18n', function(str) { return gettext(str); });
var dragAndDrop = (function($) { var dragAndDrop = (function($) {
var _fn = { var _fn = {
...@@ -425,7 +434,8 @@ function DragAndDropEditBlock(runtime, element) { ...@@ -425,7 +434,8 @@ function DragAndDropEditBlock(runtime, element) {
if (response.result === 'success') { if (response.result === 'success') {
window.location.reload(false); window.location.reload(false);
} else { } else {
$('.xblock-editor-error-message', element).html('Error: '+response.message); $('.xblock-editor-error-message', element)
.html(gettext('Error: ') + response.message);
$('.xblock-editor-error-message', element).css('display', 'block'); $('.xblock-editor-error-message', element).css('display', 'block');
} }
}); });
......
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
style: {display: input.is_visible ? 'block' : 'none'}}, [ style: {display: input.is_visible ? 'block' : 'none'}}, [
h('input.input', {type: 'text', value: input.value, disabled: input.has_value, h('input.input', {type: 'text', value: input.value, disabled: input.has_value,
focusHook: focus_hook}), focusHook: focus_hook}),
h('button.submit-input', {disabled: input.has_value}, 'ok') h('button.submit-input', {disabled: input.has_value}, gettext('ok'))
]) ])
); );
}; };
...@@ -77,8 +77,8 @@ ...@@ -77,8 +77,8 @@
var reset_button_display = ctx.display_reset_button ? 'block' : 'none'; var reset_button_display = ctx.display_reset_button ? 'block' : 'none';
return ( return (
h('section.feedback', [ h('section.feedback', [
h('div.reset-button', {style: {display: reset_button_display}}, 'Reset exercise'), h('div.reset-button', {style: {display: reset_button_display}}, gettext('Reset exercise')),
h('div.title1', {style: {display: feedback_display}}, 'Feedback'), h('div.title1', {style: {display: feedback_display}}, gettext('Feedback')),
h('p.message', {style: {display: feedback_display}, h('p.message', {style: {display: feedback_display},
innerHTML: ctx.feedback_html}) innerHTML: ctx.feedback_html})
]) ])
...@@ -94,7 +94,7 @@ ...@@ -94,7 +94,7 @@
h('section.xblock--drag-and-drop', [ h('section.xblock--drag-and-drop', [
problemHeader, problemHeader,
h('section.problem', {role: 'application'}, [ h('section.problem', {role: 'application'}, [
h('div.title1', 'Question'), h('div.title1', gettext('Question')),
h('p', {innerHTML: ctx.question_html}) h('p', {innerHTML: ctx.question_html})
]), ]),
h('section.drag-container', [ h('section.drag-container', [
......
...@@ -10,26 +10,26 @@ ...@@ -10,26 +10,26 @@
<section class="drag-builder"> <section class="drag-builder">
<div class="tab feedback-tab"> <div class="tab feedback-tab">
<p class="tab-content"> <p class="tab-content">
Note: don't edit the question if students already answered it! Delete it and create a new one. {% trans "Note: don't edit the question if students already answered it! Delete it and create a new one." %}
</p> </p>
<section class="tab-content"> <section class="tab-content">
<form class="feedback-form"> <form class="feedback-form">
<h3>Question title</h3> <h3>{% trans "Question title" %}</h3>
<input class="display-name" value="{{ self.display_name }}" /> <input class="display-name" value="{{ self.display_name }}" />
<input class="show-title" type="checkbox" value="{{ self.show_title }}" <input class="show-title" type="checkbox" value="{{ self.show_title }}"
{% if self.show_title %}checked="checked"{% endif %}> Show title {% if self.show_title %}checked="checked"{% endif %}> {% trans "Show title" %}
<h3>Maximum score</h3> <h3>{% trans "Maximum score" %}</h3>
<input class="weight" value="1" value="{{ self.weight }}"/> <input class="weight" value="1" value="{{ self.weight }}"/>
<h3>Question text</h3> <h3>{% trans "Question text" %}</h3>
<textarea class="question-text">{{ self.question_text }}</textarea> <textarea class="question-text">{{ self.question_text }}</textarea>
<h3>Introduction Feedback</h3> <h3>{% trans "Introduction Feedback" %}</h3>
<textarea class="intro-feedback">{{ self.data.feedback.start }}</textarea> <textarea class="intro-feedback">{{ self.data.feedback.start }}</textarea>
<h3>Final Feedback</h3> <h3>{% trans "Final Feedback" %}</h3>
<textarea class="final-feedback">{{ self.data.feedback.finish }}</textarea> <textarea class="final-feedback">{{ self.data.feedback.finish }}</textarea>
</form> </form>
</section> </section>
...@@ -37,21 +37,21 @@ ...@@ -37,21 +37,21 @@
<div class="tab zones-tab hidden"> <div class="tab zones-tab hidden">
<header class="tab-header"> <header class="tab-header">
<h3>Zone Positions</h3> <h3>{% trans "Zone Positions" %}</h3>
</header> </header>
<section class="tab-content"> <section class="tab-content">
<section class="tab-content target-image-form"> <section class="tab-content target-image-form">
<label>New background URL:</label> <label>{% trans "New background URL" %}:</label>
<input type="text"> <input type="text">
<button class="btn">Change background</button> <button class="btn">{% trans "Change background" %}</button>
</section> </section>
<section class="tab-content display-labels-form"> <section class="tab-content display-labels-form">
<label for="display-labels">Display label names on the image:</label> <label for="display-labels">{% trans "Display label names on the image" %}:</label>
<input name="display-labels" id="display-labels" type="checkbox" /> <input name="display-labels" id="display-labels" type="checkbox" />
</section> </section>
<div class="items"> <div class="items">
<form class="zones-form"></form> <form class="zones-form"></form>
<a href="#" class="add-zone add-element"><div class="icon add"></div>Add a zone</a> <a href="#" class="add-zone add-element"><div class="icon add"></div>{% trans "Add a zone" %}</a>
</div> </div>
<div class="target"> <div class="target">
<div class="target-img"></div> <div class="target-img"></div>
...@@ -61,7 +61,7 @@ ...@@ -61,7 +61,7 @@
<div class="tab items-tab hidden"> <div class="tab items-tab hidden">
<header class="tab-header"> <header class="tab-header">
<h3>Items</h3> <h3>{% trans "Items" %}</h3>
</header> </header>
<section class="tab-content"> <section class="tab-content">
<form class="item-styles-form"> <form class="item-styles-form">
...@@ -74,7 +74,7 @@ ...@@ -74,7 +74,7 @@
aria-labelledby="item-background-color-label" aria-labelledby="item-background-color-label"
aria-describedby="item-background-color-description"> aria-describedby="item-background-color-description">
<div id="item-background-color-description" class="item-styles-form-help"> <div id="item-background-color-description" class="item-styles-form-help">
{{ self.fields.item_background_color.help }} {{ help_texts.item_background_color }}
</div> </div>
<h3 id="item-text-color-label"> <h3 id="item-text-color-label">
{% trans "Text color" %} {% trans "Text color" %}
...@@ -85,7 +85,7 @@ ...@@ -85,7 +85,7 @@
aria-labelledby="item-text-color-label" aria-labelledby="item-text-color-label"
aria-describedby="item-text-color-description"> aria-describedby="item-text-color-description">
<div id="item-text-color-description" class="item-styles-form-help"> <div id="item-text-color-description" class="item-styles-form-help">
{{ self.fields.item_text_color.help }} {{ help_texts.item_text_color }}
</div> </div>
</form> </form>
</section> </section>
...@@ -93,7 +93,7 @@ ...@@ -93,7 +93,7 @@
<form class="items-form"></form> <form class="items-form"></form>
</section> </section>
<footer class="tab-footer"> <footer class="tab-footer">
<a href="#" class="add-item add-element"><div class="icon add"></div>Add an item</a> <a href="#" class="add-item add-element"><div class="icon add"></div>{% trans "Add an item" %}</a>
</footer> </footer>
</div> </div>
......
...@@ -10,15 +10,15 @@ ...@@ -10,15 +10,15 @@
<script id="zone-input-tpl" type="text/html"> <script id="zone-input-tpl" type="text/html">
<div class="zone-row {{ id }}"> <div class="zone-row {{ id }}">
<label>Text</label> <label>{{i18n "Text"}}</label>
<input type="text" class="title" value="{{ title }}" /> <input type="text" class="title" value="{{ title }}" />
<a href="#" class="remove-zone hidden"> <a href="#" class="remove-zone hidden">
<div class="icon remove"></div> <div class="icon remove"></div>
</a> </a>
<div class="layout"> <div class="layout">
<label>width</label> <label>{{i18n "width"}}</label>
<input type="text" class="size width" value="{{ width }}" /> <input type="text" class="size width" value="{{ width }}" />
<label>height</label> <label>{{i18n "height"}}</label>
<input type="text" class="size height" value="{{ height }}" /> <input type="text" class="size height" value="{{ height }}" />
<br /> <br />
<label>x</label> <label>x</label>
...@@ -36,36 +36,36 @@ ...@@ -36,36 +36,36 @@
<script id="item-input-tpl" type="text/html"> <script id="item-input-tpl" type="text/html">
<div class="item"> <div class="item">
<div class="row"> <div class="row">
<label>Text</label> <label>{{i18n "Text"}}</label>
<input type="text" class="item-text" value="{{ displayName }}"/> <input type="text" class="item-text" value="{{ displayName }}"/>
<label>Zone</label> <label>{{i18n "Zone"}}</label>
<select class="zone-select">{{ dropdown }}</select> <select class="zone-select">{{ dropdown }}</select>
<a href="#" class="remove-item hidden"> <a href="#" class="remove-item hidden">
<div class="icon remove"></div> <div class="icon remove"></div>
</a> </a>
</div> </div>
<div class="row"> <div class="row">
<label>Background image URL (alternative to the text)</label> <label>{{i18n "Background image URL (alternative to the text)"}}</label>
<textarea class="background-image">{{ backgroundImage }}</textarea> <textarea class="background-image">{{ backgroundImage }}</textarea>
</div> </div>
<div class="row"> <div class="row">
<label>Success Feedback</label> <label>{{i18n "Success Feedback"}}</label>
<textarea class="success-feedback">{{ feedback.correct }}</textarea> <textarea class="success-feedback">{{ feedback.correct }}</textarea>
</div> </div>
<div class="row"> <div class="row">
<label>Error Feedback</label> <label>{{i18n "Error Feedback"}}</label>
<textarea class="error-feedback">{{ feedback.incorrect }}</textarea> <textarea class="error-feedback">{{ feedback.incorrect }}</textarea>
</div> </div>
<div class="row"> <div class="row">
<label>Width (px - 0 for auto)</label> <label>{{i18n "Width in pixels (0 for auto)"}}</label>
<input type="text" class="item-width" value="{{ width }}"></input> <input type="text" class="item-width" value="{{ width }}"></input>
<label>Height (px - 0 for auto)</label> <label>{{i18n "Height in pixels (0 for auto)"}}</label>
<input type="text" class="item-height" value="{{ height }}"></input> <input type="text" class="item-height" value="{{ height }}"></input>
</div> </div>
<div class="row"> <div class="row">
<label>Optional numerical value</label> <label>{{i18n "Optional numerical value"}}</label>
<input type="text" class="item-numerical-value" value="{{ numericalValue }}"></input> <input type="text" class="item-numerical-value" value="{{ numericalValue }}"></input>
<label>Margin ±</label> <label>{{i18n "Margin ±"}}</label>
<input type="text" class="item-numerical-margin" value="{{ numericalMargin }}"></input> <input type="text" class="item-numerical-margin" value="{{ numericalMargin }}"></input>
</div> </div>
</div> </div>
......
...@@ -10,6 +10,12 @@ from django.template import Context, Template ...@@ -10,6 +10,12 @@ from django.template import Context, Template
# Functions ######################################################### # Functions #########################################################
# Make '_' a no-op so we can scrape strings
def _(text):
return text
def load_resource(resource_path): def load_resource(resource_path):
""" """
Gets the content of a resource Gets the content of a resource
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment