mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2025-05-02 00:43:34 -04:00
Add translation tooltips for code
Tweak tooltips, add some translation keys Fixed not showing translations for English-speakers Remove comment
This commit is contained in:
parent
aa93a3ec6c
commit
66f99dd834
6 changed files with 174 additions and 1 deletions
app
locale
styles/play/level/tome
templates/play/level/tome
views/play/level/tome
|
@ -195,6 +195,50 @@
|
||||||
campaign_multiplayer_description: "... in which you code head-to-head against other players."
|
campaign_multiplayer_description: "... in which you code head-to-head against other players."
|
||||||
campaign_old_multiplayer: "(Deprecated) Old Multiplayer Arenas"
|
campaign_old_multiplayer: "(Deprecated) Old Multiplayer Arenas"
|
||||||
campaign_old_multiplayer_description: "Relics of a more civilized age. No simulations are run for these older, hero-less multiplayer arenas."
|
campaign_old_multiplayer_description: "Relics of a more civilized age. No simulations are run for these older, hero-less multiplayer arenas."
|
||||||
|
|
||||||
|
code:
|
||||||
|
if: "if" # Keywords
|
||||||
|
else: "else"
|
||||||
|
elif: "elif"
|
||||||
|
while: "while"
|
||||||
|
loop: "loop"
|
||||||
|
for: "for"
|
||||||
|
break: "break"
|
||||||
|
continue: "continue"
|
||||||
|
then: "then"
|
||||||
|
do: "do"
|
||||||
|
end: "end"
|
||||||
|
function: "function"
|
||||||
|
def: "def"
|
||||||
|
self: "self"
|
||||||
|
hero: "hero"
|
||||||
|
this: "this"
|
||||||
|
Date: "Date" # Globals
|
||||||
|
Vector: "Vector"
|
||||||
|
Array: "Array"
|
||||||
|
Function: "Function"
|
||||||
|
Math: "Math"
|
||||||
|
Number: "Number"
|
||||||
|
Object: "Object"
|
||||||
|
RegExp: "RegExp"
|
||||||
|
String: "String"
|
||||||
|
isFinite: "isFinite" # Built-ins
|
||||||
|
isNaN: "isNaN"
|
||||||
|
parseFloat: "parseFloat"
|
||||||
|
parseInt: "parseInt"
|
||||||
|
decodeURI: "decodeURI"
|
||||||
|
decodeURIComponent: "decodeURIComponent"
|
||||||
|
encodeURI: "encodeURI"
|
||||||
|
encodeURIComponent: "encodeURIComponent"
|
||||||
|
escape: "escape"
|
||||||
|
unescape: "unescape"
|
||||||
|
Infinity: "Infinity"
|
||||||
|
NaN: "NaN"
|
||||||
|
undefined: "undefined"
|
||||||
|
null: "null"
|
||||||
|
Boolean: "Boolean"
|
||||||
|
Error: "Error"
|
||||||
|
arguments: "arguments"
|
||||||
|
|
||||||
share_progress_modal:
|
share_progress_modal:
|
||||||
blurb: "You’re making great progress! Tell your parent how much you've learned with CodeCombat."
|
blurb: "You’re making great progress! Tell your parent how much you've learned with CodeCombat."
|
||||||
|
|
18
app/styles/play/level/tome/spell_translation.sass
Normal file
18
app/styles/play/level/tome/spell_translation.sass
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
@import "app/styles/mixins"
|
||||||
|
@import "app/styles/bootstrap/variables"
|
||||||
|
|
||||||
|
.spell-translation-view
|
||||||
|
position: absolute
|
||||||
|
z-index: 9001
|
||||||
|
max-width: 400px
|
||||||
|
pre
|
||||||
|
margin-bottom: 0
|
||||||
|
code
|
||||||
|
white-space: nowrap
|
||||||
|
|
||||||
|
html.no-borderimage
|
||||||
|
.spell-translation-view
|
||||||
|
background: transparent url(/images/level/popover_background.png)
|
||||||
|
background-size: 100% 100%
|
||||||
|
border: 0
|
||||||
|
|
3
app/templates/play/level/tome/spell_translation.jade
Normal file
3
app/templates/play/level/tome/spell_translation.jade
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
pre
|
||||||
|
|
||||||
|
code
|
|
@ -48,7 +48,7 @@ module.exports = class Spell
|
||||||
@source = @originalSource = p.aiSource
|
@source = @originalSource = p.aiSource
|
||||||
@thangs = {}
|
@thangs = {}
|
||||||
if @canRead() # We can avoid creating these views if we'll never use them.
|
if @canRead() # We can avoid creating these views if we'll never use them.
|
||||||
@view = new SpellView {spell: @, level: options.level, session: @session, otherSession: @otherSession, worker: @worker, god: options.god}
|
@view = new SpellView {spell: @, level: options.level, session: @session, otherSession: @otherSession, worker: @worker, god: options.god, @supermodel}
|
||||||
@view.render() # Get it ready and code loaded in advance
|
@view.render() # Get it ready and code loaded in advance
|
||||||
@tabView = new SpellListTabEntryView spell: @, supermodel: @supermodel, codeLanguage: @language, level: options.level
|
@tabView = new SpellListTabEntryView spell: @, supermodel: @supermodel, codeLanguage: @language, level: options.level
|
||||||
@tabView.render()
|
@tabView.render()
|
||||||
|
|
99
app/views/play/level/tome/SpellTranslationView.coffee
Normal file
99
app/views/play/level/tome/SpellTranslationView.coffee
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
CocoView = require 'views/core/CocoView'
|
||||||
|
LevelComponent = require 'models/LevelComponent'
|
||||||
|
template = require 'templates/play/level/tome/spell_translation'
|
||||||
|
Range = ace.require('ace/range').Range
|
||||||
|
TokenIterator = ace.require('ace/token_iterator').TokenIterator
|
||||||
|
serializedClasses =
|
||||||
|
Thang: require 'lib/world/thang'
|
||||||
|
Vector: require 'lib/world/vector'
|
||||||
|
Rectangle: require 'lib/world/rectangle'
|
||||||
|
Ellipse: require 'lib/world/ellipse'
|
||||||
|
LineSegment: require 'lib/world/line_segment'
|
||||||
|
utils = require 'core/utils'
|
||||||
|
|
||||||
|
module.exports = class SpellTranslationView extends CocoView
|
||||||
|
className: 'spell-translation-view'
|
||||||
|
template: template
|
||||||
|
|
||||||
|
events:
|
||||||
|
'mousemove': ->
|
||||||
|
@$el.hide()
|
||||||
|
|
||||||
|
constructor: (options) ->
|
||||||
|
super options
|
||||||
|
@ace = options.ace
|
||||||
|
@thang = options.thang
|
||||||
|
@spell = options.spell
|
||||||
|
@supermodel = options.supermodel
|
||||||
|
|
||||||
|
|
||||||
|
levelComponents = @supermodel.getModels LevelComponent
|
||||||
|
@componentTranslations = levelComponents.reduce((acc, lc) ->
|
||||||
|
for doc in (lc.get('propertyDocumentation') ? [])
|
||||||
|
translated = utils.i18n(doc, 'name', null, false)
|
||||||
|
acc[doc.name] = translated if translated isnt doc.name
|
||||||
|
acc
|
||||||
|
, {})
|
||||||
|
|
||||||
|
@onMouseMove = _.throttle @onMouseMove, 25
|
||||||
|
|
||||||
|
afterRender: ->
|
||||||
|
super()
|
||||||
|
@ace.on 'mousemove', @onMouseMove
|
||||||
|
|
||||||
|
setTooltipText: (text) =>
|
||||||
|
@$el.find('code').text text
|
||||||
|
@$el.show().css(@pos)
|
||||||
|
|
||||||
|
isIdentifier: (t) ->
|
||||||
|
t and (t.type in ['identifier', 'keyword'] or t.value is 'this')
|
||||||
|
|
||||||
|
onMouseMove: (e) =>
|
||||||
|
return if @destroyed
|
||||||
|
pos = e.getDocumentPosition()
|
||||||
|
it = new TokenIterator e.editor.session, pos.row, pos.column
|
||||||
|
endOfLine = it.getCurrentToken()?.index is it.$rowTokens.length - 1
|
||||||
|
while it.getCurrentTokenRow() is pos.row and not @isIdentifier(token = it.getCurrentToken())
|
||||||
|
break if endOfLine or not token # Don't iterate beyond end or beginning of line
|
||||||
|
it.stepBackward()
|
||||||
|
unless @isIdentifier(token)
|
||||||
|
@word = null
|
||||||
|
@update()
|
||||||
|
return
|
||||||
|
try
|
||||||
|
# Ace was breaking under some (?) conditions, dependent on mouse location.
|
||||||
|
# with $rowTokens = [] (but should have things)
|
||||||
|
start = it.getCurrentTokenColumn()
|
||||||
|
catch error
|
||||||
|
start = 0
|
||||||
|
end = start + token.value.length
|
||||||
|
if @isIdentifier(token)
|
||||||
|
@word = token.value
|
||||||
|
@markerRange = new Range pos.row, start, pos.row, end
|
||||||
|
@reposition(e.domEvent)
|
||||||
|
@update()
|
||||||
|
|
||||||
|
reposition: (e) ->
|
||||||
|
offsetX = e.offsetX ? e.clientX - $(e.target).offset().left
|
||||||
|
offsetY = e.offsetY ? e.clientY - $(e.target).offset().top
|
||||||
|
w = $(document).width() - 20
|
||||||
|
offsetX = w - $(e.target).offset().left - @$el.width() if e.clientX + @$el.width() > w
|
||||||
|
@pos = {left: offsetX + 80, top: offsetY - 20}
|
||||||
|
@$el.css(@pos)
|
||||||
|
|
||||||
|
onMouseOut: ->
|
||||||
|
@word = null
|
||||||
|
@markerRange = null
|
||||||
|
@update()
|
||||||
|
|
||||||
|
update: ->
|
||||||
|
i18nKey = 'code.'+@word
|
||||||
|
translation = @componentTranslations[@word] or $.t(i18nKey)
|
||||||
|
if @word and translation and translation not in [i18nKey, @word]
|
||||||
|
@setTooltipText translation
|
||||||
|
else
|
||||||
|
@$el.hide()
|
||||||
|
|
||||||
|
destroy: ->
|
||||||
|
@ace?.removeEventListener 'mousemove', @onMouseMove
|
||||||
|
super()
|
|
@ -6,6 +6,7 @@ Range = ace.require('ace/range').Range
|
||||||
UndoManager = ace.require('ace/undomanager').UndoManager
|
UndoManager = ace.require('ace/undomanager').UndoManager
|
||||||
Problem = require './Problem'
|
Problem = require './Problem'
|
||||||
SpellDebugView = require './SpellDebugView'
|
SpellDebugView = require './SpellDebugView'
|
||||||
|
SpellTranslationView = require './SpellTranslationView'
|
||||||
SpellToolbarView = require './SpellToolbarView'
|
SpellToolbarView = require './SpellToolbarView'
|
||||||
LevelComponent = require 'models/LevelComponent'
|
LevelComponent = require 'models/LevelComponent'
|
||||||
UserCodeProblem = require 'models/UserCodeProblem'
|
UserCodeProblem = require 'models/UserCodeProblem'
|
||||||
|
@ -56,6 +57,7 @@ module.exports = class SpellView extends CocoView
|
||||||
|
|
||||||
constructor: (options) ->
|
constructor: (options) ->
|
||||||
super options
|
super options
|
||||||
|
@supermodel = options.supermodel
|
||||||
@worker = options.worker
|
@worker = options.worker
|
||||||
@session = options.session
|
@session = options.session
|
||||||
@listenTo(@session, 'change:multiplayer', @onMultiplayerChanged)
|
@listenTo(@session, 'change:multiplayer', @onMultiplayerChanged)
|
||||||
|
@ -638,6 +640,10 @@ module.exports = class SpellView extends CocoView
|
||||||
return if @options.level.get('type', true) in ['hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder'] # We'll turn this on later, maybe, but not yet.
|
return if @options.level.get('type', true) in ['hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder'] # We'll turn this on later, maybe, but not yet.
|
||||||
@debugView = new SpellDebugView ace: @ace, thang: @thang, spell:@spell
|
@debugView = new SpellDebugView ace: @ace, thang: @thang, spell:@spell
|
||||||
@$el.append @debugView.render().$el.hide()
|
@$el.append @debugView.render().$el.hide()
|
||||||
|
|
||||||
|
createTranslationView: ->
|
||||||
|
@translationView = new SpellTranslationView { @ace, @thang, @spell, @supermodel }
|
||||||
|
@$el.append @translationView.render().$el.hide()
|
||||||
|
|
||||||
createToolbarView: ->
|
createToolbarView: ->
|
||||||
@toolbarView = new SpellToolbarView ace: @ace
|
@toolbarView = new SpellToolbarView ace: @ace
|
||||||
|
@ -661,6 +667,8 @@ module.exports = class SpellView extends CocoView
|
||||||
@spellThang = @spell.thangs[@thang.id]
|
@spellThang = @spell.thangs[@thang.id]
|
||||||
@createDebugView() unless @debugView
|
@createDebugView() unless @debugView
|
||||||
@debugView?.thang = @thang
|
@debugView?.thang = @thang
|
||||||
|
@createTranslationView() unless @translationView
|
||||||
|
@translationView?.thang = @thang
|
||||||
@toolbarView?.toggleFlow false
|
@toolbarView?.toggleFlow false
|
||||||
@updateAether false, false
|
@updateAether false, false
|
||||||
# @addZatannaSnippets()
|
# @addZatannaSnippets()
|
||||||
|
@ -1336,6 +1344,7 @@ module.exports = class SpellView extends CocoView
|
||||||
@aceSession?.selection.off 'changeCursor', @onCursorActivity
|
@aceSession?.selection.off 'changeCursor', @onCursorActivity
|
||||||
@destroyAceEditor(@ace)
|
@destroyAceEditor(@ace)
|
||||||
@debugView?.destroy()
|
@debugView?.destroy()
|
||||||
|
@translationView?.destroy()
|
||||||
@toolbarView?.destroy()
|
@toolbarView?.destroy()
|
||||||
@zatanna.addSnippets [], @editorLang if @editorLang?
|
@zatanna.addSnippets [], @editorLang if @editorLang?
|
||||||
$(window).off 'resize', @onWindowResize
|
$(window).off 'resize', @onWindowResize
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue