diff --git a/blocks.js b/blocks.js index e56d0edc..8e16529c 100644 --- a/blocks.js +++ b/blocks.js @@ -9,7 +9,7 @@ written by Jens Mönig jens@moenig.org - Copyright (C) 2014 by Jens Mönig + Copyright (C) 2015 by Jens Mönig This file is part of Snap!. @@ -65,6 +65,7 @@ RingMorph BoxMorph* CommentMorph + ScriptFocusMorph * from morphic.js @@ -155,8 +156,7 @@ DialogBoxMorph, BlockInputFragmentMorph, PrototypeHatBlockMorph, Costume*/ // Global stuff //////////////////////////////////////////////////////// -modules.blocks = '2014-November-21'; - +modules.blocks = '2015-August-14'; var SyntaxElementMorph; var BlockMorph; @@ -183,6 +183,7 @@ var SymbolMorph; var CommentMorph; var ArgLabelMorph; var TextSlotMorph; +var ScriptFocusMorph; WorldMorph.prototype.customMorphs = function () { // add examples to the world's demo menu @@ -340,6 +341,7 @@ SyntaxElementMorph.prototype.setScale = function (num) { }; SyntaxElementMorph.prototype.setScale(1); +SyntaxElementMorph.prototype.isCachingInputs = false; // SyntaxElementMorph instance creation: @@ -356,8 +358,13 @@ SyntaxElementMorph.prototype.init = function () { SyntaxElementMorph.uber.init.call(this); this.defaults = []; + this.cachedInputs = null; }; +// SyntaxElementMorph stepping: + +SyntaxElementMorph.prototype.step = null; + // SyntaxElementMorph accessing: SyntaxElementMorph.prototype.parts = function () { @@ -375,10 +382,39 @@ SyntaxElementMorph.prototype.parts = function () { SyntaxElementMorph.prototype.inputs = function () { // answer my arguments and nested reporters - return this.parts().filter(function (part) { - return part instanceof SyntaxElementMorph; - }); + if (isNil(this.cachedInputs) || !this.isCachingInputs) { + this.cachedInputs = this.parts().filter(function (part) { + return part instanceof SyntaxElementMorph; + }); + } + // this.debugCachedInputs(); + return this.cachedInputs; +}; +SyntaxElementMorph.prototype.debugCachedInputs = function () { + // private - only used for manually debugging inputs caching + var realInputs, i; + if (!isNil(this.cachedInputs)) { + realInputs = this.parts().filter(function (part) { + return part instanceof SyntaxElementMorph; + }); + } + if (this.cachedInputs.length !== realInputs.length) { + throw new Error('cached inputs size do not match: ' + + this.constructor.name); + } + for (i = 0; i < realInputs.length; i += 1) { + if (this.cachedInputs[i] !== realInputs[i]) { + throw new Error('cached input does not match: ' + + this.constructor.name + + ' #' + + i + + ' ' + + this.cachedInputs[i].constructor.name + + ' != ' + + realInputs[i].constructor.name); + } + } }; SyntaxElementMorph.prototype.allInputs = function () { @@ -494,6 +530,7 @@ SyntaxElementMorph.prototype.replaceInput = function (oldArg, newArg) { replacement.drawNew(); this.fixLayout(); } + this.cachedInputs = null; this.endLayout(); }; @@ -529,6 +566,7 @@ SyntaxElementMorph.prototype.silentReplaceInput = function (oldArg, newArg) { replacement.drawNew(); this.fixLayout(); } + this.cachedInputs = null; }; SyntaxElementMorph.prototype.revertToDefaultInput = function (arg, noValues) { @@ -571,6 +609,7 @@ SyntaxElementMorph.prototype.revertToDefaultInput = function (arg, noValues) { } else if (deflt instanceof RingMorph) { deflt.fixBlockColor(); } + this.cachedInputs = null; }; SyntaxElementMorph.prototype.isLocked = function () { @@ -587,6 +626,48 @@ SyntaxElementMorph.prototype.topBlock = function () { return this; }; +// SyntaxElementMorph reachable variables + +SyntaxElementMorph.prototype.getVarNamesDict = function () { + var block = this.parentThatIsA(BlockMorph), + rcvr, + tempVars = [], + dict; + + if (!block) { + return {}; + } + rcvr = block.receiver(); + block.allParents().forEach(function (morph) { + if (morph instanceof PrototypeHatBlockMorph) { + tempVars.push.apply( + tempVars, + morph.inputs()[0].inputFragmentNames() + ); + } else if (morph instanceof BlockMorph) { + morph.inputs().forEach(function (inp) { + if (inp instanceof TemplateSlotMorph) { + tempVars.push(inp.contents()); + } else if (inp instanceof MultiArgMorph) { + inp.children.forEach(function (m) { + if (m instanceof TemplateSlotMorph) { + tempVars.push(m.contents()); + } + }); + } + }); + } + }); + if (rcvr) { + dict = rcvr.variables.allNamesDict(); + tempVars.forEach(function (name) { + dict[name] = name; + }); + return dict; + } + return {}; +}; + // SyntaxElementMorph drag & drop: SyntaxElementMorph.prototype.reactToGrabOf = function (grabbedMorph) { @@ -848,6 +929,20 @@ SyntaxElementMorph.prototype.labelPart = function (spec) { true // read-only ); break; + case '%interaction': + part = new InputSlotMorph( + null, // text + false, // numeric? + { + 'clicked' : ['clicked'], + 'pressed' : ['pressed'], + 'dropped' : ['dropped'], + 'mouse-entered' : ['mouse-entered'], + 'mouse-departed' : ['mouse-departed'] + }, + true // read-only + ); + break; case '%dates': part = new InputSlotMorph( null, // text @@ -1063,9 +1158,9 @@ SyntaxElementMorph.prototype.labelPart = function (spec) { acos : ['acos'], atan : ['atan'], ln : ['ln'], - // log : 'log', - 'e^' : ['e^'] - // '10^' : '10^' + log : ['log'], + 'e^' : ['e^'], + '10^' : ['10^'] }, true ); @@ -1143,6 +1238,15 @@ SyntaxElementMorph.prototype.labelPart = function (spec) { ); part.isStatic = true; break; + case '%shd': + part = new InputSlotMorph( + null, + false, + 'shadowedVariablesMenu', + true + ); + part.isStatic = true; + break; case '%lst': part = new InputSlotMorph( null, @@ -1369,16 +1473,19 @@ SyntaxElementMorph.prototype.labelPart = function (spec) { new Point() : this.embossing; part.drawNew(); } else { - part = new StringMorph(spec); - part.fontName = this.labelFontName; - part.fontStyle = this.labelFontStyle; - part.fontSize = this.fontSize; - part.color = new Color(255, 255, 255); - part.isBold = true; - part.shadowColor = this.color.darker(this.labelContrast); - part.shadowOffset = MorphicPreferences.isFlat ? - new Point() : this.embossing; - part.drawNew(); + part = new StringMorph( + spec, // text + this.fontSize, // fontSize + this.labelFontStyle, // fontStyle + true, // bold + false, // italic + false, // isNumeric + MorphicPreferences.isFlat ? + new Point() : this.embossing, // shadowOffset + this.color.darker(this.labelContrast), // shadowColor + new Color(255, 255, 255), // color + this.labelFontName // fontName + ); } return part; }; @@ -1775,7 +1882,6 @@ SyntaxElementMorph.prototype.endLayout = function () { this.topBlock().fullChanged(); }; - // BlockMorph ////////////////////////////////////////////////////////// /* @@ -1841,7 +1947,8 @@ SyntaxElementMorph.prototype.endLayout = function () { %att - chameleon colored rectangular drop-down for attributes %fun - chameleon colored rectangular drop-down for math functions %typ - chameleon colored rectangular drop-down for data types - %var - chameleon colored rectangular drop-down for variable names + %var - chameleon colored rectangular drop-down for variable names + %shd - Chameleon colored rectuangular drop-down for shadowed var names %lst - chameleon colored rectangular drop-down for list names %b - chameleon colored hexagonal slot (for predicates) %l - list icon @@ -1895,6 +2002,7 @@ BlockMorph.uber = SyntaxElementMorph.prototype; // BlockMorph preferences settings: +BlockMorph.prototype.isCachingInputs = true; BlockMorph.prototype.zebraContrast = 40; // alternating color brightness // BlockMorph sound feedback: @@ -1928,6 +2036,7 @@ BlockMorph.prototype.init = function () { BlockMorph.uber.init.call(this); this.color = new Color(0, 17, 173); + this.cashedInputs = null; }; BlockMorph.prototype.receiver = function () { @@ -2008,7 +2117,8 @@ BlockMorph.prototype.setSpec = function (spec) { } part = myself.labelPart(word); myself.add(part); - if (!(part instanceof CommandSlotMorph)) { + if (!(part instanceof CommandSlotMorph || + part instanceof StringMorph)) { part.drawNew(); } if (part instanceof RingMorph) { @@ -2033,6 +2143,7 @@ BlockMorph.prototype.setSpec = function (spec) { }); this.blockSpec = spec; this.fixLayout(); + this.cachedInputs = null; }; BlockMorph.prototype.buildSpec = function () { @@ -2074,6 +2185,8 @@ BlockMorph.prototype.userMenu = function () { world = this.world(), myself = this, shiftClicked = world.currentKey === 16, + proc = this.activeProcess(), + vNames = proc ? proc.context.outerContext.variables.names() : [], alternatives, top, blck; @@ -2174,9 +2287,9 @@ BlockMorph.prototype.userMenu = function () { ); if (this instanceof CommandBlockMorph && this.nextBlock()) { menu.addItem( - this.thumbnail(0.5, 60, false), + (proc ? this.fullCopy() : this).thumbnail(0.5, 60), function () { - var cpy = this.fullCopy(), + var cpy = myself.fullCopy(), nb = cpy.nextBlock(), ide = myself.parentThatIsA(IDE_Morph); if (nb) {nb.destroy(); } @@ -2202,6 +2315,20 @@ BlockMorph.prototype.userMenu = function () { }, 'open a new window\nwith a picture of this script' ); + if (proc) { + if (vNames.length) { + menu.addLine(); + vNames.forEach(function (vn) { + menu.addItem( + vn + '...', + function () { + proc.doShowVar(vn); + } + ); + }); + } + return menu; + } if (this.parentThatIsA(RingMorph)) { menu.addLine(); menu.addItem("unringify", 'unringify'); @@ -2425,6 +2552,7 @@ BlockMorph.prototype.restoreInputs = function (oldInputs) { } i += 1; }); + this.cachedInputs = null; }; BlockMorph.prototype.showHelp = function () { @@ -2891,6 +3019,17 @@ BlockMorph.prototype.getHighlight = function () { return null; }; +BlockMorph.prototype.outline = function (color, border) { + var highlight = new BlockHighlightMorph(), + fb = this.fullBounds(), + edge = border; + highlight.setExtent(fb.extent().add(edge * 2)); + highlight.color = color; + highlight.image = this.highlightImage(color, border); + highlight.setPosition(fb.origin.subtract(new Point(edge, edge))); + return highlight; +}; + // BlockMorph zebra coloring BlockMorph.prototype.fixBlockColor = function (nearestBlock, isForced) { @@ -2964,6 +3103,12 @@ BlockMorph.prototype.alternateBlockColor = function () { this.fixChildrensBlockColor(true); // has issues if not forced }; +BlockMorph.prototype.ghost = function () { + this.setColor( + SpriteMorph.prototype.blockColor[this.category].lighter(35) + ); +}; + BlockMorph.prototype.fixLabelColor = function () { if (this.zebraContrast > 0 && this.category) { var clr = SpriteMorph.prototype.blockColor[this.category]; @@ -3012,6 +3157,14 @@ BlockMorph.prototype.fullCopy = function () { ans.setSpec(this.instantiationSpec); } ans.allChildren().filter(function (block) { + if (block instanceof SyntaxElementMorph) { + block.cachedInputs = null; + if (block instanceof InputSlotMorph) { + block.contents().clearSelection(); + } + } else if (block instanceof CursorMorph) { + block.destroy(); + } return !isNil(block.comment); }).forEach(function (block) { var cmnt = block.comment.fullCopy(); @@ -3020,15 +3173,24 @@ BlockMorph.prototype.fullCopy = function () { //block.comment = null; }); + ans.cachedInputs = null; return ans; }; +BlockMorph.prototype.reactToTemplateCopy = function () { + this.forceNormalColoring(); +}; + // BlockMorph events BlockMorph.prototype.mouseClickLeft = function () { var top = this.topBlock(), receiver = top.receiver(), + shiftClicked = this.world().currentKey === 16, stage; + if (shiftClicked && !this.isTemplate) { + return this.focus(); + } if (top instanceof PrototypeHatBlockMorph) { return top.mouseClickLeft(); } @@ -3040,40 +3202,67 @@ BlockMorph.prototype.mouseClickLeft = function () { } }; +BlockMorph.prototype.focus = function () { + var scripts = this.parentThatIsA(ScriptsMorph), + world = this.world(), + focus; + if (!scripts || !ScriptsMorph.prototype.enableKeyboard) {return; } + if (scripts.focus) {scripts.focus.stopEditing(); } + world.stopEditing(); + focus = new ScriptFocusMorph(scripts, this); + scripts.focus = focus; + focus.getFocus(world); + if (this instanceof HatBlockMorph) { + focus.nextCommand(); + } +}; + +BlockMorph.prototype.activeProcess = function () { + var top = this.topBlock(), + receiver = top.receiver(), + stage; + if (top instanceof PrototypeHatBlockMorph) { + return null; + } + if (receiver) { + stage = receiver.parentThatIsA(StageMorph); + if (stage) { + return stage.threads.findProcess(top); + } + } + return null; +}; + // BlockMorph thumbnail -BlockMorph.prototype.thumbnail = function (scale, clipWidth, noShadow) { - var block = this.fullCopy(), - nb = block.nextBlock(), +BlockMorph.prototype.thumbnail = function (scale, clipWidth) { + var nb = this.nextBlock(), fadeout = 12, ext, trgt, ctx, gradient; - if (nb) {nb.destroy(); } - if (!noShadow) {block.addShadow(); } - ext = block.fullBounds().extent(); - if (!noShadow) { - ext = ext.subtract(this.shadowBlur * - (useBlurredShadows && !MorphicPreferences.isFlat ? 1 : 2)); - } + + if (nb) {nb.isVisible = false; } + ext = this.fullBounds().extent(); trgt = newCanvas(new Point( - Math.min(ext.x * scale, clipWidth || ext.x), + clipWidth ? Math.min(ext.x * scale, clipWidth) : ext.x * scale, ext.y * scale )); ctx = trgt.getContext('2d'); ctx.scale(scale, scale); - ctx.drawImage(block.fullImage(), 0, 0); + ctx.drawImage(this.fullImage(), 0, 0); // draw fade-out - if (trgt.width === clipWidth) { + if (clipWidth && ext.x * scale > clipWidth) { gradient = ctx.createLinearGradient( trgt.width / scale - fadeout, 0, trgt.width / scale, 0 ); - gradient.addColorStop(0, new Color(255, 255, 255, 0).toString()); - gradient.addColorStop(1, 'white'); + gradient.addColorStop(0, 'transparent'); + gradient.addColorStop(1, 'black'); + ctx.globalCompositeOperation = 'destination-out'; ctx.fillStyle = gradient; ctx.fillRect( trgt.width / scale - fadeout, @@ -3082,6 +3271,7 @@ BlockMorph.prototype.thumbnail = function (scale, clipWidth, noShadow) { trgt.height / scale ); } + if (nb) {nb.isVisible = true; } return trgt; }; @@ -4589,6 +4779,7 @@ RingMorph.uber = ReporterBlockMorph.prototype; // RingMorph preferences settings: +RingMorph.prototype.isCachingInputs = false; // RingMorph.prototype.edge = 2; // RingMorph.prototype.rounding = 9; // RingMorph.prototype.alpha = 0.8; @@ -4728,6 +4919,7 @@ ScriptsMorph.uber = FrameMorph.prototype; ScriptsMorph.prototype.cleanUpMargin = 20; ScriptsMorph.prototype.cleanUpSpacing = 15; ScriptsMorph.prototype.isPreferringEmptySlots = true; +ScriptsMorph.prototype.enableKeyboard = true; // ScriptsMorph instance creation: @@ -4747,6 +4939,9 @@ ScriptsMorph.prototype.init = function (owner) { this.lastPreservedBlocks = null; this.lastNextBlock = null; + // keyboard editing support: + this.focus = null; + ScriptsMorph.uber.init.call(this); this.setColor(new Color(70, 70, 70)); }; @@ -4757,6 +4952,9 @@ ScriptsMorph.prototype.fullCopy = function () { var cpy = new ScriptsMorph(), pos = this.position(), child; + if (this.focus) { + this.focus.stopEditing(); + } this.children.forEach(function (morph) { if (!morph.block) { // omit anchored comments child = morph.fullCopy(); @@ -4776,13 +4974,18 @@ ScriptsMorph.prototype.fullCopy = function () { // ScriptsMorph stepping: ScriptsMorph.prototype.step = function () { - var hand = this.world().hand, + var world = this.world(), + hand = world.hand, block; if (this.feedbackMorph.parent) { this.feedbackMorph.destroy(); this.feedbackMorph.parent = null; } + if (this.focus && (!world.keyboardReceiver || + world.keyboardReceiver instanceof StageMorph)) { + this.focus.getFocus(world); + } if (hand.children.length === 0) { return null; } @@ -5245,6 +5448,27 @@ ScriptsMorph.prototype.reactToDropOf = function (droppedMorph, hand) { this.adjustBounds(); }; +// ScriptsMorph events + +ScriptsMorph.prototype.mouseClickLeft = function (pos) { + var shiftClicked = this.world().currentKey === 16; + if (shiftClicked) { + return this.edit(pos); + } + if (this.focus) {this.focus.stopEditing(); } +}; + +// ScriptsMorph keyboard support + +ScriptsMorph.prototype.edit = function (pos) { + var world = this.world(); + if (this.focus) {this.focus.stopEditing(); } + world.stopEditing(); + if (!ScriptsMorph.prototype.enableKeyboard) {return; } + this.focus = new ScriptFocusMorph(this, this, pos); + this.focus.getFocus(world); +}; + // ArgMorph ////////////////////////////////////////////////////////// /* @@ -6509,7 +6733,7 @@ InputSlotMorph.prototype.setContents = function (aStringOrFloat) { // InputSlotMorph drop-down menu: -InputSlotMorph.prototype.dropDownMenu = function () { +InputSlotMorph.prototype.dropDownMenu = function (enableKeyboard) { var choices = this.choices, key, menu = new MenuMorph( @@ -6540,7 +6764,12 @@ InputSlotMorph.prototype.dropDownMenu = function () { } } if (menu.items.length > 0) { - menu.popUpAtHand(this.world()); + if (enableKeyboard) { + menu.popup(this.world(), this.bottomLeft()); + menu.getFocus(); + } else { + menu.popUpAtHand(this.world()); + } } else { return null; } @@ -6795,46 +7024,6 @@ InputSlotMorph.prototype.soundsMenu = function () { return dict; }; -InputSlotMorph.prototype.getVarNamesDict = function () { - var block = this.parentThatIsA(BlockMorph), - rcvr, - tempVars = [], - dict; - - if (!block) { - return {}; - } - rcvr = block.receiver(); - block.allParents().forEach(function (morph) { - if (morph instanceof PrototypeHatBlockMorph) { - tempVars.push.apply( - tempVars, - morph.inputs()[0].inputFragmentNames() - ); - } else if (morph instanceof BlockMorph) { - morph.inputs().forEach(function (inp) { - if (inp instanceof TemplateSlotMorph) { - tempVars.push(inp.contents()); - } else if (inp instanceof MultiArgMorph) { - inp.children.forEach(function (m) { - if (m instanceof TemplateSlotMorph) { - tempVars.push(m.contents()); - } - }); - } - }); - } - }); - if (rcvr) { - dict = rcvr.variables.allNamesDict(); - tempVars.forEach(function (name) { - dict[name] = name; - }); - return dict; - } - return {}; -}; - InputSlotMorph.prototype.setChoices = function (dict, readonly) { // externally specify choices and read-only status, // used for custom blocks @@ -6852,10 +7041,26 @@ InputSlotMorph.prototype.setChoices = function (dict, readonly) { this.fixLayout(); }; +InputSlotMorph.prototype.shadowedVariablesMenu = function () { + var block = this.parentThatIsA(BlockMorph), + rcvr, + dict = {}; + + if (!block) {return dict; } + rcvr = block.receiver(); + if (rcvr) { + rcvr.inheritedVariableNames(true).forEach(function (name) { + dict[name] = name; + }); + } + return dict; +}; + // InputSlotMorph layout: InputSlotMorph.prototype.fixLayout = function () { - var contents = this.contents(), + var width, height, arrowWidth, + contents = this.contents(), arrow = this.arrow(); contents.isNumeric = this.isNumeric; @@ -6872,35 +7077,32 @@ InputSlotMorph.prototype.fixLayout = function () { arrow.setSize(this.fontSize); arrow.show(); } else { - arrow.setSize(0); arrow.hide(); } - this.setHeight( - contents.height() - + this.edge * 2 - // + this.typeInPadding * 2 - ); + arrowWidth = arrow.isVisible ? arrow.width() : 0; + + height = contents.height() + this.edge * 2; // + this.typeInPadding * 2 if (this.isNumeric) { - this.setWidth(contents.width() - + Math.floor(arrow.width() * 0.5) - + this.height() - + this.typeInPadding * 2 - ); + width = contents.width() + + Math.floor(arrowWidth * 0.5) + + height + + this.typeInPadding * 2; } else { - this.setWidth(Math.max( + width = Math.max( contents.width() - + arrow.width() + + arrowWidth + this.edge * 2 + this.typeInPadding * 2, contents.rawHeight ? // single vs. multi-line contents - contents.rawHeight() + arrow.width() - : contents.height() / 1.2 + arrow.width(), + contents.rawHeight() + arrowWidth + : contents.height() / 1.2 + arrowWidth, this.minWidth // for text-type slots - )); + ); } + this.setExtent(new Point(width, height)); if (this.isNumeric) { contents.setPosition(new Point( - Math.floor(this.height() / 2), + Math.floor(height / 2), this.edge ).add(new Point(this.typeInPadding, 0)).add(this.position())); } else { @@ -6910,10 +7112,12 @@ InputSlotMorph.prototype.fixLayout = function () { ).add(new Point(this.typeInPadding, 0)).add(this.position())); } - arrow.setPosition(new Point( - this.right() - arrow.width() - this.edge, - contents.top() - )); + if (arrow.isVisible) { + arrow.setPosition(new Point( + this.right() - arrowWidth - this.edge, + contents.top() + )); + } if (this.parent) { if (this.parent.fixLayout) { @@ -6930,6 +7134,15 @@ InputSlotMorph.prototype.fixLayout = function () { // InputSlotMorph events: +InputSlotMorph.prototype.mouseDownLeft = function (pos) { + if (this.isReadOnly || this.arrow().bounds.containsPoint(pos)) { + this.escalateEvent('mouseDownLeft', pos); + } else { + this.contents().edit(); + this.contents().selectAll(); + } +}; + InputSlotMorph.prototype.mouseClickLeft = function (pos) { if (this.arrow().bounds.containsPoint(pos)) { this.dropDownMenu(); @@ -10906,3 +11119,738 @@ CommentMorph.prototype.destroy = function () { CommentMorph.prototype.stackHeight = function () { return this.height(); }; + +// ScriptFocusMorph ////////////////////////////////////////////////////////// + +/* + I offer keyboard navigation for syntax elements, blocks and scripts: + + activate: + - shift + click on a scripting pane's background + - shift + click on any block + - shift + enter in the IDE's edit mode + + stop editing: + - left-click on scripting pane's background + - esc + + navigate among scripts: + - tab: next script + - backtab (shift + tab): last script + + start editing a new script: + - shift + enter + + navigate among commands within a script: + - down arrow: next command + - up arrow: last command + + navigate among all elements within a script: + - right arrow: next element (block or input) + - left arrow: last element + + move the currently edited script (stack of blocks): + - shift + arrow keys (left, right, up, down) + + editing scripts: + + - backspace: + * delete currently focused reporter + * delete command above current insertion mark (blinking) + * collapse currently focused variadic input by one element + + - enter: + * edit currently focused input slot + * expand currently focused variadic input by one element + + - space: + * activate currently focused input slot's pull-down menu, if any + * show a menu of reachable variables for the focused input or reporter + + - any other key: + start searching for insertable matching blocks + + - in menus triggered by this feature: + * navigate with up / down arrow keys + * trigger selection with enter + * cancel menu with esc + + - in the search bar triggered b this feature: + * keep typing / deleting to narrow and update matches + * navigate among shown matches with up / down arrow keys + * insert selected match at the focus' position with enter + * cancel searching and inserting with esc + + running the currently edited script: + * shift+ctrl+enter simulates clicking the edited script with the mouse +*/ + +// ScriptFocusMorph inherits from BoxMorph: + +ScriptFocusMorph.prototype = new BoxMorph(); +ScriptFocusMorph.prototype.constructor = ScriptFocusMorph; +ScriptFocusMorph.uber = BoxMorph.prototype; + +// ScriptFocusMorph instance creation: + +function ScriptFocusMorph(editor, initialElement, position) { + this.init(editor, initialElement, position); +} + +ScriptFocusMorph.prototype.init = function ( + editor, + initialElement, + position +) { + this.editor = editor; // a ScriptsMorph + this.element = initialElement; + this.atEnd = false; + ScriptFocusMorph.uber.init.call(this); + if (this.element instanceof ScriptsMorph) { + this.setPosition(position); + } +}; + +// ScriptFocusMorph keyboard focus: + +ScriptFocusMorph.prototype.getFocus = function (world) { + if (!world) {world = this.world(); } + if (world && world.keyboardReceiver !== this) { + world.stopEditing(); + } + world.keyboardReceiver = this; + this.fixLayout(); +}; + +// ScriptFocusMorph layout: + +ScriptFocusMorph.prototype.fixLayout = function () { + this.changed(); + if (this.element instanceof CommandBlockMorph || + this.element instanceof CommandSlotMorph || + this.element instanceof ScriptsMorph) { + this.manifestStatement(); + } else { + this.manifestExpression(); + } + this.editor.add(this); // come to front + this.scrollIntoView(); + this.changed(); +}; + +ScriptFocusMorph.prototype.manifestStatement = function () { + var newScript = this.element instanceof ScriptsMorph, + y = this.element.top(); + this.border = 0; + this.edge = 0; + this.alpha = 1; + this.color = this.editor.feedbackColor; + this.setExtent(new Point( + newScript ? + SyntaxElementMorph.prototype.hatWidth : this.element.width(), + Math.max( + SyntaxElementMorph.prototype.corner, + SyntaxElementMorph.prototype.feedbackMinHeight + ) + )); + if (this.element instanceof CommandSlotMorph) { + y += SyntaxElementMorph.prototype.corner; + } else if (this.atEnd) { + y = this.element.bottom(); + } + if (!newScript) { + this.setPosition(new Point( + this.element.left(), + y + )); + } + this.fps = 2; + this.show(); + this.step = function () { + this.toggleVisibility(); + }; +}; + +ScriptFocusMorph.prototype.manifestExpression = function () { + this.edge = SyntaxElementMorph.prototype.rounding; + this.border = Math.max( + SyntaxElementMorph.prototype.edge, + 3 + ); + this.color = this.editor.feedbackColor.copy(); + this.color.a = 0.5; + this.borderColor = this.editor.feedbackColor; + + this.bounds = this.element.fullBounds() + .expandBy(Math.max( + SyntaxElementMorph.prototype.edge * 2, + SyntaxElementMorph.prototype.reporterDropFeedbackPadding + )); + this.drawNew(); + delete this.fps; + delete this.step; + this.show(); +}; + +// ScriptFocusMorph editing + +ScriptFocusMorph.prototype.trigger = function () { + var current = this.element; + if (current instanceof MultiArgMorph) { + if (current.arrows().children[1].isVisible) { + current.addInput(); + this.fixLayout(); + } + return; + } + if (current.parent instanceof TemplateSlotMorph) { + current.mouseClickLeft(); + return; + } + if (current instanceof InputSlotMorph) { + if (!current.isReadOnly) { + delete this.fps; + delete this.step; + this.hide(); + this.world().onNextStep = function () { + current.contents().edit(); + current.contents().selectAll(); + }; + } else if (current.choices) { + current.dropDownMenu(true); + delete this.fps; + delete this.step; + this.hide(); + } + } +}; + +ScriptFocusMorph.prototype.menu = function () { + var current = this.element; + if (current instanceof InputSlotMorph && current.choices) { + current.dropDownMenu(true); + delete this.fps; + delete this.step; + this.hide(); + } else { + this.insertVariableGetter(); + } +}; + +ScriptFocusMorph.prototype.deleteLastElement = function () { + var current = this.element; + if (current.parent instanceof ScriptsMorph) { + if (this.atEnd || current instanceof ReporterBlockMorph) { + current.destroy(); + this.element = this.editor; + this.atEnd = false; + } + } else if (current instanceof MultiArgMorph) { + if (current.arrows().children[0].isVisible) { + current.removeInput(); + } + } else if (current instanceof ReporterBlockMorph) { + if (!current.isTemplate) { + this.lastElement(); + current.prepareToBeGrabbed(); + current.destroy(); + } + } else if (current instanceof CommandBlockMorph) { + if (this.atEnd) { + this.element = current.parent; + current.userDestroy(); + } else { + if (current.parent instanceof CommandBlockMorph) { + current.parent.userDestroy(); + } + } + } + this.editor.adjustBounds(); + this.fixLayout(); +}; + +ScriptFocusMorph.prototype.insertBlock = function (block) { + var pb; + block.isTemplate = false; + block.isDraggable = true; + + if (block.snapSound) { + block.snapSound.play(); + } + + if (this.element instanceof ScriptsMorph) { + this.editor.add(block); + this.element = block; + if (block instanceof CommandBlockMorph) { + block.setLeft(this.left()); + if (block.isStop()) { + block.setTop(this.top()); + } else { + block.setBottom(this.top()); + this.atEnd = true; + } + } else { + block.setCenter(this.center()); + block.setLeft(this.left()); + } + } else if (this.element instanceof CommandBlockMorph) { + if (this.atEnd) { + this.element.nextBlock(block); + this.element = block; + this.fixLayout(); + } else { + // to be done: special case if block.isStop() + pb = this.element.parent; + if (pb instanceof ScriptsMorph) { // top block + block.setLeft(this.element.left()); + block.setBottom(this.element.top() + this.element.corner); + this.editor.add(block); + block.nextBlock(this.element); + this.fixLayout(); + } else if (pb instanceof CommandSlotMorph) { + pb.nestedBlock(block); + } else if (pb instanceof CommandBlockMorph) { + pb.nextBlock(block); + } + } + } else if (this.element instanceof CommandSlotMorph) { + // to be done: special case if block.isStop() + this.element.nestedBlock(block); + this.element = block; + this.atEnd = true; + } else { + pb = this.element.parent; + if (pb instanceof ScriptsMorph) { + this.editor.add(block); + block.setPosition(this.element.position()); + this.element.destroy(); + } else { + pb.replaceInput(this.element, block); + } + this.element = block; + } + block.fixBlockColor(); + this.editor.adjustBounds(); + // block.scrollIntoView(); + this.fixLayout(); +}; + +ScriptFocusMorph.prototype.insertVariableGetter = function () { + var types = this.blockTypes(), + vars, + myself = this, + menu = new MenuMorph(); + if (!types || !contains(types, 'reporter')) { + return; + } + vars = InputSlotMorph.prototype.getVarNamesDict.call(this.element); + Object.keys(vars).forEach(function (vName) { + var block = SpriteMorph.prototype.variableBlock(vName); + block.addShadow(new Point(3, 3)); + menu.addItem( + block, + function () { + block.removeShadow(); + myself.insertBlock(block); + } + ); + }); + if (menu.items.length > 0) { + menu.popup(this.world(), this.element.bottomLeft()); + menu.getFocus(); + } +}; + +ScriptFocusMorph.prototype.stopEditing = function () { + this.editor.focus = null; + this.world().keyboardReceiver = null; + this.destroy(); +}; + +// ScriptFocusMorph navigation + +ScriptFocusMorph.prototype.lastElement = function () { + var items = this.items(), + idx; + if (!items.length) { + this.shiftScript(new Point(-50, 0)); + return; + } + if (this.atEnd) { + this.element = items[items.length - 1]; + this.atEnd = false; + } else { + idx = items.indexOf(this.element) - 1; + if (idx < 0) {idx = items.length - 1; } + this.element = items[idx]; + } + if (this.element instanceof CommandSlotMorph && + this.element.nestedBlock()) { + this.lastElement(); + } else if (this.element instanceof HatBlockMorph) { + if (items.length > 1) { + this.lastElement(); + } else { + this.atEnd = true; + } + } + this.fixLayout(); +}; + +ScriptFocusMorph.prototype.nextElement = function () { + var items = this.items(), idx, nb; + if (!items.length) { + this.shiftScript(new Point(50, 0)); + return; + } + idx = items.indexOf(this.element) + 1; + if (idx >= items.length) { + idx = 0; + } + this.atEnd = false; + this.element = items[idx]; + if (this.element instanceof CommandSlotMorph) { + nb = this.element.nestedBlock(); + if (nb) {this.element = nb; } + } else if (this.element instanceof HatBlockMorph) { + if (items.length === 1) { + this.atEnd = true; + } else { + this.nextElement(); + } + } + this.fixLayout(); +}; + +ScriptFocusMorph.prototype.lastCommand = function () { + var cm = this.element.parentThatIsA(CommandBlockMorph), + pb; + if (!cm) { + if (this.element instanceof ScriptsMorph) { + this.shiftScript(new Point(0, -50)); + } + return; + } + if (this.element instanceof CommandBlockMorph) { + if (this.atEnd) { + this.atEnd = false; + } else { + pb = cm.parent.parentThatIsA(CommandBlockMorph); + if (pb) { + this.element = pb; + } else { + pb = cm.topBlock().bottomBlock(); + if (pb) { + this.element = pb; + this.atEnd = true; + } + } + } + } else { + this.element = cm; + this.atEnd = false; + } + if (this.element instanceof HatBlockMorph && !this.atEnd) { + this.lastCommand(); + } + this.fixLayout(); +}; + +ScriptFocusMorph.prototype.nextCommand = function () { + var cm = this.element, + tb, + nb, + cs; + if (cm instanceof ScriptsMorph) { + this.shiftScript(new Point(0, 50)); + return; + } + while (!(cm instanceof CommandBlockMorph)) { + cm = cm.parent; + if (cm instanceof ScriptsMorph) { + return; + } + } + if (this.atEnd) { + cs = cm.parentThatIsA(CommandSlotMorph); + if (cs) { + this.element = cs.parentThatIsA(CommandBlockMorph); + this.atEnd = false; + this.nextCommand(); + } else { + tb = cm.topBlock().parentThatIsA(CommandBlockMorph); + if (tb) { + this.element = tb; + this.atEnd = false; + if (this.element instanceof HatBlockMorph) { + this.nextCommand(); + } + } + } + } else { + nb = cm.nextBlock(); + if (nb) { + this.element = nb; + } else { + this.element = cm; + this.atEnd = true; + } + } + this.fixLayout(); +}; + +ScriptFocusMorph.prototype.nextScript = function () { + var scripts = this.sortedScripts(), + idx; + if (scripts.length < 1) {return; } + if (this.element instanceof ScriptsMorph) { + this.element = scripts[0]; + } + idx = scripts.indexOf(this.element.topBlock()) + 1; + if (idx >= scripts.length) {idx = 0; } + this.element = scripts[idx]; + this.element.scrollIntoView(); + this.atEnd = false; + if (this.element instanceof HatBlockMorph) { + return this.nextElement(); + } + this.fixLayout(); +}; + +ScriptFocusMorph.prototype.lastScript = function () { + var scripts = this.sortedScripts(), + idx; + if (scripts.length < 1) {return; } + if (this.element instanceof ScriptsMorph) { + this.element = scripts[0]; + } + idx = scripts.indexOf(this.element.topBlock()) - 1; + if (idx < 0) {idx = scripts.length - 1; } + this.element = scripts[idx]; + this.element.scrollIntoView(); + this.atEnd = false; + if (this.element instanceof HatBlockMorph) { + return this.nextElement(); + } + this.fixLayout(); +}; + +ScriptFocusMorph.prototype.shiftScript = function (deltaPoint) { + var tb; + if (this.element instanceof ScriptsMorph) { + this.moveBy(deltaPoint); + } else { + tb = this.element.topBlock(); + if (tb && !(tb instanceof PrototypeHatBlockMorph)) { + tb.moveBy(deltaPoint); + } + } + this.editor.adjustBounds(); + this.fixLayout(); +}; + +ScriptFocusMorph.prototype.newScript = function () { + var pos = this.position(); + if (!(this.element instanceof ScriptsMorph)) { + pos = this.element.topBlock().fullBounds().bottomLeft().add( + new Point(0, 50) + ); + } + this.setPosition(pos); + this.element = this.editor; + this.editor.adjustBounds(); + this.fixLayout(); +}; + +ScriptFocusMorph.prototype.runScript = function () { + if (this.element instanceof ScriptsMorph) {return; } + this.element.topBlock().mouseClickLeft(); +}; + +ScriptFocusMorph.prototype.items = function () { + if (this.element instanceof ScriptsMorph) {return []; } + var script = this.element.topBlock(); + return script.allChildren().filter(function (each) { + return each instanceof SyntaxElementMorph && + !(each instanceof TemplateSlotMorph) && + (!each.isStatic || + each.choices || + each instanceof RingMorph || + each instanceof MultiArgMorph || + each instanceof CommandSlotMorph); + }); +}; + +ScriptFocusMorph.prototype.sortedScripts = function () { + var scripts = this.editor.children.filter(function (each) { + return each instanceof BlockMorph; + }); + scripts.sort(function (a, b) { + // make sure the prototype hat block always stays on top + return a instanceof PrototypeHatBlockMorph ? 0 : a.top() - b.top(); + }); + return scripts; +}; + +// ScriptFocusMorph block types + +ScriptFocusMorph.prototype.blockTypes = function () { + // answer an array of possible block types that fit into + // the current situation, NULL if no block can be inserted + + if (this.element.isTemplate) {return null; } + if (this.element instanceof ScriptsMorph) { + return ['hat', 'command', 'reporter', 'predicate', 'ring']; + } + if (this.element instanceof HatBlockMorph || + this.element instanceof CommandSlotMorph) { + return ['command']; + } + if (this.element instanceof CommandBlockMorph) { + if (this.atEnd && this.element.isStop()) { + return null; + } + if (this.element.parent instanceof ScriptsMorph) { + return ['hat', 'command']; + } + return ['command']; + } + if (this.element instanceof ReporterBlockMorph) { + if (this.element.getSlotSpec() === '%n') { + return ['reporter']; + } + return ['reporter', 'predicate', 'ring']; + } + if (this.element.getSpec() === '%n') { + return ['reporter']; + } + if (this.element.isStatic) { + return null; + } + return ['reporter', 'predicate', 'ring']; +}; + + +// ScriptFocusMorph keyboard events + +ScriptFocusMorph.prototype.processKeyDown = function (event) { + this.processKeyEvent( + event, + this.reactToKeyEvent + ); +}; + +ScriptFocusMorph.prototype.processKeyUp = function (event) { + nop(event); +}; + +ScriptFocusMorph.prototype.processKeyPress = function (event) { + nop(event); +}; + + +ScriptFocusMorph.prototype.processKeyEvent = function (event, action) { + var keyName, ctrl, shift; + + //console.log(event.keyCode); + this.world().hand.destroyTemporaries(); // remove result bubbles, if any + switch (event.keyCode) { + case 8: + keyName = 'backspace'; + break; + case 9: + keyName = 'tab'; + break; + case 13: + keyName = 'enter'; + break; + case 16: + case 17: + case 18: + return; + case 27: + keyName = 'esc'; + break; + case 32: + keyName = 'space'; + break; + case 37: + keyName = 'left arrow'; + break; + case 39: + keyName = 'right arrow'; + break; + case 38: + keyName = 'up arrow'; + break; + case 40: + keyName = 'down arrow'; + break; + default: + keyName = String.fromCharCode(event.keyCode || event.charCode); + } + ctrl = (event.ctrlKey || event.metaKey) ? 'ctrl ' : ''; + shift = event.shiftKey ? 'shift ' : ''; + keyName = ctrl + shift + keyName; + action.call(this, keyName); +}; + +ScriptFocusMorph.prototype.reactToKeyEvent = function (key) { + var evt = key.toLowerCase(), + shift = 50, + types, + vNames; + + // console.log(evt); + switch (evt) { + case 'esc': + return this.stopEditing(); + case 'enter': + return this.trigger(); + case 'shift enter': + return this.newScript(); + case 'ctrl shift enter': + return this.runScript(); + case 'space': + return this.menu(); + case 'left arrow': + return this.lastElement(); + case 'shift left arrow': + return this.shiftScript(new Point(-shift, 0)); + case 'right arrow': + return this.nextElement(); + case 'shift right arrow': + return this.shiftScript(new Point(shift, 0)); + case 'up arrow': + return this.lastCommand(); + case 'shift up arrow': + return this.shiftScript(new Point(0, -shift)); + case 'down arrow': + return this.nextCommand(); + case 'shift down arrow': + return this.shiftScript(new Point(0, shift)); + case 'tab': + return this.nextScript(); + case 'shift tab': + return this.lastScript(); + case 'backspace': + return this.deleteLastElement(); + default: + types = this.blockTypes(); + if (!(this.element instanceof ScriptsMorph) && + contains(types, 'reporter')) { + vNames = Object.keys(this.element.getVarNamesDict()); + } + if (types) { + delete this.fps; + delete this.step; + this.show(); + this.editor.owner.searchBlocks( + key, + types, + vNames, + this + ); + } + } +}; diff --git a/byob.js b/byob.js index ec714f11..13392b5a 100644 --- a/byob.js +++ b/byob.js @@ -102,11 +102,11 @@ ArrowMorph, PushButtonMorph, contains, InputSlotMorph, ShadowMorph, ToggleButtonMorph, IDE_Morph, MenuMorph, copy, ToggleElementMorph, Morph, fontHeight, StageMorph, SyntaxElementMorph, SnapSerializer, CommentMorph, localize, CSlotMorph, SpeechBubbleMorph, MorphicPreferences, -SymbolMorph, isNil*/ +SymbolMorph, isNil, CursorMorph*/ // Global stuff //////////////////////////////////////////////////////// -modules.byob = '2015-January-21'; +modules.byob = '2015-July-28'; // Declarations @@ -429,6 +429,7 @@ CustomCommandBlockMorph.prototype.refresh = function () { // find unnahmed upvars and label them // to their internal definition (default) + this.cachedInputs = null; this.inputs().forEach(function (inp, idx) { if (inp instanceof TemplateSlotMorph && inp.contents() === '\u2191') { inp.setContents(def.inputNames()[idx]); @@ -443,6 +444,7 @@ CustomCommandBlockMorph.prototype.restoreInputs = function (oldInputs) { myself = this; if (this.isPrototype) {return; } + this.cachedInputs = null; this.inputs().forEach(function (inp) { old = oldInputs[i]; if (old instanceof ReporterBlockMorph && @@ -460,6 +462,7 @@ CustomCommandBlockMorph.prototype.restoreInputs = function (oldInputs) { } i += 1; }); + this.cachedInputs = null; }; CustomCommandBlockMorph.prototype.refreshDefaults = function () { @@ -472,6 +475,7 @@ CustomCommandBlockMorph.prototype.refreshDefaults = function () { } idx += 1; }); + this.cachedInputs = null; }; CustomCommandBlockMorph.prototype.refreshPrototype = function () { @@ -924,6 +928,9 @@ CustomReporterBlockMorph.prototype.refresh = function () { if (!this.isPrototype) { this.isPredicate = (this.definition.type === 'predicate'); } + if (this.parent instanceof SyntaxElementMorph) { + this.parent.cachedInputs = null; + } this.drawNew(); }; @@ -1720,8 +1727,9 @@ BlockEditorMorph.prototype.popUp = function () { // BlockEditorMorph ops -BlockEditorMorph.prototype.accept = function () { +BlockEditorMorph.prototype.accept = function (origin) { // check DialogBoxMorph comment for accept() + if (origin instanceof CursorMorph) {return; } if (this.action) { if (typeof this.target === 'function') { if (typeof this.action === 'function') { @@ -1740,7 +1748,8 @@ BlockEditorMorph.prototype.accept = function () { this.close(); }; -BlockEditorMorph.prototype.cancel = function () { +BlockEditorMorph.prototype.cancel = function (origin) { + if (origin instanceof CursorMorph) {return; } //this.refreshAllBlockInstances(); this.close(); }; @@ -1865,6 +1874,9 @@ BlockEditorMorph.prototype.context = function (prototypeHat) { if (topBlock === null) { return null; } + topBlock.allChildren().forEach(function (c) { + if (c instanceof BlockMorph) {c.cachedInputs = null; } + }); stackFrame = Process.prototype.reify.call( null, topBlock, @@ -1956,8 +1968,13 @@ PrototypeHatBlockMorph.prototype.init = function (definition) { PrototypeHatBlockMorph.prototype.mouseClickLeft = function () { // relay the mouse click to my prototype block to - // pop-up a Block Dialog + // pop-up a Block Dialog, unless the shift key + // is pressed, in which case initiate keyboard + // editing support + if (this.world().currentKey === 16) { // shift-clicked + return this.focus(); + } this.children[0].mouseClickLeft(); }; @@ -2039,7 +2056,13 @@ BlockLabelFragment.prototype.defTemplateSpecFragment = function () { )) { suff = ' \u03BB'; } else if (this.defaultValue) { - suff = ' = ' + this.defaultValue.toString(); + if (this.type === '%n') { + suff = ' # = ' + this.defaultValue.toString(); + } else { // 'any' or 'text' + suff = ' = ' + this.defaultValue.toString(); + } + } else if (this.type === '%n') { + suff = ' #'; } return this.labelString + suff; }; @@ -2974,7 +2997,7 @@ InputSlotDialogMorph.prototype.editSlotOptions = function () { new DialogBoxMorph( myself, function (options) { - myself.fragment.options = options; + myself.fragment.options = options.trim(); }, myself ).promptCode( @@ -3281,15 +3304,17 @@ BlockExportDialogMorph.prototype.selectNone = function () { // BlockExportDialogMorph ops BlockExportDialogMorph.prototype.exportBlocks = function () { - var str = this.serializer.serialize(this.blocks); + var str = encodeURIComponent( + this.serializer.serialize(this.blocks) + ); if (this.blocks.length > 0) { - window.open(encodeURI('data:text/xml,' + str - + '')); + + ''); } else { new DialogBoxMorph().inform( 'Export blocks', diff --git a/gui.js b/gui.js index e3b141e3..d93d4282 100644 --- a/gui.js +++ b/gui.js @@ -43,6 +43,7 @@ TurtleIconMorph CostumeIconMorph WardrobeMorph + StageHandleMorph; credits @@ -65,11 +66,11 @@ ScriptsMorph, isNil, SymbolMorph, BlockExportDialogMorph, BlockImportDialogMorph, SnapTranslator, localize, List, InputSlotMorph, SnapCloud, Uint8Array, HandleMorph, SVG_Costume, fontHeight, hex_sha512, sb, CommentMorph, CommandBlockMorph, BlockLabelPlaceHolderMorph, Audio, -SpeechBubbleMorph*/ +SpeechBubbleMorph, ScriptFocusMorph*/ // Global stuff //////////////////////////////////////////////////////// -modules.gui = '2015-February-06'; +modules.gui = '2015-July-28'; // Declarations @@ -81,6 +82,18 @@ var TurtleIconMorph; var WardrobeMorph; var SoundIconMorph; var JukeboxMorph; +var StageHandleMorph; + +// Get the full url without "snap.html" +var baseURL = (function getPath(location) { + var origin, path, slash; + path = location.pathname; // starts with a / + origin = location.origin; // has no trailing / + slash = path.lastIndexOf('/'); + path = path.slice(0, slash + 1); // keep a trailing / + return origin + path; +}(window.location)); + // IDE_Morph /////////////////////////////////////////////////////////// @@ -202,6 +215,7 @@ IDE_Morph.prototype.init = function (isAutoFill) { // restore saved user preferences this.userLanguage = null; // user language preference for startup + this.projectsInURLs = false; this.applySavedSettings(); // additional properties: @@ -224,6 +238,7 @@ IDE_Morph.prototype.init = function (isAutoFill) { this.spriteBar = null; this.spriteEditor = null; this.stage = null; + this.stageHandle = null; this.corralBar = null; this.corral = null; @@ -316,7 +331,8 @@ IDE_Morph.prototype.openIn = function (world) { } throw new Error('unable to retrieve ' + url); } catch (err) { - return; + myself.showMessage('unable to retrieve project'); + return ''; } } @@ -396,8 +412,21 @@ IDE_Morph.prototype.openIn = function (world) { myself.shield.destroy(); myself.shield = null; msg.destroy(); - myself.toggleAppMode(true); - myself.runScripts(); + + if (dict.editMode) { + myself.toggleAppMode(false); + } else { + myself.toggleAppMode(true); + } + + if (!dict.noRun) { + myself.runScripts(); + } + + if (dict.hideControls) { + myself.controlBar.hide(); + window.onbeforeunload = function () {nop(); }; + } } ]); }, @@ -971,9 +1000,7 @@ IDE_Morph.prototype.createPalette = function (forSearching) { IDE_Morph.prototype.createStage = function () { // assumes that the logo pane has already been created - if (this.stage) { - this.stage.destroy(); - } + if (this.stage) {this.stage.destroy(); } StageMorph.prototype.frameRate = 0; this.stage = new StageMorph(this.globalVariables); this.stage.setExtent(this.stage.dimensions); // dimensions are fixed @@ -988,6 +1015,13 @@ IDE_Morph.prototype.createStage = function () { this.add(this.stage); }; +IDE_Morph.prototype.createStageHandle = function () { + // assumes that the stage has already been created + if (this.stageHandle) {this.stageHandle.destroy(); } + this.stageHandle = new StageHandleMorph(this.stage); + this.add(this.stageHandle); +}; + IDE_Morph.prototype.createSpriteBar = function () { // assumes that the categories pane has already been created var rotationStyleButtons = [], @@ -1351,6 +1385,7 @@ IDE_Morph.prototype.createCorral = function () { // assumes the corral bar has already been created var frame, template, padding = 5, myself = this; + this.createStageHandle(); if (this.corral) { this.corral.destroy(); } @@ -1482,10 +1517,10 @@ IDE_Morph.prototype.fixLayout = function (situation) { ) * 10) / 10); this.stage.setCenter(this.center()); } else { -// this.stage.setScale(this.isSmallStage ? 0.5 : 1); this.stage.setScale(this.isSmallStage ? this.stageRatio : 1); this.stage.setTop(this.logo.bottom() + padding); this.stage.setRight(this.right()); + this.stageHandle.fixLayout(); } // spriteBar @@ -1534,7 +1569,12 @@ IDE_Morph.prototype.setProjectName = function (string) { IDE_Morph.prototype.setExtent = function (point) { var padding = new Point(430, 110), minExt, - ext; + ext, + maxWidth, + minWidth, + maxHeight, + minRatio, + maxRatio; // determine the minimum dimensions making sense for the current mode if (this.isAppMode) { @@ -1542,21 +1582,29 @@ IDE_Morph.prototype.setExtent = function (point) { this.controlBar.height() + 10 ); } else { - /* // auto-switches to small stage mode, commented out b/c I don't like it - if (point.x < 910) { - this.isSmallStage = true; - this.stageRatio = 0.5; + if (this.stageRatio > 1) { + minExt = padding.add(StageMorph.prototype.dimensions); + } else { + minExt = padding.add( + StageMorph.prototype.dimensions.multiplyBy(this.stageRatio) + ); } - */ - minExt = this.isSmallStage ? - padding.add(StageMorph.prototype.dimensions.divideBy(2)) - : padding.add(StageMorph.prototype.dimensions); -/* - minExt = this.isSmallStage ? - new Point(700, 350) : new Point(910, 490); -*/ } ext = point.max(minExt); + + // adjust stage ratio if necessary + maxWidth = ext.x - (this.spriteBar.tabBar.fullBounds().right() - + this.left()); + minWidth = SpriteIconMorph.prototype.thumbSize.x * 3; + maxHeight = (ext.y - SpriteIconMorph.prototype.thumbSize.y * 3.5); + minRatio = minWidth / this.stage.dimensions.x; + maxRatio = Math.min( + (maxWidth / this.stage.dimensions.x), + (maxHeight / this.stage.dimensions.y) + ); + this.stageRatio = Math.min(maxRatio, Math.max(minRatio, this.stageRatio)); + + // apply IDE_Morph.uber.setExtent.call(this, ext); this.fixLayout(); }; @@ -1742,6 +1790,9 @@ IDE_Morph.prototype.stopAllScripts = function () { }; IDE_Morph.prototype.selectSprite = function (sprite) { + if (this.currentSprite && this.currentSprite.scripts.focus) { + this.currentSprite.scripts.focus.stopEditing(); + } this.currentSprite = sprite; this.createPalette(); this.createSpriteBar(); @@ -1795,7 +1846,9 @@ IDE_Morph.prototype.applySavedSettings = function () { language = this.getSetting('language'), click = this.getSetting('click'), longform = this.getSetting('longform'), - plainprototype = this.getSetting('plainprototype'); + longurls = this.getSetting('longurls'), + plainprototype = this.getSetting('plainprototype'), + keyboard = this.getSetting('keyboard'); // design if (design === 'flat') { @@ -1828,6 +1881,20 @@ IDE_Morph.prototype.applySavedSettings = function () { InputSlotDialogMorph.prototype.isLaunchingExpanded = true; } + // project data in URLs + if (longurls) { + this.projectsInURLs = true; + } else { + this.projectsInURLs = false; + } + + // keyboard editing + if (keyboard) { + ScriptsMorph.prototype.enableKeyboard = true; + } else { + ScriptsMorph.prototype.enableKeyboard = false; + } + // plain prototype labels if (plainprototype) { BlockLabelPlaceHolderMorph.prototype.plainLabel = true; @@ -2277,6 +2344,17 @@ IDE_Morph.prototype.settingsMenu = function () { 'uncheck to run scripts\nat normal speed', 'check to prioritize\nscript execution' ); + addPreference( + 'Cache Inputs', + function () { + BlockMorph.prototype.isCachingInputs = + !BlockMorph.prototype.isCachingInputs; + }, + BlockMorph.prototype.isCachingInputs, + 'uncheck to stop caching\ninputs (for debugging the evaluator)', + 'check to cache inputs\nboosts recursion', + true + ); addPreference( 'Rasterize SVGs', function () { @@ -2301,6 +2379,21 @@ IDE_Morph.prototype.settingsMenu = function () { 'check for alternative\nGUI design', false ); + addPreference( + 'Project URLs', + function () { + myself.projectsInURLs = !myself.projectsInURLs; + if (myself.projectsInURLs) { + myself.saveSetting('longurls', true); + } else { + myself.removeSetting('longurls'); + } + }, + myself.projectsInURLs, + 'uncheck to disable\nproject data in URLs', + 'check to enable\nproject data in URLs', + true + ); addPreference( 'Sprite Nesting', function () { @@ -2312,6 +2405,22 @@ IDE_Morph.prototype.settingsMenu = function () { 'check to enable\nsprite composition', true ); + addPreference( + 'Keyboard Editing', + function () { + ScriptsMorph.prototype.enableKeyboard = + !ScriptsMorph.prototype.enableKeyboard; + if (ScriptsMorph.prototype.enableKeyboard) { + myself.saveSetting('keyboard', true); + } else { + myself.removeSetting('keyboard'); + } + }, + ScriptsMorph.prototype.enableKeyboard, + 'uncheck to disable\nkeyboard editing support', + 'check to enable\nkeyboard editing support', + false + ); menu.addLine(); // everything below this line is stored in the project addPreference( 'Thread safe scripts', @@ -2351,6 +2460,20 @@ IDE_Morph.prototype.settingsMenu = function () { 'check for block\nto text mapping features', false ); + addPreference( + 'Inheritance support', + function () { + StageMorph.prototype.enableInheritance = + !StageMorph.prototype.enableInheritance; + myself.currentSprite.blocksCache.variables = null; + myself.currentSprite.paletteCache.variables = null; + myself.refreshPalette(); + }, + StageMorph.prototype.enableInheritance, + 'uncheck to disable\nsprite inheritance features', + 'check for sprite\ninheritance features', + false + ); menu.popup(world, pos); }; @@ -2373,7 +2496,8 @@ IDE_Morph.prototype.projectMenu = function () { menu.addItem( 'Save to disk', 'saveProjectToDisk', - 'experimental - store this project\nin your downloads folder', + 'store this project\nin the downloads folder\n' + + '(in supporting browsers)', new Color(100, 0, 0) ); } @@ -2462,13 +2586,10 @@ IDE_Morph.prototype.projectMenu = function () { function () { // read a list of libraries from an external file, var libMenu = new MenuMorph(this, 'Import library'), - libUrl = 'http://snap.berkeley.edu/snapsource/libraries/' + - 'LIBRARIES'; + libUrl = baseURL + 'libraries/' + 'LIBRARIES'; function loadLib(name) { - var url = 'http://snap.berkeley.edu/snapsource/libraries/' - + name - + '.xml'; + var url = baseURL + 'libraries/' + name + '.xml'; myself.droppedText(myself.getURL(url), name); } @@ -2585,7 +2706,7 @@ IDE_Morph.prototype.aboutSnap = function () { module, btn1, btn2, btn3, btn4, licenseBtn, translatorsBtn, world = this.world(); - aboutTxt = 'Snap! 4.0\nBuild Your Own Blocks\n\n--- beta ---\n\n' + aboutTxt = 'Snap! 4.0.2\nBuild Your Own Blocks\n\n' + 'Copyright \u24B8 2015 Jens M\u00F6nig and ' + 'Brian Harvey\n' + 'jens@moenig.org, bh@cs.berkeley.edu\n\n' @@ -2619,7 +2740,7 @@ IDE_Morph.prototype.aboutSnap = function () { creditsTxt = localize('Contributors') + '\n\nNathan Dinsmore: Saving/Loading, Snap-Logo Design, ' - + 'countless bugfixes' + + '\ncountless bugfixes and optimizations' + '\nKartik Chandra: Paint Editor' + '\nMichael Ball: Time/Date UI, many bugfixes' + '\n"Ava" Yuan Yuan: Graphic Effects' @@ -2802,6 +2923,7 @@ IDE_Morph.prototype.newProject = function () { StageMorph.prototype.codeMappings = {}; StageMorph.prototype.codeHeaders = {}; StageMorph.prototype.enableCodeMapping = false; + StageMorph.prototype.enableInheritance = false; SpriteMorph.prototype.useFlatLineEnds = false; this.setProjectName(''); this.projectNotes = ''; @@ -2848,7 +2970,7 @@ IDE_Morph.prototype.rawSaveProject = function (name) { try { localStorage['-snap-project-' + name] = str = this.serializer.serialize(this.stage); - location.hash = '#open:' + str; + this.setURL('#open:' + str); this.showMessage('Saved!', 1); } catch (err) { this.showMessage('Save failed: ' + err); @@ -2856,7 +2978,7 @@ IDE_Morph.prototype.rawSaveProject = function (name) { } else { localStorage['-snap-project-' + name] = str = this.serializer.serialize(this.stage); - location.hash = '#open:' + str; + this.setURL('#open:' + str); this.showMessage('Saved!', 1); } } @@ -2897,7 +3019,7 @@ IDE_Morph.prototype.exportProject = function (name, plain) { str = encodeURIComponent( this.serializer.serialize(this.stage) ); - location.hash = '#open:' + str; + this.setURL('#open:' + str); window.open('data:text/' + (plain ? 'plain,' + str : 'xml,' + str)); menu.destroy(); @@ -2910,7 +3032,7 @@ IDE_Morph.prototype.exportProject = function (name, plain) { str = encodeURIComponent( this.serializer.serialize(this.stage) ); - location.hash = '#open:' + str; + this.setURL('#open:' + str); window.open('data:text/' + (plain ? 'plain,' + str : 'xml,' + str)); menu.destroy(); @@ -2935,7 +3057,9 @@ IDE_Morph.prototype.exportGlobalBlocks = function () { }; IDE_Morph.prototype.exportSprite = function (sprite) { - var str = this.serializer.serialize(sprite.allParts()); + var str = encodeURIComponent( + this.serializer.serialize(sprite.allParts()) + ); window.open('data:text/xml, 0) { + context.beginPath(); + context.moveTo(x, y - (l - r)); + context.lineTo(x, y + (l - r)); + context.stroke(); + } + x += (w * 2); + l *= 2; + } + if (shadowColor) { + context.strokeStyle = shadowColor.toString(); + x = aCanvas.width / 12 + w; + l = aCanvas.height / 8; + for (i = 0; i < 3; i += 1) { + if (i > 0) { + context.beginPath(); + context.moveTo(x, y - (l - r)); + context.lineTo(x, y + (l - r)); + context.stroke(); + } + x += (w * 2); + l *= 2; + } + } +}; + +// StageHandleMorph layout: + +StageHandleMorph.prototype.fixLayout = function () { + if (!this.target) {return; } + var ide = this.target.parentThatIsA(IDE_Morph); + this.setTop(this.target.top() + 10); + this.setRight(this.target.left()); + if (ide) {ide.add(this); } // come to front +}; + +// StageHandleMorph stepping: + +StageHandleMorph.prototype.step = null; + +StageHandleMorph.prototype.mouseDownLeft = function (pos) { + var world = this.world(), + offset = this.right() - pos.x, + myself = this, + ide = this.target.parentThatIsA(IDE_Morph); + + if (!this.target) { + return null; + } + ide.isSmallStage = true; + ide.controlBar.stageSizeButton.refresh(); + this.step = function () { + var newPos, newWidth; + if (world.hand.mouseButton) { + newPos = world.hand.bounds.origin.x + offset; + newWidth = myself.target.right() - newPos; + ide.stageRatio = newWidth / myself.target.dimensions.x; + ide.setExtent(world.extent()); + + } else { + this.step = null; + ide.isSmallStage = !(ide.stageRatio === 1); + ide.controlBar.stageSizeButton.refresh(); + } + }; +}; + +// StageHandleMorph events: + +StageHandleMorph.prototype.mouseEnter = function () { + this.image = this.highlightImage; + this.changed(); +}; + +StageHandleMorph.prototype.mouseLeave = function () { + this.image = this.normalImage; + this.changed(); +}; + diff --git a/help/SnapManual.pdf b/help/SnapManual.pdf index 53672319..219c1da7 100644 Binary files a/help/SnapManual.pdf and b/help/SnapManual.pdf differ diff --git a/help/createClone.png b/help/createClone.png new file mode 100644 index 00000000..b00e8676 Binary files /dev/null and b/help/createClone.png differ diff --git a/help/doCallCC.png b/help/doCallCC.png new file mode 100644 index 00000000..d286ad43 Binary files /dev/null and b/help/doCallCC.png differ diff --git a/help/doPauseAll.png b/help/doPauseAll.png new file mode 100644 index 00000000..975fa734 Binary files /dev/null and b/help/doPauseAll.png differ diff --git a/help/doSetFastTracking.png b/help/doSetFastTracking.png new file mode 100644 index 00000000..7ee62a95 Binary files /dev/null and b/help/doSetFastTracking.png differ diff --git a/help/doStopOthers.png b/help/doStopOthers.png new file mode 100644 index 00000000..b90dff9b Binary files /dev/null and b/help/doStopOthers.png differ diff --git a/help/doStopThis.png b/help/doStopThis.png new file mode 100644 index 00000000..cc072acd Binary files /dev/null and b/help/doStopThis.png differ diff --git a/help/getLastMessage.png b/help/getLastMessage.png new file mode 100644 index 00000000..44846520 Binary files /dev/null and b/help/getLastMessage.png differ diff --git a/help/manual/.gitignore b/help/manual/.gitignore new file mode 100644 index 00000000..cb5f3c2b --- /dev/null +++ b/help/manual/.gitignore @@ -0,0 +1,7 @@ +*.aux +*.log +*.out +*.toc +en/snap-manual.pdf +pl/snap-podrecznik.pdf +*.synctex.gz diff --git a/help/manual/common/defs.tex b/help/manual/common/defs.tex new file mode 100644 index 00000000..bb4d7851 --- /dev/null +++ b/help/manual/common/defs.tex @@ -0,0 +1,39 @@ +\usepackage[T1]{fontenc} +\usepackage[utf8]{inputenc} +\usepackage{baskervald} % Default font +\usepackage{setspace} \onehalfspacing +\usepackage{graphicx} +\usepackage{color} +\usepackage{textcomp} +\usepackage{hyperref} + +% This macro produces a "Snap!" logo. +% +% Note that in Polish (and other languages), nouns are inflected. The form "Snap!" with suffix looks plain stupid, so the macro takes a suffix as argument. If the suffix is non-empty, no exclamation mark is generated, and the suffix is used instead. +\newcommand{\Snap}[1]{% + \textsf{% + Snap% + \ifx\\#1\\\textit{!\@}% + \else #1% + \fi% + }% +} + +\newcommand{\code}[1]{\textsf{#1}} +\newcommand{\defaultGraphicsScale}{0.6} + +\renewcommand{\thechapter}{\Roman{chapter}} +\renewcommand{\thesection}{\Alph{section}} +\renewcommand{\thesubsection}{} + +\newcommand{\inlinepic}[1]{% + \raisebox{-4pt}{% + \includegraphics[scale=\defaultGraphicsScale]{#1}% + }% +} + +\newcommand{\bigpic}[1]{ + \begin{center} + \includegraphics[scale=\defaultGraphicsScale]{#1} + \end{center} +} diff --git a/help/manual/en/move-10-steps.png b/help/manual/en/move-10-steps.png new file mode 100644 index 00000000..3d276da3 Binary files /dev/null and b/help/manual/en/move-10-steps.png differ diff --git a/help/manual/en/snap-manual.tex b/help/manual/en/snap-manual.tex new file mode 100644 index 00000000..036ad1ea --- /dev/null +++ b/help/manual/en/snap-manual.tex @@ -0,0 +1,159 @@ +\documentclass{report} + +\input{../common/defs.tex} + +\begin{document} + +\title{\Snap{} Reference Manual} +\author{Brian Harvey \and Jens M\"{o}nig} +\date{} + +\maketitle + +\tableofcontents + +\chapter*{} +\section*{Acknowledgements} + +We have been extremely lucky in our mentors. Jens cut his teeth in the company of the Smalltalk pioneers: Alan Kay, Dan Ingalls, and the rest of the gang who invented personal computing and object oriented programming in the great days of Xerox PARC. He worked with John Maloney, of the MIT Scratch Team, who developed the Morphic graphics framework that's still at the heart of \Snap{}. The brilliant design of Scratch, from the Lifelong Kindergarten Group at the MIT Media Lab, is crucial to \Snap{}. + +\textbf{\emph{Our earlier version, BYOB, was a direct modification of the Scratch source code. \Snap{} is a complete rewrite, but its code structure and its user interface remain deeply indebted to Scratch. And the Scratch Team, who could have seen us as rivals, have been entirely supportive and welcoming to us.}} + +Brian grew up at the MIT and Stanford Artificial Intelligence Labs, learning from Lisp inventor John McCarthy, Scheme inventors Gerald~J. Sussman and Guy Steele, and the authors of the world's best computer science book, \textit{Structure and Interpretation of Computer Programs}, Hal Abelson and Gerald~J. Sussman with Julie Sussman, among many other heroes of computer science. + +\textbf{\emph{In the glory days of the MIT Logo Lab, we used to say, ``Logo is Lisp disguised as BASIC.'' Now, with its first class procedures, lexical scope, and first class continuations, \Snap{} is Scheme disguised as Scratch.}} + +We have been fortunate to get to know an amazing group of brilliant middle school (!\@) and high school students through the Scratch Advanced Topics forum, several of whom have contributed code to \Snap{}: Kartik Chandra, Nathan Dinsmore, Connor Hudson, and Ian Reynolds. Many more have contributed ideas and alpha-testing bug reports. UC Berkeley students who've contributed code include Michael Ball, Achal Dave, Kyle Hotchkiss, Ivan Motyashov, and Yuan Yuan. Contributors of translations are too numerous to list here, but they're in the ``About...'' box in \Snap{} itself. This work was supported in part by the National Science Foundation grant 1143566, and in part by MioSoft. + +\clearpage + +\begin{center} +\bf \Huge \Snap{} Reference Manual \\ +\huge Version 4.0 +\vspace{40pt} +\end{center} + +\Snap{} (formerly BYOB) is an extended reimplementation of Scratch (\url{http://scratch.mit.edu}) that allows you to Build Your Own Blocks. It also features first class lists, first class procedures, and continuations. These added capabilities make it suitable for a serious introduction to computer science for high school or college students. To run \Snap{}, open a browser window and connect to either \url{http://snap.berkeley.edu/run} to start with a minimal set of blocks or \url{http://snap.berkeley.edu/init} to load a small set of additional blocks (a little slower startup, but recommended for convenience and assumed in this manual). + +\clearpage + +\chapter{Blocks, Scripts, and Sprites} + +This chapter describes the \Snap{} features inherited from Scratch; experienced Scratch users can skip to section~\ref{sec:nesting-sprites}. + +\Snap{} is a programming language---a notation in which you can tell a computer what you want it to do. Unlike most programming languages, though, \Snap{} is a visual language; instead of writing a program using the keyboard, the \Snap{} programmer uses the same drag-and-drop interface familiar to computer users. + +Start \Snap{}. You should see the following arrangement of regions in the window: + +\begin{center} +\includegraphics[width=\textwidth]{window-regions} +\end{center} + +(The proportions of these areas may be different, depending on the size and shape of your browser window.) + +A \Snap{} program consists of one or more \emph{scripts}, each of which is made of \emph{blocks}. Here's a typical script: + +\label{fig:typical-script} +\bigpic{typical-script} + +The five blocks that make up this script have three different colors, corresponding to three of the eight \emph{palettes} in which blocks can be found. The palette area at the left edge of the window shows one palette at a time, chosen with the eight buttons just above the palette area. In this script, the gold blocks are from the Control palette; the green block is from the Pen palette; and the blue blocks are from the Motion palette. A script is assembled by dragging blocks from a palette into the \emph{scripting area} in the middle part of the window. Blocks snap together (hence the name \Snap{} for the language) when you drag a block so that its indentation is near the tab of the one above it: + +\bigpic{snapping-blocks} + +The white horizontal line is a signal that if you let go of the green block it will snap into the tab of the gold one. + +\subsection{Hat Blocks and Command Blocks} + +At the top of the script is a \emph{hat} block, which indicates when the script should be carried out. Hat block names typically start with the word ``\code{when}''; in this example, the script should be run when the green flag near the right end of the \Snap{} tool bar is clicked. (The \Snap{} tool bar is part of the \Snap{} window, not the same as the browser's or operating system's menu bar.) A script isn't required to have a hat block, but if not, then the script will be run only if the user clicks on the script itself. A script can't have more than one hat block, and the hat block can be used only at the top of the script; its distinctive shape is meant to remind you of that. + +The other blocks in this script are \emph{command} blocks. Each command block corresponds to an action that \Snap{} already knows how to carry out. For example, the block \inlinepic{move-10-steps} tells the sprite (the arrowhead shape on the \emph{stage} at the right end of the window) to move ten steps (a step is a very small unit of distance) in the direction in which the arrowhead is pointing. We'll see shortly that there can be more than one sprite, and that each sprite has its own scripts. Also, a sprite doesn't have to look like an arrowhead, but can have any picture as a costume. The shape of the \code{move} block is meant to remind you of a Lego\texttrademark{} brick; a script is a stack of blocks. (The word ``block'' denotes both the graphical shape on the screen and the procedure, the action, that the block carries out.) + +The number~10 in the \code{move} block above is called an \emph{input} to the block. By clicking on the white oval, you can type any number in place of the 10. The sample script on page~\pageref{fig:typical-script} uses 100 as the input value. We'll see later that inputs can have non-oval shapes that accept values other than numbers. We'll also see that you can compute input values, instead of typing a particular value into the oval. A block can have more than one input slot. For example, the \code{glide} block located about halfway down the Motion palette has three inputs. + +Most command blocks have that brick shape, but some, like the \code{repeat} block in the sample script, are \emph{C-shaped}. Most C-shaped blocks are found in the Control palette. The slot inside the C shape is a special kind of input slot that accepts a \emph{script} as the input. In the sample script, the \code{repeat} block has two inputs: the number 4 and the script + +\bigpic{typical-script-inner} + + + +\section{Sprites and Parallelism} +\subsection{Costumes and Sounds} +\subsection{Inter-Sprite Communication with Broadcast} +\section{Nesting Sprites: Anchors and Parts} +\label{sec:nesting-sprites} +\section{Reporter Blocks and Expressions} +\section{Predicates and Conditional Evaluation} +\section{Variables} +\subsection{Global Variables} +\subsection{Script Variables} +\section{Etcetera} +\chapter{Saving and Loading Projects and Media} +\section{Local Storage} +\subsection{Localstore} +\subsection{XML Export} +\section{Cloud Storage} +\section{Loading Saved Projects} +\chapter{Building a Block} +\section{Simple Blocks} +\subsection{Custom Blocks with Inputs} +\section{Recursion} +\section{Block Libraries} +\chapter{First Class Lists} +\section{The list Block} +\section{Lists of Lists} +\section{Functional and Imperative List Programming} +\section{Higher Order List Operations and Rings} +\chapter{Typed Inputs} +\section{Scratch's Type Notation} +\section{The \Snap{} Input Type Dialog} +\subsection{Procedure Types} +\subsection{Pulldown inputs} +\subsection{Input variants} +\subsection{Prototype Hints} +\subsection{Title Text and Symbols} +\chapter{Procedures as Data} +\section{Call and Run} +\subsection{Call/Run with inputs} +\subsection{Variables in Ring Slots} +\section{Writing Higher Order Procedures} +\subsection{Recursive Calls to Multiple-Input Blocks} +\section{Formal Parameters} +\section{Procedures as Data} +\section{Special Forms} +\subsection{Special Forms in Scratch} +\chapter{Object Oriented Programming} +\section{Local State with Script Variables} +\section{Messages and Dispatch Procedures} +\section{Inheritance via Delegation} +\section{An Implementation of Prototyping OOP} +\chapter{The Outside World} +\section{The World Wide Web} +\section{Hardware Devices} +\section{Date and Time} +\chapter{Continuations} +\section{Continuation Passing Style} +\section{Call/Run w/Continuation} +\subsection{Nonlocal exit} +\chapter{User Interface Elements} +\section{Tool Bar Features} +\subsection{The \Snap{} Logo Menu} +\subsection{The File Menu} +\subsection{The Cloud Menu} +\subsection{The Settings Menu} +\subsection{Stage Resizing Buttons} +\subsection{Project Control Buttons} +\section{The Palette Area} +\subsection{Context Menus for Palette Blocks} +\subsection{Context Menu for the Palette Background} +\section{The Scripting Area} +\subsection{Sprite Appearance and Behavior Controls} +\subsection{Scripting Area Tabs} +\subsection{Scripts and Blocks Within Scripts} +\subsection{Scripting Area Background Context Menu} +\subsection{Controls in the Costumes Tab} +\subsection{The Paint Editor} +\subsection{Controls in the Sounds Tab} +\section{Controls on the Stage} +\section{The Sprite Corral and Sprite Creation Buttons} + +\end{document} diff --git a/help/manual/en/snapping-blocks.png b/help/manual/en/snapping-blocks.png new file mode 100644 index 00000000..0dc5922b Binary files /dev/null and b/help/manual/en/snapping-blocks.png differ diff --git a/help/manual/en/typical-script-inner.png b/help/manual/en/typical-script-inner.png new file mode 100644 index 00000000..b5503f7c Binary files /dev/null and b/help/manual/en/typical-script-inner.png differ diff --git a/help/manual/en/typical-script.png b/help/manual/en/typical-script.png new file mode 100644 index 00000000..6763aadb Binary files /dev/null and b/help/manual/en/typical-script.png differ diff --git a/help/manual/en/window-regions.png b/help/manual/en/window-regions.png new file mode 100644 index 00000000..7fe4e98a Binary files /dev/null and b/help/manual/en/window-regions.png differ diff --git a/help/manual/pl/laczenie-blokow.png b/help/manual/pl/laczenie-blokow.png new file mode 100644 index 00000000..b640b5f7 Binary files /dev/null and b/help/manual/pl/laczenie-blokow.png differ diff --git a/help/manual/pl/obszary-okna.pdf b/help/manual/pl/obszary-okna.pdf new file mode 100644 index 00000000..d4e5800e Binary files /dev/null and b/help/manual/pl/obszary-okna.pdf differ diff --git a/help/manual/pl/obszary-okna.pdf_tex b/help/manual/pl/obszary-okna.pdf_tex new file mode 100644 index 00000000..6fc4bdf3 --- /dev/null +++ b/help/manual/pl/obszary-okna.pdf_tex @@ -0,0 +1,59 @@ +%% Creator: Inkscape inkscape 0.48.4, www.inkscape.org +%% PDF/EPS/PS + LaTeX output extension by Johan Engelen, 2010 +%% Accompanies image file 'obszary-okna.pdf' (pdf, eps, ps) +%% +%% To include the image in your LaTeX document, write +%% \input{.pdf_tex} +%% instead of +%% \includegraphics{.pdf} +%% To scale the image, write +%% \def\svgwidth{} +%% \input{.pdf_tex} +%% instead of +%% \includegraphics[width=]{.pdf} +%% +%% Images with a different path to the parent latex file can +%% be accessed with the `import' package (which may need to be +%% installed) using +%% \usepackage{import} +%% in the preamble, and then including the image with +%% \import{}{.pdf_tex} +%% Alternatively, one can specify +%% \graphicspath{{/}} +%% +%% For more information, please see info/svg-inkscape on CTAN: +%% http://tug.ctan.org/tex-archive/info/svg-inkscape +%% +\begingroup% + \makeatletter% + \providecommand\color[2][]{% + \errmessage{(Inkscape) Color is used for the text in Inkscape, but the package 'color.sty' is not loaded}% + \renewcommand\color[2][]{}% + }% + \providecommand\transparent[1]{% + \errmessage{(Inkscape) Transparency is used (non-zero) for the text in Inkscape, but the package 'transparent.sty' is not loaded}% + \renewcommand\transparent[1]{}% + }% + \providecommand\rotatebox[2]{#2}% + \ifx\svgwidth\undefined% + \setlength{\unitlength}{855.2bp}% + \ifx\svgscale\undefined% + \relax% + \else% + \setlength{\unitlength}{\unitlength * \real{\svgscale}}% + \fi% + \else% + \setlength{\unitlength}{\svgwidth}% + \fi% + \global\let\svgwidth\undefined% + \global\let\svgscale\undefined% + \makeatother% + \begin{picture}(1,0.60243218)% + \put(0,0){\includegraphics[width=\unitlength]{obszary-okna.pdf}}% + \put(0.37031041,0.03597468){\color[rgb]{1,0,0}\makebox(0,0)[b]{\smash{\emph{\Large Obszar skryptów}}}}% + \put(0.42733084,0.57941921){\color[rgb]{1,0,0}\makebox(0,0)[b]{\smash{\emph{\small Pasek narzędzi}}}}% + \put(0.77489765,0.03597473){\color[rgb]{1,0,0}\makebox(0,0)[b]{\smash{\emph{\Large Zagroda duszków}}}}% + \put(0.09676227,0.03597473){\color[rgb]{1,0,0}\makebox(0,0)[b]{\smash{\emph{\Large Paleta}}}}% + \put(0.77708296,0.27919271){\color[rgb]{1,0,0}\makebox(0,0)[b]{\smash{\emph{\Large Scena}}}}% + \end{picture}% +\endgroup% diff --git a/help/manual/pl/obszary-okna.svg b/help/manual/pl/obszary-okna.svg new file mode 100644 index 00000000..f593e273 --- /dev/null +++ b/help/manual/pl/obszary-okna.svg @@ -0,0 +1,1388 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + \emph{\Large Obszar skryptów} + \emph{\small Pasek narzędzi} + + + + + \emph{\Large Zagroda duszków} + \emph{\Large Paleta} + \emph{\Large Scena} + + diff --git a/help/manual/pl/przesun-o-10-krokow.png b/help/manual/pl/przesun-o-10-krokow.png new file mode 100644 index 00000000..ece840c6 Binary files /dev/null and b/help/manual/pl/przesun-o-10-krokow.png differ diff --git a/help/manual/pl/snap-podrecznik.tex b/help/manual/pl/snap-podrecznik.tex new file mode 100644 index 00000000..f041a171 --- /dev/null +++ b/help/manual/pl/snap-podrecznik.tex @@ -0,0 +1,167 @@ +% !TeX spellcheck = pl + +\documentclass{report} + +\input{../common/defs.tex} + +\usepackage[polish]{babel} +\usepackage{polski} +\frenchspacing +\usepackage{indentfirst} + +\begin{document} + +\title{\Snap{} \\ Podręcznik użytkownika} +\author{Brian Harvey \and Jens M\"{o}nig} +\date{} + +\maketitle + +\tableofcontents + +\chapter*{} +\section*{Podziękowania} + +Mieliśmy ogromne szczęście do mentorów. Jens zdobył dużo doświadczenia pracując wśród pionierów Smalltalka: Alana Kaya, Dana Ingallsa i~reszty ekipy, która wynalazła komputery osobiste i~programowanie obiektowe w~najlepszych dniach firmy Xerox PARC. Pracował z~Johnem Maloneyem z~zespołu Scratcha w~MIT\footnote{Massachusetts Institute of Technology, amerykańska uczelnia techniczna --- przyp. tłum.}, autorem platformy graficznej Morphic, wciąż stanowiącej fundament \Snap{a}. Znakomity projekt języka Scratch, autorstwa Lifelong Kindergarten Group z~MIT Media Lab, odgrywa w~\Snap{ie} kluczową rolę. + +\textbf{\emph{Nasza poprzednia wersja, BYOB, była bezpośrednią modyfikacją kodu źródłowego Scratcha. \Snap{} został napisany od zera, lecz struktura jego kodu oraz interfejs użytkownika pozostają mocno zakorzenione w~Scratchu. Z~kolei zespół Scratcha, który mógłby widzieć w~nas rywali, przyjął nas ciepło i~okazał nam całkowite wsparcie.}} + +Brian zdobywał szlify w~MIT oraz Stanford Artificial Intelligence Labs\footnote{Laboratorium sztucznej inteligencji na Uniwersytecie Stanforda --- przyp. tłum.}, gdzie uczył się pod okiem Johna McCarthy'ego, twórcy Lispa, oraz Geralda~J. Suss\-mana i~Guya Steele'a, twórców języka Scheme. Zdobywał również wiedzę od wielu innych wybitnych informatyków, w~tym autorów najlepszej książki z zakresu informatyki --- \emph{Struktury i~interpretacji programów komputerowych}: Hala Abelsona, Geralda~J. Suss\-mana i~Julie Suss\-man. + +\textbf{\emph{Za starych dobrych czasów mawialiśmy w~MIT Logo Lab: ,,Język Logo to Lisp w przebraniu BASIC-a''. Dziś, ze swoimi pierwszoklasowymi procedurami, zasięgami leksykalnymi~i pierwszoklasowymi kontynuacjami, \Snap{} jest jak Scheme w~przebraniu Scratcha.}} + +Szczęśliwym zrządzeniem losu, poprzez forum Scratch Advanced Topics, poznaliśmy wspaniałą grupę błyskotliwych uczniów gimnazjów~(!\@) i liceów. Kilku z nich wniosło swój wkład w~kod \Snap{a}: Kartik Chandra, Nathan Dinsmore, Connor Hudson i~Ian Reynolds. Ponadto wielu zgłosiło pomysły i~raporty błędów podczas testowania wersji alfa. Wśród studentów Uniwersytetu Kalifornijskiego w~Berkeley, którzy przyczynili się do rozwoju kodu, znajdują się Michael Ball, Achal Dave, Kyle Hotchkiss, Ivan Motyashov i~Yuan Yuan. Wymienianie wszystkich tłumaczy zajęłoby zbyt wiele miejsca, ale można ich odnaleźć w~okienku ,,O Snap!...'' dostępnym w~programie. Niniejsze dzieło powstało częściowo w~ramach grantu nr~1143566 udzielonego przez National Science Foundation, a częściowo przy wsparciu firmy MioSoft. + +\clearpage + +\begin{center} +\bf \Huge \Snap{} \\ +Podręcznik użytkownika \\ +\huge Wersja 4.0 \vspace{40pt} +\end{center} + +\Snap{} to rozszerzona reimplementacja języka Scratch (\url{http://scratch.mit.edu}), która pozwala na tworzenie własnych bloków (ang.\ \textit{Build Your Own Blocks}; stąd dawna nazwa \Snap{a} --- BYOB). Opisywany tu język obsługuje pierwszoklasowe listy, procedury i~kontynuacje. Te dodatkowe możliwości sprawiają, że nadaje się on do przeprowadzenia poważnego wstępu do informatyki dla uczniów liceów i szkół wyższych. Aby uruchomić środowisko \Snap{}, wystarczy otworzyć przeglądarkę internetową i~wpisać adres \url{http://snap.berkeley.edu/run}, aby zacząć pracę z~minimalnym zestawem bloków. Można też użyć adresu \url{http://snap.berkeley.edu/init}, aby załadować niewielki zestaw dodatkowych bloków. Wiąże się to z~nieco wolniejszym ładowaniem, ale jest zalecane dla wygody użytkowników (w~dalszej części podręcznika będziemy zakładali korzystanie z~tej właśnie metody). + +\clearpage + +\chapter{Bloki, skrypty i duszki} + +W~tym rozdziale poznamy kilka cech języka \Snap{} odziedziczonych po Scratchu; doświadczeni użytkownicy Scratcha mogą przejść od razu do sekcji~\ref{sec:zagnieżdżanie-duszków}. + +\Snap{} jest językiem programowania --- notacją, przy pomocy której możemy powiedzieć komputerowi, co ma zrobić. Jednak w~odróżnieniu od większości innych, \Snap{} jest językiem wizualnym; programując w~nim, zamiast posługiwać się klawiaturą, używamy metody ,,przeciągnij i~upuść'', dobrze znanej użytkownikom komputerów. + +Uruchom teraz środowisko \Snap{}. Powinieneś zobaczyć ekran podzielony na kilka obszarów: + +\begin{center} +\def\svgwidth{\textwidth} +\input{obszary-okna.pdf_tex} +\end{center} + +(Proporcje tych stref mogą się różnić, w~zależności od rozmiaru i~kształtu okna przeglądarki.) + +Program w~języku \Snap{} składa się z~jednego lub więcej \emph{skryptów}, te zaś z~kolei --- z~\emph{bloków}. Oto przykładowy skrypt: + +\label{fig:typowy-skrypt} +\bigpic{typowy-skrypt} + +Na powyższy skrypt składa się pięć bloków w~trzech różnych kolorach, odpowiadających trzem z~ośmiu \emph{palet} z~blokami. Obszar palet, znajdujący się po lewej stronie okna, pokazuje jedną paletę na raz. Do zmiany widocznej palety służy osiem przycisków znajdujących się tuż nad tym obszarem. Bloki ciemnożółte, widoczne w~naszym skrypcie, pochodzą z~palety ,,Kontrola''; zielone z~palety ,,Pisak'', a~niebieskie --- z~palety ,,Ruch''. Aby złożyć taki skrypt, należy poprzeciągać odpowiednie bloki z~palet do \emph{obszaru skryptów}, umiejscowionego na środku okna. Kiedy układamy jeden blok pod drugim w~taki sposób, aby wcięcie dolnego bloku znalazło się w~pobliżu wypustki tego powyżej, bloki łączą się ze sobą (ang. \textit{snap together}; stąd nazwa języka \Snap{}): + +\bigpic{laczenie-blokow} + +Pozioma biała linia sygnalizuje, że jeśli puścimy zielony blok, połączy się on z~wypustką ciemnożółtego. + +\subsection{Bloki-czapki i bloki poleceń} + +Na górze skryptu znajduje się \emph{blok-czapka}, który określa, kiedy skrypt ma zostać wykonany. Nazwy bloków-czapek zazwyczaj zaczynają się słowem ,,\code{kiedy}''; nasz przykładowy skrypt powinien zostać uruchomiony w~momencie kliknięcia zielonej flagi, znajdującej się w pobliżu prawej strony paska narzędzi \Snap{a}. (Pasek ten jest częścią okna programu \Snap{}; nie chodzi tutaj o pasek menu przeglądarki lub systemu operacyjnego.) Skrypt nie musi posiadać czapki, jednak w~takim przypadku zostanie wykonany tylko wtedy, gdy użytkownik sam go kliknie. Skrypt nie może mieć więcej niż jednej czapki; jej charakterystyczny kształt służy łatwiejszemu zapamiętaniu tej szczególnej własności. + +Pozostałe bloki w naszym skrypcie to \emph{bloki poleceń}. Każdy z~nich oznacza jakąś akcję, którą \Snap{} potrafi wykonać. Na przykład blok \inlinepic{przesun-o-10-krokow} nakazuje duszkowi\footnote{W grafice komputerowej słowem ,,duszek'' (ang. \textit{sprite}) nazywa się ruchomy obiekt na ekranie --- przyp. tłum.}, czyli strzałce na \emph{scenie} po prawej stronie okna, aby przesunął się o~dziesięć kroków do przodu w~kierunku, w~którym jest zwrócony. Każdy krok to niewielka odległość na ekranie. Wkrótce przekonamy się, że na scenie może być więcej duszków, a~każdy z nich może mieć własne skrypty. Ponadto duszki nie muszą wyglądać jak strzałki; ich kostiumy mogą być dowolnymi obrazkami. Kształt bloku \code{przesuń} ma za zadanie przypominać klocek, skrypt zaś jest jak wieża z klocków. Słowa ,,blok'' będziemy używać dla oznaczenia zarówno graficznego symbolu na ekranie, jak i~procedury (akcji) jaką ten blok wykonuje. + +Liczbę 10 w powyższym bloku \code{przesuń} nazywamy jego \emph{parametrem}. Kliknąwszy na białym, zaokrąglonym polu, możemy wpisać w~jej miejsce dowolną inną. W przykładowym skrypcie ze strony \pageref{fig:typowy-skrypt} parametrem jest liczba 100. Jak się później okaże, pola parametrów mogą mieć kształty inne od zaokrąglonych; oznacza to wtedy, że akceptują one wartości inne niż liczby. Zobaczymy również, że zamiast wpisywać konkretne wartości w~pola, możemy nakazać komputerowi je obliczać. Ponadto blok może mieć więcej niż jeden parametr. Na przykład blok \code{leć}, znajdujący się mniej więcej w~połowie palety ,,Ruch'', przyjmuje trzy parametry. + +Większość bloków poleceń ma kształt klocków, lecz niektóre, jak \code{powtórz} z~tego samego przykładu, wyglądają jak \emph{klamry}. Większość bloków klamrowych można znaleźć na palecie ,,Kontrola'. Wnętrze klamry jest szczególnym rodzajem pola parametru, który przyjmuje \emph{skrypt} jako parametr. W~przykładowym skrypcie blok \code{powtórz} ma dwa parametry: liczbę 4 oraz skrypt + +\bigpic{typowy-skrypt-wnetrze} + + + +\section{Sprites and Parallelism} +\subsection{Costumes and Sounds} +\subsection{Inter-Sprite Communication with Broadcast} +\section{Zagnieżdżanie duszków: kotwice i części} +\label{sec:zagnieżdżanie-duszków} +\section{Reporter Blocks and Expressions} +\section{Predicates and Conditional Evaluation} +\section{Variables} +\subsection{Global Variables} +\subsection{Script Variables} +\section{Etcetera} +\chapter{Saving and Loading Projects and Media} +\section{Local Storage} +\subsection{Localstore} +\subsection{XML Export} +\section{Cloud Storage} +\section{Loading Saved Projects} +\chapter{Building a Block} +\section{Simple Blocks} +\subsection{Custom Blocks with Inputs} +\section{Recursion} +\section{Block Libraries} +\chapter{First Class Lists} +\section{The list Block} +\section{Lists of Lists} +\section{Functional and Imperative List Programming} +\section{Higher Order List Operations and Rings} +\chapter{Typed Inputs} +\section{Scratch's Type Notation} +\section{The \Snap{} Input Type Dialog} +\subsection{Procedure Types} +\subsection{Pulldown inputs} +\subsection{Input variants} +\subsection{Prototype Hints} +\subsection{Title Text and Symbols} +\chapter{Procedures as Data} +\section{Call and Run} +\subsection{Call/Run with inputs} +\subsection{Variables in Ring Slots} +\section{Writing Higher Order Procedures} +\subsection{Recursive Calls to Multiple-Input Blocks} +\section{Formal Parameters} +\section{Procedures as Data} +\section{Special Forms} +\subsection{Special Forms in Scratch} +\chapter{Object Oriented Programming} +\section{Local State with Script Variables} +\section{Messages and Dispatch Procedures} +\section{Inheritance via Delegation} +\section{An Implementation of Prototyping OOP} +\chapter{The Outside World} +\section{The World Wide Web} +\section{Hardware Devices} +\section{Date and Time} +\chapter{Continuations} +\section{Continuation Passing Style} +\section{Call/Run w/Continuation} +\subsection{Nonlocal exit} +\chapter{User Interface Elements} +\section{Tool Bar Features} +\subsection{The \Snap{} Logo Menu} +\subsection{The File Menu} +\subsection{The Cloud Menu} +\subsection{The Settings Menu} +\subsection{Stage Resizing Buttons} +\subsection{Project Control Buttons} +\section{The Palette Area} +\subsection{Context Menus for Palette Blocks} +\subsection{Context Menu for the Palette Background} +\section{The Scripting Area} +\subsection{Sprite Appearance and Behavior Controls} +\subsection{Scripting Area Tabs} +\subsection{Scripts and Blocks Within Scripts} +\subsection{Scripting Area Background Context Menu} +\subsection{Controls in the Costumes Tab} +\subsection{The Paint Editor} +\subsection{Controls in the Sounds Tab} +\section{Controls on the Stage} +\section{The Sprite Corral and Sprite Creation Buttons} + +\end{document} diff --git a/help/manual/pl/typowy-skrypt-wnetrze.png b/help/manual/pl/typowy-skrypt-wnetrze.png new file mode 100644 index 00000000..c3618ca5 Binary files /dev/null and b/help/manual/pl/typowy-skrypt-wnetrze.png differ diff --git a/help/manual/pl/typowy-skrypt.png b/help/manual/pl/typowy-skrypt.png new file mode 100644 index 00000000..6e2efe0e Binary files /dev/null and b/help/manual/pl/typowy-skrypt.png differ diff --git a/help/receiveClick.png b/help/receiveClick.png deleted file mode 100644 index 6ace2e39..00000000 Binary files a/help/receiveClick.png and /dev/null differ diff --git a/help/receiveInteraction.png b/help/receiveInteraction.png new file mode 100644 index 00000000..76b07156 Binary files /dev/null and b/help/receiveInteraction.png differ diff --git a/help/receiveOnClone.png b/help/receiveOnClone.png new file mode 100644 index 00000000..19cdf784 Binary files /dev/null and b/help/receiveOnClone.png differ diff --git a/help/removeClone.png b/help/removeClone.png new file mode 100644 index 00000000..3afc24ae Binary files /dev/null and b/help/removeClone.png differ diff --git a/help/reportAttributeOf.png b/help/reportAttributeOf.png new file mode 100644 index 00000000..ab4aff84 Binary files /dev/null and b/help/reportAttributeOf.png differ diff --git a/help/reportCallCC.png b/help/reportCallCC.png new file mode 100644 index 00000000..8c911c6d Binary files /dev/null and b/help/reportCallCC.png differ diff --git a/help/reportDate.png b/help/reportDate.png new file mode 100644 index 00000000..f13cf387 Binary files /dev/null and b/help/reportDate.png differ diff --git a/help/reportIsFastTracking.png b/help/reportIsFastTracking.png new file mode 100644 index 00000000..2929a790 Binary files /dev/null and b/help/reportIsFastTracking.png differ diff --git a/help/reportJSFunction.png b/help/reportJSFunction.png new file mode 100644 index 00000000..ecb2f0c7 Binary files /dev/null and b/help/reportJSFunction.png differ diff --git a/help/reportTextSplit.png b/help/reportTextSplit.png new file mode 100644 index 00000000..18d1422c Binary files /dev/null and b/help/reportTextSplit.png differ diff --git a/help/reportURL.png b/help/reportURL.png new file mode 100644 index 00000000..e7c24c54 Binary files /dev/null and b/help/reportURL.png differ diff --git a/history.txt b/history.txt index bac4a70a..f0491ee9 100755 --- a/history.txt +++ b/history.txt @@ -2435,3 +2435,136 @@ ______ ------ * GUI: Added url switch #cloud: to open a shared project in edit mode +150220 +------ +* Malayam, Tamil and Telagu translations, thanks, Vinay Kumar!! +* Un-hide “Save to disk” feature (currently supported by both Chrome and Firefox, but not by Safari) +* Update German translation +* GUI: Make “project data in URLs” a hidden dev option (prevent long urls per default) + +150223 +------ +* Blocks, Objects: Add user-interaction choices to the “When I am ...” hat block +* Update German translation +* Store: Avoid incompatibility warning for very old (pre-earmarked) projects + +150224 +------ +* Store: fixed #725 + +150228 +------ +* Blocks, Store, GUI: Cache inputs, accelerates evaluating recursive reporters and warped / turbo recursive commands by up to 40% +* Objects: slightly optimize warped / turbo execution +* Threads: fixed #715 +* BYOB: fixed #716 + +150302 +------ +* BYOB: fixed #730 + +150306 +------ +* Blocks: fixed #736 + +150309 +------ +* Blocks: fixed #738 +* GUI, Blocks: Only enable input caching for blocks + +150315 +------ +* Store: fixed #743 +* GUI, html: switch from beta to release candidate + +150325 +------ +* Threads: fixed #752 + +150415 +------ +* Threads: flush Stage>>keysPressed when prompting the user +* Objects: fixed #770 + +150426 +------ +* Store: fixed #784 + +150501 +------ +* Morphic, Blocks: select all text when first clicking an input slot +* BYOB: indicate numeric inputs in the block prototype with the # sign +* Threads: return empty string when querying first letter of a list +* GUI: hide “save to disk” option behind shift-click again (has issues in Chrome) +* GUI: parameters for embedding projects in iFrames, thanks, Bernat! + +=== Release v4.0 === + +150518 +------ +* Objects, GUI: Fix encoding for exported sprites (esp. comments) +* Portuguese translation update, thanks, Manuel!! + +150521 +------ +* BYOB: Fix encoding for exported libraries of global blocks + +150523 +------ +* BYOB: Fix encoding glitch + +150608 +------ +* Blocks: Fixed #820 + +150625 +------ +* Morphic, Objects, Blocks, XML: Optimizations and dramatic speed-up. Thanks, Nathan!! +* Objects: push maximum clone count up to 1000, tweak Note::play + +=== v4.0.1 (unreleased) === + +150626 +------ +* Morphic: Fix Inspector duplication, update documentation + +150727 +------ +* Polish translation update, thanks, Bartosz Leper! +* Turkish translation. Yay!! Thanks, Hakan Ataş! +* Hungarian translation. Yay!! Thanks, Makány György! +* GUI: relative-url fixes, Thanks, Michael! +* Morphic: enable exporting a screenshot of the World +* Morphic: enable more fine-grained control over dragging position correction +* Morphic: enable all Morphs to “scrollIntoView()” +* Morpic: keyboard accessibility for menus +* Objects: fixes and enhancements for nested sprites +* Blocks, Objects, BYOB, GUI: keyboard editing support +* Objects, Blocks, Threads, GUI, Store, Widgets: Prototypal inheritance for sprite-local variables +* Objects, Blocks: enable monitoring closurized non-locals and thread-temporaries (script vars of running processes) +* GUI: stage resizing handle + +150728 +------ +* GUI: fixed relative urls, thanks, Michael! +* Morphic: escalate origin with “accept” and “cancel” events from text cursors +* BYOB: keep BlockEditors open when or keys are pressed +* GUI: stop keyboard editing of blocks when selecting another sprite + +150730 +------ +* Blocks: improve keyboard editing for embedded rings + +150806 +------ +* Polish & German translation updates + +=== Release v4.0.2 === + +150809 +------ +* Interlingua support, yay!! thanks, Ken Dickey! + +150814 +------ +* Blocks: fixed #907 diff --git a/index.html b/index.html index e379b29d..6844fd45 100644 --- a/index.html +++ b/index.html @@ -20,8 +20,8 @@ - - + + diff --git a/lang-de.js b/lang-de.js index e8934429..ce2b220e 100644 --- a/lang-de.js +++ b/lang-de.js @@ -185,7 +185,7 @@ SnapTranslator.dict.de = { 'translator_e-mail': 'jens@moenig.org', // optional 'last_changed': - '2014-07-29', // this, too, will appear in the Translators tab + '2015-08-06', // this, too, will appear in the Translators tab // GUI // control bar: @@ -417,8 +417,18 @@ SnapTranslator.dict.de = { 'Wenn %greenflag angeklickt', 'when %keyHat key pressed': 'Wenn Taste %keyHat gedr\u00fcckt', - 'when I am clicked': - 'Wenn ich angeklickt werde', + 'when I am %interaction': + 'Wenn ich %interaction werde', + 'clicked': + 'angeklickt', + 'pressed': + 'gedr\u00fcckt', + 'dropped': + 'abgestellt', + 'mouse-entered': + 'vom Mauszeiger betreten', + 'mouse-departed': + 'vom Mauszeiger verlassen', 'when I receive %msgHat': 'Wenn ich %msgHat empfange', 'broadcast %msg': @@ -647,6 +657,11 @@ SnapTranslator.dict.de = { '\u00d6ffnen...', 'Save': 'Sichern', + 'Save to disk': + 'Abpeichern', + 'store this project\nin the downloads folder\n(in supporting browsers)': + 'dieses Projekt herunterladen\nund lokal speichern\n' + + '(nicht von allen Browsern unters\u00fctzt)', 'Save As...': 'Sichern als...', 'Import...': @@ -765,6 +780,10 @@ SnapTranslator.dict.de = { 'ausschalten, um Skripte\nnormal auszuf\u00fchren', 'check to enable\nIDE animations': 'einschalten um IDE-\nAnimationen zu erlauben', + 'Flat design': + 'Helles Design', + 'Keyboard Editing': + 'Tastaturunterstützung', 'Thread safe scripts': 'Threadsicherheit', 'uncheck to allow\nscript reentrance': @@ -783,6 +802,8 @@ SnapTranslator.dict.de = { 'einschalten f\u00fcr flache\nPinselstrichenden', 'uncheck for round ends of lines': 'auschalten f\u00fcr runde\nPinselstrichenden', + 'Inheritance support': + 'Prototypische Vererbung', // inputs 'with inputs': diff --git a/lang-fr.js b/lang-fr.js index 4198bf77..20da4808 100644 --- a/lang-fr.js +++ b/lang-fr.js @@ -185,7 +185,7 @@ SnapTranslator.dict.fr = { 'translator_e-mail': 'i.scool@mac.com', // optional 'last_changed': - '2014-02-04', // this, too, will appear in the Translators tab + '2015-06-25', // this, too, will appear in the Translators tab // GUI // control bar: @@ -392,7 +392,7 @@ SnapTranslator.dict.fr = { 'clear': 'effacer tout', 'pen down': - 'stylo en position d\u0027\u00EAcriture', + 'stylo en position d\u0027\u00E9criture', 'pen up': 'relever le stylo', 'set pen color to %clr': @@ -419,6 +419,8 @@ SnapTranslator.dict.fr = { 'Quand %keyHat est press\u00E9', 'when I am clicked': 'Quand je suis press\u00E9 ', + 'when I am %interaction': + 'Quand je suis %interaction', 'when I receive %msgHat': 'Quand je re\u00E7ois %msgHat', 'broadcast %msg': @@ -447,6 +449,10 @@ SnapTranslator.dict.fr = { 'arr\u00EAter le bloc', 'stop script': 'arr\u00EAter le script', + 'stop %stopOthersChoices': + 'arr\u00EAter %stopOthersChoices', + 'stop %stopChoices': + 'arr\u00EAter %stopChoices', 'stop all %stop': 'arr\u00EAter tout %stop', 'run %cmdRing %inputs': @@ -469,8 +475,16 @@ SnapTranslator.dict.fr = { 'moi-m\u00EAme', 'delete this clone': 'supprime ce clone', - 'pause all': - 'mettre en pause', + 'pause all %pause': + 'mettre en pause %pause', + 'all but this script': + 'tout sauf ce lutin', + 'other scripts in sprite': + 'les autres scripts de ce lutin', + 'this script': + 'ce script', + 'this block': + 'ce bloc', // sensing: 'touching %col ?': @@ -958,6 +972,8 @@ SnapTranslator.dict.fr = { 'tabulations', 'cr': 'retours de ligne', + 'letter': + 'lettres', // About Snap 'About Snap': @@ -1162,5 +1178,133 @@ SnapTranslator.dict.fr = { 'last': 'dernier', 'any': - 'n\u0027importe quel' + 'n\u0027importe quel', + + // miscellaneous + 'find blocks...': + 'chercher des blocs...', + 'hide primitives': + 'cacher les primitives', + 'show primitives': + 'montrer les primitives', + 'Login...': + 'Connexion...', + 'Signup...': + 'S\u0027enregistrer...', + 'Reset Password...': + 'Remise \u00E0 z\u00E9ro du mot de passe', + 'show all': + 'tout montrer', + 'pic...': + 'image...', + 'open a new window\nwith a picture of the stage': + 'ouvre une nouvelle fen\u00EAtre\navec une image de la sc\u00E8ne', + 'scripts pic...': + 'image des scripts...', + 'open a new window\nwith a picture of all scripts': + 'ouvre une nouvelle fen\u00EAtre\navec une image de tous les scripts', + 'Stage size...': + 'Taille de la sc\u00E8ne...', + 'Zoom blocks...': + 'Agrandir les blocs...', + + 'Plain prototype labels': + '\u00C9tiquettes simples de d\u00E9finition', + 'uncheck to always show (+) symbols\nin block prototype labels': + 'd\u00E9cocher pour montrer en permance le symbole (+)\ndans les \u00e9tiquettes de d\u00E9finition de bloc', + 'check to hide (+) symbols\nin block prototype labels': + 'cocher pour cacher le symbole (+)\ndans les \u00e9tiquettes de d\u00E9finition de bloc', + + 'check for flat ends of lines': + 'cocher pour dessiner des fins de ligne plates', + 'uncheck for round ends of lines': + 'd\u00E9cocher pour dessiner des fins de lignes arrondies', + 'Flat line ends': + 'Fins de ligne plates', + + 'Codification support': + 'Support de la \u00AB codification \u00BB', + 'uncheck to disable\nblock to text mapping features': + 'd\u00E9cocher pour d\u00E9activer\nla fonction de transformation :\nbloc vers texte', + 'check for block\nto text mapping features': + 'cocher pour activer\nla fonction de transformation :\nbloc vers texte', + + 'current %dates': + 'date courante %dates', + 'year':'ann\u00E9e', + 'month':'mois', + 'date':'jour', + 'hour':'heure', + 'minute':'minute', + 'second':'seconde', + 'time in milliseconds': + 'heure en millisecondes', + 'day of week': + 'jour de la semaine', + + 'brightness': + 'luminosit\u00E9', + 'transparence': + 'transparence', + 'negative': + 'n\u00E9gatif', + 'comic': + 'bande dessin\u00E9e', + + 'clicked': + 'cliqu\u00E9', + 'pressed': + 'press\u00E9', + 'dropped': + 'd\u00E9pos\u00E9', + 'mouse-entered': + 'survol\u00E9', + 'mouse-departed': + 'quitt\u00E9', + + 'JavaScript function ( %mult%s ) { %code }': + 'fonction JavaScript ( %mult%s ) { %code }', + + + // Copy / Paste + 'Press CTRL+C one more time to effectively copy to clipboard.': + 'Taper une nouvelle fois sur CTRL+C pour copier effectivement vers le presse-papier.', + 'Press CTRL+V one more time to effectively paste from clipboard.': + 'Taper une nouvelle fois sur CTRL+V pour coller effectivement depuis le presse-papier.', + 'Press CTRL+X one more time to effectively cut to clipboard.': + 'Taper une nouvelle fois sur CTRL+X pour couper effectivement vers le presse-papier.', + + // Paint.js + 'undo':'d\u00E9faire', + 'Paintbrush tool\n(free draw)': + 'Pinceau\n(dessin \u00E0 main lev\u00E9)', + 'Stroked Rectangle\n(shift: square)': + 'Rectangle\n(Maj: carr\u00E9)', + 'Stroked Ellipse\n(shift: circle)': + 'Ellipse\n(Maj: cercle)', + 'Eraser tool': + 'Gomme', + 'Set the rotation center': + 'Fixe le centre de rotation', + 'Line tool\n(shift: vertical/horizontal)': + 'Ligne\n(Maj: verticale/horizontale)', + 'Filled Rectangle\n(shift: square)': + 'Rectangle plein\n(Maj: carr\u00E9)', + 'Filled Ellipse\n(shift: circle)': + 'Ellipse pleine\n(Maj: cercle)', + 'Fill a region': + 'Remplir une r\u00E9gion', + 'Pipette tool\n(pick a color anywhere)': + 'Pipette\n(s\u00E9lectionnez une couleur n\u0027importe o\u00F9', + 'grow':'agrandir', + 'shrink':'r\u00E9duire', + 'flip \u2194': + 'miroir \u2194', + 'flip \u2195': + 'miroir \u2195', + 'Brush size': + 'Taille de pinceau', + 'Constrain proportions of shapes?\n(you can also hold shift)': + 'Contrainte sur les proportions de la forme ?\n(vous pouvez aussi maintenir appuy\u00E9 Maj)' + }; diff --git a/lang-hu.js b/lang-hu.js new file mode 100644 index 00000000..245f58ea --- /dev/null +++ b/lang-hu.js @@ -0,0 +1,1695 @@ +/* + + lang-hu.js + + A SNAP! magyar fordítása + + written by Makány György + + Copyright (C) 2015 by Makány György + + This file is part of Snap!. + + Snap! is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + + + + Note to Translators: + -------------------- + At this stage of development, Snap! can be translated to any LTR language + maintaining the current order of inputs (formal parameters in blocks). + + Translating Snap! is easy: + + + 1. Download + + Download the sources and extract them into a local folder on your + computer: + + + + Use the German translation file (named 'lang-de.js') as template for your + own translations. Start with editing the original file, because that way + you will be able to immediately check the results in your browsers while + you're working on your translation (keep the local copy of snap.html open + in your web browser, and refresh it as you progress with your + translation). + + + 2. Edit + + Edit the translation file with a regular text editor, or with your + favorite JavaScript editor. + + In the first non-commented line (the one right below this + note) replace "de" with the two-letter ISO 639-1 code for your language, + e.g. + + fr - French => SnapTranslator.dict.fr = { + it - Italian => SnapTranslator.dict.it = { + pl - Polish => SnapTranslator.dict.pl = { + pt - Portuguese => SnapTranslator.dict.pt = { + es - Spanish => SnapTranslator.dict.es = { + el - Greek => => SnapTranslator.dict.el = { + + etc. (see ) + + + 3. Translate + + Then work through the dictionary, replacing the German strings against + your translations. The dictionary is a straight-forward JavaScript ad-hoc + object, for review purposes it should be formatted as follows: + + { + 'English string': + 'Translation string', + 'last key': + } 'last value' + + and you only edit the indented value strings. Note that each key-value + pair needs to be delimited by a comma, but that there shouldn't be a comma + after the last pair (again, just overwrite the template file and you'll be + fine). + + If something doesn't work, or if you're unsure about the formalities you + should check your file with + + + + This will inform you about any missed commas etc. + + + 4. Accented characters + + Depending on which text editor and which file encoding you use you can + directly enter special characters (e.g. Umlaut, accented characters) on + your keyboard. However, I've noticed that some browsers may not display + special characters correctly, even if other browsers do. So it's best to + check your results in several browsers. If you want to be on the safe + side, it's even better to escape these characters using Unicode. + + see: + + + 5. Block specs: + + At this time your translation of block specs will only work + correctly, if the order of formal parameters and their types + are unchanged. Placeholders for inputs (formal parameters) are + indicated by a preceding % prefix and followed by a type + abbreviation. + + For example: + + 'say %s for %n secs' + + can currently not be changed into + + 'say %n secs long %s' + + and still work as intended. + + Similarly + + 'point towards %dst' + + cannot be changed into + + 'point towards %cst' + + without breaking its functionality. + + + 6. Submit + + When you're done, rename the edited file by replacing the "de" part of the + filename with the two-letter ISO 639-1 code for your language, e.g. + + fr - French => lang-fr.js + it - Italian => lang-it.js + pl - Polish => lang-pl.js + pt - Portuguese => lang-pt.js + es - Spanish => lang-es.js + el - Greek => => lang-el.js + + and send it to me for inclusion in the official Snap! distribution. + Once your translation has been included, Your name will the shown in the + "Translators" tab in the "About Snap!" dialog box, and you will be able to + directly launch a translated version of Snap! in your browser by appending + + lang:xx + + to the URL, xx representing your translations two-letter code. + + + 7. Known issues + + In some browsers accents or ornaments located in typographic ascenders + above the cap height are currently (partially) cut-off. + + Enjoy! + -Jens +*/ + +/*global SnapTranslator*/ + +SnapTranslator.dict.hu = { + +/* + Special characters: (see ) + + Ä, ä \u00c4, \u00e4 + Ö, ö \u00d6, \u00f6 + Ü, ü \u00dc, \u00fc + ß \u00df +*/ + + // translations meta information + 'language_name': + 'Magyar', // the name as it should appear in the language menu + 'language_translator': + 'Makány György', // your name for the Translators tab + 'translator_e-mail': + 'makany.gyorgy@gmail.com', // optional + 'last_changed': + '2015-07-26', // this, too, will appear in the Translators tab + + // GUI + // control bar: + 'untitled': + 'névtelen', + 'development mode': + 'fejlesztői mód', + + // categories: + 'Motion': + 'Mozgás', + 'Looks': + 'Kinézet', + 'Sound': + 'Hang', + 'Pen': + 'Toll', + 'Control': + 'Vezérlés', + 'Sensing': + 'Érzékelés', + 'Operators': + 'Műveletek', + 'Variables': + 'Változók', + 'Lists': + 'Listák', + 'Other': + 'Egyebek', + + // editor: + 'draggable': + 'vonszolható', + + // tabs: + 'Scripts': + 'Feladatok', + 'Costumes': + 'Jelmezek', + 'Sounds': + 'Hangok', + + // names: + 'Sprite': + 'Szereplő', + 'Stage': + 'Játéktér', + + // rotation styles: + 'don\'t rotate': + 'nem foroghat', + 'can rotate': + 'foroghat', + 'only face left/right': + 'jobbra-balra fordulhat', + + // new sprite button: + 'add a new sprite': + 'Új szereplő', + + // tab help + 'costumes tab help': + 'Kép importálása egy webhelyről vagy a számítógépről', + 'import a sound from your computer\nby dragging it into here': + 'Hang importálása egy webhelyről vagy a számítógépről', + + // primitive blocks: + + /* + Attention Translators: + ---------------------- + At this time your translation of block specs will only work + correctly, if the order of formal parameters and their types + are unchanged. Placeholders for inputs (formal parameters) are + indicated by a preceding % prefix and followed by a type + abbreviation. + + For example: + + 'say %s for %n secs' + + can currently not be changed into + + 'say %n secs long %s' + + and still work as intended. + + Similarly + + 'point towards %dst' + + cannot be changed into + + 'point towards %cst' + + without breaking its functionality. + */ + + // motion: + 'Stage selected:\nno motion primitives': + 'Választott játéktér:\nnincs mozgó elem', + + 'move %n steps': + 'menj %n lépést', + 'turn %clockwise %n degrees': + 'fordulj %clockwise %n fokot', + 'turn %counterclockwise %n degrees': + 'fordulj %counterclockwise %n fokot', + 'point in direction %dir': + 'nézz %dir fokos irányba', + 'point towards %dst': + 'nézz %dst irányába', + 'go to x: %n y: %n': + 'ugorj x: %n y: %n', + 'go to %dst': + 'ugorj %dst helyére', + 'glide %n secs to x: %n y: %n': + 'csússz %n mp-ig x: %n y: %n', + 'change x by %n': + 'x változzon: %n', + 'set x to %n': + 'x legyen %n', + 'change y by %n': + 'y változzon: %n', + 'set y to %n': + 'y legyen %n', + 'if on edge, bounce': + 'ha szélen vagy, pattanj vissza', + 'x position': + 'x hely', + 'y position': + 'y hely', + 'direction': + 'irány', + + // looks: + 'switch to costume %cst': + 'a jelmez legyen %cst', + 'next costume': + 'a következő jelmez', + 'costume #': + 'a jelmez sorszáma', + 'say %s for %n secs': + 'mondd %s %n mp-ig', + 'say %s': + 'mondd %s', + 'think %s for %n secs': + 'gondold %s %n mp-ig', + 'think %s': + 'gondold %s', + 'Hello!': + 'Szia!', + 'Hmm...': + 'Hmm...', + 'change %eff effect by %n': + '%eff hatás változzon %n', + 'set %eff effect to %n': + '%eff hatás legyen %n', + 'clear graphic effects': + 'töröld a grafikus hatásokat', + 'change size by %n': + 'a méret változzon %n', + 'set size to %n %': + 'a méret legyen %n %', + 'size': + 'méret', + 'show': + 'jelenj meg', + 'hide': + 'tűnj el', + 'go to front': + 'kerülj legelőre', + 'go back %n layers': + 'kerülj %n szinttel hátrébb', + + 'development mode \ndebugging primitives:': + 'Fejlesztő mód \nblokkok hibakeresése', + 'console log %mult%s': + 'konzolra írás: %mult%', + 'alert %mult%s': + 'Felbukkanó: %mult%', + + // sound: + 'play sound %snd': + 'játszd le: %snd', + 'play sound %snd until done': + 'játszd le: %snd és várd meg', + 'stop all sounds': + 'minden hangot állíts le', + 'rest for %n beats': + 'szünetelj %n ütemet', + 'play note %n for %n beats': + 'szóljon %n %n ütemig', + 'change tempo by %n': + 'a tempó változzon: %n', + 'set tempo to %n bpm': + 'a tempó legyen %n ütem/perc', + 'tempo': + 'tempó', + + // pen: + 'clear': + 'töröld a rajzokat', + 'pen down': + 'tollat le', + 'pen up': + 'tollat fel', + 'set pen color to %clr': + 'a tollszín legyen %clr', + 'change pen color by %n': + 'a tollszín változzon %n', + 'set pen color to %n': + 'a tollszín legyen %n', + 'change pen shade by %n': + 'a tollárnyalat változzon %n', + 'set pen shade to %n': + 'a tollárnyalat legyen %n', + 'change pen size by %n': + 'a tollméret változzon %n', + 'set pen size to %n': + 'a tollméret legyen %n', + 'stamp': + 'készíts lenyomatot', + + // control: + 'when %greenflag clicked': + '%greenflag -ra kattintáskor', + 'when %keyHat key pressed': + '%keyHat lenyomásakor', + 'when I am %interaction': + 'amikor %interaction ', + 'clicked': + 'rám kattintanak', + 'pressed': + 'gombnyomás történik', + 'dropped': + 'leejtenek', + 'mouse-entered': + 'az egér fölém kerül', + 'mouse-departed': + 'az egér lemegy rólam', + 'when I receive %msgHat': + '%msgHat üzenet érkezésekor', + 'broadcast %msg': + 'küldj mindenkinek %msg üzenetet', + 'broadcast %msg and wait': + 'küldj mindenkinek %msg üzenetet és várj', + 'Message name': + 'Az üzenet neve', + 'message': + 'üzenet', + 'any message': + 'bármilyen üzenet', + 'wait %n secs': + 'várj %n mp-et', + 'wait until %b': + 'várj amíg %b', + 'forever %c': + 'mindig %c', + 'repeat %n %c': + 'ismételd %n -szer %c', + 'repeat until %b %c': + 'ismételd amíg %b %c', + 'if %b %c': + 'ha %b %c', + 'if %b %c else %c': + 'ha %b %c különben %c', + 'report %s': + 'jelents %s', + 'stop %stopChoices': + '%stopChoices álljon le', + 'all': + 'minden feladat', + 'this script': + 'ez a feladat', + 'this block': + 'ez a blokk', + 'stop %stopOthersChoices': + '%stopOthersChoices álljon le', + 'all but this script': + 'minden más feladat', + 'other scripts in sprite': + 'ennek a szereplőnek minden más feladata', + 'pause all %pause': + 'Várakozzon minden %pause', + 'run %cmdRing %inputs': + 'futtasd %cmdRing %inputs értékkel', + 'launch %cmdRing %inputs': + 'induljon %cmdRing %inputs', + 'call %repRing %inputs': + 'hívd %repRing auf %inputs', + 'run %cmdRing w/continuation': + 'futtatás %cmdRing folytatásával', + 'call %cmdRing w/continuation': + 'hívd meg %cmdRing folytatásával', + 'warp %c': + 'Warp %c', + 'when I start as a clone': + 'másolatként indítva', + 'create a clone of %cln': + 'készíts másolatot %cln', + 'myself': + 'magadról', + 'delete this clone': + 'töröld ezt a másolatot', + + // sensing: + 'touching %col ?': + 'érint %col színt?', + 'touching %clr ?': + 'érint %clr színt?', + 'color %clr is touching %clr ?': + '%clr szín érint %clr színt?', + 'ask %s and wait': + 'Kérdezd meg %s és várj', + 'what\'s your name?': + 'Mi a neved?', + 'answer': + 'Válasz', + 'mouse x': + 'egér x', + 'mouse y': + 'egér y', + 'mouse down?': + 'Egér lenyomva?', + 'key %key pressed?': + '%key gomb lenyomva?', + 'distance to %dst': + 'távolság: %dst', + 'reset timer': + 'Nullázd az órát', + 'timer': + 'Stopper', + '%att of %spr': + '%att %spr objektumérték', + 'http:// %s': + 'http:// %s', + 'turbo mode?': + 'Turbó mód?', + 'set turbo mode to %b': + '%b turbó módjának bekapcsolása', + + 'filtered for %clr': + '%clr szín szűrése', + 'stack size': + 'Veremméret', + 'frames': + 'Keretek', + + // operators: + '%n mod %n': + '%n osztva %n maradéka', + 'round %n': + '%n kerekítve', + '%fun of %n': + '%fun %n', + 'pick random %n to %n': + 'véletlen %n és %n között', + '%b and %b': + '%b ÉS %b', + '%b or %b': + '%b VAGY %b', + 'not %b': + 'NEM %b', + 'true': + 'igaz', + 'false': + 'hamis', + 'join %words': + 'összefűz %words', + 'split %s by %delim': + '%s szétvágása %delim jeleknél', + 'hello': + 'szia', + 'world': + 'világ', + 'letter %n of %s': + '%n karaktere ennek: %s', + 'length of %s': + '%s hossza', + 'unicode of %s': + '%s Unicode-ra alakítva', + 'unicode %n as letter': + 'Unicode %n betűként', + 'is %s a %typ ?': + '%s egy %typ ?', + 'is %s identical to %s ?': + '%s ugyanaz, mint %s ?', + + 'type of %s': + 'típus: %s', + + // variables: + 'Make a variable': + 'Új változó', + 'Variable name': + 'Változónév', + 'Script variable name': + 'Feladatváltozó név', + 'Delete a variable': + 'Változó törlése', + + 'set %var to %s': + '%var legyen %s', + 'change %var by %n': + '%var változzon ennyivel: %n', + 'show variable %var': + 'írd ki: %var', + 'hide variable %var': + 'rejtsd el: %var', + 'script variables %scriptVars': + 'feladatváltozó: %scriptVars', + + // lists: + 'list %exp': + 'lista %exp', + '%s in front of %l': + '%s megelőzi %l', + 'item %idx of %l': + '%idx eleme a %l listának', + 'all but first of %l': + '%l elsőnkívüli elemei', + 'length of %l': + '%l hossza', + '%l contains %s': + '%l tartalmazza %s -t', + 'thing': + 'dolog', + 'add %s to %l': + '%s hozzáadása %l listához', + 'delete %ida of %l': + '%ida elem törlése %l listából', + 'insert %s at %idx of %l': + '%s beszúrása %idx . pozícióba ebbe: %l', + 'replace item %idx of %l with %s': + '%idx helyettesítése %l listában erre: %s', + + // other + 'Make a block': + 'Blokk készítése', + + // menus + // snap menu + 'About...': + 'A Snap! névjegye...', + 'Reference manual': + 'Kézikönyv', + 'Snap! website': + 'A Snap! webhelye', + 'Download source': + 'A forráskód letöltése', + 'Switch back to user mode': + 'Vissza a felhasználói üzemmódra', + 'disable deep-Morphic\ncontext menus\nand show user-friendly ones': + 'A deep-Morphic\nhelyzetérzékeny menük\nés a felhasználóbarát menük kikapcsolása', + 'Switch to dev mode': + 'Átkapcsolás fejlesztői módba', + 'enable Morphic\ncontext menus\nand inspectors,\nnot user-friendly!': + 'A Morphic helyzetérzékeny menük, nyomkövetők\nés a nem felhasználóbarát mód bekapcsolása', + + // project menu + 'Project notes...': + 'Projektadatok...', + 'New': + 'Új', + 'Open...': + 'Megnyitás...', + 'Save': + 'Mentés', + 'Save to disk': + 'Lemezre írás', + 'store this project\nin the downloads folder\n(in supporting browsers)': + 'a projekt tárolása\na letöltési mappába\n(ha a böngésző engedi)', + 'Save As...': + 'Mentés másként...', + 'Import...': + 'Importálás...', + 'file menu import hint': + 'egy exportált projekt, feladatkönyvtár,\njelmez vagy hang betöltése', + 'Export project as plain text...': + 'Projekt exportálása egyszerű szövegként...', + 'Export project...': + 'Projekt exportálása...', + 'show project data as XML\nin a new browser window': + 'a projekt adatainak megtekintése\negy új böngészőablakban', + 'Export blocks...': + 'Blokk exportálása...', + 'show global custom block definitions as XML\nin a new browser window': + 'globális felhasználói blokk definíciók\nmegtekintése egy új böngészőablakban', + 'Import tools': + 'Eszközök importálása', + 'load the official library of\npowerful blocks': + 'a hivatalos könyvtári\nblokkok betöltése', + 'Libraries...': + 'Modulkönyvtárak...', + 'Import library': + 'Modulkönyvtár importálása', + + // cloud menu + 'Login...': + 'Belépés...', + 'Signup...': + 'Feliratkozás...', + + // settings menu + 'Language...': + 'Nyelv...', + 'Zoom blocks...': + 'Blokkok bővítése...', + 'Stage size...': + 'A játéktér mérete...', + 'Stage size': + 'A játéktér mérete', + 'Stage width': + 'A játéktér szélessége', + 'Stage height': + 'A játéktér magassága', + 'Default': + 'Alapérték', + 'Blurred shadows': + 'Elmosódó árnyékok', + 'uncheck to use solid drop\nshadows and highlights': + 'vegye ki a jelölést, ha éles árnyékokat\nés kiemeléseket kíván használni', + 'check to use blurred drop\nshadows and highlights': + 'jelölje be, ha elmosódó árnyékokat\nés kiemeléseket kíván használni', + 'Zebra coloring': + 'Zebra színezés', + 'check to enable alternating\ncolors for nested blocks': + 'engedélyezi a beágyazott blokkok\neltérő színezését', + 'uncheck to disable alternating\ncolors for nested block': + 'tiltja a beágyazott blokkok\neltérő színezését', + 'Dynamic input labels': + 'Dinamikus beviteli feliratok', + 'uncheck to disable dynamic\nlabels for variadic inputs': + 'üresen hagyva tiltja a többszörös\nbeviteli mezők dinamikus feliratait', + 'check to enable dynamic\nlabels for variadic inputs': + 'bejelölve engedélyezi a többszörös\nbeviteli mezők dinamikus feliratait', + 'Prefer empty slot drops': + 'Szóköz használata üres karakterként', + 'settings menu prefer empty slots hint': + 'einschalten um leere Platzhalter\nbeim Platzieren von Bl\u00f6cken' + + 'zu bevorzugen', + 'uncheck to allow dropped\nreporters to kick out others': + 'ausschalten um das "Rauskicken"\nvon platzierten Bl\u00f6cken\n' + + 'zu erm\u00f6glichen', + 'Long form input dialog': + 'Hosszú formátumú beviteli párbeszéd', + 'Plain prototype labels': + 'Egyszerű blokk prototípus címkék', + 'uncheck to always show (+) symbols\nin block prototype labels': + 'üresen hagyva mindig látszik a (+) jel\na blokk prototípus cimkéjében', + 'check to hide (+) symbols\nin block prototype labels': + 'bejelölve látszik a (+) jel\na blokk prototípus cimkéjében', + 'check to always show slot\ntypes in the input dialog': + 'bejelölve mindig látszik a csatlakozás típusa a beviteli párbeszédablakban', + 'uncheck to use the input\ndialog in short form': + 'kapcsolja ki, ha rövidített\npárbeszédablakot akar használni', + 'Virtual keyboard': + 'Virtuális billentyűzet', + 'uncheck to disable\nvirtual keyboard support\nfor mobile devices': + 'kikapcsolva letiltja a virtuális\nbillentyűzetet a mobil eszközökön', + 'check to enable\nvirtual keyboard support\nfor mobile devices': + 'bejelölve engedélyezi a virtuális\nbillentyűzetet a mobil eszközökön', + 'Input sliders': + 'Beviteli csúszkák', + 'uncheck to disable\ninput sliders for\nentry fields': + 'kikapcsolva letiltja a csúszkákat\na beviteli mezőknél', + 'check to enable\ninput sliders for\nentry fields': + 'bekapcsolva engedélyezi a csúszkákat\na beviteli mezőknél', + 'Clicking sound': + 'A kattintás hangja', + 'uncheck to turn\nblock clicking\nsound off': + 'kikapcsolva letiltja a blokkra kattintás hangját', + 'check to turn\nblock clicking\nsound on': + 'bekapcsolva engedélyezi a blokkra kattintás hangját', + 'Animations': + 'Animációk', + 'uncheck to disable\nIDE animations': + 'kikapcsolva letiltja\naz IDE animációit', + 'Turbo mode': + 'Turbó mód', + 'check to prioritize\nscript execution': + 'bekapcsolva a programozott\nvégrehajtás lesz az elsődleges', + 'uncheck to run scripts\nat normal speed': + 'kikapcsolva normál sebességen\nfutnak a programok', + 'check to enable\nIDE animations': + 'bekapcsolva engedélyezi\naz IDE animációit', + 'Thread safe scripts': + 'Biztonságos programszálak', + 'uncheck to allow\nscript reentrance': + 'kikapcsolva engedélyezi a programok\n többszörös végrehajtását', + 'check to disallow\nscript reentrance': + 'bekapcsolva engedélyezi a programok\n többszörös végrehajtását', + 'Prefer smooth animations': + 'Finom animációk', + 'uncheck for greater speed\nat variable frame rates': + 'kapcsolja ki, ha nagyobb sebességet\nakar változtatható képfrissítéseknél', + 'check for smooth, predictable\nanimations across computers': + 'kapcsolja be, ha finomabb, kiszámíthatóbb\nanimációkat akar minden számítógépen', + 'Flat line ends': + 'Egyszerű vonalvégződés', + 'check for flat ends of lines': + 'kapcsolja be az\negyszerű vonalvégződéshez', + 'uncheck for round ends of lines': + 'kapcsolja ki a\nlekerekített vonalvégződésekhez', + + // inputs + 'with inputs': + 'bevitelekkel', + 'input names:': + 'beviteli név:', + 'Input Names:': + 'Beviteli név:', + 'input list:': + 'Beviteli lista:', + + // context menus: + 'help': + 'Súgó', + + // palette: + 'hide primitives': + 'az alapvetők elrejtése', + 'show primitives': + 'az alapvetők megjelentése', + + // blocks: + 'help...': + 'Súgó...', + 'relabel...': + 'átcimkézés...', + 'duplicate': + 'megkettőzés', + 'make a copy\nand pick it up': + 'másolat felvétele', + 'only duplicate this block': + 'csak készítsen egy másolatot\nerről a blokkról', + 'delete': + 'törlés', + 'script pic...': + 'Program képe...', + 'open a new window\nwith a picture of this script': + 'új böngészőablak megnyitása\nennek a programnak a képével', + 'ringify': + 'körülvesz', + 'unringify': + 'körülfogás megszüntetése', + + // custom blocks: + 'delete block definition...': + 'blokkdefiníció törlése', + 'edit...': + 'szerkesztés...', + + // sprites: + 'edit': + 'szerkesztés', + 'move': + 'mozgatás', + 'detach from': + 'leválasztás erről', + 'detach all parts': + 'minden rész szétválasztása', + 'export...': + 'exportálás...', + + // stage: + 'show all': + 'mindent mutat', + 'pic...': + 'kép exportálása...', + 'open a new window\nwith a picture of the stage': + 'új ablak nyitása a színpad képével', + + // scripting area + 'clean up': + 'törlés', + 'arrange scripts\nvertically': + 'a program függőleges átméretezése', + 'add comment': + 'megjegyzés hozzáadása', + 'undrop': + 'visszavétel', + 'undo the last\nblock drop\nin this pane': + 'az utolsó blokk visszavétele erről a lapról', + 'scripts pic...': + 'minden feladat képpé...', + 'open a new window\nwith a picture of all scripts': + 'új ablak nyitása\naz összes program képével', + 'make a block...': + 'blokk létrehozása...', + + // costumes + 'rename': + 'átnevezés', + 'export': + 'exportálás', + 'rename costume': + 'a jelmez átnevezése', + 'Paint a new costume': + 'Új jelmez rajzolása', + + // sounds + 'Play sound': + 'Hang lejátszása', + 'Stop sound': + 'A hang leállítása', + 'Stop': + 'Állj', + 'Play': + 'Lejátszás', + 'rename sound': + 'A hang átnevezése', + + // dialogs + // buttons + 'OK': + 'OK', + 'Ok': + 'Ok', + 'Cancel': + 'Mégsem', + 'Yes': + 'Igen', + 'No': + 'Nem', + + // help + 'Help': + 'Súgó', + + // zoom blocks + 'Zoom blocks': + 'Blokkokra közelítés', + 'build': + 'építés', + 'your own': + 'saját', + 'blocks': + 'blokkok', + 'normal (1x)': + 'normál (1x)', + 'demo (1.2x)': + 'Demó (1.2x)', + 'presentation (1.4x)': + 'Prezentáció (1.4x)', + 'big (2x)': + 'nagy (2x)', + 'huge (4x)': + 'óriási (4x)', + 'giant (8x)': + 'gigantikus (8x)', + 'monstrous (10x)': + 'szörnyeteg (10x)', + + // Project Manager + 'Untitled': + 'Névtelen', + 'Open Project': + 'Projekt megnyitása', + '(empty)': + '(üres)', + 'Saved!': + 'Mentve!', + 'Delete Project': + 'Projekt törlése', + 'Are you sure you want to delete': + 'Biztos, hogy törlöd?', + 'rename...': + 'átnevezés...', + + // costume editor + 'Costume Editor': + 'Jelmezszerkesztő', + 'click or drag crosshairs to move the rotation center': + 'kattints oda vagy vidd a szálkeresztet a forgás középpontjába', + + // project notes + 'Project Notes': + 'A projekt tudnivalói', + + // new project + 'New Project': + 'Új projekt', + 'Replace the current project with a new one?': + 'Felülírja az aktuális projektet egy újjal?', + + // save project + 'Save Project As...': + 'Projekt mentése másként...', + + // export blocks + 'Export blocks': + 'Blokkok exportja', + 'Import blocks': + 'Blokkok importja', + 'this project doesn\'t have any\ncustom global blocks yet': + 'ennek a projektnek még nincs globális felhasználói blokkjai', + 'select': + 'választás', + 'none': + 'egyik sem', + + // variable dialog + 'for all sprites': + 'minden alakzatra', + 'for this sprite only': + 'csak erre az alakzatra', + + // block dialog + 'Change block': + 'Blokk változtatása', + 'Command': + 'Parancs', + 'Reporter': + 'Függvény', + 'Predicate': + 'Kijelentés', + + // block editor + 'Block Editor': + 'Blokk szerkesztő', + 'Apply': + 'Alkalmazás', + + // block deletion dialog + 'Delete Custom Block': + 'Felhasználói blokk törlése', + 'block deletion dialog text': + 'Biztos, hogy eltávolítja ezt\na blokkot és minden példányát?', + + // input dialog + 'Create input name': + 'A bevitel nevének létrehozása', + 'Edit input name': + 'A bevitel nevének szerkesztése', + 'Edit label fragment': + 'A címke rész szerkesztése', + 'Title text': + 'A cím szövege', + 'Input name': + 'A bevitel neve', + 'Delete': + 'Törlés', + 'Object': + 'Objektum', + 'Number': + 'Szám', + 'Text': + 'Szöveg', + 'List': + 'Lista', + 'Any type': + 'Bármilyen típus', + 'Boolean (T/F)': + 'Logikai (I/H)', + 'Command\n(inline)': + 'Parancs\n(inline)', + 'Command\n(C-shape)': + 'Parancs\n(C-Form)', + 'Any\n(unevaluated)': + 'Bármilyen\n(nem kiértékelt)', + 'Boolean\n(unevaluated)': + 'Logikai(nem kiértékelt)', + 'Single input.': + 'Egyszerű bevitel.', + 'Default Value:': + 'Alapérték:', + 'Multiple inputs (value is list of inputs)': + 'Több érték bevitele (az érték a bevitelek listája)', + 'Upvar - make internal variable visible to caller': + 'A belső változók láthatóvá tétele a hívó számára', + + // About Snap + 'About Snap': + 'A Snap névjegye', + 'Back...': + 'Vissza...', + 'License...': + 'Licenc...', + 'Modules...': + 'Modulok...', + 'Credits...': + 'Közreműködők...', + 'Translators...': + 'Fordítók', + 'License': + 'Licenc', + 'current module versions:': + 'a jelenlegi modulverziók', + 'Contributors': + 'Közreműködők', + 'Translations': + 'Fordítások', + + // variable watchers + 'normal': + 'normál', + 'large': + 'nagy', + 'slider': + 'csúszka', + 'slider min...': + 'a csúszka minimuma...', + 'slider max...': + 'a csúszka maximuma...', + 'import...': + 'importálás...', + 'Slider minimum value': + 'A csúszka minimális értéke', + 'Slider maximum value': + 'A csúszka maximális értéke', + + // list watchers + 'length: ': + 'Hossz: ', + + // coments + 'add comment here...': + 'tegye ide a megjegyzést', + + // drow downs + // directions + '(90) right': + '(90) jobbra', + '(-90) left': + '(-90) balra', + '(0) up': + '(0) fel', + '(180) down': + '(180) le', + + // collision detection + 'mouse-pointer': + 'egérmutató', + 'edge': + 'csúcs', + 'pen trails': + 'ceruza nyomvonalak', + + // costumes + 'Turtle': + 'Teknős', + 'Empty': + 'Üres', + + // graphical effects + 'brightness': + 'világosság', + 'ghost': + 'átlátszóság', + 'negative': + 'negatív', + 'comic': + 'moáré', + 'confetti': + 'konfetti', + + // keys + 'space': + 'szóköz', + 'up arrow': + 'felfelé nyíl', + 'down arrow': + 'lefelé nyíl', + 'right arrow': + 'jobbra nyíl', + 'left arrow': + 'balra nyíl', + 'a': + 'a', + 'b': + 'b', + 'c': + 'c', + 'd': + 'd', + 'e': + 'e', + 'f': + 'f', + 'g': + 'g', + 'h': + 'h', + 'i': + 'i', + 'j': + 'j', + 'k': + 'k', + 'l': + 'l', + 'm': + 'm', + 'n': + 'n', + 'o': + 'o', + 'p': + 'p', + 'q': + 'q', + 'r': + 'r', + 's': + 's', + 't': + 't', + 'u': + 'u', + 'v': + 'v', + 'w': + 'w', + 'x': + 'x', + 'y': + 'y', + 'z': + 'z', + '0': + '0', + '1': + '1', + '2': + '2', + '3': + '3', + '4': + '4', + '5': + '5', + '6': + '6', + '7': + '7', + '8': + '8', + '9': + '9', + + // messages + 'new...': + 'új...', + + // math functions + 'abs': + 'abszolútérték', + 'floor': + 'egészrész', + 'sqrt': + 'négyzetgyök', + 'sin': + 'sin', + 'cos': + 'cos', + 'tan': + 'tan', + 'asin': + 'asin', + 'acos': + 'acos', + 'atan': + 'atan', + 'ln': + 'ln', + 'e^': + 'e^', + + // delimiters + 'letter': + 'betű', + 'whitespace': + 'szóköz', + 'line': + 'újsor', + 'tab': + 'tabulátor', + 'cr': + 'kocsivissza', + + // data types + 'number': + 'szám', + 'text': + 'szöveg', + 'Boolean': + 'logikai', + 'list': + 'lista', + 'command': + 'parancsblokk', + 'reporter': + 'függvényblokk', + 'predicate': + 'kijelentés', + + // list indices + 'last': + 'utolsó', + 'any': + 'bármilyen', + // Ez kimaradt a német nyelvi fájlból + 'grow': + 'növekedés', + 'shrink': + 'kicsinyítés', + 'flip ↔': + 'tükrözés ↔', + 'flip ↕': + 'tükrözés ↕', + 'Export all scripts as pic...': + 'Minden feladat exportálása képként…', + 'show a picture of all scripts\nand block definitions': + 'minden feladat és blokk\ndefinícióról készült kép mutatása', + 'current %dates': + 'aktuális %dates', + 'year': + 'év', + 'month': + 'hónap', + 'date': + 'nap', + 'day of week': + 'a hét napja', + 'hour': + 'óra', + 'minute': + 'perc', + 'second': + 'másodperc', + 'time in milliseconds': + 'idő (ezredmásodpercben)', + 'find blocks...': + 'blokkok keresése…', + 'costume name': + 'a jelmez neve', + 'Open': + 'Megnyitás', + 'Share': + 'Megosztás', + 'Snap!Cloud': + 'Snap!Felhő', + 'Cloud': + 'Felhő', + 'could not connect to:': + 'nem tud csatlakozni ide:', + 'Service:': + 'Szolgáltatás:', + 'login': + 'bejelentkezés', + 'ERROR: INVALID PASSWORD': + 'HIBA: ÉRVÉNYTELEN JELSZÓ', + 'Browser': + 'Böngésző', + 'Sign up': + 'Újként regisztrálni', + 'Signup': + 'Új regisztráció', + 'Sign in': + 'Regisztráció', + 'Logout': + 'Kijelentkezés', + 'Change Password...': + 'Jelszó megváltoztatása…', + 'Change Password': + 'Jelszó megváltoztatása', + 'Account created.': + 'Az azonosító létrejött.', + 'An e-mail with your password\nhas been sent to the address provided': + 'A megadott címre e-mailben elküldtük a jelszavát.', + 'now connected.': + 'csatlakozva.', + 'disconnected.': + 'leválasztva.', + 'Reset password': + 'A jelszó alaphelyzetre állítása', + 'Reset Password...': + 'A jelszó alaphelyzetre állítása…', + 'User name:': + 'Felhasználói név:', + 'Password:': + 'Jelszó:', + 'Old password:': + 'A jelenlegi jelszó:', + 'New password:': + 'Új jelszó:', + 'Repeat new password:': + 'Az új jelszó ismét:', + 'Birth date:': + 'Születési idő:', + 'January': + 'január', + 'February': + 'február', + 'March': + 'március', + 'April': + 'április', + 'May': + 'május', + 'June': + 'június', + 'July': + 'július', + 'August': + 'augusztus', + 'September': + 'szeptember', + 'October': + 'október', + 'November': + 'november', + 'December': + 'december', + 'year:': + 'év:', + ' or before': + ' vagy előtte', + 'E-mail address:': + 'E-mail cím:', + 'E-mail address of parent or guardian:': + 'A szülő vagy gondozó email címe:', + 'Terms of Service...': + 'Felhasználási feltételek…', + 'Privacy...': + 'Jogvédelem…', + 'I have read and agree\nto the Terms of Service': + 'Elolvastam és egyetértek\na felhasználási feltételekkel', + 'stay signed in on this computer\nuntil logging out': + 'maradjon bejelentkezve, amíg ki nem jelentkezem a számítógépről', + 'please fill out\nthis field': + 'kérem, töltse ki\nezt a mezőt.', + 'User name must be four\ncharacters or longer': + 'A felhasználói név legalább\nnégy karakteres legyen.', + 'please provide a valid\nemail address': + 'kérem, adjon meg egy\nérvényes email címet.', + 'password must be six\ncharacters or longer': + 'a jelszó legyen legalább\nhat karakter hosszú.', + 'passwords do\nnot match': + 'A jelszavak nem egyeznek.', + 'please agree to\nthe TOS': + 'fogadja el a felhasználási feltételeket.', + 'Examples': + 'Példák', + 'You are not logged in': + 'Még nem lépett be', + 'Updating\nproject list...': + 'A projeklista frissítése…', + 'Opening project...': + 'Projekt megnyitása…', + 'Fetching project\nfrom the cloud...': + 'Projekt letöltése\na felhőből…', + 'Saving project\nto the cloud...': + 'Projekt mentése\na felhőbe…', + 'Sprite Nesting': + 'Szereplők összefűzése', + 'uncheck to disable\nsprite composition': + 'kapcsolja ki a szereplők összefűzésének megakadályozásához.', + 'Codification support': + 'A kodifikáció támogatása', + 'check for block\nto text mapping features': + 'Assinalar para funcionalidades\nde mapeamento entre blocos e texto.', + 'saved.': + 'mentve.', + 'options...': + 'beállítások…', + 'read-only': + 'csak olvasható', + 'Input Slot Options': + 'Bemenő adat csatlakozási lehetőségek', + 'Enter one option per line.Optionally use "=" as key/value delimiter\ne.g.\n the answer=42': + 'Soronként egy lehetőséget írjon be.\nSzükség esetén használhatja az "=" jelet\nkulcs/érték pár elválasztására, pl.\na válasz=42', + 'paint a new sprite': + 'új alakzat rajzolása', + 'Paint a new costume': + 'Új jelmez rajzolása', + 'add a new Turtle sprite': + 'új teknőc rajzának hozzáadása', + 'Flat design': + 'Síkbeli tervezés', + 'check for alternative\nGUI design': + 'más grafikus felület ellenőrzése', + 'Rasterize SVGs': + 'SVG átalakítása bittérképbe', + 'check to rasterize\nSVGs on import': + 'SVG bittérképpé alakíthatóságának\nellenőrzése az importálás során', + 'comment pic...': + 'megjegyzés képe…', + 'open a new window\nwith a picture of this comment': + 'új ablak megnyitása\nennek a megjegyzésnek a képével', + 'undo': + 'visszavon', + 'Brush size': + 'Ecsetméret', + 'Constrain proportions of shapes?\n(you can also hold shift)': + 'Megmaradjanak az alakzat arányai?\n(ehhez használhatja a SHIFT billentyűt is)', + 'Eraser tool': + 'Törlő eszköz', + 'Paintbrush tool\n(free draw)': + 'Festőecset eszköz\n(szabadkézi rajz)', + 'Line tool\n(shift: vertical/horizontal)': + 'Vonalrajzoló eszköz\n(shift: függőleges/vízszintes)', + 'Stroked Rectangle\n(shift: square)': + 'Téglalap\n(shift: négyzet)', + 'Filled Rectangle\n(shift: square)': + 'Kitöltött téglalap\n(shift: négyzet)', + 'Stroked Ellipse\n(shift: circle)': + 'Ellipszis\n(shift: kör)', + 'Filled Ellipse\n(shift: circle)': + 'Kitöltött ellipszis\n(shift: kör)', + 'Fill a region': + 'Terület kitöltése', + 'Set the rotation center': + 'A forgatás középpontjának beállítása', + 'Pipette tool\n(pick a color anywhere)': + 'Pipetta\n(szín felvétele bárhonnan)', + 'Paint Editor': + 'Képszerkesztő', + 'square': + 'négyzet', + 'pointRight': + 'háromszög jobbra', + 'gears': + 'fogaskerék', + 'file': + 'állomány', + 'fullScreen': + 'teljes képernyő', + 'normalScreen': + 'normál képernyő', + 'smallStage': + 'kis színpad', + 'normalStage': + 'normál színpad', + 'turtle': + 'teknős', + 'stage': + 'színpad', + 'turtleOutline': + 'a teknős körvonala', + 'pause': + 'szünet', + 'flag': + 'zászló', + 'octagon': + 'nyolcszög', + 'cloud': + 'felhő', + 'cloudOutline': + 'a felhő körvonala', + 'cloudGradient': + 'a felhő áttetszősége', + 'turnRight': + 'fordulj jobbra', + 'turnLeft': + 'fordulj balra', + 'storage': + 'tárolás', + 'poster': + 'háttérkép', + 'flash': + 'villám', + 'brush': + 'ecset', + 'rectangle': + 'téglalap', + 'rectangleSolid': + 'kitöltött téglalap', + 'circle': + 'kör', + 'circleSolid': + 'kitöltött kör', + 'crosshairs': + 'szálkereszt', + 'paintbucket': + 'festékesvödör', + 'eraser': + 'radír', + 'pipette': + 'pipetta', + 'speechBubble': + 'buborék', + 'speechBubbleOutline': + 'a buborék körvonala', + 'arrowUp': + 'felfelé nyíl', + 'arrowUpOutline': + 'a felfelényíl körvonala', + 'arrowLeft': + 'balra nyíl', + 'arrowLeftOutline': + 'a balra nyíl körvonala', + 'arrowDown': + 'lefelé nyíl', + 'arrowDownOutline': + 'a lefelényíl körvonala', + 'arrowRight': + 'jobbra nyíl', + 'arrowRightOutline': + 'a jobbranyíl körvonala', + 'robot': + 'robot', + 'turn pen trails into new costume...': + 'a toll beállításainak alkalmazása egy új jelmezre…', + 'turn all pen trails and stamps\ninto a new costume for the\ncurrently selected sprite': + 'minden tollbeállítás átállítása\nés átvitele az aktuális\nalak egy új jelmezébe', + 'pen': + 'toll', + 'tip': + 'tipp', + 'middle': + 'közép', + 'last changed': + 'utoljára változtatva', + 'Are you sure you want to publish': + 'Biztosan nyilvánossá teszi', + 'Are you sure you want to unpublish': + 'Biztos, hogy nemnyilvánossá teszi', + 'Share Project': + 'A projekt megosztása', + 'Unshare Project': + 'A projekt megosztásának megszüntetése', + 'sharing\nproject...': + 'a projekt\nmegosztása…', + 'unsharing\nproject...': + 'a projekt megosztásának\nmegszüntetése…', + 'shared.': + 'megosztva.', + 'unshared.': + 'nincs megosztva.', + 'Unshare': + 'Nincs megosztás', + 'password has been changed.': + 'a jelszó megváltozott.', + 'SVG costumes are\nnot yet fully supported\nin every browser': + 'Az SVG ábrákat nem minden böngésző támogatja', + 'Save Project': + 'A projekt mentése', + 'script pic with result...': + 'a program képe az eredménnyel…', + 'open a new window\nwith a picture of both\nthis script and its result': + 'Új böngészőablak megnyitása a programnak és eredményének képével.', + 'JavaScript function ( %mult%s ) { %code }': + 'JavaScript függvény ( %mult%s ) { %code }', + 'Select categories of additional blocks to add to this project.': + 'Válassza ki a projekthez adandó blokkok kategóriáit.', + 'Import sound': + 'Hang importálása', + 'Select a sound from the media library': + 'Válasszon ki egy hangot a médiakönyvtárból.', + 'Import': + 'Import', + 'Select a costume from the media library': + 'Válasszon ki egy jelmezt a médiakönyvtárból.', + 'edit rotation point only...': + 'csak a forgáspont szerkesztése…', + 'Export Project As...': + 'Projekt exportálása mint…', + 'a variable of name \'': + 'ilyen nevű változó «', + '\'\ndoes not exist in this context': + '»\nnincs ebben a környezetben', + '(temporary)': + '(ideiglenes)', + 'expecting': + 'kötelező', + 'input(s), but getting': + 'adatbevitel, de ez érkezett', + + // kódolás + 'map %cmdRing to %codeKind %code': + 'mapear %cmdRing no %codeKind %code', + 'map String to code %code': + 'mapear texto no código %code', + 'map %codeListPart of %codeListKind to code %code': + 'mapear %codeListPart de %codeListKind no código %code', + 'code of %cmdRing': + '%cmdRing kódja', + 'delimiter': + 'határoló', + 'collection': + 'gyűjtemény', + 'variables': + 'változók', + 'parameters': + 'paraméterek', + 'code': + 'kód', + 'header': + 'fejléc', + 'header mapping...': + 'mapeamento para cabeçalho…', + 'code mapping...': + 'kód leképezés…', + 'Code mapping': + 'Kód leképezés', + 'Header mapping': + 'A fejléc leképezése', + 'Enter code that corresponds to the block\'s definition. Use the formal parameter\nnames as shown and to reference the definition body\'s generated text code.': + 'Gépelje be a blokk definíciójának megfelelő programkódot. Használja a látható formális paramétereket és a referenciát a törzs generált szövegkódjához.', + 'Enter code that corresponds to the block\'s definition. Choose your own\nformal parameter names (ignoring the ones shown).': + 'Gépelje be a blokk definíciójának megfelelő programkódot. Használja a saját formális paramétereit (hagyja figyelmen kívül a láthatókat).', + 'Enter code that corresponds to the block\'s operation (usually a single\nfunction invocation). Use <#n> to reference actual arguments as shown.': + 'Gépelje be a blokk működésének megfelelő programkódot (általában egy függvény bevezetésével). Használja a <#n> hivatkozási helyen látható aktuális argumentumokat.' +}; diff --git a/lang-ia.js b/lang-ia.js new file mode 100644 index 00000000..3c8fec91 --- /dev/null +++ b/lang-ia.js @@ -0,0 +1,1337 @@ +/* + + lang-ia.js + + Interlingua translation for SNAP! + + edited for Interlingua by Ken Dickey + + Copyright (C) 2015 by Jens Mönig + + This file is part of Snap!. + + Snap! is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + + + + Note to Translators: + -------------------- + At this stage of development, Snap! can be translated to any LTR language + maintaining the current order of inputs (formal parameters in blocks). + + Translating Snap! is easy: + + + 1. Download + + Download the sources and extract them into a local folder on your + computer: + + + + Use the German translation file (named 'lang-de.js') as template for your + own translations. Start with editing the original file, because that way + you will be able to immediately check the results in your browsers while + you're working on your translation (keep the local copy of snap.html open + in your web browser, and refresh it as you progress with your + translation). + + Or via GitHub: + git clone https://github.com/jmoenig/Snap--Build-Your-Own-Blocks.git + + 2. Edit + + Edit the translation file with a regular text editor, or with your + favorite JavaScript editor. + + In the first non-commented line (the one right below this + note) replace "de" with the two-letter ISO 639-1 code for your language, + e.g. + + fr - French => SnapTranslator.dict.fr = { + it - Italian => SnapTranslator.dict.it = { + pl - Polish => SnapTranslator.dict.pl = { + pt - Portuguese => SnapTranslator.dict.pt = { + es - Spanish => SnapTranslator.dict.es = { + el - Greek => => SnapTranslator.dict.el = { + ia - Interlingua => => SnapTranslator.dict.ia = { + + etc. (see ) + + + 3. Translate + + Then work through the dictionary, replacing the German strings against + your translations. The dictionary is a straight-forward JavaScript ad-hoc + object, for review purposes it should be formatted as follows: + + { + 'English string': + 'Translation string', + 'last key': + } 'last value' + + and you only edit the indented value strings. Note that each key-value + pair needs to be delimited by a comma, but that there shouldn't be a comma + after the last pair (again, just overwrite the template file and you'll be + fine). + + If something doesn't work, or if you're unsure about the formalities you + should check your file with + + + + This will inform you about any missed commas etc. + + + 4. Accented characters + + Depending on which text editor and which file encoding you use you can + directly enter special characters (e.g. Umlaut, accented characters) on + your keyboard. However, I've noticed that some browsers may not display + special characters correctly, even if other browsers do. So it's best to + check your results in several browsers. If you want to be on the safe + side, it's even better to escape these characters using Unicode. + + see: + + + 5. Block specs: + + At this time your translation of block specs will only work + correctly, if the order of formal parameters and their types + are unchanged. Placeholders for inputs (formal parameters) are + indicated by a preceding % prefix and followed by a type + abbreviation. + + For example: + + 'say %s for %n secs' + + can currently not be changed into + + 'say %n secs long %s' + + and still work as intended. + + Similarly + + 'point towards %dst' + + cannot be changed into + + 'point towards %cst' + + without breaking its functionality. + + + 6. Submit + + When you're done, rename the edited file by replacing the "de" part of the + filename with the two-letter ISO 639-1 code for your language, e.g. + + fr - French => lang-fr.js + it - Italian => lang-it.js + pl - Polish => lang-pl.js + pt - Portuguese => lang-pt.js + es - Spanish => lang-es.js + el - Greek => => lang-el.js + ia - Interlingua => lange-ia.js + + and send it to me for inclusion in the official Snap! distribution. + Once your translation has been included, Your name will the shown in the + "Translators" tab in the "About Snap!" dialog box, and you will be able to + directly launch a translated version of Snap! in your browser by appending + + lang:xx + + to the URL, xx representing your translations two-letter code. + + + 7. Known issues + + In some browsers accents or ornaments located in typographic ascenders + above the cap height are currently (partially) cut-off. + + Enjoy! + -Jens +*/ + +/* + * De nota: + * + * https://translatewiki.net/wiki/Portal:Ia + * + * In my view, a "variable" is a box (cassa) in which one + * stores a value -- vs a "constant", which is a named value. + */ + +/*global SnapTranslator*/ + +SnapTranslator.dict.ia = { + +/* + Special characters: (see ) + + None +*/ + + // translations meta information + 'language_name': + 'Interlingua', // the name as it should appear in the language menu + 'language_translator': + 'Ken Dickey', // your name for the Translators tab + 'translator_e-mail': + 'Ken.Dickey@whidbey.com', // optional + 'last_changed': + '2015-08-09', // this, too, will appear in the Translators tab + + // GUI + // control bar: + 'untitled': + 'innominate', // 'nulle titulo' + 'development mode': + 'disveloppation moda', + + // categories: + 'Motion': + 'Movimento', + 'Looks': + 'Apparentia', + 'Sound': + 'Sono', + 'Pen': + 'Penna', + 'Control': + 'Reger', + 'Sensing': + 'Sensation', + 'Operators': + 'Operators', + 'Variables': + 'Cassas', + 'Lists': + 'Listas', + 'Other': + 'Altere', + + // editor: + 'draggable': + 'traheribile', + + // tabs: + 'Scripts': + 'Scriptes', + 'Costumes': + 'Costumes', + 'Sounds': + 'Sonas', + + // names: + 'Sprite': + 'Spirito', // 'Animo' + 'Stage': + 'Scena', + + // rotation styles: + 'don\'t rotate': + 'non rota', + 'can rotate': + 'capabile de rota', + 'only face left/right': + 'sol facie sinistre o dextre', + + // new sprite button: + 'add a new sprite': + 'adde spirito nove', + + // tab help + 'costumes tab help': + 'costumes adjuta', + 'import a sound from your computer\nby dragging it into here': + 'face importa un sono per trahe hic', + + // primitive blocks: + + /* + Attention Translators: + ---------------------- + At this time your translation of block specs will only work + correctly, if the order of formal parameters and their types + are unchanged. Placeholders for inputs (formal parameters) are + indicated by a preceding % prefix and followed by a type + abbreviation. + + For example: + + 'say %s for %n secs' + + can currently not be changed into + + 'say %n secs long %s' + + and still work as intended. + + Similarly + + 'point towards %dst' + + cannot be changed into + + 'point towards %cst' + + without breaking its functionality. + */ + + // motion: + 'Stage selected:\nno motion primitives': + 'Scena selecte:\n' + + 'nulle motion primitives', + + 'move %n steps': + 'move %n passos', + 'turn %clockwise %n degrees': + 'torna %clockwise %n grados', // dirige + 'turn %counterclockwise %n degrees': + 'torna %counterclockwise %n grados', + 'point in direction %dir': + 'puncta direction %dir', + 'point towards %dst': + 'puncta erga %dst', + 'go to x: %n y: %n': + 'ir a x: %n y: %n', // 'adi' + 'go to %dst': + 'ir a %dst', + 'glide %n secs to x: %n y: %n': + 'glissa %n secundes a x: %n y: %n', + 'change x by %n': + 'cambia x per %n', + 'set x to %n': + 'in x pone %n', // 'pone in x le valo %n', + 'change y by %n': + 'cambia y per %n', + 'set y to %n': + 'in y pone %n', + 'if on edge, bounce': + 'si in bordo talia, recula', + 'x position': + 'x position', + 'y position': + 'y position', + 'direction': + 'direction', + + // looks: + 'switch to costume %cst': + 'cambio a costume %cst', + 'next costume': + 'proxime costume', + 'costume #': + 'costume numero', + 'say %s for %n secs': + 'dice %s per %n secundes', + 'say %s': + 'dice %s', + 'think %s for %n secs': + 'pensa %s per %n secundes', + 'think %s': + 'pensa %s', + 'Hello!': + 'Hallo!', + 'Hmm...': + 'Hmm...', + 'change %eff effect by %n': + 'cambia %eff effecto per %n', + 'set %eff effect to %n': + 'in %eff pone effecto %n', + 'clear graphic effects': + 'depura effectos graphic', + 'change size by %n': + 'accrescimento dimensiones per %n', + 'set size to %n %': + 'delimita dimentiones a %n %', + 'size': + 'dimentiones', + 'show': + 'expone', // 'monstra' + 'hide': + 'cela', // 'occulta' + 'go to front': + 'antepone', // 'ir maxima ante', + 'go back %n layers': + 'ir detra %n strato', + + 'development mode \ndebugging primitives:': + 'disveloppa modo \n' + + 'anti-defacto primitives', + 'console log %mult%s': + 'entra in registration %mult%s', + 'alert %mult%s': + 'alerte %mult%s', + + // sound: + 'play sound %snd': + 'sona %snd', // 'face sono %snd', + 'play sound %snd until done': + 'sona %snd usque complete', // 'sona %snd integral', + 'stop all sounds': + 'cessar sona tote', + 'rest for %n beats': + 'pausa per %n pulsia', + 'play note %n for %n beats': + 'sona nota %n per %n pulsia', + 'change tempo by %n': + 'cambio tempo per %n', + 'set tempo to %n bpm': + 'face tempo a %n pulsia per minuta', + 'tempo': + 'tempo', + + // pen: + 'clear': + 'depura', + 'pen down': + 'face penna a basso', + 'pen up': + 'face penna in alto', + 'set pen color to %clr': + 'face color del penna a %clr', + 'change pen color by %n': + 'cambia color del penna a %n', + 'set pen color to %n': + 'face color del penna a %n', + 'change pen shade by %n': + 'cambio tinta del penna per %n', + 'set pen shade to %n': + 'face tinta del penna a %n', + 'change pen size by %n': + 'cambio dimension del penna per %n', + 'set pen size to %n': + 'face dimension del penna a %n', + 'stamp': + 'timbra', // 'cunea' 'stampa' + + // control: + 'when %greenflag clicked': + 'cuando %greenflag clic', + 'when %keyHat key pressed': + 'cuando %keyHat clave pressa', + 'when I am %interaction': + 'cuando io es %interaction', + 'clicked': + 'clicco', + 'pressed': + 'pressa', + 'dropped': + 'depone', + 'mouse-entered': + 'mure entra', + 'mouse-departed': + 'mure parti', // 'quita' + 'when I receive %msgHat': + 'cuando io recipe %msgHat', + 'broadcast %msg': + 'mitte %msg a omne', + 'broadcast %msg and wait': + 'mitte %msg a omni e attende', + 'Message name': + 'Nomine de message', + 'message': + 'message', + 'any message': + 'qualcosa message', // 'cualcunque message' + 'wait %n secs': + 'attende %n secundes', + 'wait until %b': + 'attende donec %b', + 'forever %c': + 'sin termino %c', + 'repeat %n %c': + 'itera %n %c', + 'repeat until %b %c': + 'itera donec %b %c', + 'if %b %c': + 'si %b %c', + 'if %b %c else %c': + 'si %b %c nisi %c', + 'report %s': + 'reporta %s', // 'valor restituite' + 'stop %stopChoices': + 'cessa %stopChoices', + 'all': + 'omni', + 'this script': + 'iste scripte', // 'este' + 'this block': + 'iste bloco', + 'stop %stopOthersChoices': + 'cessa %stopOthersChoices', + 'all but this script': + 'omni excepte iste scripte', + 'other scripts in sprite': + 'altere scriptes in iste spirito', + 'pause all %pause': + 'pausa omni %pause', + 'run %cmdRing %inputs': + 'comencia %cmdRing %inputs', // 'initio' + 'launch %cmdRing %inputs': + 'lancea %cmdRing %inputs', + 'call %repRing %inputs': + 'evoca %repRing %inputs', + 'run %cmdRing w/continuation': + 'comencia %cmdRing con continuation', + 'call %cmdRing w/continuation': + 'evoca %cmdRing con continuation', + 'warp %c': + 'ordi %c', // 'ordito' + 'when I start as a clone': + 'quando io comencia como copia', + 'create a clone of %cln': + 'face un copia de %cln', + 'myself': + 'io mesme', + 'delete this clone': + 'dele ista copia', + + // sensing: + 'touching %col ?': + 'continge %col ?', + 'touching %clr ?': + 'continge %clr ?', + 'color %clr is touching %clr ?': + 'color %clr es continge %clr ?', + 'ask %s and wait': + 'demanda %s e attende', + 'what\'s your name?': + 'que es tu nomine?', + 'answer': + 'responde', + 'mouse x': + 'mure x position', + 'mouse y': + 'mure y position', + 'mouse down?': + 'a mure es a basso?', + 'key %key pressed?': + 'a clave %key pressa?', + 'distance to %dst': + 'distantia a %dst', + 'reset timer': + 'recomenciar le chronometria', + 'timer': + 'chronometria', + '%att of %spr': + '%att de %spr', + 'http:// %s': + 'http:// %s', + 'turbo mode?': + 'a turbo modo?', + 'set turbo mode to %b': + 'face turbo modo a %b', + + 'filtered for %clr': + 'filtra per %clr', + 'stack size': + 'pila dimensione', + 'frames': + 'quadros', + + // operators: + '%n mod %n': + '%n modulo %n', + 'round %n': + '%n rotunda', + '%fun of %n': + '%fun de %n', + 'pick random %n to %n': + 'al aventura inter %n e %n', // 'al hasardo' + '%b and %b': + '%b e %b', + '%b or %b': + '%b o %b', + 'not %b': + 'non %b', + 'true': + 'ver', + 'false': + 'false', + 'join %words': + 'junge %words', + 'split %s by %delim': + 'fisse %s de %delim', + 'hello': + 'Hallo', + 'world': + 'Mundo', + 'letter %n of %s': + 'character %n de %s', + 'length of %s': + 'longor de %s', + 'unicode of %s': + 'Unicode valor de %s', + 'unicode %n as letter': + 'Unicode character pro %n', + 'is %s a %typ ?': + 'a es %s de %typ ?', + 'is %s identical to %s ?': + 'a es %s identic a %s ?', // 'mesme' ? + + 'type of %s': + 'typo de %s', + + // variables: + 'Make a variable': + 'Nove Cassa', // 'Face Cassa' + 'Variable name': + 'Nomine de Cassa', // global? + 'Script variable name': + 'Nomine de Scripte Cassa', + 'Delete a variable': + 'Dele un Cassa', + + 'set %var to %s': + 'in %var pone %s', + 'change %var by %n': + 'cambio %var per %n', + 'show variable %var': + 'expone cassa %var', + 'hide variable %var': + 'cella cassa %var', // 'occulta' + 'script variables %scriptVars': + 'cassas de scripte %scriptVars', + + // lists: + 'list %exp': + 'Liste %exp', + '%s in front of %l': + '%s es ante que %l', + 'item %idx of %l': + 'elemento %idx de %l', + 'all but first of %l': + 'onme excepte prime de %l', + 'length of %l': + 'longor de %l', + '%l contains %s': + '%l contine %s', + 'thing': + 'cosa', + 'add %s to %l': + 'adde %s e %l', + 'delete %ida of %l': + 'dele %ida de %l', + 'insert %s at %idx of %l': + 'inserta %s in %idx de %l', + 'replace item %idx of %l with %s': + 'reimplacia elemento %idx de %l con %s', // surroga + + // other + 'Make a block': + 'Face un bloco', + + // menus + // snap menu + 'About...': + 'In re Snap!...', + 'Reference manual': + 'Manual referentia ', + 'Snap! website': + 'Snap! sito web', + 'Download source': + 'Discarga fonte', + 'Switch back to user mode': + 'Cambio retro a modo usator', + 'disable deep-Morphic\ncontext menus\nand show user-friendly ones': + 'Face inactive profunde Morphic\n' + + 'menus contexto e\n' + + 'expone se usator amicabile', + 'Switch to dev mode': + 'Cambio a modo disveloppator', + 'enable Morphic\ncontext menus\nand inspectors,\nnot user-friendly!': + 'Face active Morphic\n' + + 'menus contexto e inspector,\n' + + 'non amicabile de usatores', + + // project menu + 'Project notes...': + 'Annotos de projecto...', + 'New': + 'Nova', + 'Open...': + 'Aperte...', + 'Save': + 'Salvo', // 'Secur' + 'Save to disk': + 'Salvo in file', // 'Salve/Secur a systema de files' + 'store this project\nin the downloads folder\n(in supporting browsers)': + 'Pone esti projecto\n' + + 'in dossier discarga\n' + + '(per navigators sustene)', + 'Save As...': + 'Salvo como nomine...', + 'Import...': + 'Importa...', + 'file menu import hint': + 'Importa insinua per menu de file ', + 'Export project as plain text...': + 'Exporta projecto in texto simple...', + 'Export project...': + 'Exporta projecto...', + 'show project data as XML\nin a new browser window': + 'Expone dato de projecto in XML\n' + + 'immane nove fenestra de navigator', + // vitrina + 'Export blocks...': + 'Exporta blocos...', + 'show global custom block definitions as XML\nin a new browser window': + 'Expone blocos artificiose global como XML\n' + + 'immane nove fenestra de navigator', + 'Import tools': + 'Importa utensiles', + 'load the official library of\npowerful blocks': + 'Incarga bibliotheca official de blocos potente', + 'Libraries...': + 'Bibliothecas...', + 'Import library': + 'Importa bibliotheca', + + // cloud menu + 'Login...': + 'Authenticar se...', + 'Signup...': + 'Abonamento...', + + // settings menu + 'Language...': + 'Lingua...', + 'Zoom blocks...': + 'Zoom blocos...', + 'Stage size...': + 'Scena dimensiones...', + 'Stage size': + 'Scena dimensiones', + 'Stage width': + 'Scena traverso', + 'Stage height': + 'Scena statura', + 'Default': + 'Normal', + 'Blurred shadows': + 'Umbre indistincte', + 'uncheck to use solid drop\nshadows and highlights': + 'dismarca por usa gutta umbras\n' + + 'e accentuas solide', + 'check to use blurred drop\nshadows and highlights': + 'marca a selecte por usa gutta umbras\n' + + 'e accentuas indistincte', + 'Zebra coloring': + 'Zebra colorito', + 'check to enable alternating\ncolors for nested blocks': + 'marca a selecta colors alternative\n' + + 'por blocos annida', + 'uncheck to disable alternating\ncolors for nested block': + 'dismarca a disactiva colors alternative\n' + + 'por blocos annida', + 'Dynamic input labels': + 'Dynamic etiquettas entrata', + 'uncheck to disable dynamic\nlabels for variadic inputs': + 'dismarca a disactiva dynamic\n' + + 'etiquettas varia entrata', // 'variante' + 'check to enable dynamic\nlabels for variadic inputs': + 'marca a activa dynamic\n' + + 'etiquetta varia entrata', + 'Prefer empty slot drops': + 'Dar le preferentia a cader in apatur vacue', + // ..' in foramine vacue' + 'settings menu prefer empty slots hint': + 'Dar le preferentia in menu predefinite\n' + + ' per apatur vacue insinua', + 'uncheck to allow dropped\nreporters to kick out others': + 'dismarca a activar reporters cadera\n' + + 'a capabile displacia alteres', + 'Long form input dialog': + 'Usa dialogo entrata forma longe', + 'Plain prototype labels': + 'Face plan le etiquettas prototypic', + 'uncheck to always show (+) symbols\nin block prototype labels': + 'dismarca a expone (+) symbolos\n' + + 'in etiquettas prototypic per blocos ', + 'check to hide (+) symbols\nin block prototype labels': + 'marca a cella (+) symbols\n' + + 'in etiquettas prototypic per blocos', + 'check to always show slot\ntypes in the input dialog': + 'marca a expone apatur typos\n' + + 'in dialogo entrata', + 'uncheck to use the input\ndialog in short form': + 'dismarka a usa dialogo entrata forma curte', + 'Virtual keyboard': + 'Virtual claviero', + 'uncheck to disable\nvirtual keyboard support\nfor mobile devices': + 'dismarca a disactivar virtual claviero\n' + + 'per dispositivo mobile', + 'check to enable\nvirtual keyboard support\nfor mobile devices': + 'marca a activar virtual claviero\n' + + 'per dispositivo mobile', + 'Input sliders': + 'Entrata glissatores', + 'uncheck to disable\ninput sliders for\nentry fields': + 'dismarca a disactivar\n' + + 'entrata glissatores\n' + + 'pro campos entrate', + 'check to enable\ninput sliders for\nentry fields': + 'marca a activar\n' + + 'entrata glissatores\n' + + 'pro campos entrate', + 'Clicking sound': + 'Sona de clicca', + 'uncheck to turn\nblock clicking\nsound off': + 'dismarca a disactivar\nsona de clicca', + 'check to turn\nblock clicking\nsound on': + 'marca a activar\nsona de clicca', + 'Animations': + 'Animations', + 'uncheck to disable\nIDE animations': + 'dismarca a disactivar\nIDE-Animations', + 'Turbo mode': + 'Turbo modo', + 'check to prioritize\nscript execution': + 'marca a prioitate\nexecution de scripte', // 'exequer' + 'uncheck to run scripts\nat normal speed': + 'dismarca a comencia scriptes\n' + + 'a velocitate normal', // 'celeritate' + 'check to enable\nIDE animations': + 'marca a activar \nIDE animations', + 'Thread safe scripts': + 'Filo secur scriptes', + 'uncheck to allow\nscript reentrance': + 'dismarca a permitte\nscripte readmitte', + 'check to disallow\nscript reentrance': + 'marca a prohibi\nscripte readmitte', + 'Prefer smooth animations': + 'Prefere aminationes lisia', + 'uncheck for greater speed\nat variable frame rates': + 'dismarca pro plus veloce\n' // 'accelera' + + 'ma variable rata\n' + + 'de frame monstra', + 'check for smooth, predictable\nanimations across computers': + 'marca pro predice lisia\n' + + 'animationes trans computator systemas', // multi-platteforma + 'Flat line ends': + 'Lineas fin quadrate', + 'check for flat ends of lines': + 'marca pro lineas fin quadrate', + 'uncheck for round ends of lines': + 'dismarca pro lineas fin rotunde', + + // inputs + 'with inputs': + 'Con entratas', + 'input names:': + 'Entrata nomines:', + 'Input Names:': + 'Entrata nomines:', + 'input list:': + 'Entrata Listes:', + + // context menus: + 'help': + 'adjuva', + + // palette: + 'hide primitives': + 'cela primativos', + 'show primitives': + 'expone primativos', + + // blocks: + 'help...': + 'adjunta...', + 'relabel...': + 'redacto etiquettas...', + 'duplicate': + 'duplica', + 'make a copy\nand pick it up': + 'duplica e prende in mano', + 'only duplicate this block': + 'duploca solo esto bloco', + 'delete': + 'dele', + 'script pic...': + 'scripte pictura...', + 'open a new window\nwith a picture of this script': + 'Aperte fenestra nove\n' + + 'con pictura de este scripte', + 'ringify': + 'Anulamento', + 'unringify': + 'Disanulamento', + + // custom blocks: + 'delete block definition...': + 'dele definition del bloco', + 'edit...': + 'edita...', + + // sprites: + 'edit': + 'edita', + 'move': + 'move', + 'detach from': + 'distacca de', + 'detach all parts': + 'distacca omni partes', + 'export...': + 'exporta...', + + // stage: + 'show all': + 'monstra omni', + 'pic...': + 'pictura...', + 'open a new window\nwith a picture of the stage': + 'expone nove fenestra\n' + + 'con pictura del scena', + + // scripting area + 'clean up': + 'abluenta', + 'arrange scripts\nvertically': + 'presentar scriptes\n' + 'verticalitate', + 'add comment': + 'adde un commento', + 'undrop': + 'disdepone', + 'undo the last\nblock drop\nin this pane': + 'disfacer bloco depone antea\n' + + 'in este pannello', + 'scripts pic...': + 'scriptes pictura...', + 'open a new window\nwith a picture of all scripts': + 'expone nove fenestra\n' + + 'con pictura del omni scriptes', + 'make a block...': + 'face un bloco...', + + // costumes + 'rename': + 'edita le nomine', + 'export': + 'exporta', + 'rename costume': + 'edita le nomine del costume', + + // sounds + 'Play sound': + 'Sona le sono', + 'Stop sound': + 'Arresta sono', + 'Stop': + 'Halto', + 'Play': + 'Sona', + 'rename sound': + 'Edita le nomine del sono', + + // dialogs + // buttons + 'OK': + 'OK', + 'Ok': + 'OK', + 'Cancel': + 'Revoca', + 'Yes': + 'Si', + 'No': + 'Non', + + // help + 'Help': + 'Adjuta', + + // zoom blocks + 'Zoom blocks': + 'Zoom blocos', + 'build': + 'edifica', + 'your own': + 'vostre', + 'blocks': + 'blocos', + 'normal (1x)': + 'normal (1x)', + 'demo (1.2x)': + 'por demonstration (1.2x)', + 'presentation (1.4x)': + 'por presentation (1.4x)', + 'big (2x)': + 'grande (2x)', + 'huge (4x)': + 'grosse (4x)', + 'giant (8x)': + 'gigante (8x)', + 'monstrous (10x)': // 'monstruose' + 'maxima (10x)', + + // Project Manager + 'Untitled': + 'Nulle titulo', // 'Innominate' + 'Open Project': + 'Aperte Projecto', + '(empty)': + '(vacue)', + 'Saved!': + 'Secur!', // 'Faceva secur per salvo a file' + 'Delete Project': + 'Dele Projecto', + 'Are you sure you want to delete': + 'A certe que vos vole a dele?', + 'rename...': + 'Edita le nomine...', + + // costume editor + 'Costume Editor': + 'Costume Editor', + 'click or drag crosshairs to move the rotation center': + 'clicca o trahe capilo cruce \n' + + 'a move le centro de rotation', + + // project notes + 'Project Notes': + 'Annotos del projecto', + + // new project + 'New Project': + 'Projecto Nove', + 'Replace the current project with a new one?': + 'A surroga le projecto existente pro un nove?', + + // save project + 'Save Project As...': + 'Secur Projecto Como...', + + // export blocks + 'Export blocks': + 'Exporta blocos', + 'Import blocks': + 'Importa blocos', + 'this project doesn\'t have any\ncustom global blocks yet': + 'esti projecto no trova\n' + + 'blocos artificiose global', + 'select': + 'selecta', + 'none': + 'necun', // 'necuno' + + // variable dialog + 'for all sprites': + 'por omni spiritos', + 'for this sprite only': + 'solo por este spirito', + + // block dialog + 'Change block': + 'Cambia bloco', + 'Command': + 'Commando', + 'Reporter': + 'Reporter', + 'Predicate': + 'Proposition', + + // block editor + 'Block Editor': + 'Editor de blocos', + 'Apply': + 'Applica', + + // block deletion dialog + 'Delete Custom Block': + 'Dele bloco artificiose', + 'block deletion dialog text': + 'Edita bloco dele dialogo texto', //?? + + // input dialog + 'Create input name': + 'Crea entrata nomine', + 'Edit input name': + 'Edita entrata nomine', + 'Edit label fragment': + 'Edita etiquetta fragmento', // 'Edit texto clasma' + 'Title text': + 'Titulo texto', + 'Input name': + 'Entrata nomine', + 'Delete': + 'Dele', + 'Object': + 'Objecto', + 'Number': + 'Numero', + 'Text': + 'Texto', + 'List': + 'Liste', + 'Any type': + 'Qualcunque Typo', + 'Boolean (T/F)': + 'Ver o False (V/F)', + 'Command\n(inline)': + 'Commando\n(in linea)', + 'Command\n(C-shape)': + 'Commando\n(C-forma)', + 'Any\n(unevaluated)': + 'Qualcunque\n(non-evaluta)', + 'Boolean\n(unevaluated)': + 'Ver o False\n(non-evaluta)', + 'Single input.': + 'Sol entrata', + 'Default Value:': + 'Valor predefiniva:', // normal + 'Multiple inputs (value is list of inputs)': + 'entrata plure (valor es lista)', // 'aliquot' + 'Upvar - make internal variable visible to caller': + 'Cassa in Alto - face cassa interne visible a evocator', + + // About Snap + 'About Snap': + 'in re Snap', + 'Back...': + 'a retro!...', + 'License...': + 'Licentia...', + 'Modules...': + 'Modulos...', + 'Credits...': + 'Credito...', + 'Translators...': + 'Traductores...', + 'License': + 'Licentia', + 'current module versions:': + 'currente modulo versiones', + 'Contributors': + 'Contribuentes', + 'Translations': + 'Traductiones..', + + // variable watchers (observa loco de valores = cassa) + 'normal': + 'normal', + 'large': + 'grande', + 'slider': + 'glissator', + 'slider min...': + 'glissator minime...', + 'slider max...': + 'glissator maxime...', + 'import...': + 'importa...', + 'Slider minimum value': + 'glissator minime valor', + 'Slider maximum value': + 'glissator maxime valor', + + // list watchers + 'length: ': + 'Longor: ', + + // coments + 'add comment here...': + 'adde commento hic', + + // drow downs + // directions + '(90) right': + '(90) dextera', + '(-90) left': + '(-90) sinistra', + '(0) up': + '(0) alto', + '(180) down': + '(180) basso', + + // collision detection + 'mouse-pointer': + 'mure punctator', + 'edge': + 'bordo talia', + 'pen trails': + 'penna tracia', + + // costumes + 'Turtle': + 'Tortuca', + 'Empty': + 'Vacue', + + // graphical effects + 'brightness': + 'brillantia', // 'nitor' + 'ghost': + 'apparition', // 'spectro' + 'negative': + 'negative', + 'comic': + 'comic', + 'confetti': + 'confetti', + + // keys + 'space': + 'spatio vacue', + 'up arrow': + 'alto flecha', // 'sagitta' + 'down arrow': + 'basso flecha', + 'right arrow': + 'dextera flecha', + 'left arrow': + 'sinistra flecha', + 'a': + 'a', + 'b': + 'b', + 'c': + 'c', + 'd': + 'd', + 'e': + 'e', + 'f': + 'f', + 'g': + 'g', + 'h': + 'h', + 'i': + 'i', + 'j': + 'j', + 'k': + 'k', + 'l': + 'l', + 'm': + 'm', + 'n': + 'n', + 'o': + 'o', + 'p': + 'p', + 'q': + 'q', + 'r': + 'r', + 's': + 's', + 't': + 't', + 'u': + 'u', + 'v': + 'v', + 'w': + 'w', + 'x': + 'x', + 'y': + 'y', + 'z': + 'z', + '0': + '0', + '1': + '1', + '2': + '2', + '3': + '3', + '4': + '4', + '5': + '5', + '6': + '6', + '7': + '7', + '8': + '8', + '9': + '9', + + // messages + 'new...': + 'Nove...', + + // math functions + 'abs': + 'abs', + 'floor': + 'floor', + 'sqrt': + 'sqrt', + 'sin': + 'sin', + 'cos': + 'cos', + 'tan': + 'tan', + 'asin': + 'asin', + 'acos': + 'acos', + 'atan': + 'atan', + 'ln': + 'ln', + 'e^': + 'e^', + + // delimiters + 'letter': + 'character', + 'whitespace': + 'spatio blanco', // spatio vacue' + 'line': + 'linea', + 'tab': + 'tabulator', + 'cr': + 'fin de linea', + + // data types + 'number': + 'Numero', + 'text': + 'Texto', + 'Boolean': + 'Ver o False', + 'list': + 'Lista', + 'command': + 'Commando', + 'reporter': + 'Reporter', + 'predicate': + 'Proposition', + + // list indices + 'last': + 'ultime', + 'any': + 'alcuno' // 'qualcun' +}; diff --git a/lang-ml.js b/lang-ml.js new file mode 100644 index 00000000..415a280e --- /dev/null +++ b/lang-ml.js @@ -0,0 +1,1282 @@ +/* + + lang-de.js + + German translation for SNAP! + + written by Jens Mönig + + Copyright (C) 2014 by Jens Mönig + + This file is part of Snap!. + + Snap! is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + + + + Note to Translators: + -------------------- + At this stage of development, Snap! can be translated to any LTR language + maintaining the current order of inputs (formal parameters in blocks). + + Translating Snap! is easy: + + + 1. Download + + Download the sources and extract them into a local folder on your + computer: + + + + Use the German translation file (named 'lang-de.js') as template for your + own translations. Start with editing the original file, because that way + you will be able to immediately check the results in your browsers while + you're working on your translation (keep the local copy of snap.html open + in your web browser, and refresh it as you progress with your + translation). + + + 2. Edit + + Edit the translation file with a regular text editor, or with your + favorite JavaScript editor. + + In the first non-commented line (the one right below this + note) replace "de" with the two-letter ISO 639-1 code for your language, + e.g. + + fr - French => SnapTranslator.dict.fr = { + it - Italian => SnapTranslator.dict.it = { + pl - Polish => SnapTranslator.dict.pl = { + pt - Portuguese => SnapTranslator.dict.pt = { + es - Spanish => SnapTranslator.dict.es = { + el - Greek => => SnapTranslator.dict.el = { + + etc. (see ) + + + 3. Translate + + Then work through the dictionary, replacing the German strings against + your translations. The dictionary is a straight-forward JavaScript ad-hoc + object, for review purposes it should be formatted as follows: + + { + 'English string': + 'Translation string', + 'last key': + } 'last value' + + and you only edit the indented value strings. Note that each key-value + pair needs to be delimited by a comma, but that there shouldn't be a comma + after the last pair (again, just overwrite the template file and you'll be + fine). + + If something doesn't work, or if you're unsure about the formalities you + should check your file with + + + + This will inform you about any missed commas etc. + + + 4. Accented characters + + Depending on which text editor and which file encoding you use you can + directly enter special characters (e.g. Umlaut, accented characters) on + your keyboard. However, I've noticed that some browsers may not display + special characters correctly, even if other browsers do. So it's best to + check your results in several browsers. If you want to be on the safe + side, it's even better to escape these characters using Unicode. + + see: + + + 5. Block specs: + + At this time your translation of block specs will only work + correctly, if the order of formal parameters and their types + are unchanged. Placeholders for inputs (formal parameters) are + indicated by a preceding % prefix and followed by a type + abbreviation. + + For example: + + 'say %s for %n secs' + + can currently not be changed into + + 'say %n secs long %s' + + and still work as intended. + + Similarly + + 'point towards %dst' + + cannot be changed into + + 'point towards %cst' + + without breaking its functionality. + + + 6. Submit + + When you're done, rename the edited file by replacing the "de" part of the + filename with the two-letter ISO 639-1 code for your language, e.g. + + fr - French => lang-fr.js + it - Italian => lang-it.js + pl - Polish => lang-pl.js + pt - Portuguese => lang-pt.js + es - Spanish => lang-es.js + el - Greek => => lang-el.js + + and send it to me for inclusion in the official Snap! distribution. + Once your translation has been included, Your name will the shown in the + "Translators" tab in the "About Snap!" dialog box, and you will be able to + directly launch a translated version of Snap! in your browser by appending + + lang:xx + + to the URL, xx representing your translations two-letter code. + + + 7. Known issues + + In some browsers accents or ornaments located in typographic ascenders + above the cap height are currently (partially) cut-off. + + Enjoy! + -Jens +*/ + +/*global SnapTranslator*/ + +SnapTranslator.dict.ml = { + +/* + Special characters: (see ) + + Ä, ä \u00c4, \u00e4 + Ö, ö \u00d6, \u00f6 + Ü, ü \u00dc, \u00fc + ß \u00df +*/ + + // translations meta information + 'language_name': + 'Malayalam', // the name as it should appear in the language menu + 'language_translator': + 'vinayakumar R', // your name for the Translators tab + 'translator_e-mail': + 'vnkmr7620@gmail.com', // optional + 'last_changed': + '2015-02-20', // this, too, will appear in the Translators tab + + // GUI + // control bar: + 'untitled': + 'തലക്കെട്ടില്ലാത്ത', + 'development mode': + 'വികസനം സമ്പ്രദായം', + + // categories: + 'Motion': + 'ചലനം', + 'Looks': + 'കാഴ്‌ച', + 'Sound': + 'ശബ്‌ദം', + 'Pen': + 'പേന', + 'Control': + 'നിയന്ത്രണം', + 'Sensing': + 'ഗ്രഹണം', + 'Operators': + 'ക്രിയകള്', + 'Variables': + 'ചരങ്ങള്‍', + 'Lists': + 'പട്ടിക', + 'Other': + 'വേറൊന്ന്', + + // editor: + 'draggable': + 'വലിച്ചിഴയ്‌ക്കുക', + + // tabs: + 'Scripts': + 'ലിപികള്‍', + 'Costumes': + 'വേഷം', + 'Sounds': + 'ശബ്‌ദകള്‍', + + // names: + 'Sprite': + 'ദേവത', + 'Stage': + 'നില', + + // rotation styles: + 'don\'t rotate': + 'തിരികരുത്', + 'can rotate': + 'തിരിക്കാന്‍ കഴിയും', + 'only face left/right': + 'മാത്രം നോകുക ഇടത്‌/വലത്ത്', + + // new sprite button: + 'add a new sprite': + 'പുതിയ ദേവത ചേര്‍ക്കുക', + + // tab help + 'costumes tab help': + 'വേഷം ലഘുപട്ടിക സഹായം', + 'import a sound from your computer\nby dragging it into here': + 'കമ്പ്യൂട്ടറില്‍ നിന്നും ശബ്തം ഇറക്കുമതി\n ഇവിടെ വലിച്ചിട്ടുക', + + // primitive blocks: + + /* + Attention Translators: + ---------------------- + At this time your translation of block specs will only work + correctly, if the order of formal parameters and their types + are unchanged. Placeholders for inputs (formal parameters) are + indicated by a preceding % prefix and followed by a type + abbreviation. + + For example: + + 'say %s for %n secs' + + can currently not be changed into + + 'say %n secs long %s' + + and still work as intended. + + Similarly + + 'point towards %dst' + + cannot be changed into + + 'point towards %cst' + + without breaking its functionality. + */ + + // motion: + 'Stage selected:\nno motion primitives': + 'B\u00fchne ausgew\u00e4hlt:\nkeine Standardbewegungsbl\u00f6cke\n' + + 'vorhanden', + + 'move %n steps': + 'ചലിക്കുക %n പടികള്', + 'turn %clockwise %n degrees': + 'drehe %clockwise %n Grad', + 'turn %counterclockwise %n degrees': + 'drehe %counterclockwise %n Grad', + 'point in direction %dir': + 'ലേക്ക് തിരിയുക %dir', + 'point towards %dst': + 'ലേക്ക് തിരിയുക %dst', + 'go to x: %n y: %n': + 'ലേക്ക് പോവുക x: %n y: %n', + 'go to %dst': + 'ലേക്ക് പോവുക %dst', + 'glide %n secs to x: %n y: %n': + 'സെകന്റില്‍ %n ലേക്ക് നീങ്ങുക x: %n y: %n', + 'change x by %n': + 'xനെ %n കൊണ്ട് മാറ്റുക', + 'set x to %n': + 'xനെ %n ആക്കുക', + 'change y by %n': + 'yനെ %n കൊണ്ട് മാറ്റുക', + 'set y to %n': + 'yനെ %n ആക്കുക', + 'if on edge, bounce': + 'അറ്റത്താണെങ്കില്‍ തിരിച്ചു നടക്കുക', + 'x position': + 'xസ്ഥാന', + 'y position': + 'yസ്ഥാനം', + 'direction': + 'ദിശ', + + // looks: + 'switch to costume %cst': + 'മത്തെ രൂപമാക്കുക %cst', + 'next costume': + 'അടുത്ത രൂപം', + 'costume #': + 'രൂപ #', + 'say %s for %n secs': + '%s %n സെകന്റ് പറയുക', + 'say %s': + '%s പറയുക', + 'think %s for %n secs': + '%n സെകന്റ് %s ചിന്തിക്കുക', + 'think %s': + '%s ചിന്തിക്കുക', + 'Hello!': + 'ഹലോ!', + 'Hmm...': + 'ഹ് മ് മും...', + 'change %eff effect by %n': + '%eff നെ %n കൊണ്ട് മാറ്റുക', + 'set %eff effect to %n': + '%eff എന്ന സ്പെഷല്‍ എഫെക്റ്റ് %n ആക്കുക', + 'clear graphic effects': + 'ഗ്രാഫിക്‌ ഇഫെക്റ്റ്സ് മാറ്റുക', + 'change size by %n': + 'വലിപ്പം %n കൊണ്ട് മാറ്റുക', + 'set size to %n %': + 'വലിപ്പം %n % ആക്കുക', + 'size': + 'വലിപ്', + 'show': + 'പ്രത്യക്ഷമാവുക', + 'hide': + 'ഒളിക്കുക', + 'go to front': + 'ഉപരിതലത്തിലോട്ടു വരിക', + 'go back %n layers': + '%n പാളി അകത്തേക്ക് പോവുക', + + 'development mode \ndebugging primitives:': + 'Hackermodus \nDebugging-Bl\u00f6cke', + 'console log %mult%s': + 'schreibe in die Konsole: %mult%s', + 'alert %mult%s': + 'Pop-up: %mult%s', + + // sound: + 'play sound %snd': + '%snd ശബ്ദമുണ്ടാക്കുക', + 'play sound %snd until done': + 'തീരുന്നതു വരെ %snd ശബ്ദമുണ്ടാക്കുക', + 'stop all sounds': + 'stoppe alle Kl\u00e4nge', + 'rest for %n beats': + '%n ബീറ്റ് സമയം കാത്തിരിക്കുക', + 'play note %n for %n beats': + '%n മത്തെ സ്വരം %n ബീറ്റ്സ് അവതരിപ്പിക്കുക', + 'change tempo by %n': + 'ടെംപോ %n കൊണ്ട് മാറ്റുക', + 'set tempo to %n bpm': + 'ടെംപോ %n ബീറ്റ്സ്/മിനിറ്റ് ആക്കുക', + 'tempo': + 'ടെംപ', + + // pen: + 'clear': + 'മായ്ക്കുക', + 'pen down': + 'വരയ്ക്കാന്‍ തുടങ്ങുക', + 'pen up': + 'വരയുന്നത് നിര്‍ത്തുക', + 'set pen color to %clr': + 'പേനയുടെ നിറം %clr ആക്കുക', + 'change pen color by %n': + 'പേനയുടെ നിറം %n കൊണ്ട് മാറ്റുക', + 'set pen color to %n': + 'പേനയുടെ നിറം %n ആക്കുക', + 'change pen shade by %n': + 'പേനയുടെ ഷേഡ് %n കൊണ്ട് മാറ്റുക', + 'set pen shade to %n': + 'പേനയുടെ ഷേഡ് %n ആക്കുക', + 'change pen size by %n': + 'പേനയുടെ വലിപ്പം %n കൊണ്ട് മാറ്റുക', + 'set pen size to %n': + 'പേനയുടെ വലിപ്പം %n ആക്കുക', + 'stamp': + 'ഒട്ടിക്കുക', + + // control: + 'when %greenflag clicked': + '%greenflag ക്ലിക്ക് ചെയ്യുമ്പോള്‍', + 'when %keyHat key pressed': + '%keyHat കീ അമര്‍ത്തുമ്പോള്‍', + 'when I am clicked': + 'Wenn ich angeklickt werde', + 'when I receive %msgHat': + 'ഞാന്‍ %msgHat സ്വീകരിക്കുമ്പോള്‍', + 'broadcast %msg': + '%msg വിളംബരം ചെയ്യുക', + 'broadcast %msg and wait': + '%msg വിളംബരം ചെയ്തു കാത്തിരിക്കുക', + 'Message name': + 'സന്ദേശത്തിന്റെ പേര്', + 'message': + 'സന്ദേശത്തിന്റ', + 'any message': + 'eine beliebige Nachricht', + 'wait %n secs': + '%n സെകന്റ് കാത്തിരിക്കുക', + 'wait until %b': + '%b ആവുന്നത് വരെ കാത്തിരിക്കുക', + 'forever %c': + 'എല്ലായ്പ്പോഴു %c', + 'repeat %n %c': + 'തവണ ആവര്‍ത്തിക്കുക %n %c', + 'repeat until %b %c': + '%b %c ആവുന്നത് വരെ ആവര്‍ത്തിക്കുക', + 'if %b %c': + '%b %c ആണെങ്കില്‍', + 'if %b %c else %c': + '%b %c ആണെങ്കില്‍ അല്ലെങ്കില്‍ %c', + 'report %s': + 'berichte %s', + 'stop %stopChoices': + 'നിര്‍ത്തുക %stopChoices', + 'all': + 'എല്ലാ', + 'this script': + 'ഈ സീരിയല്‍ ', + 'this block': + 'ഈ ബ്ലോക്കുകള്‍', + 'stop %stopOthersChoices': + 'നിര്‍ത്തുക %stopOthersChoices', + 'all but this script': + 'alles au\u00dfer diesem Skript', + 'other scripts in sprite': + 'andere Skripte in diesem Objekt', + 'pause all %pause': + 'pausiere alles %pause', + 'run %cmdRing %inputs': + 'f\u00fchre %cmdRing aus %inputs', + 'launch %cmdRing %inputs': + 'starte %cmdRing %inputs', + 'call %repRing %inputs': + 'rufe %repRing auf %inputs', + 'run %cmdRing w/continuation': + 'f\u00fchre %cmdRing mit Continuation aus', + 'call %cmdRing w/continuation': + 'rufe %cmdRing mit Continuation auf', + 'warp %c': + 'Warp %c', + 'when I start as a clone': + 'Wenn ich geklont werde', + 'create a clone of %cln': + 'klone %cln', + 'myself': + 'mich', + 'delete this clone': + 'entferne diesen Klon', + + // sensing: + 'touching %col ?': + '%col തൊടുന്നുണ്ടോ?', + 'touching %clr ?': + '%clr തൊടുന്നുണ്ടോ?', + 'color %clr is touching %clr ?': + '%clr കളര്‍ %clr നെ തൊടുന്നുണ്ടോ?', + 'ask %s and wait': + '%s ചോദിച്ചു കാത്തിരിക്കുക', + 'what\'s your name?': + 'താങ്കളുടെ പേര് എന്താണ്?', + 'answer': + 'ഉത്തര', + 'mouse x': + 'മൗസിന്റെ x സ്ഥാന', + 'mouse y': + 'മൗസിന്റെ y സ്ഥാന', + 'mouse down?': + 'മൗസ് താഴെയാണോ?', + 'key %key pressed?': + '%key കീ അമര്‍ത്തിയോ?', + 'distance to %dst': + '%dst ലേക്കുള്ള ദൂരം', + 'reset timer': + 'ടൈമര്‍ വീണ്ടും തുടങ്ങുക', + 'timer': + 'ടൈമര്‍', + '%att of %spr': + '%att ന്‍റ %spr', + 'http:// %s': + 'http:// %s', + 'turbo mode?': + 'Turbomodus?', + 'set turbo mode to %b': + 'setze Turbomodus auf %b', + + 'filtered for %clr': + 'nach %clr gefiltert', + 'stack size': + 'Stapelgr\u00f6\u00dfe', + 'frames': + 'Rahmenz\u00e4hler', + + // operators: + '%n mod %n': + '%n ശിഷ് %n', + 'round %n': + '%n റൗണ്ട് ചെയ്യുക', + '%fun of %n': + '%fun ന്‍റ %n', + 'pick random %n to %n': + '%n മുതല്‍ %n വരെയുള്ള ഏതെങ്കിലും സംഖ്യ എടുക്കുക', + '%b and %b': + '%b കൂടാത %b', + '%b or %b': + '%b അഥവ %b', + 'not %b': + '%b അല്ല', + 'true': + 'ശര', + 'false': + 'തെറ്റ്', + 'join %words': + 'മായി യോജിപ്പിക്കുക %words', + 'split %s by %delim': + 'trenne %s nach %delim', + 'hello': + 'ഹലോ', + 'world': + 'ലോകം', + 'letter %n of %s': + '%s ന്‍റെ %n മത്തെ അക്ഷരം', + 'length of %s': + '%s ന്‍റെ നീള', + 'unicode of %s': + 'Unicode Wert von %s', + 'unicode %n as letter': + 'Unicode %n als Buchstabe', + 'is %s a %typ ?': + 'ist %s ein(e) %typ ?', + 'is %s identical to %s ?': + 'ist %s identisch mit %s ?', + + 'type of %s': + 'Typ von %s', + + // variables: + 'Make a variable': + 'ഒരു ചരം ഉണ്ടാക്കുക', + 'Variable name': + 'ചരത്തിന്റെ പേര്', + 'Script variable name': + 'കോഡ് ചരത്തിന്റെ പേര്', + 'Delete a variable': + 'ഒരു ചരം ഡിലീറ്റ് ചെയ്യുക', + + 'set %var to %s': + '%var നെ %s ആക്കി മാറ്റുക', + 'change %var by %n': + '%var നെ %n കൊണ്ട് മാറ്റുക', + 'show variable %var': + '%var എന്ന ചരം കാണിക്കുക', + 'hide variable %var': + '%var എന്ന ചരത്തെ ഒളിപ്പിച്ചു വയ്ക്കുക', + 'script variables %scriptVars': + 'Skriptvariablen %scriptVars', + + // lists: + 'list %exp': + 'Liste %exp', + '%s in front of %l': + '%s am Anfang von %l', + 'item %idx of %l': + 'Element %idx von %l', + 'all but first of %l': + 'alles au\u00dfer dem ersten von %l', + 'length of %l': + 'L\u00e4nge von %l', + '%l contains %s': + '%l enth\u00e4lt %s', + 'thing': + 'etwas', + 'add %s to %l': + 'f\u00fcge %s zu %l hinzu', + 'delete %ida of %l': + 'entferne %ida aus %l', + 'insert %s at %idx of %l': + 'f\u00fcge %s als %idx in %l ein', + 'replace item %idx of %l with %s': + 'ersetze Element %idx in %l durch %s', + + // other + 'Make a block': + 'Neuer Block', + + // menus + // snap menu + 'About...': + '\u00dcber Snap!...', + 'Reference manual': + 'Handbuch lesen', + 'Snap! website': + 'Snap! Webseite', + 'Download source': + 'Quellcode runterladen', + 'Switch back to user mode': + 'zur\u00fcck zum Benutzermodus', + 'disable deep-Morphic\ncontext menus\nand show user-friendly ones': + 'verl\u00e4sst Morphic', + 'Switch to dev mode': + 'zum Hackermodus wechseln', + 'enable Morphic\ncontext menus\nand inspectors,\nnot user-friendly!': + 'erm\u00f6glicht Morphic Funktionen', + + // project menu + 'Project notes...': + 'പ്രോജെക്റ്റ്‌ കുറിപ്പുകള്‍....', + 'New': + 'പുതിയ', + 'Open...': + 'ഓപ്പണ്‍ ചെയ്യുക...', + 'Save': + 'സേവ് ചെയ്യുക', + 'Save As...': + 'എന്ന് സേവ് ചെയ്യുക...', + 'Import...': + 'കൊണ്ടുവരിക...', + 'file menu import hint': + 'l\u00e4dt ein exportiertes Projekt,\neine Bibliothek mit ' + + 'Bl\u00f6cken\n' + + 'ein Kost\u00fcm oder einen Klang', + 'Export project as plain text...': + 'Projekt als normalen Text exportieren...', + 'Export project...': + 'Projekt exportieren...', + 'show project data as XML\nin a new browser window': + 'zeigt das Projekt als XML\nin einem neuen Browserfenster an', + 'Export blocks...': + 'Bl\u00f6cke exportieren...', + 'show global custom block definitions as XML\nin a new browser window': + 'zeigt globale Benutzerblockdefinitionen\nals XML im Browser an', + 'Import tools': + 'Tools laden', + 'load the official library of\npowerful blocks': + 'das offizielle Modul mit\nm\u00e4chtigen Bl\u00f6cken laden', + 'Libraries...': + 'Module...', + 'Import library': + 'Modul laden', + + // cloud menu + 'Login...': + 'Anmelden...', + 'Signup...': + 'Benutzerkonto einrichten...', + + // settings menu + 'Language...': + 'ഭാഷ...', + 'Zoom blocks...': + 'Bl\u00f6cke vergr\u00f6\u00dfern...', + 'Stage size...': + 'സ്റ്റേജ് വലിപ്...', + 'Stage size': + 'സ്റ്റേജ് വലിപ്', + 'Stage width': + 'B\u00fchnenbreite', + 'Stage height': + 'B\u00fchnenh\u00f6he', + 'Default': + 'Normal', + 'Blurred shadows': + 'Weiche Schatten', + 'uncheck to use solid drop\nshadows and highlights': + 'abschalten f\u00fcr harte Schatten\nund Beleuchtung', + 'check to use blurred drop\nshadows and highlights': + 'einschalten f\u00fcr harte Schatten\nund Beleuchtung', + 'Zebra coloring': + 'Zebrafarben', + 'check to enable alternating\ncolors for nested blocks': + 'einschalten \u00fcr abwechselnde Farbnuancen\nin Bl\u00f6cken', + 'uncheck to disable alternating\ncolors for nested block': + 'ausschalten verhindert abwechselnde\nFarbnuancen in Bl\u00f6cken', + 'Dynamic input labels': + 'Eingabenbeschriftung', + 'uncheck to disable dynamic\nlabels for variadic inputs': + 'ausschalten verhindert Beschriftung\nvon Mehrfacheingaben', + 'check to enable dynamic\nlabels for variadic inputs': + 'einschalten um Mehrfacheingabefelder\nautomatisch zu beschriften', + 'Prefer empty slot drops': + 'Leere Platzhalter bevorzugen', + 'settings menu prefer empty slots hint': + 'einschalten um leere Platzhalter\nbeim Platzieren von Bl\u00f6cken' + + 'zu bevorzugen', + 'uncheck to allow dropped\nreporters to kick out others': + 'ausschalten um das "Rauskicken"\nvon platzierten Bl\u00f6cken\n' + + 'zu erm\u00f6glichen', + 'Long form input dialog': + 'Ausf\u00fchrlicher Input-Dialog', + 'Plain prototype labels': + 'Einfache Prototyp-Beschriftung', + 'uncheck to always show (+) symbols\nin block prototype labels': + 'ausschalten, um (+) Zeichen\nim Blockeditor zu verbergen', + 'check to hide (+) symbols\nin block prototype labels': + 'einschalten, um (+) Zeichen\nim Blockeditor immer anzuzeigen', + 'check to always show slot\ntypes in the input dialog': + 'einschalten, um immer die Datentypen\nim Input-Dialog zu sehen', + 'uncheck to use the input\ndialog in short form': + 'ausschalten f\u00fcr kurzen\nInput-Dialog', + 'Virtual keyboard': + 'Virtuelle Tastatur', + 'uncheck to disable\nvirtual keyboard support\nfor mobile devices': + 'ausschalten um die virtuelle\nTastatur auf mobilen Ger\u00e4ten\n' + + 'zu sperren', + 'check to enable\nvirtual keyboard support\nfor mobile devices': + 'einschalten um die virtuelle\nTastatur auf mobilen Ger\u00e4ten\n' + + 'zu erm\u00f6glichen', + 'Input sliders': + 'Eingabeschieber', + 'uncheck to disable\ninput sliders for\nentry fields': + 'ausschalten um Schieber\nin Eingabefeldern zu verhindern', + 'check to enable\ninput sliders for\nentry fields': + 'einschalten um Schieber\nin Eingabefeldern zu aktivieren', + 'Clicking sound': + 'Akustisches Klicken', + 'uncheck to turn\nblock clicking\nsound off': + 'ausschalten um akustisches\nKlicken zu deaktivieren', + 'check to turn\nblock clicking\nsound on': + 'einschalten um akustisches\nKlicken zu aktivieren', + 'Animations': + 'Animationen', + 'uncheck to disable\nIDE animations': + 'ausschalten um IDE-\nAnimationen zu verhindern', + 'Turbo mode': + 'Turbomodus', + 'check to prioritize\nscript execution': + 'einschalten, um Skripte\nzu priorisieren', + 'uncheck to run scripts\nat normal speed': + 'ausschalten, um Skripte\nnormal auszuf\u00fchren', + 'check to enable\nIDE animations': + 'einschalten um IDE-\nAnimationen zu erlauben', + 'Thread safe scripts': + 'Threadsicherheit', + 'uncheck to allow\nscript reentrance': + 'verhindert, dass unvollendete\nSkripte erneut gestartet werden', + 'check to disallow\nscript reentrance': + 'verhindert, dass unvollendete\nSkripte erneut gestartet werden', + 'Prefer smooth animations': + 'Fixe Framerate', + 'uncheck for greater speed\nat variable frame rates': + 'ausschalten, um Animationen \ndynamischer auszuf\u00fchren', + 'check for smooth, predictable\nanimations across computers': + 'einschalten, damit Animationen\n\u00fcberall gleich laufen', + 'Flat line ends': + 'Flache Pinselstriche', + 'check for flat ends of lines': + 'einschalten f\u00fcr flache\nPinselstrichenden', + 'uncheck for round ends of lines': + 'auschalten f\u00fcr runde\nPinselstrichenden', + + // inputs + 'with inputs': + 'mit Eingaben', + 'input names:': + 'Eingaben:', + 'Input Names:': + 'Eingaben:', + 'input list:': + 'Eingabeliste:', + + // context menus: + 'help': + 'സഹായ', + + // palette: + 'hide primitives': + 'Basisbl\u00f6cke ausblenden', + 'show primitives': + 'Basisbl\u00f6cke anzeigen', + + // blocks: + 'help...': + 'സഹായ...', + 'relabel...': + 'Umbenennen...', + 'duplicate': + 'ഡ്യൂപ്ലിക്കേറ്റ്‌', + 'make a copy\nand pick it up': + 'eine Kopie aufnehmen', + 'only duplicate this block': + 'nur diesen Block duplizieren', + 'delete': + 'ഡിലീറ്റ് ചെയ്യുക', + 'script pic...': + 'Skriptbild...', + 'open a new window\nwith a picture of this script': + 'ein neues Browserfenster mit einem\nBild dieses Skripts \u00f6ffnen', + 'ringify': + 'Umringen', + 'unringify': + 'Entringen', + + // custom blocks: + 'delete block definition...': + 'Blockdefinition l\u00f6schen', + 'edit...': + 'Bearbeiten...', + + // sprites: + 'edit': + 'എഡിറ്റ്‌', + 'move': + 'നീങ്ങുക', + 'detach from': + 'Abtrennen von', + 'detach all parts': + 'Alle Teile abtrennen', + 'export...': + 'കൊടുത്തയയ്ക്കുക...', + + // stage: + 'show all': + 'Alles zeigen', + 'pic...': + 'Bild exportieren...', + 'open a new window\nwith a picture of the stage': + 'ein neues Browserfenster mit einem\nBild der B\u00fchne \u00f6ffnen', + + // scripting area + 'clean up': + 'Aufr\u00e4umen', + 'arrange scripts\nvertically': + 'Skripte der Reihe nach\nanordnen', + 'add comment': + 'Anmerkung hinzuf\u00fcgen', + 'undrop': + 'R\u00fcckg\u00e4ngig', + 'undo the last\nblock drop\nin this pane': + 'Setzen des letzten Blocks\nwiderrufen', + 'scripts pic...': + 'Bild aller Scripte...', + 'open a new window\nwith a picture of all scripts': + 'ein neues Browserfenster mit einem\nBild aller Skripte \u00f6ffnen', + 'make a block...': + 'Neuen Block bauen...', + + // costumes + 'rename': + 'Umbenennen', + 'export': + 'കൊടുത്തയയ്ക്കുക', + 'rename costume': + 'Kost\u00fcm umbenennen', + + // sounds + 'Play sound': + 'ശബ്ദമുണ്ടാക്കുക', + 'Stop sound': + 'Klang\nanhalten', + 'Stop': + 'Halt', + 'Play': + 'തുടങ്ങുക', + 'rename sound': + 'Klang umbenennen', + + // dialogs + // buttons + 'OK': + 'ഓക', + 'Ok': + 'ഓക', + 'Cancel': + 'ക്യാന്‍സല്‍ ചെയ്യുക', + 'Yes': + 'അതെ', + 'No': + 'അല്ല', + + // help + 'Help': + 'സഹായ', + + // zoom blocks + 'Zoom blocks': + 'Bl\u00f6cke vergr\u00f6\u00dfern', + 'build': + 'baue', + 'your own': + 'eigene', + 'blocks': + 'Bl\u00f6cke', + 'normal (1x)': + 'normal (1x)', + 'demo (1.2x)': + 'Demo (1.2x)', + 'presentation (1.4x)': + 'Pr\u00e4sentation (1.4x)', + 'big (2x)': + 'gro\u00df (2x)', + 'huge (4x)': + 'riesig (4x)', + 'giant (8x)': + 'gigantisch (8x)', + 'monstrous (10x)': + 'ungeheuerlich (10x)', + + // Project Manager + 'Untitled': + 'Unbenannt', + 'Open Project': + 'പ്രോജെക്റ്റ്‌ ഓപ്പണ്‍ ചെയ്യുക', + '(empty)': + '(leer)', + 'Saved!': + 'Gesichert!', + 'Delete Project': + 'Projekt l\u00f6schen', + 'Are you sure you want to delete': + 'Wirklich l\u00f6schen?', + 'rename...': + 'Umbenennen...', + + // costume editor + 'Costume Editor': + 'Kost\u00fcmeditor', + 'click or drag crosshairs to move the rotation center': + 'Fadenkreuz anklicken oder bewegen um den Drehpunkt zu setzen', + + // project notes + 'Project Notes': + 'പ്രോജെക്റ്റ്‌ കുറിപ്പുകള്‍', + + // new project + 'New Project': + 'Neues Projekt', + 'Replace the current project with a new one?': + 'Das aktuelle Projekt durch ein neues ersetzen?', + + // save project + 'Save Project As...': + 'Projekt Sichern Als...', + + // export blocks + 'Export blocks': + 'Bl\u00f6cke exportieren', + 'Import blocks': + 'Bl\u00f6cke importieren', + 'this project doesn\'t have any\ncustom global blocks yet': + 'in diesem Projekt gibt es noch keine\nglobalen Bl\u00f6cke', + 'select': + 'ausw\u00e4hlen', + 'none': + 'nichts', + + // variable dialog + 'for all sprites': + 'f\u00fcr alle', + 'for this sprite only': + 'nur f\u00fcr dieses Objekt', + + // block dialog + 'Change block': + 'Block ver\u00e4ndern', + 'Command': + 'Befehl', + 'Reporter': + 'Funktion', + 'Predicate': + 'Pr\u00e4dikat', + + // block editor + 'Block Editor': + 'Blockeditor', + 'Apply': + 'Anwenden', + + // block deletion dialog + 'Delete Custom Block': + 'Block L\u00f6schen', + 'block deletion dialog text': + 'Soll dieser Block mit allen seinen Exemplare\n' + + 'wirklich gel\u00f6scht werden?', + + // input dialog + 'Create input name': + 'Eingabe erstellen', + 'Edit input name': + 'Eingabe bearbeiten', + 'Edit label fragment': + 'Beschriftung bearbeiten', + 'Title text': + 'Beschriftung', + 'Input name': + 'Eingabe', + 'Delete': + 'L\u00f6schen', + 'Object': + 'Objekt', + 'Number': + 'Zahl', + 'Text': + 'Text', + 'List': + 'Liste', + 'Any type': + 'Beliebig', + 'Boolean (T/F)': + 'Boolsch (W/F)', + 'Command\n(inline)': + 'Befehl', + 'Command\n(C-shape)': + 'Befehl\n(C-Form)', + 'Any\n(unevaluated)': + 'Beliebig\n(zitiert)', + 'Boolean\n(unevaluated)': + 'Boolsch\n(zitiert)', + 'Single input.': + 'Einzeleingabe.', + 'Default Value:': + 'Standardwert:', + 'Multiple inputs (value is list of inputs)': + 'Mehrere Eingaben (als Liste)', + 'Upvar - make internal variable visible to caller': + 'Interne Variable au\u00dfen sichtbar machen', + + // About Snap + 'About Snap': + '\u00dcber Snap', + 'Back...': + 'Zur\u00fcck...', + 'License...': + 'Lizenz...', + 'Modules...': + 'Komponenten...', + 'Credits...': + 'Mitwirkende...', + 'Translators...': + '\u00dcbersetzer', + 'License': + 'Lizenz', + 'current module versions:': + 'Komponenten-Versionen', + 'Contributors': + 'Mitwirkende', + 'Translations': + '\u00dcbersetzungen', + + // variable watchers + 'normal': + 'normal', + 'large': + 'gro\u00df', + 'slider': + 'Regler', + 'slider min...': + 'Minimalwert...', + 'slider max...': + 'Maximalwert...', + 'import...': + 'Importieren...', + 'Slider minimum value': + 'Minimalwert des Reglers', + 'Slider maximum value': + 'Maximalwert des Reglers', + + // list watchers + 'length: ': + 'L\u00e4nge: ', + + // coments + 'add comment here...': + 'Anmerkung hier hinzuf\u00fcgen', + + // drow downs + // directions + '(90) right': + '(90) rechts', + '(-90) left': + '(-90) links', + '(0) up': + '(0) oben', + '(180) down': + '(180) unten', + + // collision detection + 'mouse-pointer': + 'Mauszeiger', + 'edge': + 'Kante', + 'pen trails': + 'Malspuren', + + // costumes + 'Turtle': + 'Richtungszeiger', + 'Empty': + 'Leer', + + // graphical effects + 'brightness': + 'Helligeit', + 'ghost': + 'Durchsichtigkeit', + 'negative': + 'Farbumkehr', + 'comic': + 'Moire', + 'confetti': + 'Farbverschiebung', + + // keys + 'space': + 'Leertaste', + 'up arrow': + 'Pfeil nach oben', + 'down arrow': + 'Pfeil nach unten', + 'right arrow': + 'Pfeil nach rechts', + 'left arrow': + 'Pfeil nach links', + 'a': + 'a', + 'b': + 'b', + 'c': + 'c', + 'd': + 'd', + 'e': + 'e', + 'f': + 'f', + 'g': + 'g', + 'h': + 'h', + 'i': + 'i', + 'j': + 'j', + 'k': + 'k', + 'l': + 'l', + 'm': + 'm', + 'n': + 'n', + 'o': + 'o', + 'p': + 'p', + 'q': + 'q', + 'r': + 'r', + 's': + 's', + 't': + 't', + 'u': + 'u', + 'v': + 'v', + 'w': + 'w', + 'x': + 'x', + 'y': + 'y', + 'z': + 'z', + '0': + '0', + '1': + '1', + '2': + '2', + '3': + '3', + '4': + '4', + '5': + '5', + '6': + '6', + '7': + '7', + '8': + '8', + '9': + '9', + + // messages + 'new...': + 'Neu...', + + // math functions + 'abs': + 'Betrag', + 'floor': + 'Abgerundet', + 'sqrt': + 'Wurzel', + 'sin': + 'sin', + 'cos': + 'cos', + 'tan': + 'tan', + 'asin': + 'asin', + 'acos': + 'acos', + 'atan': + 'atan', + 'ln': + 'ln', + 'e^': + 'e^', + + // delimiters + 'letter': + 'Buchstabe', + 'whitespace': + 'Leerraum', + 'line': + 'Zeilenvorschub', + 'tab': + 'Tabulator', + 'cr': + 'Wagenr\u00fccklauf', + + // data types + 'number': + 'Zahl', + 'text': + 'Text', + 'Boolean': + 'Boole', + 'list': + 'Liste', + 'command': + 'Befehlsblock', + 'reporter': + 'Funktionsblock', + 'predicate': + 'Pr\u00e4dikat', + + // list indices + 'last': + 'letztes', + 'any': + 'beliebiges' +}; diff --git a/lang-pl.js b/lang-pl.js index 669a22b9..c0c4c49f 100644 --- a/lang-pl.js +++ b/lang-pl.js @@ -190,7 +190,7 @@ SnapTranslator.dict.pl = { 'translator_e-mail': 'witek@oeiizk.waw.pl', // optional 'last_changed': - '2013-08-05', // this, too, will appear in the Translators tab + '2015-08-06', // this, too, will appear in the Translators tab // GUI // control bar: @@ -248,8 +248,8 @@ SnapTranslator.dict.pl = { 'tylko lewo/prawo', // new sprite button: - 'add a new sprite': - 'dodaj nowego duszka', + 'add a new Turtle sprite': + 'dodaj nowego duszka-żółwia', // tab help 'costumes tab help': @@ -331,7 +331,7 @@ SnapTranslator.dict.pl = { 'switch to costume %cst': 'zmie\u0144 kostium na %cst', 'next costume': - 'nast\u0118pny kostium', + 'następny kostium', 'costume #': 'kostium nr ', 'say %s for %n secs': @@ -343,7 +343,7 @@ SnapTranslator.dict.pl = { 'think %s': 'pomy\u015Bl %s', 'Hello!': - 'Hallo!', + 'Cześć!', 'Hmm...': 'Hmm...', 'change %eff effect by %n': @@ -421,8 +421,18 @@ SnapTranslator.dict.pl = { 'kiedy klikni\u0119to %greenflag', 'when %keyHat key pressed': 'kiedy klawisz %keyHat naci\u015Bni\u0119ty', - 'when I am clicked': - 'kiedy duszek klikni\u0119ty', + 'when I am %interaction': + 'kiedy zostanę %interaction', + 'clicked': + 'kliknięty', + 'pressed': + 'naciśnięty', + 'dropped': + 'upuszczony', + 'mouse-entered': + 'najechany przez kursor myszy', + 'mouse-departed': + 'opuszczony przez kursor myszy', 'when I receive %msgHat': 'kiedy otrzymam %msgHat', 'broadcast %msg': @@ -545,9 +555,9 @@ SnapTranslator.dict.pl = { 'join %words': 'po\u0142\u0105cz %words', 'hello': - 'Hallo', + 'witaj', 'world': - 's\u0142owo', + 'świecie', 'letter %n of %s': 'litera %n z %s', 'length of %s': @@ -673,6 +683,8 @@ SnapTranslator.dict.pl = { 'Logowanie...', 'Signup...': 'Rejestracja...', + 'Reset Password...': + 'Zresetuj hasło...', // settings menu 'Language...': @@ -857,7 +869,7 @@ SnapTranslator.dict.pl = { 'Ok': 'Ok', 'Cancel': - 'Poniechaj', + 'Anuluj', 'Yes': 'Tak', 'No': @@ -903,9 +915,53 @@ SnapTranslator.dict.pl = { 'Delete Project': 'Usu\u0144 projekt', 'Are you sure you want to delete': - 'Czy napewno chcesz usun\u0105\u0107?', + 'Czy napewno chcesz usun\u0105\u0107', 'rename...': 'przemianuj', + 'Cloud': + 'Chmura', + 'Browser': + 'Przeglądarka', + 'Examples': + 'Przykłady', + 'You are not logged in': + 'Nie jesteś zalogowany', + 'Updating\nproject list...': + 'Aktualizowanie\nlisty projektów...', + 'last changed': + 'ostatnio zmieniony', + 'Open': + 'Otwórz', + 'Share': + 'Udostępnij', + 'Unshare': + 'Wyłącz udostępnianie', + 'Share Project': + 'Udostępnij projekt', + 'Unshare Project': + 'Wyłącz udostępnianie projektu', + 'Are you sure you want to publish': + 'Czy na pewno chcesz opublikować projekt', + 'Are you sure you want to unpublish': + 'Czy na pewno chcesz wyłączyć publikowanie projektu', + 'sharing\nproject...': + 'Udostępnianie\nprojektu...', + 'shared.': + 'Projekt udostępniony.', + 'unsharing\nproject...': + 'Wyłączanie\nudostępniania projektu...', + 'unshared.': + 'Udostępnianie wyłączone.', + 'Fetching project\nfrom the cloud...': + 'Wczytywanie projektu\nz chmury...', + 'Opening project...': + 'Otwieranie projektu...', + 'Save Project': + 'Zapisz projekt', + 'Saving project\nto the cloud...': + 'Zapisywanie projektu\ndo chmury...', + 'saved.': + 'Projekt zapisany.', // costume editor 'Costume Editor': @@ -1081,7 +1137,7 @@ SnapTranslator.dict.pl = { // costumes 'Turtle': - 'Duszek', + 'Żółw', 'Empty': 'Pusty', @@ -1221,5 +1277,61 @@ SnapTranslator.dict.pl = { 'last': 'ostatni', 'any': - 'dowolny' + 'dowolny', + + // Sign up dialog + 'Sign up': + 'Rejestracja', + 'User name:': + 'Nazwa użytkownika:', + 'Birth date:': + 'Data urodzenia:', + 'year:': + 'rok:', + 'E-mail address:': + 'Adres e-mail:', + 'E-mail address of parent or guardian:': + 'Adres e-mail rodzica lub opiekuna:', + 'Terms of Service...': + 'Regulamin...', + 'Privacy...': + 'Polityka prywatności...', + 'I have read and agree\nto the Terms of Service': + 'Przeczytałem i zgadzam się\nz Regulaminem', + 'January': + 'styczeń', + 'February': + 'luty', + 'March': + 'marzec', + 'April': + 'kwiecień', + 'May': + 'maj', + 'June': + 'czerwiec', + 'July': + 'lipiec', + 'August': + 'sierpień', + 'September': + 'wrzesień', + 'October': + 'październik', + 'November': + 'listopad', + 'December': + 'grudzień', + 'please fill out\nthis field': + 'Proszę wypełnić\nto pole', + 'please agree to\nthe TOS': + 'Proszę zaakceptować\nRegulamin', + 'Sign in': + 'Zaloguj się', + 'Password:': + 'Hasło:', + 'stay signed in on this computer\nuntil logging out': + 'Zapamiętaj mnie na tym komputerze\naż do wylogowania', + 'Reset password': + 'Zresetuj hasło' }; diff --git a/lang-pt.js b/lang-pt.js index 2d3804ab..cd743099 100755 --- a/lang-pt.js +++ b/lang-pt.js @@ -185,7 +185,7 @@ SnapTranslator.dict.pt = { 'translator_e-mail': 'mmsequeira@gmail.com', 'last_changed': - '2014-10-01', + '2015-08-02', // GUI // control bar: @@ -417,8 +417,18 @@ SnapTranslator.dict.pt = { 'Quando alguém clicar em %greenflag', 'when %keyHat key pressed': 'Quando alguém pressionar a tecla %keyHat', - 'when I am clicked': - 'Quando alguém clicar em ti', + 'when I am %interaction': + 'Quando o rato %interaction', + 'clicked': + 'clicar em ti', + 'pressed': + 'pressionar em ti', + 'dropped': + 'te largar', + 'mouse-entered': + 'entrar em ti', + 'mouse-departed': + 'sair de ti', 'when I receive %msgHat': 'Quando receberes a mensagem %msgHat', 'broadcast %msg': @@ -647,13 +657,17 @@ SnapTranslator.dict.pt = { 'Abrir um projecto…', 'Save': 'Guardar este projecto', + 'Save to disk': + 'Guardar no disco', + 'store this project\nin the downloads folder\n(in supporting browsers)': + 'Guardar este projecto\nna sua pasta de descargas\n' + + '(em navegadores que o suportem).', 'Save As...': 'Guardar este projecto como…', 'Import...': 'Importar…', 'file menu import hint': - 'Abrir um projecto exportado,\n' - + 'substitundo o projecto corrente, ou\n' + 'Abrir um projecto exportado,\nsubstitundo o projecto corrente, ou\n' + 'importar uma biblioteca de blocos, um\n' + 'traje ou um som para o projecto corrente.', 'Export project as plain text...': @@ -1443,10 +1457,6 @@ SnapTranslator.dict.pt = { 'Suportar produção de código', 'check for block\nto text mapping features': 'Assinalar para funcionalidades\nde mapeamento entre blocos e texto.', - 'Save to disk': - 'Guardar no disco', - 'experimental - store this project\nin your downloads folder': - 'Experimental - Guardar este projecto\nna sua pasta de descargas.', 'saved.': 'guardado.', 'options...': @@ -1692,5 +1702,17 @@ SnapTranslator.dict.pt = { + 'nomes para os parâmetros (ignorando os nomes mostrados).', 'Enter code that corresponds to the block\'s operation (usually a single\nfunction invocation). Use <#n> to reference actual arguments as shown.': 'Introduza o código que corresponda à operação do bloco (normalmente uma simples\n' - + 'invocação de rotina). Use <#n> para referenciar os argumentos tal como mostrado' + + 'invocação de rotina). Use <#n> para referenciar os argumentos tal como mostrado', + 'Keyboard Editing': + 'Edição usando o teclado', + 'uncheck to disable\nkeyboard editing support': + 'Desassinalar para desactivar\na edição usando o teclado.', + 'check to enable\nkeyboard editing support': + 'Assinalar para activar\na edição usando o teclado.', + 'Inheritance support': + 'Suporte para herança', + 'uncheck to disable\nsprite inheritance features': + 'Desassinalar para desactivar\nfuncionalidades de herança de actores.', + 'check for sprite\ninheritance features': + 'Assinalar para activar\nfuncionalidades de herança de actores.' }; diff --git a/lang-ta.js b/lang-ta.js new file mode 100644 index 00000000..c672e918 --- /dev/null +++ b/lang-ta.js @@ -0,0 +1,1283 @@ +/* + + lang-de.js + + German translation for SNAP! + + written by Jens Mönig + + Copyright (C) 2014 by Jens Mönig + + This file is part of Snap!. + + Snap! is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + + + + Note to Translators: + -------------------- + At this stage of development, Snap! can be translated to any LTR language + maintaining the current order of inputs (formal parameters in blocks). + + Translating Snap! is easy: + + + 1. Download + + Download the sources and extract them into a local folder on your + computer: + + + + Use the German translation file (named 'lang-de.js') as template for your + own translations. Start with editing the original file, because that way + you will be able to immediately check the results in your browsers while + you're working on your translation (keep the local copy of snap.html open + in your web browser, and refresh it as you progress with your + translation). + + + 2. Edit + + Edit the translation file with a regular text editor, or with your + favorite JavaScript editor. + + In the first non-commented line (the one right below this + note) replace "de" with the two-letter ISO 639-1 code for your language, + e.g. + + fr - French => SnapTranslator.dict.fr = { + it - Italian => SnapTranslator.dict.it = { + pl - Polish => SnapTranslator.dict.pl = { + pt - Portuguese => SnapTranslator.dict.pt = { + es - Spanish => SnapTranslator.dict.es = { + el - Greek => => SnapTranslator.dict.el = { + + etc. (see ) + + + 3. Translate + + Then work through the dictionary, replacing the German strings against + your translations. The dictionary is a straight-forward JavaScript ad-hoc + object, for review purposes it should be formatted as follows: + + { + 'English string': + 'Translation string', + 'last key': + } 'last value' + + and you only edit the indented value strings. Note that each key-value + pair needs to be delimited by a comma, but that there shouldn't be a comma + after the last pair (again, just overwrite the template file and you'll be + fine). + + If something doesn't work, or if you're unsure about the formalities you + should check your file with + + + + This will inform you about any missed commas etc. + + + 4. Accented characters + + Depending on which text editor and which file encoding you use you can + directly enter special characters (e.g. Umlaut, accented characters) on + your keyboard. However, I've noticed that some browsers may not display + special characters correctly, even if other browsers do. So it's best to + check your results in several browsers. If you want to be on the safe + side, it's even better to escape these characters using Unicode. + + see: + + + 5. Block specs: + + At this time your translation of block specs will only work + correctly, if the order of formal parameters and their types + are unchanged. Placeholders for inputs (formal parameters) are + indicated by a preceding % prefix and followed by a type + abbreviation. + + For example: + + 'say %s for %n secs' + + can currently not be changed into + + 'say %n secs long %s' + + and still work as intended. + + Similarly + + 'point towards %dst' + + cannot be changed into + + 'point towards %cst' + + without breaking its functionality. + + + 6. Submit + + When you're done, rename the edited file by replacing the "de" part of the + filename with the two-letter ISO 639-1 code for your language, e.g. + + fr - French => lang-fr.js + it - Italian => lang-it.js + pl - Polish => lang-pl.js + pt - Portuguese => lang-pt.js + es - Spanish => lang-es.js + el - Greek => => lang-el.js + + and send it to me for inclusion in the official Snap! distribution. + Once your translation has been included, Your name will the shown in the + "Translators" tab in the "About Snap!" dialog box, and you will be able to + directly launch a translated version of Snap! in your browser by appending + + lang:xx + + to the URL, xx representing your translations two-letter code. + + + 7. Known issues + + In some browsers accents or ornaments located in typographic ascenders + above the cap height are currently (partially) cut-off. + + Enjoy! + -Jens +*/ + +/*global SnapTranslator*/ + +SnapTranslator.dict.ta = { + +/* + Special characters: (see ) + + Ä, ä \u00c4, \u00e4 + Ö, ö \u00d6, \u00f6 + Ü, ü \u00dc, \u00fc + ß \u00df +*/ + + // translations meta information + 'language_name': + 'Tamil', // the name as it should appear in the language menu + 'language_translator': + 'vinayakumar R', // your name for the Translators tab + 'translator_e-mail': + 'vnkmr7620@gmail.com', // optional + 'last_changed': + '2015-02-20', // this, too, will appear in the Translators tab + + // GUI + // control bar: + 'untitled': + 'Unbenannt', + 'development mode': + 'Hackermodus', + + // categories: + 'Motion': + 'நகர்ச்ச', + 'Looks': + 'தோற்றம்', + 'Sound': + 'ஒல', + 'Pen': + 'பேனா', + 'Control': + 'கன்ட்ரொல்', + 'Sensing': + 'உணருதல்', + 'Operators': + 'ஆபரேட்டர்கள்', + 'Variables': + 'வேரியபில்கள்', + 'Lists': + 'பட்டியல்', + 'Other': + 'Andere', + + // editor: + 'draggable': + 'greifbar', + + // tabs: + 'Scripts': + 'Skripte', + 'Costumes': + 'உடைகள்', + 'Sounds': + 'ஒலஒல', + + // names: + 'Sprite': + 'Objekt', + 'Stage': + 'மேட', + + // rotation styles: + 'don\'t rotate': + 'சுழற்றாத', + 'can rotate': + 'சுழற்ற முடியும்', + 'only face left/right': + 'kann sich nur nach\nlinks/rechts drehen', + + // new sprite button: + 'add a new sprite': + 'ein neues Objekt\nhinzuf\u00fcgen', + + // tab help + 'costumes tab help': + 'Bilder durch hereinziehen von einer anderen\n' + + 'Webseite or vom Computer importieren', + 'import a sound from your computer\nby dragging it into here': + 'Kl\u00e4nge durch hereinziehen importieren', + + // primitive blocks: + + /* + Attention Translators: + ---------------------- + At this time your translation of block specs will only work + correctly, if the order of formal parameters and their types + are unchanged. Placeholders for inputs (formal parameters) are + indicated by a preceding % prefix and followed by a type + abbreviation. + + For example: + + 'say %s for %n secs' + + can currently not be changed into + + 'say %n secs long %s' + + and still work as intended. + + Similarly + + 'point towards %dst' + + cannot be changed into + + 'point towards %cst' + + without breaking its functionality. + */ + + // motion: + 'Stage selected:\nno motion primitives': + 'B\u00fchne ausgew\u00e4hlt:\nkeine Standardbewegungsbl\u00f6cke\n' + + 'vorhanden', + + 'move %n steps': + '%n அடிகள் நகரவும்', + 'turn %clockwise %n degrees': + 'drehe %clockwise %n Grad', + 'turn %counterclockwise %n degrees': + 'drehe %counterclockwise %n Grad', + 'point in direction %dir': + '%dir திசையை சுட்டிக்கட்டவும்', + 'point towards %dst': + '%dst நோக்கி சுட்டிக்கட்டவும்', + 'go to x: %n y: %n': + 'x: %n y: %n க்கு செல்லவும்', + 'go to %dst': + '%dst க்கு செல்லவும்', + 'glide %n secs to x: %n y: %n': + 'gleite %n Sek. zu x: %n y: %n', + 'change x by %n': + 'x %n அளவு மாற்றவும்', + 'set x to %n': + 'x %n ஆக்கவும்', + 'change y by %n': + 'y %n அளவு மாற்றவும்', + 'set y to %n': + 'y %n ஆக்கவும்', + 'if on edge, bounce': + 'pralle vom Rand ab', + 'x position': + 'x இடம்', + 'y position': + 'y இடம்', + 'direction': + 'திச', + + // looks: + 'switch to costume %cst': + '%cst உடைக்கு மாற்ற', + 'next costume': + 'அடுத்த உட', + 'costume #': + 'உட #', + 'say %s for %n secs': + '%n விநாடிகள் %s சொல்', + 'say %s': + '%s சொல்', + 'think %s for %n secs': + '%n விநாடிகள் %s யோச', + 'think %s': + '%s யோச', + 'Hello!': + 'வணக்கம்!', + 'Hmm...': + 'Hmm...', + 'change %eff effect by %n': + '\u00e4ndere %eff -Effekt um %n', + 'set %eff effect to %n': + 'setze %eff -Effekt auf %n', + 'clear graphic effects': + 'க்ராபிக்ஸ் எபெக்ட்டை அழித்து விடு', + 'change size by %n': + 'கன அளவை %n அளவு மாற்றவும்', + 'set size to %n %': + 'கனம் %n % ஆக்கவும்', + 'size': + 'பரிமாணம்', + 'show': + 'காண்ப', + 'hide': + 'மறைக்கவும்', + 'go to front': + 'முன் செல்லவும்', + 'go back %n layers': + '%n அடுக்குகள் பின்னால் செல்லவும்', + + 'development mode \ndebugging primitives:': + 'Hackermodus \nDebugging-Bl\u00f6cke', + 'console log %mult%s': + 'schreibe in die Konsole: %mult%s', + 'alert %mult%s': + 'Pop-up: %mult%s', + + // sound: + 'play sound %snd': + '%snd ஒலிக்கவும்', + 'play sound %snd until done': + 'நிற்க்கும் வரை %snd ஒலிக்கவும்', + 'stop all sounds': + 'எல்லா ஒலிகளையும் நிருத்த', + 'rest for %n beats': + '%n தாள தட்டு காத்திருக்கவும்', + 'play note %n for %n beats': + '%n ஸ்வரம் %n தாள தட்டு வாசிக்கவும்', + 'change tempo by %n': + '%n அளவு தாளத்தை மாற்றவும்', + 'set tempo to %n bpm': + 'தாளம் %n bpm ஆக்கவும்', + 'tempo': + 'தாளம்', + + // pen: + 'clear': + 'அழ', + 'pen down': + 'பேனா கீழே', + 'pen up': + 'பேனா மேல', + 'set pen color to %clr': + 'பேனா நிரம் %clr ஆக்கவும்', + 'change pen color by %n': + 'பேனா நிறத்தை %n அளவு மாற்றவும்', + 'set pen color to %n': + 'பேனா நிரம் %n ஆக்கவும்', + 'change pen shade by %n': + 'பேனா ஷெடை %n அளவு மாற்றவும்', + 'set pen shade to %n': + 'பேனா ஷேட் %n ஆக்கவும்', + 'change pen size by %n': + 'பேனா கன அளவை %n அளவு மாற்றவும்', + 'set pen size to %n': + 'பேனா கனம் %n ஆக்கவும்', + 'stamp': + 'அச்சு', + + // control: + 'when %greenflag clicked': + '%greenflag அழுத்தும்பொழுது', + 'when %keyHat key pressed': + '%keyHat கீ அழுத்தும்பொழுது', + 'when I am clicked': + 'Wenn ich angeklickt werde', + 'when I receive %msgHat': + '%msgHat பெறுகையில்', + 'broadcast %msg': + '%msg செலித்தி', + 'broadcast %msg and wait': + '%msg செலித்தி காத்திருக்கவும்', + 'Message name': + 'Nachricht', + 'message': + 'Nachricht', + 'any message': + 'eine beliebige Nachricht', + 'wait %n secs': + '%n விநாடிகள் காத்திருக்கவும்', + 'wait until %b': + '%b வரை காத்திருக்கவும்', + 'forever %c': + 'எப்போதும் %c', + 'repeat %n %c': + 'திரும்பச்செய் %n %c', + 'repeat until %b %c': + '%b %c வரை திரும்பச்செய்', + 'if %b %c': + '%b %c என்றால்', + 'if %b %c else %c': + '%b என்றால் அல்லது %c', + 'report %s': + 'berichte %s', + 'stop %stopChoices': + 'நிருத்து %stopChoices', + 'all': + 'alles', + 'this script': + 'இந்த ச்கிரிப்ட்ட', + 'this block': + 'diesen Block', + 'stop %stopOthersChoices': + 'stoppe %stopOthersChoices', + 'all but this script': + 'alles au\u00dfer diesem Skript', + 'other scripts in sprite': + 'andere Skripte in diesem Objekt', + 'pause all %pause': + 'pausiere alles %pause', + 'run %cmdRing %inputs': + 'f\u00fchre %cmdRing aus %inputs', + 'launch %cmdRing %inputs': + 'starte %cmdRing %inputs', + 'call %repRing %inputs': + 'rufe %repRing auf %inputs', + 'run %cmdRing w/continuation': + 'f\u00fchre %cmdRing mit Continuation aus', + 'call %cmdRing w/continuation': + 'rufe %cmdRing mit Continuation auf', + 'warp %c': + 'Warp %c', + 'when I start as a clone': + 'Wenn ich geklont werde', + 'create a clone of %cln': + 'klone %cln', + 'myself': + 'mich', + 'delete this clone': + 'entferne diesen Klon', + + // sensing: + 'touching %col ?': + 'தொடுகிரதா %col ?', + 'touching %clr ?': + 'தொடுகிரதா %clr ?', + 'color %clr is touching %clr ?': + '%clr கலர் %clr யை தொடுகிரதா?', + 'ask %s and wait': + '%s காத்திருக்க சொல்', + 'what\'s your name?': + 'உங்கள் பெயர் என்ன ?', + 'answer': + 'பதில்', + 'mouse x': + 'மவுஸ் x', + 'mouse y': + 'மவுஸ் y', + 'mouse down?': + 'Maustaste gedr\u00fcckt?', + 'key %key pressed?': + '%key கீ அழுத்தி இருக்கிரதா', + 'distance to %dst': + '%dst வரை தூரம்', + 'reset timer': + 'டைமெர் ரீசெட்', + 'timer': + 'டைமெர்', + '%att of %spr': + '%att von %spr', + 'http:// %s': + 'http:// %s', + 'turbo mode?': + 'Turbomodus?', + 'set turbo mode to %b': + 'setze Turbomodus auf %b', + + 'filtered for %clr': + 'nach %clr gefiltert', + 'stack size': + 'Stapelgr\u00f6\u00dfe', + 'frames': + 'Rahmenz\u00e4hler', + + // operators: + '%n mod %n': + '%n மாட் %n', + 'round %n': + '%n gerundet', + '%fun of %n': + '%fun ன் %n', + 'pick random %n to %n': + 'Zufallszahl von %n bis %n', + '%b and %b': + '%b மற்றும் %b', + '%b or %b': + '%b அல்லத %b', + 'not %b': + 'இல்ல %b', + 'true': + 'சர', + 'false': + 'தவறு', + 'join %words': + 'சேர்க்கவும் %words', + 'split %s by %delim': + 'trenne %s nach %delim', + 'hello': + 'வணக்கம்', + 'world': + 'உலகம்', + 'letter %n of %s': + '%s ன் %n வது எழுத்து', + 'length of %s': + '%s ன் நீளம்', + 'unicode of %s': + 'Unicode Wert von %s', + 'unicode %n as letter': + 'Unicode %n als Buchstabe', + 'is %s a %typ ?': + 'ist %s ein(e) %typ ?', + 'is %s identical to %s ?': + 'ist %s identisch mit %s ?', + + 'type of %s': + 'Typ von %s', + + // variables: + 'Make a variable': + 'வேரியபில் செய்', + 'Variable name': + 'மாறிழியின் பெயர்', + 'Script variable name': + 'ச்கிரிப்ட்ட மாறிழியின் பெயர்', + 'Delete a variable': + 'வேரியபில் அழி', + + 'set %var to %s': + '%var %n ஆக்கவும்', + 'change %var by %n': + '%var %n அளவு மாற்றவும்', + 'show variable %var': + '%var வேரியபிலை காண்பி', + 'hide variable %var': + '%var வேரியபிலை மறைக்கவும்', + 'script variables %scriptVars': + 'Skriptvariablen %scriptVars', + + // lists: + 'list %exp': + 'Liste %exp', + '%s in front of %l': + '%s am Anfang von %l', + 'item %idx of %l': + 'Element %idx von %l', + 'all but first of %l': + 'alles au\u00dfer dem ersten von %l', + 'length of %l': + 'L\u00e4nge von %l', + '%l contains %s': + '%l enth\u00e4lt %s', + 'thing': + 'etwas', + 'add %s to %l': + 'f\u00fcge %s zu %l hinzu', + 'delete %ida of %l': + 'entferne %ida aus %l', + 'insert %s at %idx of %l': + 'f\u00fcge %s als %idx in %l ein', + 'replace item %idx of %l with %s': + 'ersetze Element %idx in %l durch %s', + + // other + 'Make a block': + 'Neuer Block', + + // menus + // snap menu + 'About...': + '\u00dcber Snap!...', + 'Reference manual': + 'Handbuch lesen', + 'Snap! website': + 'Snap! Webseite', + 'Download source': + 'Quellcode runterladen', + 'Switch back to user mode': + 'zur\u00fcck zum Benutzermodus', + 'disable deep-Morphic\ncontext menus\nand show user-friendly ones': + 'verl\u00e4sst Morphic', + 'Switch to dev mode': + 'zum Hackermodus wechseln', + 'enable Morphic\ncontext menus\nand inspectors,\nnot user-friendly!': + 'erm\u00f6glicht Morphic Funktionen', + + // project menu + 'Project notes...': + 'Projektanmerkungen...', + 'New': + 'புதிய புதிய பின்னணி', + 'Open...': + 'திறக்க...', + 'Save': + 'சேம', + 'Save As...': + 'எனச் சேம...', + 'Import...': + 'Importieren...', + 'file menu import hint': + 'l\u00e4dt ein exportiertes Projekt,\neine Bibliothek mit ' + + 'Bl\u00f6cken\n' + + 'ein Kost\u00fcm oder einen Klang', + 'Export project as plain text...': + 'Projekt als normalen Text exportieren...', + 'Export project...': + 'Projekt exportieren...', + 'show project data as XML\nin a new browser window': + 'zeigt das Projekt als XML\nin einem neuen Browserfenster an', + 'Export blocks...': + 'Bl\u00f6cke exportieren...', + 'show global custom block definitions as XML\nin a new browser window': + 'zeigt globale Benutzerblockdefinitionen\nals XML im Browser an', + 'Import tools': + 'Tools laden', + 'load the official library of\npowerful blocks': + 'das offizielle Modul mit\nm\u00e4chtigen Bl\u00f6cken laden', + 'Libraries...': + 'Module...', + 'Import library': + 'Modul laden', + + // cloud menu + 'Login...': + 'Anmelden...', + 'Signup...': + 'Benutzerkonto einrichten...', + + // settings menu + 'Language...': + 'மொழ...', + 'Zoom blocks...': + 'Bl\u00f6cke vergr\u00f6\u00dfern...', + 'Stage size...': + 'B\u00fchnengr\u00f6\u00dfe...', + 'Stage size': + 'B\u00fchnengr\u00f6\u00dfe', + 'Stage width': + 'B\u00fchnenbreite', + 'Stage height': + 'B\u00fchnenh\u00f6he', + 'Default': + 'Normal', + 'Blurred shadows': + 'Weiche Schatten', + 'uncheck to use solid drop\nshadows and highlights': + 'abschalten f\u00fcr harte Schatten\nund Beleuchtung', + 'check to use blurred drop\nshadows and highlights': + 'einschalten f\u00fcr harte Schatten\nund Beleuchtung', + 'Zebra coloring': + 'Zebrafarben', + 'check to enable alternating\ncolors for nested blocks': + 'einschalten \u00fcr abwechselnde Farbnuancen\nin Bl\u00f6cken', + 'uncheck to disable alternating\ncolors for nested block': + 'ausschalten verhindert abwechselnde\nFarbnuancen in Bl\u00f6cken', + 'Dynamic input labels': + 'Eingabenbeschriftung', + 'uncheck to disable dynamic\nlabels for variadic inputs': + 'ausschalten verhindert Beschriftung\nvon Mehrfacheingaben', + 'check to enable dynamic\nlabels for variadic inputs': + 'einschalten um Mehrfacheingabefelder\nautomatisch zu beschriften', + 'Prefer empty slot drops': + 'Leere Platzhalter bevorzugen', + 'settings menu prefer empty slots hint': + 'einschalten um leere Platzhalter\nbeim Platzieren von Bl\u00f6cken' + + 'zu bevorzugen', + 'uncheck to allow dropped\nreporters to kick out others': + 'ausschalten um das "Rauskicken"\nvon platzierten Bl\u00f6cken\n' + + 'zu erm\u00f6glichen', + 'Long form input dialog': + 'Ausf\u00fchrlicher Input-Dialog', + 'Plain prototype labels': + 'Einfache Prototyp-Beschriftung', + 'uncheck to always show (+) symbols\nin block prototype labels': + 'ausschalten, um (+) Zeichen\nim Blockeditor zu verbergen', + 'check to hide (+) symbols\nin block prototype labels': + 'einschalten, um (+) Zeichen\nim Blockeditor immer anzuzeigen', + 'check to always show slot\ntypes in the input dialog': + 'einschalten, um immer die Datentypen\nim Input-Dialog zu sehen', + 'uncheck to use the input\ndialog in short form': + 'ausschalten f\u00fcr kurzen\nInput-Dialog', + 'Virtual keyboard': + 'Virtuelle Tastatur', + 'uncheck to disable\nvirtual keyboard support\nfor mobile devices': + 'ausschalten um die virtuelle\nTastatur auf mobilen Ger\u00e4ten\n' + + 'zu sperren', + 'check to enable\nvirtual keyboard support\nfor mobile devices': + 'einschalten um die virtuelle\nTastatur auf mobilen Ger\u00e4ten\n' + + 'zu erm\u00f6glichen', + 'Input sliders': + 'Eingabeschieber', + 'uncheck to disable\ninput sliders for\nentry fields': + 'ausschalten um Schieber\nin Eingabefeldern zu verhindern', + 'check to enable\ninput sliders for\nentry fields': + 'einschalten um Schieber\nin Eingabefeldern zu aktivieren', + 'Clicking sound': + 'Akustisches Klicken', + 'uncheck to turn\nblock clicking\nsound off': + 'ausschalten um akustisches\nKlicken zu deaktivieren', + 'check to turn\nblock clicking\nsound on': + 'einschalten um akustisches\nKlicken zu aktivieren', + 'Animations': + 'Animationen', + 'uncheck to disable\nIDE animations': + 'ausschalten um IDE-\nAnimationen zu verhindern', + 'Turbo mode': + 'Turbomodus', + 'check to prioritize\nscript execution': + 'einschalten, um Skripte\nzu priorisieren', + 'uncheck to run scripts\nat normal speed': + 'ausschalten, um Skripte\nnormal auszuf\u00fchren', + 'check to enable\nIDE animations': + 'einschalten um IDE-\nAnimationen zu erlauben', + 'Thread safe scripts': + 'Threadsicherheit', + 'uncheck to allow\nscript reentrance': + 'verhindert, dass unvollendete\nSkripte erneut gestartet werden', + 'check to disallow\nscript reentrance': + 'verhindert, dass unvollendete\nSkripte erneut gestartet werden', + 'Prefer smooth animations': + 'Fixe Framerate', + 'uncheck for greater speed\nat variable frame rates': + 'ausschalten, um Animationen \ndynamischer auszuf\u00fchren', + 'check for smooth, predictable\nanimations across computers': + 'einschalten, damit Animationen\n\u00fcberall gleich laufen', + 'Flat line ends': + 'Flache Pinselstriche', + 'check for flat ends of lines': + 'einschalten f\u00fcr flache\nPinselstrichenden', + 'uncheck for round ends of lines': + 'auschalten f\u00fcr runde\nPinselstrichenden', + + // inputs + 'with inputs': + 'mit Eingaben', + 'input names:': + 'Eingaben:', + 'Input Names:': + 'Eingaben:', + 'input list:': + 'Eingabeliste:', + + // context menus: + 'help': + 'Hilfe', + + // palette: + 'hide primitives': + 'Basisbl\u00f6cke ausblenden', + 'show primitives': + 'Basisbl\u00f6cke anzeigen', + + // blocks: + 'help...': + 'உதவ...', + 'relabel...': + 'Umbenennen...', + 'duplicate': + 'நகல் செய்', + 'make a copy\nand pick it up': + 'eine Kopie aufnehmen', + 'only duplicate this block': + 'nur diesen Block duplizieren', + 'delete': + 'அழ', + 'script pic...': + 'Skriptbild...', + 'open a new window\nwith a picture of this script': + 'ein neues Browserfenster mit einem\nBild dieses Skripts \u00f6ffnen', + 'ringify': + 'Umringen', + 'unringify': + 'Entringen', + + // custom blocks: + 'delete block definition...': + 'Blockdefinition l\u00f6schen', + 'edit...': + 'Bearbeiten...', + + // sprites: + 'edit': + 'திருத்த', + 'move': + 'நகர்த்து', + 'detach from': + 'Abtrennen von', + 'detach all parts': + 'Alle Teile abtrennen', + 'export...': + 'Exportieren...', + + // stage: + 'show all': + 'Alles zeigen', + 'pic...': + 'Bild exportieren...', + 'open a new window\nwith a picture of the stage': + 'ein neues Browserfenster mit einem\nBild der B\u00fchne \u00f6ffnen', + + // scripting area + 'clean up': + 'சுத்தம் செய்', + 'arrange scripts\nvertically': + 'Skripte der Reihe nach\nanordnen', + 'add comment': + 'Anmerkung hinzuf\u00fcgen', + 'undrop': + 'R\u00fcckg\u00e4ngig', + 'undo the last\nblock drop\nin this pane': + 'Setzen des letzten Blocks\nwiderrufen', + 'scripts pic...': + 'Bild aller Scripte...', + 'open a new window\nwith a picture of all scripts': + 'ein neues Browserfenster mit einem\nBild aller Skripte \u00f6ffnen', + 'make a block...': + 'Neuen Block bauen...', + + // costumes + 'rename': + 'Umbenennen', + 'export': + 'Exportieren', + 'rename costume': + 'Kost\u00fcm umbenennen', + + // sounds + 'Play sound': + 'Klang\nabspielen', + 'Stop sound': + 'Klang\nanhalten', + 'Stop': + 'நிறுத்த', + 'Play': + 'Los', + 'rename sound': + 'Klang umbenennen', + + // dialogs + // buttons + 'OK': + 'சர', + 'Ok': + 'சர', + 'Cancel': + 'கென்செல்', + 'Yes': + 'ஆம்', + 'No': + 'இல்ல', + + // help + 'Help': + 'உதவ', + + // zoom blocks + 'Zoom blocks': + 'Bl\u00f6cke vergr\u00f6\u00dfern', + 'build': + 'baue', + 'your own': + 'eigene', + 'blocks': + 'Bl\u00f6cke', + 'normal (1x)': + 'normal (1x)', + 'demo (1.2x)': + 'Demo (1.2x)', + 'presentation (1.4x)': + 'Pr\u00e4sentation (1.4x)', + 'big (2x)': + 'gro\u00df (2x)', + 'huge (4x)': + 'riesig (4x)', + 'giant (8x)': + 'gigantisch (8x)', + 'monstrous (10x)': + 'ungeheuerlich (10x)', + + // Project Manager + 'Untitled': + 'Unbenannt', + 'Open Project': + 'Project \u00f6ffnen', + '(empty)': + '(leer)', + 'Saved!': + 'Gesichert!', + 'Delete Project': + 'Projekt l\u00f6schen', + 'Are you sure you want to delete': + 'Wirklich l\u00f6schen?', + 'rename...': + 'Umbenennen...', + + // costume editor + 'Costume Editor': + 'Kost\u00fcmeditor', + 'click or drag crosshairs to move the rotation center': + 'Fadenkreuz anklicken oder bewegen um den Drehpunkt zu setzen', + + // project notes + 'Project Notes': + 'Projektanmerkungen', + + // new project + 'New Project': + 'Neues Projekt', + 'Replace the current project with a new one?': + 'Das aktuelle Projekt durch ein neues ersetzen?', + + // save project + 'Save Project As...': + 'Projekt Sichern Als...', + + // export blocks + 'Export blocks': + 'Bl\u00f6cke exportieren', + 'Import blocks': + 'Bl\u00f6cke importieren', + 'this project doesn\'t have any\ncustom global blocks yet': + 'in diesem Projekt gibt es noch keine\nglobalen Bl\u00f6cke', + 'select': + 'ausw\u00e4hlen', + 'none': + 'nichts', + + // variable dialog + 'for all sprites': + 'f\u00fcr alle', + 'for this sprite only': + 'nur f\u00fcr dieses Objekt', + + // block dialog + 'Change block': + 'Block ver\u00e4ndern', + 'Command': + 'Befehl', + 'Reporter': + 'Funktion', + 'Predicate': + 'Pr\u00e4dikat', + + // block editor + 'Block Editor': + 'Blockeditor', + 'Apply': + 'Anwenden', + + // block deletion dialog + 'Delete Custom Block': + 'Block L\u00f6schen', + 'block deletion dialog text': + 'Soll dieser Block mit allen seinen Exemplare\n' + + 'wirklich gel\u00f6scht werden?', + + // input dialog + 'Create input name': + 'Eingabe erstellen', + 'Edit input name': + 'Eingabe bearbeiten', + 'Edit label fragment': + 'Beschriftung bearbeiten', + 'Title text': + 'Beschriftung', + 'Input name': + 'Eingabe', + 'Delete': + 'L\u00f6schen', + 'Object': + 'Objekt', + 'Number': + 'Zahl', + 'Text': + 'Text', + 'List': + 'Liste', + 'Any type': + 'Beliebig', + 'Boolean (T/F)': + 'Boolsch (W/F)', + 'Command\n(inline)': + 'Befehl', + 'Command\n(C-shape)': + 'Befehl\n(C-Form)', + 'Any\n(unevaluated)': + 'Beliebig\n(zitiert)', + 'Boolean\n(unevaluated)': + 'Boolsch\n(zitiert)', + 'Single input.': + 'Einzeleingabe.', + 'Default Value:': + 'Standardwert:', + 'Multiple inputs (value is list of inputs)': + 'Mehrere Eingaben (als Liste)', + 'Upvar - make internal variable visible to caller': + 'Interne Variable au\u00dfen sichtbar machen', + + // About Snap + 'About Snap': + '\u00dcber Snap', + 'Back...': + 'Zur\u00fcck...', + 'License...': + 'Lizenz...', + 'Modules...': + 'Komponenten...', + 'Credits...': + 'Mitwirkende...', + 'Translators...': + '\u00dcbersetzer', + 'License': + 'Lizenz', + 'current module versions:': + 'Komponenten-Versionen', + 'Contributors': + 'Mitwirkende', + 'Translations': + '\u00dcbersetzungen', + + // variable watchers + 'normal': + 'normal', + 'large': + 'gro\u00df', + 'slider': + 'Regler', + 'slider min...': + 'Minimalwert...', + 'slider max...': + 'Maximalwert...', + 'import...': + 'Importieren...', + 'Slider minimum value': + 'Minimalwert des Reglers', + 'Slider maximum value': + 'Maximalwert des Reglers', + + // list watchers + 'length: ': + 'L\u00e4nge: ', + + // coments + 'add comment here...': + 'Anmerkung hier hinzuf\u00fcgen', + + // drow downs + // directions + '(90) right': + '(90) rechts', + '(-90) left': + '(-90) links', + '(0) up': + '(0) oben', + '(180) down': + '(180) unten', + + // collision detection + 'mouse-pointer': + 'Mauszeiger', + 'edge': + 'Kante', + 'pen trails': + 'Malspuren', + + // costumes + 'Turtle': + 'Richtungszeiger', + 'Empty': + 'Leer', + + // graphical effects + 'brightness': + 'Helligeit', + 'ghost': + 'Durchsichtigkeit', + 'negative': + 'Farbumkehr', + 'comic': + 'Moire', + 'confetti': + 'Farbverschiebung', + + // keys + 'space': + 'இடைவெள', + 'up arrow': + 'மேல் அம்புக்குற', + 'down arrow': + 'Pfeil nach unten', + 'right arrow': + 'வலது அம்புக்குற', + 'left arrow': + 'Pfeil nach links', + 'a': + 'a', + 'b': + 'b', + 'c': + 'c', + 'd': + 'd', + 'e': + 'e', + 'f': + 'f', + 'g': + 'g', + 'h': + 'h', + 'i': + 'i', + 'j': + 'j', + 'k': + 'k', + 'l': + 'l', + 'm': + 'm', + 'n': + 'n', + 'o': + 'o', + 'p': + 'p', + 'q': + 'q', + 'r': + 'r', + 's': + 's', + 't': + 't', + 'u': + 'u', + 'v': + 'v', + 'w': + 'w', + 'x': + 'x', + 'y': + 'y', + 'z': + 'z', + '0': + '0', + '1': + '1', + '2': + '2', + '3': + '3', + '4': + '4', + '5': + '5', + '6': + '6', + '7': + '7', + '8': + '8', + '9': + '9', + + // messages + 'new...': + 'Neu...', + + // math functions + 'abs': + 'Betrag', + 'floor': + 'Abgerundet', + 'sqrt': + 'Wurzel', + 'sin': + 'sin', + 'cos': + 'cos', + 'tan': + 'tan', + 'asin': + 'asin', + 'acos': + 'acos', + 'atan': + 'atan', + 'ln': + 'ln', + 'e^': + 'e^', + + // delimiters + 'letter': + 'Buchstabe', + 'whitespace': + 'Leerraum', + 'line': + 'Zeilenvorschub', + 'tab': + 'Tabulator', + 'cr': + 'Wagenr\u00fccklauf', + + // data types + 'number': + 'Zahl', + 'text': + 'Text', + 'Boolean': + 'Boole', + 'list': + 'Liste', + 'command': + 'Befehlsblock', + 'reporter': + 'Funktionsblock', + 'predicate': + 'Pr\u00e4dikat', + + // list indices + 'last': + 'letztes', + 'any': + 'beliebiges' +}; diff --git a/lang-te.js b/lang-te.js new file mode 100644 index 00000000..bd1c5dd1 --- /dev/null +++ b/lang-te.js @@ -0,0 +1,1283 @@ +/* + + lang-de.js + + German translation for SNAP! + + written by Jens Mönig + + Copyright (C) 2014 by Jens Mönig + + This file is part of Snap!. + + Snap! is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + + + + Note to Translators: + -------------------- + At this stage of development, Snap! can be translated to any LTR language + maintaining the current order of inputs (formal parameters in blocks). + + Translating Snap! is easy: + + + 1. Download + + Download the sources and extract them into a local folder on your + computer: + + + + Use the German translation file (named 'lang-de.js') as template for your + own translations. Start with editing the original file, because that way + you will be able to immediately check the results in your browsers while + you're working on your translation (keep the local copy of snap.html open + in your web browser, and refresh it as you progress with your + translation). + + + 2. Edit + + Edit the translation file with a regular text editor, or with your + favorite JavaScript editor. + + In the first non-commented line (the one right below this + note) replace "de" with the two-letter ISO 639-1 code for your language, + e.g. + + fr - French => SnapTranslator.dict.fr = { + it - Italian => SnapTranslator.dict.it = { + pl - Polish => SnapTranslator.dict.pl = { + pt - Portuguese => SnapTranslator.dict.pt = { + es - Spanish => SnapTranslator.dict.es = { + el - Greek => => SnapTranslator.dict.el = { + + etc. (see ) + + + 3. Translate + + Then work through the dictionary, replacing the German strings against + your translations. The dictionary is a straight-forward JavaScript ad-hoc + object, for review purposes it should be formatted as follows: + + { + 'English string': + 'Translation string', + 'last key': + } 'last value' + + and you only edit the indented value strings. Note that each key-value + pair needs to be delimited by a comma, but that there shouldn't be a comma + after the last pair (again, just overwrite the template file and you'll be + fine). + + If something doesn't work, or if you're unsure about the formalities you + should check your file with + + + + This will inform you about any missed commas etc. + + + 4. Accented characters + + Depending on which text editor and which file encoding you use you can + directly enter special characters (e.g. Umlaut, accented characters) on + your keyboard. However, I've noticed that some browsers may not display + special characters correctly, even if other browsers do. So it's best to + check your results in several browsers. If you want to be on the safe + side, it's even better to escape these characters using Unicode. + + see: + + + 5. Block specs: + + At this time your translation of block specs will only work + correctly, if the order of formal parameters and their types + are unchanged. Placeholders for inputs (formal parameters) are + indicated by a preceding % prefix and followed by a type + abbreviation. + + For example: + + 'say %s for %n secs' + + can currently not be changed into + + 'say %n secs long %s' + + and still work as intended. + + Similarly + + 'point towards %dst' + + cannot be changed into + + 'point towards %cst' + + without breaking its functionality. + + + 6. Submit + + When you're done, rename the edited file by replacing the "de" part of the + filename with the two-letter ISO 639-1 code for your language, e.g. + + fr - French => lang-fr.js + it - Italian => lang-it.js + pl - Polish => lang-pl.js + pt - Portuguese => lang-pt.js + es - Spanish => lang-es.js + el - Greek => => lang-el.js + + and send it to me for inclusion in the official Snap! distribution. + Once your translation has been included, Your name will the shown in the + "Translators" tab in the "About Snap!" dialog box, and you will be able to + directly launch a translated version of Snap! in your browser by appending + + lang:xx + + to the URL, xx representing your translations two-letter code. + + + 7. Known issues + + In some browsers accents or ornaments located in typographic ascenders + above the cap height are currently (partially) cut-off. + + Enjoy! + -Jens +*/ + +/*global SnapTranslator*/ + +SnapTranslator.dict.te = { + +/* + Special characters: (see ) + + Ä, ä \u00c4, \u00e4 + Ö, ö \u00d6, \u00f6 + Ü, ü \u00dc, \u00fc + ß \u00df +*/ + + // translations meta information + 'language_name': + 'Telagu', // the name as it should appear in the language menu + 'language_translator': + 'vinayakumar R', // your name for the Translators tab + 'translator_e-mail': + 'vnkmr7620@gmail.com', // optional + 'last_changed': + '2015-02-20', // this, too, will appear in the Translators tab + + // GUI + // control bar: + 'untitled': + 'Unbenannt', + 'development mode': + 'Hackermodus', + + // categories: + 'Motion': + 'చలన', + 'Looks': + 'కనబడ', + 'Sound': + 'శబ్దమ', + 'Pen': + 'పెన్', + 'Control': + 'నియంత్రణ', + 'Sensing': + 'స్పర్శించుట', + 'Operators': + 'చేసేవి', + 'Variables': + 'చరరాశులు', + 'Lists': + 'జాబితా', + 'Other': + 'Andere', + + // editor: + 'draggable': + 'greifbar', + + // tabs: + 'Scripts': + 'ఆజ్ఞ', + 'Costumes': + 'వేషధారణ', + 'Sounds': + 'శబ్దాల', + + // names: + 'Sprite': + 'రూపమ', + 'Stage': + 'వేదిక', + + // rotation styles: + 'don\'t rotate': + 'తిరుగవద్', + 'can rotate': + 'తిరుగ గలద', + 'only face left/right': + 'ముఖం ఎడమ-కుడి వైపు మాత్రమే', + + // new sprite button: + 'add a new sprite': + 'ein neues Objekt\nhinzuf\u00fcgen', + + // tab help + 'costumes tab help': + 'Bilder durch hereinziehen von einer anderen\n' + + 'Webseite or vom Computer importieren', + 'import a sound from your computer\nby dragging it into here': + 'Kl\u00e4nge durch hereinziehen importieren', + + // primitive blocks: + + /* + Attention Translators: + ---------------------- + At this time your translation of block specs will only work + correctly, if the order of formal parameters and their types + are unchanged. Placeholders for inputs (formal parameters) are + indicated by a preceding % prefix and followed by a type + abbreviation. + + For example: + + 'say %s for %n secs' + + can currently not be changed into + + 'say %n secs long %s' + + and still work as intended. + + Similarly + + 'point towards %dst' + + cannot be changed into + + 'point towards %cst' + + without breaking its functionality. + */ + + // motion: + 'Stage selected:\nno motion primitives': + 'B\u00fchne ausgew\u00e4hlt:\nkeine Standardbewegungsbl\u00f6cke\n' + + 'vorhanden', + + 'move %n steps': + '%n అడుగులు జరుగ', + 'turn %clockwise %n degrees': + 'drehe %clockwise %n Grad', + 'turn %counterclockwise %n degrees': + 'drehe %counterclockwise %n Grad', + 'point in direction %dir': + 'బిందువు %dir దిశలో', + 'point towards %dst': + 'బిందువు %dst వైపునక', + 'go to x: %n y: %n': + 'x: %n y: %n కు వెళ్', + 'go to %dst': + '%dst కు వెళ్', + 'glide %n secs to x: %n y: %n': + '%n సెకన్లకు x: %n y: %n జరుగున', + 'change x by %n': + 'x విలువ %n కి మార్', + 'set x to %n': + 'x విలువకు %n పెట్', + 'change y by %n': + 'y విలువ %n కి మార్', + 'set y to %n': + 'y విలువకు %n పెట్', + 'if on edge, bounce': + 'అంచున ఉంటే, దూక', + 'x position': + 'x స్థానం', + 'y position': + 'y స్థానం', + 'direction': + 'దిక్', + + // looks: + 'switch to costume %cst': + 'వేషధారణ %cst కు బదలాయించు', + 'next costume': + 'తదుపరి వేషధారణ', + 'costume #': + 'వేషధారణ #', + 'say %s for %n secs': + '%n సెకన్ల కోసం %s అని చెప్', + 'say %s': + '%s అని చెప్', + 'think %s for %n secs': + '%n సెకన్ల కోసం %s ఆలోచించ', + 'think %s': + '%s ఆలోచించ', + 'Hello!': + '"హలో!', + 'Hmm...': + 'హమ్.మ్..', + 'change %eff effect by %n': + '%n ప్రభావంతో %eff మారున', + 'set %eff effect to %n': + '%n ప్రయోజనంతో %eff పెట్', + 'clear graphic effects': + 'గ్రాఫిక్ ప్రయోజనాలు తొలగించుట', + 'change size by %n': + 'పరిమాణంను %n కి మార్', + 'set size to %n %': + '%n % కు పరిమాణాన్ని పెట్', + 'size': + 'Gr\u00f6\u00dfe', + 'show': + 'చూపించ', + 'hide': + 'దాచిపెట్', + 'go to front': + 'ముందుకు వెళ్', + 'go back %n layers': + '%n లేయర్లు తిరిగి వెళ్ళుట', + + 'development mode \ndebugging primitives:': + 'Hackermodus \nDebugging-Bl\u00f6cke', + 'console log %mult%s': + 'schreibe in die Konsole: %mult%s', + 'alert %mult%s': + 'Pop-up: %mult%s', + + // sound: + 'play sound %snd': + '%snd శబ్దం వాయించ', + 'play sound %snd until done': + '%snd ఆగువరకు శబ్దం వాయించ', + 'stop all sounds': + 'అన్నీ శబ్దాలు నిలుప', + 'rest for %n beats': + 'spiele Pause f\u00fcr %n Schl\u00e4ge', + 'play note %n for %n beats': + '%n సంజ్ఞను వాయించు %n బీట్స్ కోస', + 'change tempo by %n': + 'కదలికలోని తీవ్రతను %n మార్', + 'set tempo to %n bpm': + '%n బి.పి.యం.కు కదలికలోని తీవ్రతను పెట్', + 'tempo': + 'కదలికలోని తీవ్రత', + + // pen: + 'clear': + 'తొలగించుట', + 'pen down': + 'పెన్ను క్రిందకి', + 'pen up': + 'పెన్ను పైకి', + 'set pen color to %clr': + 'పెన్ను రంగును %clr కు పెట్', + 'change pen color by %n': + 'పెన్ను రంగు %n కు మార్', + 'set pen color to %n': + 'పెన్ను రంగును %n కు పెట్', + 'change pen shade by %n': + 'పెన్ను రంగు షేడ్ %n కు మార్', + 'set pen shade to %n': + 'పెన్ను రంగు షేడ్ %n కు పెట్', + 'change pen size by %n': + 'న్ను పరిమాణం మార్చేందుకు %n', + 'set pen size to %n': + 'పెన్ను పరిమాణం %n కు పెట్టు', + 'stamp': + 'ముద్', + + // control: + 'when %greenflag clicked': + '%greenflag ఒత్తినప్పుడ', + 'when %keyHat key pressed': + '%keyHat కీ ఒత్తినప్పుడ', + 'when I am clicked': + 'Wenn ich angeklickt werde', + 'when I receive %msgHat': + '%msgHat నేను స్వీకరించినప్పుడు', + 'broadcast %msg': + 'ప్రసార %msg', + 'broadcast %msg and wait': + '%msg ని ప్రసారం చేసి, వేచివుండు', + 'Message name': + 'సందేశం పేర', + 'message': + 'సందేశ', + 'any message': + 'ఏదైనా సందేశ', + 'wait %n secs': + '%n సెకన్లు వేచియుండ', + 'wait until %b': + '%b వరకూ వేచియుండ', + 'forever %c': + 'ఎప్పటికి %c', + 'repeat %n %c': + '%n %c పునరావృత', + 'repeat until %b %c': + '%b %c పునరావృతం అయ్యేంతవరక', + 'if %b %c': + 'ఒకవేళ %b %c', + 'if %b %c else %c': + 'ఒకవేళ %b %c ఇంకా %c', + 'report %s': + 'berichte %s', + 'stop %stopChoices': + 'నిలుపు %stopChoices', + 'all': + 'అన్', + 'this script': + 'ఈ ఆజ్', + 'this block': + 'diesen Block', + 'stop %stopOthersChoices': + 'నిలుప %stopOthersChoices', + 'all but this script': + 'alles au\u00dfer diesem Skript', + 'other scripts in sprite': + 'andere Skripte in diesem Objekt', + 'pause all %pause': + 'pausiere alles %pause', + 'run %cmdRing %inputs': + 'f\u00fchre %cmdRing aus %inputs', + 'launch %cmdRing %inputs': + 'starte %cmdRing %inputs', + 'call %repRing %inputs': + 'rufe %repRing auf %inputs', + 'run %cmdRing w/continuation': + 'f\u00fchre %cmdRing mit Continuation aus', + 'call %cmdRing w/continuation': + 'rufe %cmdRing mit Continuation auf', + 'warp %c': + 'Warp %c', + 'when I start as a clone': + 'Wenn ich geklont werde', + 'create a clone of %cln': + 'klone %cln', + 'myself': + 'mich', + 'delete this clone': + 'entferne diesen Klon', + + // sensing: + 'touching %col ?': + '%col తాకుతుందా?', + 'touching %clr ?': + '%clr రంగును తాకుతుందా?', + 'color %clr is touching %clr ?': + '%clr రంగు %clr తాకుతుందా?', + 'ask %s and wait': + '%s అడిగి, వేచియుండ', + 'what\'s your name?': + 'నీ పేరు ఏమిటి?', + 'answer': + 'సమాధాన', + 'mouse x': + 'మౌస్ x', + 'mouse y': + 'మౌస్ y', + 'mouse down?': + 'మౌస్ ఒత్తారా?', + 'key %key pressed?': + '%key కీ ఒత్తారా?', + 'distance to %dst': + '%dst కు దూరం', + 'reset timer': + 'సమయసూచిని మళ్ళీ పెట్', + 'timer': + 'సమయసూచి', + '%att of %spr': + '%att లో %spr', + 'http:// %s': + 'http:// %s', + 'turbo mode?': + 'Turbomodus?', + 'set turbo mode to %b': + 'setze Turbomodus auf %b', + + 'filtered for %clr': + 'nach %clr gefiltert', + 'stack size': + 'Stapelgr\u00f6\u00dfe', + 'frames': + 'Rahmenz\u00e4hler', + + // operators: + '%n mod %n': + '%n శేష %n', + 'round %n': + '%n గుండ్రమ', + '%fun of %n': + '%fun లో %n', + 'pick random %n to %n': + '%n నుండి %n ను యాదృచ్ఛికంగా ఎంచుకోండి', + '%b and %b': + '%b మరియ %b', + '%b or %b': + '%b లేదా %b', + 'not %b': + 'లేద %b', + 'true': + 'సత్', + 'false': + 'తప్', + 'join %words': + 'కలుప %words', + 'split %s by %delim': + 'trenne %s nach %delim', + 'hello': + 'హలో', + 'world': + 'ప్రపంచం', + 'letter %n of %s': + 'Zeichen %n von %s', + 'length of %s': + 'L\u00e4nge von %s', + 'unicode of %s': + 'Unicode Wert von %s', + 'unicode %n as letter': + 'Unicode %n als Buchstabe', + 'is %s a %typ ?': + 'ist %s ein(e) %typ ?', + 'is %s identical to %s ?': + 'ist %s identisch mit %s ?', + + 'type of %s': + 'Typ von %s', + + // variables: + 'Make a variable': + 'చరరాశిని కల్పించు', + 'Variable name': + 'చరరాశి పేరు ?', + 'Script variable name': + 'Skriptvariablenname', + 'Delete a variable': + 'చరరాశిని తొలగించ', + + 'set %var to %s': + '%var లో %s ను పెట్', + 'change %var by %n': + '%var మార్చడానికి %n', + 'show variable %var': + 'చరరాశి %var ను చూప', + 'hide variable %var': + '%var చరరాశిని దాచు', + 'script variables %scriptVars': + 'Skriptvariablen %scriptVars', + + // lists: + 'list %exp': + 'Liste %exp', + '%s in front of %l': + '%s am Anfang von %l', + 'item %idx of %l': + 'Element %idx von %l', + 'all but first of %l': + 'alles au\u00dfer dem ersten von %l', + 'length of %l': + 'L\u00e4nge von %l', + '%l contains %s': + '%l enth\u00e4lt %s', + 'thing': + 'etwas', + 'add %s to %l': + 'f\u00fcge %s zu %l hinzu', + 'delete %ida of %l': + 'entferne %ida aus %l', + 'insert %s at %idx of %l': + 'f\u00fcge %s als %idx in %l ein', + 'replace item %idx of %l with %s': + 'ersetze Element %idx in %l durch %s', + + // other + 'Make a block': + 'Neuer Block', + + // menus + // snap menu + 'About...': + '\u00dcber Snap!...', + 'Reference manual': + 'Handbuch lesen', + 'Snap! website': + 'Snap! Webseite', + 'Download source': + 'Quellcode runterladen', + 'Switch back to user mode': + 'zur\u00fcck zum Benutzermodus', + 'disable deep-Morphic\ncontext menus\nand show user-friendly ones': + 'verl\u00e4sst Morphic', + 'Switch to dev mode': + 'zum Hackermodus wechseln', + 'enable Morphic\ncontext menus\nand inspectors,\nnot user-friendly!': + 'erm\u00f6glicht Morphic Funktionen', + + // project menu + 'Project notes...': + 'రాజెక్ట్ గమనికల...', + 'New': + 'కొత్', + 'Open...': + 'తెరువ...', + 'Save': + 'సేవ్ చేయ', + 'Save As...': + 'వదిలేయడానికి ముందు మార్పులను సేవ్ చేయ...', + 'Import...': + 'దిగుమతి...', + 'file menu import hint': + 'l\u00e4dt ein exportiertes Projekt,\neine Bibliothek mit ' + + 'Bl\u00f6cken\n' + + 'ein Kost\u00fcm oder einen Klang', + 'Export project as plain text...': + 'Projekt als normalen Text exportieren...', + 'Export project...': + 'Projekt exportieren...', + 'show project data as XML\nin a new browser window': + 'zeigt das Projekt als XML\nin einem neuen Browserfenster an', + 'Export blocks...': + 'Bl\u00f6cke exportieren...', + 'show global custom block definitions as XML\nin a new browser window': + 'zeigt globale Benutzerblockdefinitionen\nals XML im Browser an', + 'Import tools': + 'Tools laden', + 'load the official library of\npowerful blocks': + 'das offizielle Modul mit\nm\u00e4chtigen Bl\u00f6cken laden', + 'Libraries...': + 'Module...', + 'Import library': + 'Modul laden', + + // cloud menu + 'Login...': + 'Anmelden...', + 'Signup...': + 'Benutzerkonto einrichten...', + + // settings menu + 'Language...': + 'భాష...', + 'Zoom blocks...': + 'Bl\u00f6cke vergr\u00f6\u00dfern...', + 'Stage size...': + 'B\u00fchnengr\u00f6\u00dfe...', + 'Stage size': + 'B\u00fchnengr\u00f6\u00dfe', + 'Stage width': + 'B\u00fchnenbreite', + 'Stage height': + 'B\u00fchnenh\u00f6he', + 'Default': + 'Normal', + 'Blurred shadows': + 'Weiche Schatten', + 'uncheck to use solid drop\nshadows and highlights': + 'abschalten f\u00fcr harte Schatten\nund Beleuchtung', + 'check to use blurred drop\nshadows and highlights': + 'einschalten f\u00fcr harte Schatten\nund Beleuchtung', + 'Zebra coloring': + 'Zebrafarben', + 'check to enable alternating\ncolors for nested blocks': + 'einschalten \u00fcr abwechselnde Farbnuancen\nin Bl\u00f6cken', + 'uncheck to disable alternating\ncolors for nested block': + 'ausschalten verhindert abwechselnde\nFarbnuancen in Bl\u00f6cken', + 'Dynamic input labels': + 'Eingabenbeschriftung', + 'uncheck to disable dynamic\nlabels for variadic inputs': + 'ausschalten verhindert Beschriftung\nvon Mehrfacheingaben', + 'check to enable dynamic\nlabels for variadic inputs': + 'einschalten um Mehrfacheingabefelder\nautomatisch zu beschriften', + 'Prefer empty slot drops': + 'Leere Platzhalter bevorzugen', + 'settings menu prefer empty slots hint': + 'einschalten um leere Platzhalter\nbeim Platzieren von Bl\u00f6cken' + + 'zu bevorzugen', + 'uncheck to allow dropped\nreporters to kick out others': + 'ausschalten um das "Rauskicken"\nvon platzierten Bl\u00f6cken\n' + + 'zu erm\u00f6glichen', + 'Long form input dialog': + 'Ausf\u00fchrlicher Input-Dialog', + 'Plain prototype labels': + 'Einfache Prototyp-Beschriftung', + 'uncheck to always show (+) symbols\nin block prototype labels': + 'ausschalten, um (+) Zeichen\nim Blockeditor zu verbergen', + 'check to hide (+) symbols\nin block prototype labels': + 'einschalten, um (+) Zeichen\nim Blockeditor immer anzuzeigen', + 'check to always show slot\ntypes in the input dialog': + 'einschalten, um immer die Datentypen\nim Input-Dialog zu sehen', + 'uncheck to use the input\ndialog in short form': + 'ausschalten f\u00fcr kurzen\nInput-Dialog', + 'Virtual keyboard': + 'Virtuelle Tastatur', + 'uncheck to disable\nvirtual keyboard support\nfor mobile devices': + 'ausschalten um die virtuelle\nTastatur auf mobilen Ger\u00e4ten\n' + + 'zu sperren', + 'check to enable\nvirtual keyboard support\nfor mobile devices': + 'einschalten um die virtuelle\nTastatur auf mobilen Ger\u00e4ten\n' + + 'zu erm\u00f6glichen', + 'Input sliders': + 'Eingabeschieber', + 'uncheck to disable\ninput sliders for\nentry fields': + 'ausschalten um Schieber\nin Eingabefeldern zu verhindern', + 'check to enable\ninput sliders for\nentry fields': + 'einschalten um Schieber\nin Eingabefeldern zu aktivieren', + 'Clicking sound': + 'Akustisches Klicken', + 'uncheck to turn\nblock clicking\nsound off': + 'ausschalten um akustisches\nKlicken zu deaktivieren', + 'check to turn\nblock clicking\nsound on': + 'einschalten um akustisches\nKlicken zu aktivieren', + 'Animations': + 'ఆనిమేషన్ (సజీవత్వము)', + 'uncheck to disable\nIDE animations': + 'ausschalten um IDE-\nAnimationen zu verhindern', + 'Turbo mode': + 'Turbomodus', + 'check to prioritize\nscript execution': + 'einschalten, um Skripte\nzu priorisieren', + 'uncheck to run scripts\nat normal speed': + 'ausschalten, um Skripte\nnormal auszuf\u00fchren', + 'check to enable\nIDE animations': + 'einschalten um IDE-\nAnimationen zu erlauben', + 'Thread safe scripts': + 'Threadsicherheit', + 'uncheck to allow\nscript reentrance': + 'verhindert, dass unvollendete\nSkripte erneut gestartet werden', + 'check to disallow\nscript reentrance': + 'verhindert, dass unvollendete\nSkripte erneut gestartet werden', + 'Prefer smooth animations': + 'Fixe Framerate', + 'uncheck for greater speed\nat variable frame rates': + 'ausschalten, um Animationen \ndynamischer auszuf\u00fchren', + 'check for smooth, predictable\nanimations across computers': + 'einschalten, damit Animationen\n\u00fcberall gleich laufen', + 'Flat line ends': + 'Flache Pinselstriche', + 'check for flat ends of lines': + 'einschalten f\u00fcr flache\nPinselstrichenden', + 'uncheck for round ends of lines': + 'auschalten f\u00fcr runde\nPinselstrichenden', + + // inputs + 'with inputs': + 'mit Eingaben', + 'input names:': + 'Eingaben:', + 'Input Names:': + 'Eingaben:', + 'input list:': + 'Eingabeliste:', + + // context menus: + 'help': + 'సహాయ', + + // palette: + 'hide primitives': + 'Basisbl\u00f6cke ausblenden', + 'show primitives': + 'Basisbl\u00f6cke anzeigen', + + // blocks: + 'help...': + 'సహాయ...', + 'relabel...': + 'Umbenennen...', + 'duplicate': + 'నకల', + 'make a copy\nand pick it up': + 'eine Kopie aufnehmen', + 'only duplicate this block': + 'nur diesen Block duplizieren', + 'delete': + 'తొలగించ', + 'script pic...': + 'Skriptbild...', + 'open a new window\nwith a picture of this script': + 'ein neues Browserfenster mit einem\nBild dieses Skripts \u00f6ffnen', + 'ringify': + 'Umringen', + 'unringify': + 'Entringen', + + // custom blocks: + 'delete block definition...': + 'Blockdefinition l\u00f6schen', + 'edit...': + 'సవరించ...', + + // sprites: + 'edit': + 'సవరించ', + 'move': + 'జరుగ', + 'detach from': + 'Abtrennen von', + 'detach all parts': + 'Alle Teile abtrennen', + 'export...': + 'ఎగుమతి...', + + // stage: + 'show all': + 'Alles zeigen', + 'pic...': + 'Bild exportieren...', + 'open a new window\nwith a picture of the stage': + 'ein neues Browserfenster mit einem\nBild der B\u00fchne \u00f6ffnen', + + // scripting area + 'clean up': + 'శుభ్రం చేయ', + 'arrange scripts\nvertically': + 'Skripte der Reihe nach\nanordnen', + 'add comment': + 'వ్యాఖ్యానించ', + 'undrop': + 'R\u00fcckg\u00e4ngig', + 'undo the last\nblock drop\nin this pane': + 'Setzen des letzten Blocks\nwiderrufen', + 'scripts pic...': + 'Bild aller Scripte...', + 'open a new window\nwith a picture of all scripts': + 'ein neues Browserfenster mit einem\nBild aller Skripte \u00f6ffnen', + 'make a block...': + 'Neuen Block bauen...', + + // costumes + 'rename': + 'Umbenennen', + 'export': + 'ఎగుమతి', + 'rename costume': + 'Kost\u00fcm umbenennen', + + // sounds + 'Play sound': + 'శబ్దం వాయించ', + 'Stop sound': + 'Klang\nanhalten', + 'Stop': + 'ఆప', + 'Play': + 'ఆడ', + 'rename sound': + 'Klang umbenennen', + + // dialogs + // buttons + 'OK': + 'సరే', + 'Ok': + 'సరే', + 'Cancel': + 'రద్', + 'Yes': + 'అవున', + 'No': + 'లేద', + + // help + 'Help': + 'సహాయ', + + // zoom blocks + 'Zoom blocks': + 'Bl\u00f6cke vergr\u00f6\u00dfern', + 'build': + 'baue', + 'your own': + 'eigene', + 'blocks': + 'Bl\u00f6cke', + 'normal (1x)': + 'normal (1x)', + 'demo (1.2x)': + 'Demo (1.2x)', + 'presentation (1.4x)': + 'Pr\u00e4sentation (1.4x)', + 'big (2x)': + 'gro\u00df (2x)', + 'huge (4x)': + 'riesig (4x)', + 'giant (8x)': + 'gigantisch (8x)', + 'monstrous (10x)': + 'ungeheuerlich (10x)', + + // Project Manager + 'Untitled': + 'Unbenannt', + 'Open Project': + 'Project \u00f6ffnen', + '(empty)': + '(leer)', + 'Saved!': + 'Gesichert!', + 'Delete Project': + 'Projekt l\u00f6schen', + 'Are you sure you want to delete': + 'Wirklich l\u00f6schen?', + 'rename...': + 'Umbenennen...', + + // costume editor + 'Costume Editor': + 'Kost\u00fcmeditor', + 'click or drag crosshairs to move the rotation center': + 'Fadenkreuz anklicken oder bewegen um den Drehpunkt zu setzen', + + // project notes + 'Project Notes': + '"ప్రాజెక్ట్ గమనికల', + + // new project + 'New Project': + 'Neues Projekt', + 'Replace the current project with a new one?': + 'Das aktuelle Projekt durch ein neues ersetzen?', + + // save project + 'Save Project As...': + 'Projekt Sichern Als...', + + // export blocks + 'Export blocks': + 'Bl\u00f6cke exportieren', + 'Import blocks': + 'Bl\u00f6cke importieren', + 'this project doesn\'t have any\ncustom global blocks yet': + 'in diesem Projekt gibt es noch keine\nglobalen Bl\u00f6cke', + 'select': + 'ausw\u00e4hlen', + 'none': + 'nichts', + + // variable dialog + 'for all sprites': + 'f\u00fcr alle', + 'for this sprite only': + 'nur f\u00fcr dieses Objekt', + + // block dialog + 'Change block': + 'Block ver\u00e4ndern', + 'Command': + 'Befehl', + 'Reporter': + 'Funktion', + 'Predicate': + 'Pr\u00e4dikat', + + // block editor + 'Block Editor': + 'Blockeditor', + 'Apply': + 'Anwenden', + + // block deletion dialog + 'Delete Custom Block': + 'Block L\u00f6schen', + 'block deletion dialog text': + 'Soll dieser Block mit allen seinen Exemplare\n' + + 'wirklich gel\u00f6scht werden?', + + // input dialog + 'Create input name': + 'Eingabe erstellen', + 'Edit input name': + 'Eingabe bearbeiten', + 'Edit label fragment': + 'Beschriftung bearbeiten', + 'Title text': + 'Beschriftung', + 'Input name': + 'Eingabe', + 'Delete': + 'L\u00f6schen', + 'Object': + 'Objekt', + 'Number': + 'Zahl', + 'Text': + 'Text', + 'List': + 'Liste', + 'Any type': + 'Beliebig', + 'Boolean (T/F)': + 'Boolsch (W/F)', + 'Command\n(inline)': + 'Befehl', + 'Command\n(C-shape)': + 'Befehl\n(C-Form)', + 'Any\n(unevaluated)': + 'Beliebig\n(zitiert)', + 'Boolean\n(unevaluated)': + 'Boolsch\n(zitiert)', + 'Single input.': + 'Einzeleingabe.', + 'Default Value:': + 'Standardwert:', + 'Multiple inputs (value is list of inputs)': + 'Mehrere Eingaben (als Liste)', + 'Upvar - make internal variable visible to caller': + 'Interne Variable au\u00dfen sichtbar machen', + + // About Snap + 'About Snap': + '\u00dcber Snap', + 'Back...': + 'Zur\u00fcck...', + 'License...': + 'Lizenz...', + 'Modules...': + 'Komponenten...', + 'Credits...': + 'Mitwirkende...', + 'Translators...': + '\u00dcbersetzer', + 'License': + 'Lizenz', + 'current module versions:': + 'Komponenten-Versionen', + 'Contributors': + 'Mitwirkende', + 'Translations': + '\u00dcbersetzungen', + + // variable watchers + 'normal': + 'normal', + 'large': + 'gro\u00df', + 'slider': + 'Regler', + 'slider min...': + 'Minimalwert...', + 'slider max...': + 'Maximalwert...', + 'import...': + 'Importieren...', + 'Slider minimum value': + 'Minimalwert des Reglers', + 'Slider maximum value': + 'Maximalwert des Reglers', + + // list watchers + 'length: ': + 'L\u00e4nge: ', + + // coments + 'add comment here...': + 'Anmerkung hier hinzuf\u00fcgen', + + // drow downs + // directions + '(90) right': + '(90) rechts', + '(-90) left': + '(-90) links', + '(0) up': + '(0) oben', + '(180) down': + '(180) unten', + + // collision detection + 'mouse-pointer': + 'Mauszeiger', + 'edge': + 'Kante', + 'pen trails': + 'Malspuren', + + // costumes + 'Turtle': + 'Richtungszeiger', + 'Empty': + 'Leer', + + // graphical effects + 'brightness': + 'Helligeit', + 'ghost': + 'Durchsichtigkeit', + 'negative': + 'Farbumkehr', + 'comic': + 'Moire', + 'confetti': + 'Farbverschiebung', + + // keys + 'space': + 'Leertaste', + 'up arrow': + 'Pfeil nach oben', + 'down arrow': + 'Pfeil nach unten', + 'right arrow': + 'Pfeil nach rechts', + 'left arrow': + 'Pfeil nach links', + 'a': + 'a', + 'b': + 'b', + 'c': + 'c', + 'd': + 'd', + 'e': + 'e', + 'f': + 'f', + 'g': + 'g', + 'h': + 'h', + 'i': + 'i', + 'j': + 'j', + 'k': + 'k', + 'l': + 'l', + 'm': + 'm', + 'n': + 'n', + 'o': + 'o', + 'p': + 'p', + 'q': + 'q', + 'r': + 'r', + 's': + 's', + 't': + 't', + 'u': + 'u', + 'v': + 'v', + 'w': + 'w', + 'x': + 'x', + 'y': + 'y', + 'z': + 'z', + '0': + '0', + '1': + '1', + '2': + '2', + '3': + '3', + '4': + '4', + '5': + '5', + '6': + '6', + '7': + '7', + '8': + '8', + '9': + '9', + + // messages + 'new...': + 'Neu...', + + // math functions + 'abs': + 'Betrag', + 'floor': + 'Abgerundet', + 'sqrt': + 'Wurzel', + 'sin': + 'sin', + 'cos': + 'cos', + 'tan': + 'tan', + 'asin': + 'asin', + 'acos': + 'acos', + 'atan': + 'atan', + 'ln': + 'ln', + 'e^': + 'e^', + + // delimiters + 'letter': + 'Buchstabe', + 'whitespace': + 'Leerraum', + 'line': + 'Zeilenvorschub', + 'tab': + 'Tabulator', + 'cr': + 'Wagenr\u00fccklauf', + + // data types + 'number': + 'Zahl', + 'text': + 'Text', + 'Boolean': + 'Boole', + 'list': + 'Liste', + 'command': + 'Befehlsblock', + 'reporter': + 'Funktionsblock', + 'predicate': + 'Pr\u00e4dikat', + + // list indices + 'last': + 'letztes', + 'any': + 'beliebiges' +}; diff --git a/lang-tr.js b/lang-tr.js new file mode 100644 index 00000000..0b852bbd --- /dev/null +++ b/lang-tr.js @@ -0,0 +1,1275 @@ +/* + + lang-de.js + + German translation for SNAP! + + written by Jens Mönig + + Copyright (C) 2012 by Jens Mönig + + This file is part of Snap!. + + Snap! is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + + + + Note to Translators: + -------------------- + At this stage of development, Snap! can be translated to any LTR language + maintaining the current order of inputs (formal parameters in blocks). + + Translating Snap! is easy: + + + 1. Download + + Download the sources and extract them into a local folder on your + computer: + + + + Use the German translation file (named 'lang-de.js') as template for your + own translations. Start with editing the original file, because that way + you will be able to immediately check the results in your browsers while + you're working on your translation (keep the local copy of snap.html open + in your web browser, and refresh it as you progress with your + translation). + + + 2. Edit + + Edit the translation file with a regular text editor, or with your + favorite JavaScript editor. + + In the first non-commented line (the one right below this + note) replace "de" with the two-letter ISO 639-1 code for your language, + e.g. + + fr - French => SnapTranslator.dict.fr = { + it - Italian => SnapTranslator.dict.it = { + pl - Polish => SnapTranslator.dict.pl = { + pt - Portuguese => SnapTranslator.dict.pt = { + es - Spanish => SnapTranslator.dict.es = { + el - Greek => => SnapTranslator.dict.el = { + + etc. (see ) + + + 3. Translate + + Then work through the dictionary, replacing the German strings against + your translations. The dictionary is a straight-forward JavaScript ad-hoc + object, for review purposes it should be formatted as follows: + + { + 'English string': + 'Translation string', + 'last key': + } 'last value' + + and you only edit the indented value strings. Note that each key-value + pair needs to be delimited by a comma, but that there shouldn't be a comma + after the last pair (again, just overwrite the template file and you'll be + fine). + + If something doesn't work, or if you're unsure about the formalities you + should check your file with + + + + This will inform you about any missed commas etc. + + + 4. Accented characters + + Depending on which text editor and which file encoding you use you can + directly enter special characters (e.g. Umlaut, accented characters) on + your keyboard. However, I've noticed that some browsers may not display + special characters correctly, even if other browsers do. So it's best to + check your results in several browsers. If you want to be on the safe + side, it's even better to escape these characters using Unicode. + + see: + + + 5. Block specs: + + At this time your translation of block specs will only work + correctly, if the order of formal parameters and their types + are unchanged. Placeholders for inputs (formal parameters) are + indicated by a preceding % prefix and followed by a type + abbreviation. + + For example: + + 'say %s for %n secs' + + can currently not be changed into + + 'say %n secs long %s' + + and still work as intended. + + Similarly + + 'point towards %dst' + + cannot be changed into + + 'point towards %cst' + + without breaking its functionality. + + + 6. Submit + + When you're done, rename the edited file by replacing the "de" part of the + filename with the two-letter ISO 639-1 code for your language, e.g. + + fr - French => lang-fr.js + it - Italian => lang-it.js + pl - Polish => lang-pl.js + pt - Portuguese => lang-pt.js + es - Spanish => lang-es.js + el - Greek => => lang-el.js + + and send it to me for inclusion in the official Snap! distribution. + Once your translation has been included, Your name will the shown in the + "Translators" tab in the "About Snap!" dialog box, and you will be able to + directly launch a translated version of Snap! in your browser by appending + + lang:xx + + to the URL, xx representing your translations two-letter code. + + + 7. Known issues + + In some browsers accents or ornaments located in typographic ascenders + above the cap height are currently (partially) cut-off. + + Enjoy! + -Jens +*/ + +/*global SnapTranslator*/ + +SnapTranslator.dict.tr = { + +/* + Special characters: (see ) + + Ä, ä \u00c4, \u00e4 + Ö, ö \u00d6, \u00f6 + Ü, ü \u00dc, \u00fc + ß \u00df +*/ + + // translations meta information + 'language_name': + 'Türkçe', // the name as it should appear in the language menu + 'language_translator': + 'Hakan Atas', // your name for the Translators tab + 'translator_e-mail': + 'hakanatas@gmail.com', // optional + 'last_changed': + '2015-7-26', // this, too, will appear in the Translators tab + + // GUI + // control bar: + 'untitled': + 'adsız', + 'development mode': + 'geliştirici modu', + + // categories: + 'Motion': + 'Hareket', + 'Looks': + 'Görünümler', + 'Sound': + 'Ses', + 'Pen': + 'Kalem', + 'Control': + 'Kontrol', + 'Sensing': + 'Algılama', + 'Operators': + 'İşlemler', + 'Variables': + 'Değişkenler', + 'Lists': + 'Listeler', + 'Other': + 'Diğerleri', + + // editor: + 'draggable': + 'sürüklenebilir', + + // tabs: + 'Scripts': + 'Betikler', + 'Costumes': + 'Kostümler', + 'Sounds': + 'Sesler', + + // names: + 'Sprite': + 'Karakter', + 'Stage': + 'Sahne', + + // rotation styles: + 'don\'t rotate': + 'dönebilir', + 'can rotate': + 'dönemez', + 'only face left/right': + 'sadece sağa/sola dönebilir', + + // new sprite button: + 'add a new sprite': + 'yeni bir karakter ekle', + + // tab help + 'costumes tab help': + 'kostüm sekmesi yardımı', + 'import a sound from your computer\nby dragging it into here': + 'bilgisayarınızdan bir sesi\n' + + 'buraya sürükleyerek içeri aktarın', + + // primitive blocks: + + /* + Attention Translators: + ---------------------- + At this time your translation of block specs will only work + correctly, if the order of formal parameters and their types + are unchanged. Placeholders for inputs (formal parameters) are + indicated by a preceding % prefix and followed by a type + abbreviation. + + For example: + + 'say %s for %n secs' + + can currently not be changed into + + 'say %n secs long %s' + + and still work as intended. + + Similarly + + 'point towards %dst' + + cannot be changed into + + 'point towards %cst' + + without breaking its functionality. + */ + + // motion: + 'Stage selected:\nno motion primitives': + 'Seçili sahne:\nhareket temelleri yok', + 'move %n steps': + '%n adım git', + 'turn %clockwise %n degrees': + '%clockwise yönünde %n derece dön', + 'turn %counterclockwise %n degrees': + '%counterclockwise yönünde %n derece dön', + 'point in direction %dir': + '%dir yönüne dön', + 'point towards %dst': + '%dst e doğru dön', + 'go to x: %n y: %n': + 'x: %n y: %n git', + 'go to %dst': + '%dst git', + 'glide %n secs to x: %n y: %n': + 'x: %n y: %n noktasına %n saniyede süzül', + 'change x by %n': + 'x\'i %n değiştir', + 'set x to %n': + 'x\'i %n ayarla', + 'change y by %n': + 'y\'i %n değiştir', + 'set y to %n': + 'y\'i %n olarak ayarla', + 'if on edge, bounce': + 'kenardaysan sek', + 'x position': + 'x-pozisyonu', + 'y position': + 'y-pozisyonu', + 'direction': + 'doğrultu', + + // looks: + 'switch to costume %cst': + 'kostümü %cst olarak değiştir', + 'next costume': + 'sonraki kostüm', + 'costume #': + 'kostüm no:', + 'say %s for %n secs': + '%s saniye %n söyle', + 'say %s': + '%s söyle', + 'think %s for %n secs': + '%s saniye %n diye düşün', + 'think %s': + '%s diye düşün', + 'Hello!': + 'Merhaba!', + 'Hmm...': + 'Hmm...', + 'change %eff effect by %n': + '%eff etkisini %n değiştir', + 'set %eff effect to %n': + '%eff etkisini %n yap', + 'clear graphic effects': + 'görsel etkileri temizle', + 'change size by %n': + 'büyüklüğünü %n değiştir', + 'set size to %n %': + 'büyüklüğü % %n yap', + 'size': + 'büyüklük', + 'show': + 'göster', + 'hide': + 'gizle', + 'go to front': + 'öne git', + 'go back %n layers': + '%n katman alta in', + + 'development mode \ndebugging primitives:': + 'geliştirici modu \nhata ayıklama temelleri', + 'console log %mult%s': + 'log dosyasına yaz %mult%s', + 'alert %mult%s': + 'uyarı: %mult%s', + + // sound: + 'play sound %snd': + '%snd sesini çal', + 'play sound %snd until done': + '%snd sesini bitene kadar çal', + 'stop all sounds': + 'tüm sesleri durdur', + 'rest for %n beats': + '%n vuruş sus', + 'play note %n for %n beats': + '%n notasını %n vuruş çal', + 'change tempo by %n': + 'tempoyu %n değiştir', + 'set tempo to %n bpm': + 'tempoyu %n yap', + 'tempo': + 'tempo', + + // pen: + 'clear': + 'temizle', + 'pen down': + 'kalemi bastır', + 'pen up': + 'kalemi kaldır', + 'set pen color to %clr': + 'kalemin rengini %clr yap', + 'change pen color by %n': + 'kalemin rengini %n değiştir', + 'set pen color to %n': + 'kalemin rengini %n yap', + 'change pen shade by %n': + 'kalemin tonunu %n değiştir', + 'set pen shade to %n': + 'kalemin tonunu %n yap', + 'change pen size by %n': + 'kalemin kalınlığını %n değiştir', + 'set pen size to %n': + 'kalemin kalınlığını %n yap', + 'stamp': + 'damga', + + // control: + 'when %greenflag clicked': + '%greenflag tıklanınca', + 'when %keyHat key pressed': + '%keyHat tuşu basılınca', + 'when I am clicked': + 'bu kukla tıklanınca', + 'when I receive %msgHat': + '%msgHat haberi gelince', + 'broadcast %msg': + '%msg yayımla', + 'broadcast %msg and wait': + '%msg yayımla ve bekle', + 'Message name': + 'Mesaj adı', + 'message': + 'mesaj', + 'any message': + 'herhangi bir mesaj', + 'wait %n secs': + '%n sn bekle', + 'wait until %b': + '%b olana kadar bekle', + 'forever %c': + 'sürekli %c', + 'repeat %n %c': + '%n kere tekrarla %c', + 'repeat until %b %c': + '%b olana kadar tekrarla %c', + 'if %b %c': + 'eğer %b %c', + 'if %b %c else %c': + 'eğer %b %c değilse %c', + 'report %s': + 'rapor %s', + 'stop %stopChoices': + 'durdur %stopChoices', + 'all': + 'tümü', + 'this script': + 'bu script', + 'this block': + 'bu blok', + 'stop %stopOthersChoices': + 'durdur %stopOthersChoices', + 'all but this script': + 'bu hariç diğerleri', + 'other scripts in sprite': + 'bu karakter içindeki diğer betikler', + 'pause all %pause': + 'tümünü beklet %pause', + 'run %cmdRing %inputs': + 'çalıştır %cmdRing %inputs', + 'launch %cmdRing %inputs': + 'başlat %cmdRing %inputs', + 'call %repRing %inputs': + 'çağır %repRing %inputs', + 'run %cmdRing w/continuation': + 'çalıştır %cmdRing w/sürekli', + 'call %cmdRing w/continuation': + 'çağır %cmdRing w/sürekli', + 'warp %c': + 'çarpıtmak %c', + 'when I start as a clone': + 'Klon olarak başlatığında', + 'create a clone of %cln': + '%cln klonunu oluştur', + 'myself': + 'kendim', + 'delete this clone': + 'bu klonu sil', + + // sensing: + 'touching %col ?': + '%col a değiyor mu?', + 'touching %clr ?': + '%clr rengine değiyor mu?', + 'color %clr is touching %clr ?': + '%clr rengi %clr rengine değdi mi?', + 'ask %s and wait': + '%s sor ve bekle', + 'what\'s your name?': + 'adınız ne?', + 'answer': + 'cevap', + 'mouse x': + 'Fare x-konumu', + 'mouse y': + 'Fare y-konumu', + 'mouse down?': + 'fareye basılı mı?', + 'key %key pressed?': + '%key tuşu basılı mı?', + 'distance to %dst': + '%dst a mesafe', + 'reset timer': + 'zamanlayıcıyı sıfırla', + 'timer': + 'zamanlayıcı', + '%att of %spr': + '%spr nun %att ', + 'http:// %s': + 'http:// %s', + 'turbo mode?': + 'Turbomod?', + 'set turbo mode to %b': + 'turbo modu %b yap', + + 'filtered for %clr': + '%clr için filtrele', + 'stack size': + 'yığın büyüklüğü', + 'frames': + 'çerçeveler', + + // operators: + '%n mod %n': + '%n mod %n', + 'round %n': + '%n yuvarla', + '%fun of %n': + '%fun un %n si', + 'pick random %n to %n': + '%n ile %n arasında rastgele bir sayı seç', + '%b and %b': + '%b ve %b', + '%b or %b': + '%b veya %b', + 'not %b': + '%b değil', + 'true': + 'doğru', + 'false': + 'yanlış', + 'join %words': + '%words birleştir', + 'split %s by %delim': + 'parçala ayır %s , %delim e gore', + 'hello': + 'merhaba', + 'world': + 'dünya', + 'letter %n of %s': + '%n in harfleri %s', + 'length of %s': + '%s in uzunluğu', + 'unicode of %s': + '%s in unicode hali', + 'unicode %n as letter': + 'harf olarak %n in unicode hali', + 'is %s a %typ ?': + '%s bir %typ mi?', + 'is %s identical to %s ?': + '%s ile %s aynı mı?', + + 'type of %s': + '%s un tipi', + + // variables: + 'Make a variable': + 'Değişken oluştur', + 'Variable name': + 'Değişken adı', + 'Script variable name': + 'Script değişken adı', + 'Delete a variable': + 'Değişkeni sil', + + 'set %var to %s': + '%var %s olsun', + 'change %var by %n': + '%var i %n değiştir', + 'show variable %var': + '%var değişkenini göster', + 'hide variable %var': + '%var değişkenini gizle', + 'script variables %scriptVars': + '%scriptVars script değişkenleri', + + // lists: + 'list %exp': + 'Liste %exp', + '%s in front of %l': + '%s nin %l önündeki', + 'item %idx of %l': + 'item %idx of %l', + 'all but first of %l': + '%l in ilk elemanı hariç tümü', + 'length of %l': + '%l nin uzunluğu', + '%l contains %s': + '%l %s i içeriyor', + 'thing': + 'şey', + 'add %s to %l': + '%s i %l ye ekle', + 'delete %ida of %l': + 'sil %ida nın %l', + 'insert %s at %idx of %l': + 'ekle %s %idx indeksine %l listesinin', + 'replace item %idx of %l with %s': + 'yer değiştir %idx %l listesinin %s ile', + + // other + 'Make a block': + 'Yeni bir blok oluştur', + + // menus + // snap menu + 'About...': + 'Snap Hakkında!...', + 'Reference manual': + 'El kitapçığı', + 'Snap! website': + 'Snap! web sitesi', + 'Download source': + 'Indirilebilir kaynak', + 'Switch back to user mode': + 'Kullanıcı moduna geri dön', + 'disable deep-Morphic\ncontext menus\nand show user-friendly ones': + 'verl\u00e4sst Morphic', + 'Switch to dev mode': + 'geliştirici moduna dön', + 'enable Morphic\ncontext menus\nand inspectors,\nnot user-friendly!': + 'etkinleştir Morfik\niçerik menüsü\nve gözlemleme\nkullanıcı dostu değil ', + + // project menu + 'Project notes...': + 'Proje notları...', + 'New': + 'Yeni', + 'Open...': + 'Aç...', + 'Save': + 'Kaydet', + 'Save As...': + 'Farklı kaydet...', + 'Import...': + 'İçeri aktar...', + 'file menu import hint': + 'dosya menü içeri aktar ipucu', + 'Export project as plain text...': + 'Düz metin olarak projeyi dışarı aktar...', + 'Export project...': + 'Projeyi dışarı aktar...', + 'show project data as XML\nin a new browser window': + 'Yeni bir pencerede\nproje verilerini XML olarak göster', + 'Export blocks...': + 'Blokları dışarı aktar...', + 'show global custom block definitions as XML\nin a new browser window': + 'blok tanımlarını XML dosyası olarak\nyeni bir pencerede göster', + 'Import tools': + 'Araçları içeri aktar', + 'load the official library of\npowerful blocks': + 'güçlü blokların\nresmi kütüphanesini yükletin', + 'Libraries...': + 'Kütüphaneler...', + 'Import library': + 'Kütüphaneyi içeri aktar', + + // cloud menu + 'Login...': + 'Giriş yap...', + 'Signup...': + 'Kayıt ol...', + + // settings menu + 'Language...': + 'Dil...', + 'Zoom blocks...': + 'Yaklaşma blokları...', + 'Stage size...': + 'Sahne büyüklüğü...', + 'Stage size': + 'Sahne büyüküğü', + 'Stage width': + 'Sahne genişliği', + 'Stage height': + 'Sahne yüksekliği', + 'Default': + 'Varsayılan', + 'Blurred shadows': + 'Bulanış gölgeler', + 'uncheck to use solid drop\nshadows and highlights': + 'katı gölge ve ışıkları kullanmak için seçimi kaldırın', + 'check to use blurred drop\nshadows and highlights': + 'gölge ve ışıkları bulanık hale getirmek için\nseçim yapın', + 'Zebra coloring': + 'çizgili boyama', + 'check to enable alternating\ncolors for nested blocks': + 'iç içe bloklarda değişmeli renkler için\ntik atın', + 'uncheck to disable alternating\ncolors for nested block': + 'iç içe bloklarda değişmeli renkleri\n kaldırmak için seçimi kaldırın', + 'Dynamic input labels': + 'Dinamik girdi etiketleri', + 'uncheck to disable dynamic\nlabels for variadic inputs': + 'farklı girdiler için dinamik etkiletlemeyi\nkaldırmak için seçimi kaldırın', + 'check to enable dynamic\nlabels for variadic inputs': + 'farklı girdiler için dinamik etkiletlemeyi\netkinleştirmek için seçimi kaldırın', + 'Prefer empty slot drops': + 'Boş slotları tercih et', + 'settings menu prefer empty slots hint': + 'boş slotlar için menü ayarları', + 'uncheck to allow dropped\nreporters to kick out others': + 'uncheck to allow dropped\nreporters to kick out others', + 'Long form input dialog': + 'girdi dialogları için uzun form', + 'Plain prototype labels': + 'Düz protatip etkiletleri', + 'uncheck to always show (+) symbols\nin block prototype labels': + 'prototip etiketinde (+) sembolünün\ngörünmesi için seçimi kaldırın', + 'check to hide (+) symbols\nin block prototype labels': + 'prototip etiketinde (+) sembolünün\ngizlenmesi için seçin', + 'check to always show slot\ntypes in the input dialog': + 'girdi dialoglarında\ntipinin görünmesi için seçin', + 'uncheck to use the input\ndialog in short form': + 'girdi dialoglarını kısa form\nolarak kullanmak için seçimi kaldırın', + 'Virtual keyboard': + 'Sanal klavye', + 'uncheck to disable\nvirtual keyboard support\nfor mobile devices': + 'mobil araçlar için\nsanal klavye desteğini\nkaldırmak için seçimi kaldırın', + 'check to enable\nvirtual keyboard support\nfor mobile devices': + 'mobil araçlar için\nsanal klavye desteğini\naktifleştirmek için seçin', + 'Input sliders': + 'Girdi sürgüleri', + 'uncheck to disable\ninput sliders for\nentry fields': + 'girdi alanlarındanki girdi sürgülerini etkisizleştirmek için seçimi kaldırın', + 'check to enable\ninput sliders for\nentry fields': + 'girdi alanlarındanki girdi sürgülerini etkisizleştirmek için seçin', + 'Clicking sound': + 'Sesi tıklayın', + 'uncheck to turn\nblock clicking\nsound off': + 'sesi kapatmak için\nseçimi kaldırın', + 'check to turn\nblock clicking\nsound on': + 'sesi açmak için\nseçim yapın', + 'Animations': + 'Animasyonlar', + 'uncheck to disable\nIDE animations': + 'animasyonları etkisezliştirmek için\nseçimi kaldırın', + 'Turbo mode': + 'Turbo Mod', + 'check to prioritize\nscript execution': + 'Betikleme çalışmasına öncelik\nvermek için seçim yapın', + 'uncheck to run scripts\nat normal speed': + 'betiklemelerin normal hızla çalışması\niçin seçimi kaldırın', + 'check to enable\nIDE animations': + 'IDE animasyonlarını\naktifleştirmek için seçim yapın', + 'Thread safe scripts': + 'Güvenli betik parçacığı', + 'uncheck to allow\nscript reentrance': + 'betiklemeye tekrar girişe\nizin vermek için seçimi kaldırın', + 'check to disallow\nscript reentrance': + 'vbetiklemeye tekrar girişe\nizin vermemek için seçimi kaldırın', + 'Prefer smooth animations': + 'Pürüzsüz animayonu tercih et', + 'uncheck for greater speed\nat variable frame rates': + 'çerçevelerin daha hızlanması\niçin seçimi kaldırın', + 'check for smooth, predictable\nanimations across computers': + 'bilgisayarlar arası düz,tahmin edilebilir\nanimasyonlar için seçim yapın', + 'Flat line ends': + 'Düz çizgi bitimleri', + 'check for flat ends of lines': + 'düz biten bitim çizgileri\niçin seçin', + 'uncheck for round ends of lines': + 'yumuşak köşeli bitim çizgileri\niçin seçimi kaldırın', + + // inputs + 'with inputs': + 'girdi ile', + 'input names:': + 'girdi isimleri:', + 'Input Names:': + 'girdi isimleri:', + 'input list:': + 'girdi listesi:', + + // context menus: + 'help': + 'yardım', + + // palette: + 'hide primitives': + 'primitifleri gizle', + 'show primitives': + 'primitifleri göster', + + // blocks: + 'help...': + 'yardım...', + 'relabel...': + 'yeniden adlandır...', + 'duplicate': + 'kopyala', + 'make a copy\nand pick it up': + 'kopya oluştur\nve onu al', + 'only duplicate this block': + 'sadece bu bloğun kopyasını oluştur', + 'delete': + 'sil', + 'script pic...': + 'betik resmi...', + 'open a new window\nwith a picture of this script': + 'bu betiğin resmini\n yeni bir pencerede açın', + 'ringify': + 'ringify', + 'unringify': + 'unringify', + + // custom blocks: + 'delete block definition...': + 'blok tanımlarını sil...', + 'edit...': + 'düzenle...', + + // sprites: + 'edit': + 'düzenle', + 'move': + 'hareket et', + 'detach from': + 'parçayı ayır', + 'detach all parts': + 'tüm parçaları ayır', + 'export...': + 'dşıarı aktar...', + + // stage: + 'show all': + 'hepsini göster', + 'pic...': + 'resimler...', + 'open a new window\nwith a picture of the stage': + 'sahnenin bir resmi ile\n yeni bir pence aç', + + // scripting area + 'clean up': + 'temizle', + 'arrange scripts\nvertically': + 'scriptleri dikey olarak düzenle', + 'add comment': + 'yorum ekle', + 'undrop': + 'bırak', + 'undo the last\nblock drop\nin this pane': + 'levhaya bıraktığın\n son bloğu geri al', + 'scripts pic...': + 'script resimleri...', + 'open a new window\nwith a picture of all scripts': + 'tüm scriptleri bir resim ile\n yeni bir pencerede aç', + 'make a block...': + 'bir blok oluştur...', + + // costumes + 'rename': + 'yeniden adlandır', + 'export': + 'dışarı aktar', + 'rename costume': + 'Köstümü yeniden adlandır', + + // sounds + 'Play sound': + 'Sesi oynat', + 'Stop sound': + 'Sesi durdur', + 'Stop': + 'Durdur', + 'Play': + 'Oyna', + 'rename sound': + 'sesi yeniden adlandır', + + // dialogs + // buttons + 'OK': + 'TAMAM', + 'Ok': + 'Tamam', + 'Cancel': + 'İptal', + 'Yes': + 'Evet', + 'No': + 'Hayır', + + // help + 'Help': + 'Yardım', + + // zoom blocks + 'Zoom blocks': + 'Yakınlaştırma blokları', + 'build': + 'inşaa et', + 'your own': + 'kendinizin', + 'blocks': + 'blokları', + 'normal (1x)': + 'normal (1x)', + 'demo (1.2x)': + 'Demo (1.2x)', + 'presentation (1.4x)': + 'Sunum (1.4x)', + 'big (2x)': + 'büyük (2x)', + 'huge (4x)': + 'kocaman (4x)', + 'giant (8x)': + 'devasa (8x)', + 'monstrous (10x)': + 'çok büyük (10x)', + + // Project Manager + 'Untitled': + 'Adsız', + 'Open Project': + 'Projec aç', + '(empty)': + '(boş)', + 'Saved!': + 'Kaydedildi!', + 'Delete Project': + 'Projeyi sil', + 'Are you sure you want to delete': + 'Silmek istediğinize emin misiniz?', + 'rename...': + 'yeniden adlandır...', + + // costume editor + 'Costume Editor': + 'Kostüm editörü', + 'click or drag crosshairs to move the rotation center': + 'dönme merkezini hareket ettirmek için referans noktasına tıklayın ya da sürükleyin', + + // project notes + 'Project Notes': + 'Proje Notları', + + // new project + 'New Project': + 'Yeni proje', + 'Replace the current project with a new one?': + 'Şu an ki projeyi yenisiyle değiştirelim mi?', + + // save project + 'Save Project As...': + 'Projeyi farklı kaydet...', + + // export blocks + 'Export blocks': + 'Blokları dışarı aktar', + 'Import blocks': + 'Blokları içeri aktar', + 'this project doesn\'t have any\ncustom global blocks yet': + 'bu proje henüz herhangi bir global blok içermiyor', + 'select': + 'seç', + 'none': + 'hiçbiri', + + // variable dialog + 'for all sprites': + 'tüm karakterler için', + 'for this sprite only': + 'sadece bu karakter için', + + // block dialog + 'Change block': + 'Bloğu değiştir', + 'Command': + 'Komut', + 'Reporter': + 'Fonksiyon', + 'Predicate': + 'Beyan etme', + + // block editor + 'Block Editor': + 'Blok Editörü', + 'Apply': + 'Uygula', + + // block deletion dialog + 'Delete Custom Block': + 'Bloğu Sil', + 'block deletion dialog text': + 'BSoll dieser Block mit allen seinen Exemplare\n' + + 'wirklich gel\u00f6scht werden?', + + // input dialog + 'Create input name': + 'Girdi oluştur', + 'Edit input name': + 'Girdiyi düzenle', + 'Edit label fragment': + 'Etiketi düzenle', + 'Title text': + 'Başlık', + 'Input name': + 'Girdi Adı', + 'Delete': + 'Sil', + 'Object': + 'Obje', + 'Number': + 'Sayı', + 'Text': + 'Metin', + 'List': + 'Liste', + 'Any type': + 'Herhangi bir tip', + 'Boolean (T/F)': + 'Mantıksal (D/Y)', + 'Command\n(inline)': + 'Komut', + 'Command\n(C-shape)': + 'Komut\n(C-Şenlinde)', + 'Any\n(unevaluated)': + 'Herhangi\n(değerlendirilmemiş)', + 'Boolean\n(unevaluated)': + 'Mantıksal\n(değerlendirilmemiş)', + 'Single input.': + 'Tek girdi.', + 'Default Value:': + 'Varsayılan değer:', + 'Multiple inputs (value is list of inputs)': + 'Çoklu girdi (liste olarak)', + 'Upvar - make internal variable visible to caller': + 'İç değişkeni çağırıcıya görünür kıl', + + // About Snap + 'About Snap': + 'Snap hakkında', + 'Back...': + 'Geriye...', + 'License...': + 'Lisans...', + 'Modules...': + 'Komponenten...', + 'Credits...': + 'Katkıda bulunanlar...', + 'Translators...': + 'Çevirmenler...', + 'License': + 'Lisans', + 'current module versions:': + 'Şu anki versiyonlar', + 'Contributors': + 'Katkıda bulunanlar', + 'Translations': + 'Çeviriler', + + // variable watchers + 'normal': + 'normal', + 'large': + 'geniş', + 'slider': + 'sürgü', + 'slider min...': + 'sürgü en düşük...', + 'slider max...': + 'sürgü en yüksek...', + 'import...': + 'içeri aktar...', + 'Slider minimum value': + 'Sürgünün en düşük değeri', + 'Slider maximum value': + 'Sürgünün en yüksek değeri', + + // list watchers + 'length: ': + 'uzunluk: ', + + // coments + 'add comment here...': + '.. buraya yorum ekle', + + // drow downs + // directions + '(90) right': + '(90) sağ', + '(-90) left': + '(-90) sol', + '(0) up': + '(0) yukarı', + '(180) down': + '(180) aşağı', + + // collision detection + 'mouse-pointer': + 'Fare-İşaretçisi', + 'corner': + 'kenar', + 'pen trails': + 'Malspuren', + + // costumes + 'Turtle': + 'Kaplumbağa', + 'Empty': + 'Boş', + + // graphical effects + 'brightness': + 'parlaklık', + 'ghost': + 'hayalet', + 'negative': + 'negatif', + 'comic': + 'komik', + 'confetti': + 'konfeti', + + // keys + 'space': + 'boşluk', + 'up arrow': + 'yukarı ok', + 'down arrow': + 'aşağı ok', + 'right arrow': + 'sol ok', + 'left arrow': + 'sağ ok', + 'a': + 'a', + 'b': + 'b', + 'c': + 'c', + 'd': + 'd', + 'e': + 'e', + 'f': + 'f', + 'g': + 'g', + 'h': + 'h', + 'i': + 'i', + 'j': + 'j', + 'k': + 'k', + 'l': + 'l', + 'm': + 'm', + 'n': + 'n', + 'o': + 'o', + 'p': + 'p', + 'q': + 'q', + 'r': + 'r', + 's': + 's', + 't': + 't', + 'u': + 'u', + 'v': + 'v', + 'w': + 'w', + 'x': + 'x', + 'y': + 'y', + 'z': + 'z', + '0': + '0', + '1': + '1', + '2': + '2', + '3': + '3', + '4': + '4', + '5': + '5', + '6': + '6', + '7': + '7', + '8': + '8', + '9': + '9', + + // messages + 'new...': + 'yeni...', + + // math functions + 'abs': + 'MutlakDeğer', + 'floor': + 'alt değer', + 'sqrt': + 'Karekök', + 'sin': + 'sin', + 'cos': + 'cos', + 'tan': + 'tan', + 'asin': + 'asin', + 'acos': + 'acos', + 'atan': + 'atan', + 'ln': + 'ln', + 'e^': + 'e^', + + // delimiters + 'letter': + 'harf', + 'whitespace': + 'alfabe dışı', + 'line': + 'çizgi', + 'tab': + 'sekme', + 'cr': + 'karakter', + + // data types + 'number': + 'sayı', + 'text': + 'metin', + 'Boolean': + 'mantıksal', + 'list': + 'Liste', + 'command': + 'komut', + 'reporter': + 'fonksiyonlar', + 'predicate': + 'ön ek', + + // list indices + 'last': + 'son', + 'any': + 'herhangi' +}; diff --git a/libraries/LIBRARIES b/libraries/LIBRARIES index f11aa852..8905553b 100644 --- a/libraries/LIBRARIES +++ b/libraries/LIBRARIES @@ -3,3 +3,5 @@ list-utilities List utilities stream-tools Streams (lazy lists) variadic-reporters Variadic reporters word-sentence Words, sentences +cases Multi-branched conditional (switch) +leap-library LEAP Motion controller diff --git a/libraries/cases.xml b/libraries/cases.xml new file mode 100644 index 00000000..8a170f7b --- /dev/null +++ b/libraries/cases.xml @@ -0,0 +1 @@ +
cont
catchtag
\ No newline at end of file diff --git a/libraries/iteration-composition.xml b/libraries/iteration-composition.xml index 0f16bb6e..d2afe059 100644 --- a/libraries/iteration-composition.xml +++ b/libraries/iteration-composition.xml @@ -1 +1 @@ -Call f(f(f(...(f(x))))) n times where the three input slots are n, f, and x from left to right. The # variable can be used inside f to represent how many times f has been called.Call f(f(f(...(f(x))))) until condition is true, where the three input slots are condition, f, and x from left to right. The # variable can be used inside f or condition to indicate how many times f has been called.Returns the function f(g(x)) where f and g are the two inputs.Like the built-in REPEAT UNTIL block, except that the ending condition is not tested until the script has been run the first time. So the script is run at least once.Run the script repeatedly, as long as the given condition is true. Runs the script at least once before testing the condition.Runs the script repeatedly, as long as the condition is true. Tests the condition before the first time the script is run. Like the built in REPEAT UNTIL except that in this block the condition must be true, not false.Runs the script the specified number of times, like the built-in REPEAT block, but this one provides the # variable that can be used inside the script. Try REPEAT (200) MOVE (#) STEPS RIGHT 92 with the pen down. \ No newline at end of file +Call f(f(f(...(f(x))))) n times where the three input slots are n, f, and x from left to right. The # variable can be used inside f to represent how many times f has been called.
Call f(f(f(...(f(x))))) until condition is true, where the three input slots are condition, f, and x from left to right. The # variable can be used inside f or condition to indicate how many times f has been called.
Returns the function f(g(x)) where f and g are the two inputs.
Like the built-in REPEAT UNTIL block, except that the ending condition is not tested until the script has been run the first time. So the script is run at least once.
Run the script repeatedly, as long as the given condition is true. Runs the script at least once before testing the condition.
Runs the script repeatedly, as long as the condition is true. Tests the condition before the first time the script is run. Like the built in REPEAT UNTIL except that in this block the condition must be true, not false.
Runs the script the specified number of times, like the built-in REPEAT block, but this one provides the # variable that can be used inside the script. Try REPEAT (200) MOVE (#) STEPS RIGHT 92 with the pen down.
1110
\ No newline at end of file diff --git a/libraries/leap-library.xml b/libraries/leap-library.xml new file mode 100644 index 00000000..b8252204 --- /dev/null +++ b/libraries/leap-library.xml @@ -0,0 +1 @@ +
x1
yaw1
x1
1
1
\ No newline at end of file diff --git a/libraries/stream-tools.xml b/libraries/stream-tools.xml index 66efceca..e2775c54 100644 --- a/libraries/stream-tools.xml +++ b/libraries/stream-tools.xml @@ -1 +1 @@ -
4234
1datamapmany1data lists
1001
\ No newline at end of file +
4234
1datamapmany1data lists
1001
1
\ No newline at end of file diff --git a/lists.js b/lists.js index bd856fe4..94592287 100644 --- a/lists.js +++ b/lists.js @@ -7,7 +7,7 @@ written by Jens Mönig and Brian Harvey jens@moenig.org, bh@cs.berkeley.edu - Copyright (C) 2014 by Jens Mönig and Brian Harvey + Copyright (C) 2015 by Jens Mönig and Brian Harvey This file is part of Snap!. @@ -61,7 +61,7 @@ PushButtonMorph, SyntaxElementMorph, Color, Point, WatcherMorph, StringMorph, SpriteMorph, ScrollFrameMorph, CellMorph, ArrowMorph, MenuMorph, snapEquals, Morph, isNil, localize, MorphicPreferences*/ -modules.lists = '2014-November-20'; +modules.lists = '2015-July-27'; var List; var ListWatcherMorph; @@ -158,9 +158,8 @@ List.prototype.add = function (element, index) { if no index is specifed, append the element */ var idx = index || this.length() + 1, - obj = element === 0 ? 0 - : element === false ? false - : element || null; + obj = isNil(element) ? null : element; + this.becomeArray(); this.contents.splice(idx - 1, 0, obj); this.changed(); @@ -634,6 +633,7 @@ ListWatcherMorph.prototype.setStartIndex = function (index) { }; ListWatcherMorph.prototype.fixLayout = function () { + if (!this.label) {return; } Morph.prototype.trackChanges = false; if (this.frame) { this.arrangeCells(); diff --git a/locale.js b/locale.js index 5ec6013e..151314c4 100644 --- a/locale.js +++ b/locale.js @@ -42,7 +42,7 @@ /*global modules, contains*/ -modules.locale = '2015-January-21'; +modules.locale = '2015-August-06'; // Global stuff @@ -149,7 +149,7 @@ SnapTranslator.dict.de = { 'translator_e-mail': 'jens@moenig.org', 'last_changed': - '2014-07-29' + '2015-08-06' }; SnapTranslator.dict.it = { @@ -209,7 +209,7 @@ SnapTranslator.dict.pt = { 'translator_e-mail': 'mmsequeira@gmail.com', 'last_changed': - '2014-10-01' + '2015-08-02' }; SnapTranslator.dict.cs = { @@ -257,7 +257,7 @@ SnapTranslator.dict.fr = { 'translator_e-mail': 'i.scool@mac.com', 'last_changed': - '2014-02-04' + '2015-06-25' }; SnapTranslator.dict.si = { @@ -317,7 +317,7 @@ SnapTranslator.dict.pl = { 'translator_e-mail': 'witek@oeiizk.waw.pl', 'last_changed': - '2013-08-05' + '2015-08-06' }; SnapTranslator.dict.tw = { @@ -439,3 +439,75 @@ SnapTranslator.dict.kn = { 'last_changed': '2014-12-02' }; + +SnapTranslator.dict.ml = { + // translations meta information + 'language_name': + 'Malayalam', + 'language_translator': + 'vinayakumar R', + 'translator_e-mail': + 'vnkmr7620@gmail.com', + 'last_changed': + '2015-02-20' +}; + +SnapTranslator.dict.ta = { + // translations meta information + 'language_name': + 'Tamil', + 'language_translator': + 'vinayakumar R', + 'translator_e-mail': + 'vnkmr7620@gmail.com', + 'last_changed': + '2015-02-20' +}; + +SnapTranslator.dict.te = { + // translations meta information + 'language_name': + 'Telagu', // the name as it should appear in the language menu + 'language_translator': + 'vinayakumar R', // your name for the Translators tab + 'translator_e-mail': + 'vnkmr7620@gmail.com', // optional + 'last_changed': + '2015-02-20' +}; + +SnapTranslator.dict.tr = { + // translations meta information + 'language_name': + 'Türkçe', + 'language_translator': + 'Hakan Atas', + 'translator_e-mail': + 'hakanatas@gmail.com', + 'last_changed': + '2015-7-27' +}; + +SnapTranslator.dict.hu = { + // translations meta information + 'language_name': + 'Magyar', + 'language_translator': + 'Makány György', + 'translator_e-mail': + 'makany.gyorgy@gmail.com', + 'last_changed': + '2015-07-27' +}; + +SnapTranslator.dict.ia = { + // translations meta information + 'language_name': + 'Interlingua', + 'language_translator': + 'Ken Dickey', + 'translator_e-mail': + 'Ken.Dickey@whidbey.com', + 'last_changed': + '2015-08-09' +}; diff --git a/morphic.js b/morphic.js index 96168972..e704f4a0 100644 --- a/morphic.js +++ b/morphic.js @@ -8,7 +8,7 @@ written by Jens Mönig jens@moenig.org - Copyright (C) 2014 by Jens Mönig + Copyright (C) 2015 by Jens Mönig This file is part of Snap!. @@ -527,6 +527,12 @@ a duplicate of the template whose "isDraggable" flag is true and whose "isTemplate" flag is false, in other words: a non-template. + When creating a copy from a template, the copy's + + reactToTemplateCopy + + is invoked, if it is present. + Dragging is indicated by adding a drop shadow to the morph in hand. If a morph follows the hand without displaying a drop shadow it is merely being moved about without changing its parent (owner morph), @@ -822,13 +828,13 @@ // use context to paint stuff here }; - If your new morph stores or references other morphs outside of the - submorph tree in other properties, be sure to also override the + If your new morph stores or references to other morphs outside of + the submorph tree in other properties, be sure to also override the default - copyRecordingReferences() + updateReferences() - method accordingly if you want it to support duplication. + method if you want it to support duplication. (6) development and user modes @@ -1020,16 +1026,17 @@ programming hero. I have originally written morphic.js in Florian Balmer's Notepad2 - editor for Windows and later switched to Apple's Dashcode. I've also - come to depend on both Douglas Crockford's JSLint, Mozilla's Firebug - and Google's Chrome to get it right. + editor for Windows, later switched to Apple's Dashcode and later + still to Apple's Xcode. I've also come to depend on both Douglas + Crockford's JSLint, Mozilla's Firebug and Google's Chrome to get + it right. IX. contributors ---------------------- Joe Otto found and fixed many early bugs and taught me some tricks. Nathan Dinsmore contributed mouse wheel scrolling, cached - background texture handling and countless bug fixes. + background texture handling, countless bug fixes and optimizations. Ian Reynolds contributed backspace key handling for Chrome. Davide Della Casa contributed performance optimizations for Firefox. @@ -1041,7 +1048,7 @@ /*global window, HTMLCanvasElement, getMinimumFontHeight, FileReader, Audio, FileList, getBlurredShadowSupport*/ -var morphicVersion = '2014-December-05'; +var morphicVersion = '2015-July-28'; var modules = {}; // keep track of additional loaded modules var useBlurredShadows = getBlurredShadowSupport(); // check for Chrome-bug @@ -1236,19 +1243,9 @@ function getDocumentPositionOf(aDOMelement) { return pos; } -function clone(target) { - // answer a new instance of target's type - if (typeof target === 'object') { - var Clone = function () {nop(); }; - Clone.prototype = target; - return new Clone(); - } - return target; -} - function copy(target) { // answer a shallow copy of target - var value, c, property; + var value, c, property, keys, l, i; if (typeof target !== 'object') { return target; @@ -1259,18 +1256,16 @@ function copy(target) { } if (target instanceof target.constructor && target.constructor !== Object) { - c = clone(target.constructor.prototype); - for (property in target) { - if (Object.prototype.hasOwnProperty.call(target, property)) { - c[property] = target[property]; - } + c = Object.create(target.constructor.prototype); + keys = Object.keys(target); + for (l = keys.length, i = 0; i < l; i += 1) { + property = keys[i]; + c[property] = target[property]; } } else { c = {}; for (property in target) { - if (!c[property]) { - c[property] = target[property]; - } + c[property] = target[property]; } } return c; @@ -2205,7 +2200,7 @@ function Morph() { // Morph initialization: -Morph.prototype.init = function () { +Morph.prototype.init = function (noDraw) { Morph.uber.init.call(this); this.isMorph = true; this.bounds = new Rectangle(0, 0, 50, 40); @@ -2218,7 +2213,7 @@ Morph.prototype.init = function () { this.isTemplate = false; this.acceptsDrops = false; this.noticesTransparentClick = false; - this.drawNew(); + if (!noDraw) {this.drawNew(); } this.fps = 0; this.customContextMenu = null; this.lastTime = Date.now(); @@ -2404,19 +2399,19 @@ Morph.prototype.visibleBounds = function () { // Morph accessing - simple changes: Morph.prototype.moveBy = function (delta) { - this.changed(); - this.bounds = this.bounds.translateBy(delta); - this.children.forEach(function (child) { - child.moveBy(delta); - }); - this.changed(); + this.fullChanged(); + this.silentMoveBy(delta); + this.fullChanged(); }; Morph.prototype.silentMoveBy = function (delta) { + var children = this.children, + i = children.length; this.bounds = this.bounds.translateBy(delta); - this.children.forEach(function (child) { - child.silentMoveBy(delta); - }); + // ugly optimization avoiding forEach() + for (i; i > 0; i -= 1) { + children[i - 1].silentMoveBy(delta); + } }; Morph.prototype.setPosition = function (aPoint) { @@ -2506,6 +2501,32 @@ Morph.prototype.keepWithin = function (aMorph) { } }; +Morph.prototype.scrollIntoView = function () { + var leftOff, rightOff, topOff, bottomOff, + sf = this.parentThatIsA(ScrollFrameMorph); + if (!sf) {return; } + rightOff = Math.min( + this.fullBounds().right() - sf.right(), + sf.contents.right() - sf.right() + ); + if (rightOff > 0) { + sf.contents.moveBy(new Point(-rightOff, 0)); + } + leftOff = this.fullBounds().left() - sf.left(); + if (leftOff < 0) { + sf.contents.moveBy(new Point(-leftOff, 0)); + } + topOff = this.fullBounds().top() - sf.top(); + if (topOff < 0) { + sf.contents.moveBy(new Point(0, -topOff)); + } + bottomOff = this.fullBounds().bottom() - sf.bottom(); + if (bottomOff > 0) { + sf.contents.moveBy(new Point(0, -bottomOff)); + } + sf.adjustScrollBars(); +}; + // Morph accessing - dimensional changes requiring a complete redraw Morph.prototype.setExtent = function (aPoint) { @@ -2892,7 +2913,7 @@ Morph.prototype.fullChanged = function () { }; Morph.prototype.childChanged = function () { - // react to a change in one of my children, + // react to a change in one of my children, // default is to just pass this message on upwards // override this method for Morphs that need to adjust accordingly if (this.parent) { @@ -2929,6 +2950,18 @@ Morph.prototype.addBack = function (aMorph) { this.addChildFirst(aMorph); }; +Morph.prototype.topMorphAt = function (point) { + var i, result; + if (!this.isVisible) {return null; } + for (i = this.children.length - 1; i >= 0; i -= 1) { + result = this.children[i].topMorphAt(point); + if (result) {return result; } + } + return this.bounds.containsPoint(point) && + (this.noticesTransparentClick || !this.isTransparentAt(point)) ? this + : null; +}; + Morph.prototype.topMorphSuchThat = function (predicate) { var next; if (predicate.call(null, this)) { @@ -2944,30 +2977,6 @@ Morph.prototype.topMorphSuchThat = function (predicate) { return null; }; -Morph.prototype.morphAt = function (aPoint) { - var morphs = this.allChildren().slice(0).reverse(), - result = null; - morphs.forEach(function (m) { - if (m.fullBounds().containsPoint(aPoint) && - (result === null)) { - result = m; - } - }); - return result; -}; - -/* - alternative - more elegant and possibly more - performant - solution for morphAt. - Has some issues, commented out for now - -Morph.prototype.morphAt = function (aPoint) { - return this.topMorphSuchThat(function (m) { - return m.fullBounds().containsPoint(aPoint); - }); -}; -*/ - Morph.prototype.overlappedMorphs = function () { //exclude the World var world = this.world(), @@ -3039,45 +3048,54 @@ Morph.prototype.fullCopy = function () { Other properties are also *shallow* copied, so you must override to deep copy Arrays and (complex) Objects */ - var dict = {}, c; - c = this.copyRecordingReferences(dict); + var map = new Map(), c; + c = this.copyRecordingReferences(map); c.forAllChildren(function (m) { - m.updateReferences(dict); + m.updateReferences(map); }); return c; }; -Morph.prototype.copyRecordingReferences = function (dict) { +Morph.prototype.copyRecordingReferences = function (map) { /* Recursively copy this entire composite morph, recording the correspondence between old and new morphs in the given dictionary. This dictionary will be used to update intra-composite references in the copy. See updateReferences(). - Note: This default implementation copies ONLY morphs in the - submorph hierarchy. If a morph stores morphs in other properties - that it wants to copy, then it should override this method to do so. - The same goes for morphs that contain other complex data that - should be copied when the morph is duplicated. + + Note: This default implementation copies ONLY morphs. If a morph + stores morphs in other properties that it wants to copy, then it + should override this method to do so. The same goes for morphs that + contain other complex data that should be copied when the morph is + duplicated. */ var c = this.copy(); - dict[this] = c; + map.set(this, c); this.children.forEach(function (m) { - c.add(m.copyRecordingReferences(dict)); + c.add(m.copyRecordingReferences(map)); }); return c; }; -Morph.prototype.updateReferences = function (dict) { +Morph.prototype.updateReferences = function (map) { /* Update intra-morph references within a composite morph that has been copied. For example, if a button refers to morph X in the orginal composite then the copy of that button in the new composite should refer to the copy of X in new composite, not the original X. */ - var property; - for (property in this) { - if (this[property] && this[property].isMorph && dict[property]) { - this[property] = dict[property]; + var properties = Object.keys(this), + l = properties.length, + property, + value, + reference, + i; + for (i = 0; i < l; i += 1) { + property = properties[i]; + value = this[property]; + if (value && value.isMorph) { + reference = map.get(value); + if (reference) { this[property] = reference; } } } }; @@ -3100,6 +3118,13 @@ Morph.prototype.rootForGrab = function () { return this.parent.rootForGrab(); }; +Morph.prototype.isCorrectingOutsideDrag = function () { + // make sure I don't "trail behind" the hand when dragged + // override for morphs that you want to be dragged outside + // their full bounds + return true; +}; + Morph.prototype.wantsDropOf = function (aMorph) { // default is to answer the general flag - change for my heirs if ((aMorph instanceof HandleMorph) || @@ -3148,9 +3173,7 @@ Morph.prototype.slideBackTo = function (situation, inSteps) { this.fps = 0; this.step = function () { - myself.fullChanged(); - myself.silentMoveBy(new Point(xStep, yStep)); - myself.fullChanged(); + myself.moveBy(new Point(xStep, yStep)); stepCount += 1; if (stepCount === steps) { situation.origin.add(myself); @@ -3184,6 +3207,17 @@ Morph.prototype.move = function () { ); }; +Morph.prototype.moveCenter = function () { + this.world().activeHandle = new HandleMorph( + this, + null, + null, + null, + null, + 'moveCenter' + ); +}; + Morph.prototype.hint = function (msg) { var m, text; text = msg; @@ -3699,6 +3733,10 @@ function ShadowMorph() { this.init(); } +ShadowMorph.prototype.topMorphAt = function () { + return null; +}; + // HandleMorph //////////////////////////////////////////////////////// // I am a resize / move handle that can be attached to any Morph @@ -3728,7 +3766,7 @@ HandleMorph.prototype.init = function ( this.target = target || null; this.minExtent = new Point(minX || 0, minY || 0); this.inset = new Point(insetX || 0, insetY || insetX || 0); - this.type = type || 'resize'; // can also be 'move' + this.type = type || 'resize'; // can also be 'move', 'moveCenter' HandleMorph.uber.init.call(this); this.color = new Color(255, 255, 255); this.isDraggable = false; @@ -3753,11 +3791,15 @@ HandleMorph.prototype.drawNew = function () { ); this.image = this.normalImage; if (this.target) { - this.setPosition( - this.target.bottomRight().subtract( - this.extent().add(this.inset) - ) - ); + if (this.type === 'moveCenter') { + this.setCenter(this.target.center()); + } else { // 'resize', 'move' + this.setPosition( + this.target.bottomRight().subtract( + this.extent().add(this.inset) + ) + ); + } this.target.add(this); this.target.changed(); } @@ -3769,6 +3811,7 @@ HandleMorph.prototype.drawOnCanvas = function ( shadowColor ) { var context = aCanvas.getContext('2d'), + isSquare = (this.type.indexOf('move') === 0), p1, p11, p2, @@ -3780,7 +3823,7 @@ HandleMorph.prototype.drawOnCanvas = function ( context.strokeStyle = color.toString(); - if (this.type === 'move') { + if (isSquare) { p1 = this.bottomLeft().subtract(this.position()); p11 = p1.copy(); @@ -3817,7 +3860,7 @@ HandleMorph.prototype.drawOnCanvas = function ( context.strokeStyle = shadowColor.toString(); - if (this.type === 'move') { + if (isSquare) { p1 = this.bottomLeft().subtract(this.position()); p11 = p1.copy(); @@ -3859,12 +3902,17 @@ HandleMorph.prototype.step = null; HandleMorph.prototype.mouseDownLeft = function (pos) { var world = this.root(), - offset = pos.subtract(this.bounds.origin), + offset, myself = this; if (!this.target) { return null; } + if (this.type === 'moveCenter') { + offset = pos.subtract(this.center()); + } else { + offset = pos.subtract(this.bounds.origin); + } this.step = function () { var newPos, newExt; if (world.hand.mouseButton) { @@ -3881,6 +3929,8 @@ HandleMorph.prototype.mouseDownLeft = function (pos) { myself.extent().add(myself.inset) ) ); + } else if (this.type === 'moveCenter') { + myself.target.setCenter(newPos); } else { // type === 'move' myself.target.setPosition( newPos.subtract(this.target.extent()) @@ -3916,20 +3966,6 @@ HandleMorph.prototype.mouseLeave = function () { this.changed(); }; -// HandleMorph duplicating: - -HandleMorph.prototype.copyRecordingReferences = function (dict) { - // inherited, see comment in Morph - var c = HandleMorph.uber.copyRecordingReferences.call( - this, - dict - ); - if (c.target && dict[this.target]) { - c.target = (dict[this.target]); - } - return c; -}; - // HandleMorph menu: HandleMorph.prototype.attach = function () { @@ -4253,20 +4289,6 @@ ColorPaletteMorph.prototype.updateTarget = function () { } }; -// ColorPaletteMorph duplicating: - -ColorPaletteMorph.prototype.copyRecordingReferences = function (dict) { - // inherited, see comment in Morph - var c = ColorPaletteMorph.uber.copyRecordingReferences.call( - this, - dict - ); - if (c.target && dict[this.target]) { - c.target = (dict[this.target]); - } - return c; -}; - // ColorPaletteMorph menu: ColorPaletteMorph.prototype.developersMenu = function () { @@ -4714,7 +4736,7 @@ CursorMorph.prototype.accept = function () { if (world) { world.stopEditing(); } - this.escalateEvent('accept', null); + this.escalateEvent('accept', this); }; CursorMorph.prototype.cancel = function () { @@ -4723,7 +4745,7 @@ CursorMorph.prototype.cancel = function () { if (world) { world.stopEditing(); } - this.escalateEvent('cancel', null); + this.escalateEvent('cancel', this); }; CursorMorph.prototype.undo = function () { @@ -5833,23 +5855,6 @@ SliderMorph.prototype.updateTarget = function () { } }; -// SliderMorph duplicating: - -SliderMorph.prototype.copyRecordingReferences = function (dict) { - // inherited, see comment in Morph - var c = SliderMorph.uber.copyRecordingReferences.call( - this, - dict - ); - if (c.target && dict[this.target]) { - c.target = (dict[this.target]); - } - if (c.button && dict[this.button]) { - c.button = (dict[this.button]); - } - return c; -}; - // SliderMorph menu: SliderMorph.prototype.developersMenu = function () { @@ -5926,7 +5931,7 @@ SliderMorph.prototype.userSetStart = function (num) { this.start = Math.max(num, this.stop); }; -SliderMorph.prototype.setStart = function (num) { +SliderMorph.prototype.setStart = function (num, noUpdate) { // for context menu demo purposes var newStart; if (typeof num === 'number') { @@ -5944,12 +5949,12 @@ SliderMorph.prototype.setStart = function (num) { } } this.value = Math.max(this.value, this.start); - this.updateTarget(); + if (!noUpdate) {this.updateTarget(); } this.drawNew(); this.changed(); }; -SliderMorph.prototype.setStop = function (num) { +SliderMorph.prototype.setStop = function (num, noUpdate) { // for context menu demo purposes var newStop; if (typeof num === 'number') { @@ -5961,12 +5966,12 @@ SliderMorph.prototype.setStop = function (num) { } } this.value = Math.min(this.value, this.stop); - this.updateTarget(); + if (!noUpdate) {this.updateTarget(); } this.drawNew(); this.changed(); }; -SliderMorph.prototype.setSize = function (num) { +SliderMorph.prototype.setSize = function (num, noUpdate) { // for context menu demo purposes var newSize; if (typeof num === 'number') { @@ -5984,7 +5989,7 @@ SliderMorph.prototype.setSize = function (num) { } } this.value = Math.min(this.value, this.stop - this.size); - this.updateTarget(); + if (!noUpdate) {this.updateTarget(); } this.drawNew(); this.changed(); }; @@ -6556,7 +6561,7 @@ InspectorMorph.prototype.setExtent = function (aPoint) { this.fixLayout(); }; -//InspectorMorph editing ops: +// InspectorMorph editing ops: InspectorMorph.prototype.save = function () { var txt = this.detail.contents.children[0].text.toString(), @@ -6646,6 +6651,15 @@ InspectorMorph.prototype.step = function () { this.fixLayout(); }; +// InspectorMorph duplicating: + +InspectorMorph.prototype.updateReferences = function (map) { + var active = this.list.activeIndex(); + InspectorMorph.uber.updateReferences.call(this, map); + this.buildPanes(); + this.list.activateIndex(active); +}; + // MenuMorph /////////////////////////////////////////////////////////// // MenuMorph: referenced constructors @@ -6694,6 +6708,8 @@ MenuMorph.prototype.init = function (target, title, environment, fontSize) { this.label = null; this.world = null; this.isListContents = false; + this.hasFocus = false; + this.selection = null; // initialize inherited properties: MenuMorph.uber.init.call(this); @@ -6913,6 +6929,7 @@ MenuMorph.prototype.popup = function (world, pos) { } world.add(this); world.activeMenu = this; + this.world = world; // optionally enable keyboard support this.fullChanged(); }; @@ -6943,6 +6960,105 @@ MenuMorph.prototype.popUpCenteredInWorld = function (world) { ); }; +// MenuMorph keyboard accessibility + +MenuMorph.prototype.getFocus = function () { + this.world.keyboardReceiver = this; + this.selection = null; + this.selectFirst(); + this.hasFocus = true; +}; + +MenuMorph.prototype.processKeyDown = function (event) { + //console.log(event.keyCode); + switch (event.keyCode) { + case 13: // 'enter' + case 32: // 'space' + if (this.selection) { + this.selection.mouseClickLeft(); + } + return; + case 27: // 'esc' + return this.destroy(); + case 38: // 'up arrow' + return this.selectUp(); + case 40: // 'down arrow' + return this.selectDown(); + default: + nop(); + } +}; + +MenuMorph.prototype.processKeyUp = function (event) { + nop(event); +}; + +MenuMorph.prototype.processKeyPress = function (event) { + nop(event); +}; + +MenuMorph.prototype.selectFirst = function () { + var i; + for (i = 0; i < this.children.length; i += 1) { + if (this.children[i] instanceof MenuItemMorph) { + this.select(this.children[i]); + return; + } + } +}; + +MenuMorph.prototype.selectUp = function () { + var triggers, idx; + + triggers = this.children.filter(function (each) { + return each instanceof MenuItemMorph; + }); + if (!this.selection) { + if (triggers.length) { + this.select(triggers[0]); + } + return; + } + idx = triggers.indexOf(this.selection) - 1; + if (idx < 0) { + idx = triggers.length - 1; + } + this.select(triggers[idx]); +}; + +MenuMorph.prototype.selectDown = function () { + var triggers, idx; + + triggers = this.children.filter(function (each) { + return each instanceof MenuItemMorph; + }); + if (!this.selection) { + if (triggers.length) { + this.select(triggers[0]); + } + return; + } + idx = triggers.indexOf(this.selection) + 1; + if (idx >= triggers.length) { + idx = 0; + } + this.select(triggers[idx]); +}; + +MenuMorph.prototype.select = function (aMenuItem) { + this.unselectAllItems(); + aMenuItem.image = aMenuItem.highlightImage; + aMenuItem.changed(); + this.selection = aMenuItem; +}; + +MenuMorph.prototype.destroy = function () { + if (this.hasFocus) { + this.world.keyboardReceiver = null; + } + MenuMorph.uber.destroy.call(this); +}; + // StringMorph ///////////////////////////////////////////////////////// // I am a single line of text @@ -7017,7 +7133,7 @@ StringMorph.prototype.init = function ( this.markedBackgoundColor = new Color(60, 60, 120); // initialize inherited properties: - StringMorph.uber.init.call(this); + StringMorph.uber.init.call(this, true); // override inherited properites: this.color = color || new Color(0, 0, 0); @@ -7395,6 +7511,11 @@ StringMorph.prototype.selectionStartSlot = function () { }; StringMorph.prototype.clearSelection = function () { + if (!this.currentlySelecting && + this.startMark === 0 && + this.endMark === 0) { + return; + } this.currentlySelecting = false; this.startMark = 0; this.endMark = 0; @@ -7447,6 +7568,8 @@ StringMorph.prototype.mouseClickLeft = function (pos) { StringMorph.prototype.enableSelecting = function () { this.mouseDownLeft = function (pos) { + var crs = this.root().cursor, + already = crs ? crs.target === this : false; this.clearSelection(); if (this.isEditable && (!this.isDraggable)) { this.edit(); @@ -7454,6 +7577,7 @@ StringMorph.prototype.enableSelecting = function () { this.startMark = this.slotAt(pos); this.endMark = this.startMark; this.currentlySelecting = true; + if (!already) {this.escalateEvent('mouseDownLeft', pos); } } }; this.mouseMove = function (pos) { @@ -8060,7 +8184,7 @@ TriggerMorph.prototype.init = function ( this.environment = environment || null; this.labelString = labelString || null; this.label = null; - this.hint = hint || null; + this.hint = hint || null; // null, String, or Function this.fontSize = fontSize || MorphicPreferences.menuFontSize; this.fontStyle = fontStyle || 'sans-serif'; this.highlightColor = new Color(192, 192, 192); @@ -8131,20 +8255,6 @@ TriggerMorph.prototype.createLabel = function () { this.add(this.label); }; -// TriggerMorph duplicating: - -TriggerMorph.prototype.copyRecordingReferences = function (dict) { - // inherited, see comment in Morph - var c = TriggerMorph.uber.copyRecordingReferences.call( - this, - dict - ); - if (c.label && dict[this.label]) { - c.label = (dict[this.label]); - } - return c; -}; - // TriggerMorph action: TriggerMorph.prototype.trigger = function () { @@ -8209,10 +8319,11 @@ TriggerMorph.prototype.triggerDoubleClick = function () { // TriggerMorph events: TriggerMorph.prototype.mouseEnter = function () { + var contents = this.hint instanceof Function ? this.hint() : this.hint; this.image = this.highlightImage; this.changed(); - if (this.hint) { - this.bubbleHelp(this.hint); + if (contents) { + this.bubbleHelp(contents); } }; @@ -8489,15 +8600,19 @@ FrameMorph.prototype.fullDrawOn = function (aCanvas, aRect) { }); }; -// FrameMorph scrolling optimization: +// FrameMorph navigation: -FrameMorph.prototype.moveBy = function (delta) { - this.changed(); - this.bounds = this.bounds.translateBy(delta); - this.children.forEach(function (child) { - child.silentMoveBy(delta); - }); - this.changed(); +FrameMorph.prototype.topMorphAt = function (point) { + var i, result; + if (!(this.isVisible && this.bounds.containsPoint(point))) { + return null; + } + for (i = this.children.length - 1; i >= 0; i -= 1) { + result = this.children[i].topMorphAt(point); + if (result) {return result; } + } + return this.noticesTransparentClick || + !this.isTransparentAt(point) ? this : null; }; // FrameMorph scrolling support: @@ -8589,20 +8704,6 @@ FrameMorph.prototype.reactToGrabOf = function () { this.adjustBounds(); }; -// FrameMorph duplicating: - -FrameMorph.prototype.copyRecordingReferences = function (dict) { - // inherited, see comment in Morph - var c = FrameMorph.uber.copyRecordingReferences.call( - this, - dict - ); - if (c.frame && dict[this.scrollFrame]) { - c.frame = (dict[this.scrollFrame]); - } - return c; -}; - // FrameMorph menus: FrameMorph.prototype.developersMenu = function () { @@ -8947,32 +9048,23 @@ ScrollFrameMorph.prototype.mouseScroll = function (y, x) { // ScrollFrameMorph duplicating: -ScrollFrameMorph.prototype.copyRecordingReferences = function (dict) { - // inherited, see comment in Morph - var c = ScrollFrameMorph.uber.copyRecordingReferences.call( - this, - dict - ); - if (c.contents && dict[this.contents]) { - c.contents = (dict[this.contents]); - } - if (c.hBar && dict[this.hBar]) { - c.hBar = (dict[this.hBar]); - c.hBar.action = function (num) { - c.contents.setPosition( - new Point(c.left() - num, c.contents.position().y) +ScrollFrameMorph.prototype.updateReferences = function (map) { + var myself = this; + ScrollFrameMorph.uber.updateReferences.call(this, map); + if (this.hBar) { + this.hBar.action = function (num) { + myself.contents.setPosition( + new Point(myself.left() - num, myself.contents.position().y) ); }; } - if (c.vBar && dict[this.vBar]) { - c.vBar = (dict[this.vBar]); - c.vBar.action = function (num) { - c.contents.setPosition( - new Point(c.contents.position().x, c.top() - num) + if (this.vBar) { + this.vBar.action = function (num) { + myself.contents.setPosition( + new Point(myself.contents.position().x, myself.top() - num) ); }; } - return c; }; // ScrollFrameMorph menu: @@ -9136,6 +9228,18 @@ ListMorph.prototype.setExtent = function (aPoint) { ListMorph.uber.setExtent.call(this, aPoint); }; +ListMorph.prototype.activeIndex = function () { + return this.listContents.children.indexOf(this.active); +}; + +ListMorph.prototype.activateIndex = function (idx) { + var item = this.listContents.children[idx]; + if (!item) {return; } + item.image = item.pressImage; + item.changed(); + item.trigger(); +}; + // StringFieldMorph //////////////////////////////////////////////////// // StringFieldMorph inherit from FrameMorph: @@ -9232,20 +9336,6 @@ StringFieldMorph.prototype.mouseClickLeft = function (pos) { } }; -// StringFieldMorph duplicating: - -StringFieldMorph.prototype.copyRecordingReferences = function (dict) { - // inherited, see comment in Morph - var c = StringFieldMorph.uber.copyRecordingReferences.call( - this, - dict - ); - if (c.text && dict[this.text]) { - c.text = (dict[this.text]); - } - return c; -}; - // BouncerMorph //////////////////////////////////////////////////////// // I am a Demo of a stepping custom Morph @@ -9373,55 +9463,19 @@ HandMorph.prototype.changed = function () { if (this.world !== null) { b = this.fullBounds(); if (!b.extent().eq(new Point())) { - this.world.broken.push(this.fullBounds().spread()); + this.world.broken.push(b.spread()); } } - }; +HandMorph.prototype.fullChanged = HandMorph.prototype.changed; + // HandMorph navigation: HandMorph.prototype.morphAtPointer = function () { - var morphs = this.world.allChildren().slice(0).reverse(), - myself = this, - result = null; - - morphs.forEach(function (m) { - if (m.visibleBounds().containsPoint(myself.bounds.origin) && - result === null && - m.isVisible && - (m.noticesTransparentClick || - (!m.isTransparentAt(myself.bounds.origin))) && - (!(m instanceof ShadowMorph)) && - m.allParents().every(function (each) { - return each.isVisible; - })) { - result = m; - } - }); - if (result !== null) { - return result; - } - return this.world; + return this.world.topMorphAt(this.bounds.origin) || this.world; }; -/* - alternative - more elegant and possibly more - performant - solution for morphAtPointer. - Has some issues, commented out for now - -HandMorph.prototype.morphAtPointer = function () { - var myself = this; - return this.world.topMorphSuchThat(function (m) { - return m.visibleBounds().containsPoint(myself.bounds.origin) && - m.isVisible && - (m.noticesTransparentClick || - (! m.isTransparentAt(myself.bounds.origin))) && - (! (m instanceof ShadowMorph)); - }); -}; -*/ - HandMorph.prototype.allMorphsAtPointer = function () { var morphs = this.world.allChildren(), myself = this; @@ -9683,36 +9737,23 @@ HandMorph.prototype.processMouseMove = function (event) { morph = this.morphToGrab.fullCopy(); morph.isTemplate = false; morph.isDraggable = true; + if (morph.reactToTemplateCopy) { + morph.reactToTemplateCopy(); + } this.grab(morph); this.grabOrigin = this.morphToGrab.situation(); } if (morph) { - // if the mouse has left its fullBounds, center it + // if the mouse has left its fullBounds, allow to center it fb = morph.fullBounds(); - if (!fb.containsPoint(pos)) { + if (!fb.containsPoint(pos) && + morph.isCorrectingOutsideDrag()) { this.bounds.origin = fb.center(); this.grab(morph); this.setPosition(pos); } } } - -/* - original, more cautious code for grabbing Morphs, - retained in case of needing to fall back: - - if (morph === this.morphToGrab) { - if (morph.isDraggable) { - this.grab(morph); - } else if (morph.isTemplate) { - morph = morph.fullCopy(); - morph.isTemplate = false; - morph.isDraggable = true; - this.grab(morph); - } - } -*/ - } this.mouseOverList.forEach(function (old) { @@ -9957,16 +9998,6 @@ HandMorph.prototype.destroyTemporaries = function () { }); }; -// HandMorph dragging optimization - -HandMorph.prototype.moveBy = function (delta) { - Morph.prototype.trackChanges = false; - HandMorph.uber.moveBy.call(this, delta); - Morph.prototype.trackChanges = true; - this.fullChanged(); -}; - - // WorldMorph ////////////////////////////////////////////////////////// // I represent the element @@ -9995,6 +10026,7 @@ WorldMorph.prototype.init = function (aCanvas, fillPage) { this.isDraggable = false; this.currentKey = null; // currently pressed key code this.worldCanvas = aCanvas; + this.noticesTransparentClick = true; // additional properties: this.stamp = Date.now(); // reference in multi-world setups @@ -10509,6 +10541,13 @@ WorldMorph.prototype.contextMenu = function () { 'inspect', 'open a window on\nall properties' ); + menu.addItem( + "screenshot...", + function () { + window.open(this.fullImageClassic().toDataURL()); + }, + 'open a new window\nwith a picture of this morph' + ); menu.addLine(); menu.addItem( "restore display", diff --git a/morphic.txt b/morphic.txt index 042b7e51..11a323df 100755 --- a/morphic.txt +++ b/morphic.txt @@ -7,9 +7,9 @@ written by Jens Mönig jens@moenig.org - Copyright (C) 2012 by Jens Mönig + Copyright (C) 2015 by Jens Mönig - this documentation last changed: April 07, 2013 + this documentation last changed: June 26, 2015 This file is part of Snap!. @@ -465,9 +465,15 @@ MyMorph.prototype.mouseMove = function(pos) {}; - The only optional parameter of such a method is a Point object + All of these methods have as optional parameter a Point object indicating the current position of the Hand inside the World's - coordinate system. + coordinate system. The + + mouseMove(pos, button) + + event method has an additional optional parameter indicating the + currently pressed mouse button, which is either 'left' or 'right'. + You can use this to let users interact with 3D environments. Events may be "bubbled" up a morph's owner chain by calling @@ -522,6 +528,12 @@ a duplicate of the template whose "isDraggable" flag is true and whose "isTemplate" flag is false, in other words: a non-template. + When creating a copy from a template, the copy's + + reactToTemplateCopy + + is invoked, if it is present. + Dragging is indicated by adding a drop shadow to the morph in hand. If a morph follows the hand without displaying a drop shadow it is merely being moved about without changing its parent (owner morph), @@ -817,13 +829,13 @@ // use context to paint stuff here }; - If your new morph stores or references other morphs outside of the - submorph tree in other properties, be sure to also override the + If your new morph stores or references to other morphs outside of + the submorph tree in other properties, be sure to also override the default - copyRecordingReferences() + updateReferences() - method accordingly if you want it to support duplication. + method if you want it to support duplication. (6) development and user modes @@ -1015,16 +1027,17 @@ programming hero. I have originally written morphic.js in Florian Balmer's Notepad2 - editor for Windows and later switched to Apple's Dashcode. I've also - come to depend on both Douglas Crockford's JSLint, Mozilla's Firebug - and Google's Chrome to get it right. + editor for Windows, later switched to Apple's Dashcode and later + still to Apple's Xcode. I've also come to depend on both Douglas + Crockford's JSLint, Mozilla's Firebug and Google's Chrome to get + it right. IX. contributors ---------------------- Joe Otto found and fixed many early bugs and taught me some tricks. Nathan Dinsmore contributed mouse wheel scrolling, cached - background texture handling and countless bug fixes. + background texture handling, countless bug fixes and optimizations. Ian Reynolds contributed backspace key handling for Chrome. Davide Della Casa contributed performance optimizations for Firefox. diff --git a/objects.js b/objects.js index b433a83c..bebff6cf 100644 --- a/objects.js +++ b/objects.js @@ -105,7 +105,7 @@ InspectorMorph, ListMorph, Math, MenuItemMorph, MenuMorph, Morph, MorphicPreferences, MouseSensorMorph, Node, Object, PenMorph, Point, Rectangle, ScrollFrameMorph, ShadowMorph, SliderButtonMorph, SliderMorph, String, StringFieldMorph, StringMorph, TextMorph, -TriggerMorph, WorldMorph, clone, contains, copy, degrees, detect, +TriggerMorph, WorldMorph, contains, copy, degrees, detect, document, getDocumentPositionOf, isNaN, isObject, isString, newCanvas, nop, parseFloat, radians, standardSettings, touchScreenSettings, useBlurredShadows, version, window, modules, IDE_Morph, VariableDialogMorph, @@ -125,7 +125,7 @@ PrototypeHatBlockMorph*/ // Global stuff //////////////////////////////////////////////////////// -modules.objects = '2015-January-28'; +modules.objects = '2015-July-27'; var SpriteMorph; var StageMorph; @@ -581,11 +581,22 @@ SpriteMorph.prototype.initBlocks = function () { category: 'control', spec: 'when %keyHat key pressed' }, + + /* migrated to a newer block version: + receiveClick: { type: 'hat', category: 'control', spec: 'when I am clicked' }, + */ + + receiveInteraction: { + type: 'hat', + category: 'control', + spec: 'when I am %interaction', + defaults: ['clicked'] + }, receiveMessage: { type: 'hat', category: 'control', @@ -889,17 +900,20 @@ SpriteMorph.prototype.initBlocks = function () { reifyScript: { type: 'ring', category: 'other', - spec: '%rc %ringparms' + spec: '%rc %ringparms', + alias: 'command ring lambda' }, reifyReporter: { type: 'ring', category: 'other', - spec: '%rr %ringparms' + spec: '%rr %ringparms', + alias: 'reporter ring lambda' }, reifyPredicate: { type: 'ring', category: 'other', - spec: '%rp %ringparms' + spec: '%rp %ringparms', + alias: 'predicate ring lambda' }, reportSum: { type: 'reporter', @@ -909,12 +923,14 @@ SpriteMorph.prototype.initBlocks = function () { reportDifference: { type: 'reporter', category: 'operators', - spec: '%n \u2212 %n' + spec: '%n \u2212 %n', + alias: '-' }, reportProduct: { type: 'reporter', category: 'operators', - spec: '%n \u00D7 %n' + spec: '%n \u00D7 %n', + alias: '*' }, reportQuotient: { type: 'reporter', @@ -1092,6 +1108,13 @@ SpriteMorph.prototype.initBlocks = function () { spec: 'script variables %scriptVars' }, + // inheritance - experimental + doDeleteAttr: { + type: 'command', + category: 'variables', + spec: 'delete %shd' + }, + // Lists reportNewList: { type: 'reporter', @@ -1205,6 +1228,10 @@ SpriteMorph.prototype.initBlockMigrations = function () { doStopBlock: { selector: 'doStopThis', inputs: [['this block']] + }, + receiveClick: { + selector: 'receiveInteraction', + inputs: [['clicked']] } }; }; @@ -1253,8 +1280,6 @@ SpriteMorph.prototype.blockAlternatives = { setSize: ['changeSize'], // control: - receiveGo: ['receiveClick'], - receiveClick: ['receiveGo'], doBroadcast: ['doBroadcastAndWait'], doBroadcastAndWait: ['doBroadcast'], doIf: ['doIfElse', 'doUntil'], @@ -1335,11 +1360,13 @@ SpriteMorph.prototype.init = function (globals) { 'confetti': 0 }; + // sprite inheritance + this.exemplar = null; + SpriteMorph.uber.init.call(this); this.isDraggable = true; this.isDown = false; - this.heading = 90; this.changed(); this.drawNew(); @@ -1420,15 +1447,13 @@ SpriteMorph.prototype.setName = function (string) { SpriteMorph.prototype.drawNew = function () { var myself = this, - currentCenter = this.center(), + currentCenter, facing, // actual costume heading based on my rotation style isFlipped, - isLoadingCostume = this.costume && - typeof this.costume.loaded === 'function', + isLoadingCostume, cst, pic, // (flipped copy of) actual costume based on my rotation style - stageScale = this.parent instanceof StageMorph ? - this.parent.scale : 1, + stageScale, newX, corners = [], origin, @@ -1442,6 +1467,11 @@ SpriteMorph.prototype.drawNew = function () { this.wantsRedraw = true; return; } + currentCenter = this.center(); + isLoadingCostume = this.costume && + typeof this.costume.loaded === 'function'; + stageScale = this.parent instanceof StageMorph ? + this.parent.scale : 1; facing = this.rotationStyle ? this.heading : 90; if (this.rotationStyle === 2) { facing = 90; @@ -1589,7 +1619,7 @@ SpriteMorph.prototype.blockForSelector = function (selector, setDefaults) { : new ReporterBlockMorph(info.type === 'predicate'); block.color = this.blockColor[info.category]; block.category = info.category; - block.selector = selector; + block.selector = migration ? migration.selector : selector; if (contains(['reifyReporter', 'reifyPredicate'], block.selector)) { block.isStatic = true; } @@ -1626,7 +1656,8 @@ SpriteMorph.prototype.variableBlock = function (varName) { SpriteMorph.prototype.blockTemplates = function (category) { var blocks = [], myself = this, varNames, button, - cat = category || 'motion', txt; + cat = category || 'motion', txt, + inheritedVars = this.inheritedVariableNames(); function block(selector) { if (StageMorph.prototype.hiddenPrimitives[selector]) { @@ -1641,6 +1672,9 @@ SpriteMorph.prototype.blockTemplates = function (category) { var newBlock = SpriteMorph.prototype.variableBlock(varName); newBlock.isDraggable = false; newBlock.isTemplate = true; + if (contains(inheritedVars, varName)) { + newBlock.ghost(); + } return newBlock; } @@ -1689,15 +1723,18 @@ SpriteMorph.prototype.blockTemplates = function (category) { } function addVar(pair) { + var ide; if (pair) { - if (myself.variables.silentFind(pair[0])) { + if (myself.isVariableNameInUse(pair[0], pair[1])) { myself.inform('that name is already in use'); } else { + ide = myself.parentThatIsA(IDE_Morph); myself.addVariable(pair[0], pair[1]); - myself.toggleVariableWatcher(pair[0], pair[1]); - myself.blocksCache[cat] = null; - myself.paletteCache[cat] = null; - myself.parentThatIsA(IDE_Morph).refreshPalette(); + if (!myself.showingVariableWatcher(pair[0])) { + myself.toggleVariableWatcher(pair[0], pair[1]); + } + ide.flushBlocksCache('variables'); // b/c of inheritance + ide.refreshPalette(); } } } @@ -1829,7 +1866,7 @@ SpriteMorph.prototype.blockTemplates = function (category) { blocks.push(block('receiveGo')); blocks.push(block('receiveKey')); - blocks.push(block('receiveClick')); + blocks.push(block('receiveInteraction')); blocks.push(block('receiveMessage')); blocks.push('-'); blocks.push(block('doBroadcast')); @@ -2012,7 +2049,7 @@ SpriteMorph.prototype.blockTemplates = function (category) { button.showHelp = BlockMorph.prototype.showHelp; blocks.push(button); - if (this.variables.allNames().length > 0) { + if (this.deletableVariableNames().length > 0) { button = new PushButtonMorph( null, function () { @@ -2021,7 +2058,7 @@ SpriteMorph.prototype.blockTemplates = function (category) { null, myself ); - myself.variables.allNames().forEach(function (name) { + myself.deletableVariableNames().forEach(function (name) { menu.addItem(name, name); }); menu.popUpAtHand(myself.world()); @@ -2051,6 +2088,15 @@ SpriteMorph.prototype.blockTemplates = function (category) { blocks.push(block('doHideVar')); blocks.push(block('doDeclareVariables')); + // inheritance: + + if (StageMorph.prototype.enableInheritance) { + blocks.push('-'); + blocks.push(block('doDeleteAttr')); + } + + /////////////////////////////// + blocks.push('='); blocks.push(block('reportNewList')); @@ -2341,15 +2387,30 @@ SpriteMorph.prototype.freshPalette = function (category) { // SpriteMorph blocks searching -SpriteMorph.prototype.blocksMatching = function (searchString, strictly) { +SpriteMorph.prototype.blocksMatching = function ( + searchString, + strictly, + types, // optional, ['hat', 'command', 'reporter', 'predicate'] + varNames // optional, list of reachable unique variable names +) { // answer an array of block templates whose spec contains // the given search string, ordered by descending relevance + // types is an optional array containing block types the search + // is limited to, e.g. "command", "hat", "reporter", "predicate". + // Note that "predicate" is not subsumed by "reporter" and has + // to be specified explicitly. + // if no types are specified all blocks are searched var blocks = [], blocksDict, myself = this, search = searchString.toLowerCase(), stage = this.parentThatIsA(StageMorph); + if (!types || !types.length) { + types = ['hat', 'command', 'reporter', 'predicate', 'ring']; + } + if (!varNames) {varNames = []; } + function labelOf(aBlockSpec) { var words = (BlockMorph.prototype.parseSpec(aBlockSpec)), filtered = words.filter( @@ -2380,29 +2441,39 @@ SpriteMorph.prototype.blocksMatching = function (searchString, strictly) { return newBlock; } + // variable getters + varNames.forEach(function (vName) { + var rel = relevance(labelOf(vName), search); + if (rel !== -1) { + blocks.push([myself.variableBlock(vName), rel + '1']); + } + }); // custom blocks [this.customBlocks, stage.globalBlocks].forEach(function (blocksList) { blocksList.forEach(function (definition) { - var spec = localize(definition.blockSpec()).toLowerCase(), - rel = relevance(labelOf(spec), search); - if (rel !== -1) { - blocks.push([definition.templateInstance(), rel + '1']); + if (contains(types, definition.type)) { + var spec = localize(definition.blockSpec()).toLowerCase(), + rel = relevance(labelOf(spec), search); + if (rel !== -1) { + blocks.push([definition.templateInstance(), rel + '2']); + } } }); }); // primitives blocksDict = SpriteMorph.prototype.blocks; Object.keys(blocksDict).forEach(function (selector) { - if (!StageMorph.prototype.hiddenPrimitives[selector]) { + if (!StageMorph.prototype.hiddenPrimitives[selector] && + contains(types, blocksDict[selector].type)) { var block = blocksDict[selector], - spec = localize(block.spec).toLowerCase(), + spec = localize(block.alias || block.spec).toLowerCase(), rel = relevance(labelOf(spec), search); if ( (rel !== -1) && (!block.dev) && (!block.only || (block.only === myself.constructor)) ) { - blocks.push([primitive(selector), rel + '2']); + blocks.push([primitive(selector), rel + '3']); } } }); @@ -2410,18 +2481,43 @@ SpriteMorph.prototype.blocksMatching = function (searchString, strictly) { return blocks.map(function (each) {return each[0]; }); }; -SpriteMorph.prototype.searchBlocks = function () { +SpriteMorph.prototype.searchBlocks = function ( + searchString, + types, + varNames, + scriptFocus +) { var myself = this, unit = SyntaxElementMorph.prototype.fontSize, ide = this.parentThatIsA(IDE_Morph), oldSearch = '', - searchBar = new InputFieldMorph(''), - searchPane = ide.createPalette('forSearch'); + searchBar = new InputFieldMorph(searchString || ''), + searchPane = ide.createPalette('forSearch'), + blocksList = [], + selection, + focus; + + function showSelection() { + if (focus) {focus.destroy(); } + if (!selection || !scriptFocus) {return; } + focus = selection.outline( + MorphicPreferences.isFlat ? new Color(150, 200, 255) + : new Color(255, 255, 255), + 2 + ); + searchPane.contents.add(focus); + focus.scrollIntoView(); + } function show(blocks) { var oldFlag = Morph.prototype.trackChanges, x = searchPane.contents.left() + 5, y = (searchBar.bottom() + unit); + blocksList = blocks; + selection = null; + if (blocks.length && scriptFocus) { + selection = blocks[0]; + } Morph.prototype.trackChanges = false; searchPane.contents.children = [searchPane.contents.children[0]]; blocks.forEach(function (block) { @@ -2431,6 +2527,7 @@ SpriteMorph.prototype.searchBlocks = function () { y += unit * 0.3; }); Morph.prototype.trackChanges = oldFlag; + showSelection(); searchPane.changed(); } @@ -2447,17 +2544,52 @@ SpriteMorph.prototype.searchBlocks = function () { searchBar.drawNew(); searchPane.accept = function () { - var search = searchBar.getValue(); - if (search.length > 0) { - show(myself.blocksMatching(search)); + var search; + if (scriptFocus) { + searchBar.cancel(); + if (selection) { + scriptFocus.insertBlock(selection); + } + } else { + search = searchBar.getValue(); + if (search.length > 0) { + show(myself.blocksMatching(search)); + } } }; - searchPane.reactToKeystroke = function () { - var search = searchBar.getValue(); - if (search !== oldSearch) { - oldSearch = search; - show(myself.blocksMatching(search, search.length < 2)); + searchPane.reactToKeystroke = function (evt) { + var search, idx, code = evt ? evt.keyCode : 0; + switch (code) { + case 38: // up arrow + if (!scriptFocus || !selection) {return; } + idx = blocksList.indexOf(selection) - 1; + if (idx < 0) { + idx = blocksList.length - 1; + } + selection = blocksList[idx]; + showSelection(); + return; + case 40: // down arrow + if (!scriptFocus || !selection) {return; } + idx = blocksList.indexOf(selection) + 1; + if (idx >= blocksList.length) { + idx = 0; + } + selection = blocksList[idx]; + showSelection(); + return; + default: + search = searchBar.getValue(); + if (search !== oldSearch) { + oldSearch = search; + show(myself.blocksMatching( + search, + search.length < 2, + types, + varNames + )); + } } }; @@ -2468,6 +2600,7 @@ SpriteMorph.prototype.searchBlocks = function () { ide.fixLayout('refreshPalette'); searchBar.edit(); + if (searchString) {searchPane.reactToKeystroke(); } }; // SpriteMorph variable management @@ -2475,7 +2608,7 @@ SpriteMorph.prototype.searchBlocks = function () { SpriteMorph.prototype.addVariable = function (name, isGlobal) { var ide = this.parentThatIsA(IDE_Morph); if (isGlobal) { - this.variables.parentFrame.addVar(name); + this.globalVariables().addVar(name); if (ide) { ide.flushBlocksCache('variables'); } @@ -2487,7 +2620,10 @@ SpriteMorph.prototype.addVariable = function (name, isGlobal) { SpriteMorph.prototype.deleteVariable = function (varName) { var ide = this.parentThatIsA(IDE_Morph); - this.deleteVariableWatcher(varName); + if (!contains(this.inheritedVariableNames(true), varName)) { + // check only shadowed variables + this.deleteVariableWatcher(varName); + } this.variables.deleteVar(varName); if (ide) { ide.flushBlocksCache('variables'); // b/c the var could be global @@ -2642,7 +2778,7 @@ SpriteMorph.prototype.userMenu = function () { } menu.addItem("duplicate", 'duplicate'); menu.addItem("delete", 'remove'); - menu.addItem("move", 'move'); + menu.addItem("move", 'moveCenter'); if (!this.isClone) { menu.addItem("edit", 'edit'); } @@ -2661,7 +2797,7 @@ SpriteMorph.prototype.userMenu = function () { }; SpriteMorph.prototype.exportSprite = function () { - if (this.isCoone) {return; } + if (this.isClone) {return; } var ide = this.parentThatIsA(IDE_Morph); if (ide) { ide.exportSprite(this); @@ -2702,7 +2838,7 @@ SpriteMorph.prototype.remove = function () { SpriteMorph.prototype.createClone = function () { var stage = this.parentThatIsA(StageMorph); - if (stage && stage.cloneCount <= 300) { + if (stage && stage.cloneCount <= 1000) { this.fullCopy().clonify(stage); } }; @@ -2992,7 +3128,7 @@ SpriteMorph.prototype.applyGraphicsEffects = function (canvas) { var i; if (value !== 0) { for (i = 0; i < p.length; i += 4) { - p[i] += value; //255 = 100% of this color + p[i] += value; //255 = 100% of this color p[i + 1] += value; p[i + 2] += value; } @@ -3065,7 +3201,7 @@ SpriteMorph.prototype.setEffect = function (effect, value) { if (eff === 'ghost') { this.alpha = 1 - Math.min(Math.max(+value || 0, 0), 100) / 100; } else { - this.graphicsValues[eff] = value; + this.graphicsValues[eff] = +value; } this.drawNew(); this.changed(); @@ -3080,7 +3216,7 @@ SpriteMorph.prototype.changeEffect = function (effect, value) { if (eff === 'ghost') { this.setEffect(effect, this.getGhostEffect() + (+value || 0)); } else { - this.setEffect(effect, this.graphicsValues[eff] + value); + this.setEffect(effect, +this.graphicsValues[eff] + (+value)); } }; @@ -3160,15 +3296,24 @@ SpriteMorph.prototype.positionTalkBubble = function () { SpriteMorph.prototype.prepareToBeGrabbed = function (hand) { this.removeShadow(); this.recordLayers(); - if (!this.bounds.containsPoint(hand.position())) { + if (!this.bounds.containsPoint(hand.position()) && + this.isCorrectingOutsideDrag()) { this.setCenter(hand.position()); } this.addShadow(); }; +SpriteMorph.prototype.isCorrectingOutsideDrag = function () { + // make sure I don't "trail behind" the hand when dragged + // override for morphs that you want to be dragged outside + // their full bounds + return !this.parts.length; +}; + SpriteMorph.prototype.justDropped = function () { this.restoreLayers(); this.positionTalkBubble(); + this.receiveUserInteraction('dropped'); }; // SpriteMorph drawing: @@ -3223,6 +3368,22 @@ SpriteMorph.prototype.moveBy = function (delta, justMe) { } }; +SpriteMorph.prototype.silentMoveBy = function (delta, justMe) { + SpriteMorph.uber.silentMoveBy.call(this, delta); + if (!justMe && this.parent instanceof HandMorph) { + this.parts.forEach(function (part) { + part.moveBy(delta); + }); + } +}; + +SpriteMorph.prototype.rootForGrab = function () { + if (this.anchor) { + return this.anchor.rootForGrab(); + } + return SpriteMorph.uber.rootForGrab.call(this); +}; + SpriteMorph.prototype.slideBackTo = function (situation, inSteps) { // override the inherited default to make sure my parts follow var steps = inSteps || 5, @@ -3273,7 +3434,7 @@ SpriteMorph.prototype.nestingBounds = function () { // SpriteMorph motion primitives -Morph.prototype.setPosition = function (aPoint, justMe) { +SpriteMorph.prototype.setPosition = function (aPoint, justMe) { // override the inherited default to make sure my parts follow // unless it's justMe var delta = aPoint.subtract(this.topLeft()); @@ -3492,7 +3653,10 @@ SpriteMorph.prototype.allHatBlocksFor = function (message) { if (morph.selector) { if (morph.selector === 'receiveMessage') { event = morph.inputs()[0].evaluate(); - return event === message || (event instanceof Array); + return event === message + || (event instanceof Array + && message !== '__shout__go__' + && message !== '__clone__init__'); } if (morph.selector === 'receiveGo') { return message === '__shout__go__'; @@ -3500,9 +3664,6 @@ SpriteMorph.prototype.allHatBlocksFor = function (message) { if (morph.selector === 'receiveOnClone') { return message === '__clone__init__'; } - if (morph.selector === 'receiveClick') { - return message === '__click__'; - } } return false; }); @@ -3519,13 +3680,37 @@ SpriteMorph.prototype.allHatBlocksForKey = function (key) { }); }; +SpriteMorph.prototype.allHatBlocksForInteraction = function (interaction) { + return this.scripts.children.filter(function (morph) { + if (morph.selector) { + if (morph.selector === 'receiveInteraction') { + return morph.inputs()[0].evaluate()[0] === interaction; + } + } + return false; + }); +}; + // SpriteMorph events SpriteMorph.prototype.mouseClickLeft = function () { - var stage = this.parentThatIsA(StageMorph), - hats = this.allHatBlocksFor('__click__'), - procs = []; + return this.receiveUserInteraction('clicked'); +}; +SpriteMorph.prototype.mouseEnter = function () { + return this.receiveUserInteraction('mouse-entered'); +}; + +SpriteMorph.prototype.mouseDownLeft = function () { + return this.receiveUserInteraction('pressed'); +}; + +SpriteMorph.prototype.receiveUserInteraction = function (interaction) { + var stage = this.parentThatIsA(StageMorph), + procs = [], + hats; + if (!stage) {return; } // currently dragged + hats = this.allHatBlocksForInteraction(interaction); hats.forEach(function (block) { procs.push(stage.threads.startProcess(block, stage.isThreadSafe)); }); @@ -3605,6 +3790,7 @@ SpriteMorph.prototype.reportThreadCount = function () { SpriteMorph.prototype.findVariableWatcher = function (varName) { var stage = this.parentThatIsA(StageMorph), + globals = this.globalVariables(), myself = this; if (stage === null) { return null; @@ -3614,7 +3800,7 @@ SpriteMorph.prototype.findVariableWatcher = function (varName) { function (morph) { return morph instanceof WatcherMorph && (morph.target === myself.variables - || morph.target === myself.variables.parentFrame) + || morph.target === globals) && morph.getter === varName; } ); @@ -3622,6 +3808,7 @@ SpriteMorph.prototype.findVariableWatcher = function (varName) { SpriteMorph.prototype.toggleVariableWatcher = function (varName, isGlobal) { var stage = this.parentThatIsA(StageMorph), + globals = this.globalVariables(), watcher, others; if (stage === null) { @@ -3641,12 +3828,12 @@ SpriteMorph.prototype.toggleVariableWatcher = function (varName, isGlobal) { // if no watcher exists, create a new one if (isNil(isGlobal)) { - isGlobal = contains(this.variables.parentFrame.names(), varName); + isGlobal = contains(globals.names(), varName); } watcher = new WatcherMorph( varName, this.blockColor.variables, - isGlobal ? this.variables.parentFrame : this.variables, + isGlobal ? globals : this.variables, varName ); watcher.setPosition(stage.position().add(10)); @@ -3913,6 +4100,176 @@ SpriteMorph.prototype.replaceDoubleDefinitionsFor = function (definition) { } }; +// SpriteMorph inheritance - general + +SpriteMorph.prototype.chooseExemplar = function () { + var stage = this.parentThatIsA(StageMorph), + myself = this, + other = stage.children.filter(function (m) { + return m instanceof SpriteMorph && + (!contains(m.allExemplars(), myself)); + }), + menu; + menu = new MenuMorph( + function (aSprite) {myself.setExemplar(aSprite); }, + localize('current parent') + + ':\n' + + (this.exemplar ? this.exemplar.name : localize('none')) + ); + other.forEach(function (eachSprite) { + menu.addItem(eachSprite.name, eachSprite); + }); + menu.addLine(); + menu.addItem(localize('none'), null); + menu.popUpAtHand(this.world()); +}; + +SpriteMorph.prototype.setExemplar = function (another) { + var ide = this.parentThatIsA(IDE_Morph); + this.exemplar = another; + if (isNil(another)) { + this.variables.parentFrame = (this.globalVariables()); + } else { + this.variables.parentFrame = (another.variables); + } + if (ide) { + ide.flushBlocksCache('variables'); + ide.refreshPalette(); + } +}; + +SpriteMorph.prototype.allExemplars = function () { + // including myself + var all = [], + current = this; + while (!isNil(current)) { + all.push(current); + current = current.exemplar; + } + return all; +}; + +SpriteMorph.prototype.specimens = function () { + // without myself + var myself = this; + return this.siblings().filter(function (m) { + return m instanceof SpriteMorph && (m.exemplar === myself); + }); +}; + +SpriteMorph.prototype.allSpecimens = function () { + // without myself + var myself = this; + return this.siblings().filter(function (m) { + return m instanceof SpriteMorph && contains(m.allExemplars(), myself); + }); +}; + +// SpriteMorph inheritance - variables + +SpriteMorph.prototype.isVariableNameInUse = function (vName, isGlobal) { + if (isGlobal) { + return contains(this.variables.allNames(), vName); + } + if (contains(this.variables.names(), vName)) {return true; } + return contains(this.globalVariables().names(), vName); +}; + +SpriteMorph.prototype.globalVariables = function () { + var current = this.variables.parentFrame; + while (current.owner) { + current = current.parentFrame; + } + return current; +}; + +SpriteMorph.prototype.shadowVar = function (name, value) { + var ide = this.parentThatIsA(IDE_Morph); + this.variables.addVar(name, value); + if (ide) { + ide.flushBlocksCache('variables'); + ide.refreshPalette(); + } +}; + +SpriteMorph.prototype.inheritedVariableNames = function (shadowedOnly) { + var names = [], + own = this.variables.names(), + current = this.variables.parentFrame; + + function test(each) { + return shadowedOnly ? contains(own, each) : !contains(own, each); + } + + while (current.owner instanceof SpriteMorph) { + names.push.apply( + names, + current.names().filter(test) + ); + current = current.parentFrame; + } + return names; +}; + +SpriteMorph.prototype.deletableVariableNames = function () { + var locals = this.variables.names(), + inherited = this.inheritedVariableNames(); + return locals.concat( + this.globalVariables().names().filter( + function (each) { + return !contains(locals, each) && !contains(inherited, each); + } + ) + ); +}; + +// SpriteMorph inheritance - custom blocks + +/* +// under construction, commented out for now + +SpriteMorph.prototype.ownBlocks = function () { + var dict = {}; + this.customBlocks.forEach(function (def) { + dict[def.blockSpec()] = def; + }); + return dict; +}; + +SpriteMorph.prototype.allBlocks = function (valuesOnly) { + var dict = {}; + this.allExemplars().reverse().forEach(function (sprite) { + sprite.customBlocks.forEach(function (def) { + dict[def.blockSpec()] = def; + }); + }); + if (valuesOnly) { + return Object.keys(dict).map(function (key) {return dict[key]; }); + } + return dict; +}; + +SpriteMorph.prototype.inheritedBlocks = function (valuesOnly) { + var dict = {}, + own = Object.keys(this.ownBlocks()), + others = this.allExemplars().reverse(); + others.pop(); + others.forEach(function (sprite) { + sprite.customBlocks.forEach(function (def) { + var spec = def.blockSpec(); + if (!contains(own, spec)) { + dict[spec] = def; + } + }); + }); + if (valuesOnly) { + return Object.keys(dict).map(function (key) {return dict[key]; }); + } + return dict; +}; + +*/ + // SpriteMorph thumbnail SpriteMorph.prototype.thumbnail = function (extentPoint) { @@ -4190,6 +4547,7 @@ SpriteMorph.prototype.mouseEnterDragging = function () { }; SpriteMorph.prototype.mouseLeave = function () { + this.receiveUserInteraction('mouse-departed'); if (!this.enableNesting) {return; } this.removeHighlight(); }; @@ -4292,6 +4650,8 @@ StageMorph.prototype.codeMappings = {}; StageMorph.prototype.codeHeaders = {}; StageMorph.prototype.enableCodeMapping = false; +StageMorph.prototype.enableInheritance = false; + // StageMorph instance creation function StageMorph(globals) { @@ -4725,6 +5085,8 @@ StageMorph.prototype.processKeyEvent = function (event, action) { keyName = 'enter'; if (event.ctrlKey || event.metaKey) { keyName = 'ctrl enter'; + } else if (event.shiftKey) { + keyName = 'shift enter'; } break; case 27: @@ -4765,6 +5127,9 @@ StageMorph.prototype.fireKeyEvent = function (key) { if (evt === 'ctrl enter') { return this.fireGreenFlagEvent(); } + if (evt === 'shift enter') { + return this.editScripts(); + } if (evt === 'ctrl f') { if (!ide.isAppMode) {ide.currentSprite.searchBlocks(); } return; @@ -4865,6 +5230,25 @@ StageMorph.prototype.removeAllClones = function () { this.cloneCount = 0; }; +StageMorph.prototype.editScripts = function () { + var ide = this.parentThatIsA(IDE_Morph), + scripts, + sorted; + if (ide.isAppMode || !ScriptsMorph.prototype.enableKeyboard) {return; } + scripts = this.parentThatIsA(IDE_Morph).currentSprite.scripts; + scripts.edit(scripts.position()); + sorted = scripts.focus.sortedScripts(); + if (sorted.length) { + scripts.focus.element = sorted[0]; + if (scripts.focus.element instanceof HatBlockMorph) { + scripts.focus.nextCommand(); + } + } else { + scripts.focus.moveBy(new Point(50, 50)); + } + scripts.focus.fixLayout(); +}; + // StageMorph block templates StageMorph.prototype.blockTemplates = function (category) { @@ -4927,7 +5311,7 @@ StageMorph.prototype.blockTemplates = function (category) { function addVar(pair) { if (pair) { - if (myself.variables.silentFind(pair[0])) { + if (myself.isVariableNameInUse(pair[0])) { myself.inform('that name is already in use'); } else { myself.addVariable(pair[0], pair[1]); @@ -5020,7 +5404,7 @@ StageMorph.prototype.blockTemplates = function (category) { blocks.push(block('receiveGo')); blocks.push(block('receiveKey')); - blocks.push(block('receiveClick')); + blocks.push(block('receiveInteraction')); blocks.push(block('receiveMessage')); blocks.push('-'); blocks.push(block('doBroadcast')); @@ -5229,9 +5613,7 @@ StageMorph.prototype.blockTemplates = function (category) { blocks.push(block('doShowVar')); blocks.push(block('doHideVar')); blocks.push(block('doDeclareVariables')); - blocks.push('='); - blocks.push(block('reportNewList')); blocks.push('-'); blocks.push(block('reportCONS')); @@ -5430,7 +5812,7 @@ StageMorph.prototype.show = function () { this.changed(); }; -// StageMorph cloning overrice +// StageMorph cloning override StageMorph.prototype.createClone = nop; @@ -5574,11 +5956,27 @@ StageMorph.prototype.allHatBlocksFor StageMorph.prototype.allHatBlocksForKey = SpriteMorph.prototype.allHatBlocksForKey; +StageMorph.prototype.allHatBlocksForInteraction + = SpriteMorph.prototype.allHatBlocksForInteraction; + // StageMorph events StageMorph.prototype.mouseClickLeft = SpriteMorph.prototype.mouseClickLeft; +StageMorph.prototype.mouseEnter + = SpriteMorph.prototype.mouseEnter; + +StageMorph.prototype.mouseLeave = function () { + this.receiveUserInteraction('mouse-departed'); +}; + +StageMorph.prototype.mouseDownLeft + = SpriteMorph.prototype.mouseDownLeft; + +StageMorph.prototype.receiveUserInteraction + = SpriteMorph.prototype.receiveUserInteraction; + // StageMorph custom blocks StageMorph.prototype.deleteAllBlockInstances @@ -5605,6 +6003,18 @@ StageMorph.prototype.doubleDefinitionsFor StageMorph.prototype.replaceDoubleDefinitionsFor = SpriteMorph.prototype.replaceDoubleDefinitionsFor; +// StageMorph inheritance support - variables + +StageMorph.prototype.isVariableNameInUse + = SpriteMorph.prototype.isVariableNameInUse; + +StageMorph.prototype.globalVariables + = SpriteMorph.prototype.globalVariables; + +StageMorph.prototype.inheritedVariableNames = function () { + return []; +}; + // SpriteBubbleMorph //////////////////////////////////////////////////////// /* @@ -6374,7 +6784,7 @@ Note.prototype.play = function () { if (!this.oscillator.stop) { this.oscillator.stop = this.oscillator.noteOff; } - this.oscillator.type = 0; + this.oscillator.type = 'sine'; this.oscillator.frequency.value = Math.pow(2, (this.pitch - 69) / 12) * 440; this.oscillator.connect(this.gainNode); @@ -6818,32 +7228,51 @@ WatcherMorph.prototype.isGlobal = function (selector) { // WatcherMorph slider accessing: -WatcherMorph.prototype.setSliderMin = function (num) { +WatcherMorph.prototype.setSliderMin = function (num, noUpdate) { if (this.target instanceof VariableFrame) { - this.sliderMorph.setSize(1); - this.sliderMorph.setStart(num); - this.sliderMorph.setSize(this.sliderMorph.rangeSize() / 5); + this.sliderMorph.setSize(1, noUpdate); + this.sliderMorph.setStart(num, noUpdate); + this.sliderMorph.setSize(this.sliderMorph.rangeSize() / 5, noUpdate); } }; -WatcherMorph.prototype.setSliderMax = function (num) { +WatcherMorph.prototype.setSliderMax = function (num, noUpdate) { if (this.target instanceof VariableFrame) { - this.sliderMorph.setSize(1); - this.sliderMorph.setStop(num); - this.sliderMorph.setSize(this.sliderMorph.rangeSize() / 5); + this.sliderMorph.setSize(1, noUpdate); + this.sliderMorph.setStop(num, noUpdate); + this.sliderMorph.setSize(this.sliderMorph.rangeSize() / 5, noUpdate); } }; // WatcherMorph updating: WatcherMorph.prototype.update = function () { - var newValue, - num; + var newValue, sprite, num; + if (this.target && this.getter) { this.updateLabel(); if (this.target instanceof VariableFrame) { newValue = this.target.vars[this.getter] ? this.target.vars[this.getter].value : undefined; + if (newValue === undefined && this.target.owner) { + sprite = this.target.owner; + if (contains(sprite.inheritedVariableNames(), this.getter)) { + newValue = this.target.getVar(this.getter); + // ghost cell color + this.cellMorph.setColor( + SpriteMorph.prototype.blockColor.variables + .lighter(35) + ); + } else { + this.destroy(); + return; + } + } else { + // un-ghost the cell color + this.cellMorph.setColor( + SpriteMorph.prototype.blockColor.variables + ); + } } else { newValue = this.target[this.getter](); } @@ -6928,7 +7357,11 @@ WatcherMorph.prototype.fixLayout = function () { this.sliderMorph.button.pressColor.b += 100; this.sliderMorph.setHeight(fontSize); this.sliderMorph.action = function (num) { - myself.target.vars[myself.getter].value = Math.round(num); + myself.target.setVar( + myself.getter, + Math.round(num), + myself.target.owner + ); }; this.add(this.sliderMorph); } @@ -7025,7 +7458,46 @@ WatcherMorph.prototype.userMenu = function () { var myself = this, menu = new MenuMorph(this), on = '\u25CF', - off = '\u25CB'; + off = '\u25CB', + vNames; + + function monitor(vName) { + var stage = myself.parentThatIsA(StageMorph), + varFrame = myself.currentValue.outerContext.variables; + menu.addItem( + vName + '...', + function () { + var watcher = detect( + stage.children, + function (morph) { + return morph instanceof WatcherMorph + && morph.target === varFrame + && morph.getter === vName; + } + ), + others; + if (watcher !== null) { + watcher.show(); + watcher.fixLayout(); // re-hide hidden parts + return; + } + watcher = new WatcherMorph( + vName + ' ' + localize('(temporary)'), + SpriteMorph.prototype.blockColor.variables, + varFrame, + vName + ); + watcher.setPosition(stage.position().add(10)); + others = stage.watchers(watcher.left()); + if (others.length > 0) { + watcher.setTop(others[others.length - 1].bottom()); + } + stage.add(watcher); + watcher.fixLayout(); + } + ); + } + menu.addItem( (this.style === 'normal' ? on : off) + ' ' + localize('normal'), 'styleNormal' @@ -7124,6 +7596,14 @@ WatcherMorph.prototype.userMenu = function () { ); } ); + } else if (this.currentValue instanceof Context) { + vNames = this.currentValue.outerContext.variables.names(); + if (vNames.length) { + menu.addLine(); + vNames.forEach(function (vName) { + monitor(vName); + }); + } } } return menu; diff --git a/paint.js b/paint.js index 65ae1f6d..6d9b09c8 100644 --- a/paint.js +++ b/paint.js @@ -5,7 +5,7 @@ inspired by the Scratch paint editor. written by Kartik Chandra - Copyright (C) 2014 by Kartik Chandra + Copyright (C) 2015 by Kartik Chandra This file is part of Snap!. @@ -69,7 +69,7 @@ // Global stuff //////////////////////////////////////////////////////// -modules.paint = '2014-September-29'; +modules.paint = '2015-June-25'; // Declarations diff --git a/snap.html b/snap.html index 93b4c730..976bcd63 100755 --- a/snap.html +++ b/snap.html @@ -2,7 +2,7 @@ - Snap! Build Your Own Blocks. Beta + Snap! Build Your Own Blocks diff --git a/stitchcode/stitchcodeGUI.js b/stitchcode/stitchcodeGUI.js index 473280eb..fe9a59bd 100644 --- a/stitchcode/stitchcodeGUI.js +++ b/stitchcode/stitchcodeGUI.js @@ -1289,7 +1289,7 @@ IDE_Morph.prototype.createSpriteBar = function () { active.refresh(); // needed when programmatically tabbing myself.createSpriteEditor(); myself.fixLayout('tabEditor'); - }; + };t tab = new TabMorph( tabColors, @@ -1699,11 +1699,6 @@ IDE_Morph.prototype.snapMenu = function () { menu.popup(world, this.logo.bottomLeft()); }; -IDE_Morph.prototype.originalCreatePalette = IDE_Morph.prototype.createPalette; -IDE_Morph.prototype.createPalette = function(){ - this.originalCreatePalette(); - this.palette.color = new Color(230, 230, 230); -} IDE_Morph.prototype.originalCreateSpriteEditor = IDE_Morph.prototype.createSpriteEditor; IDE_Morph.prototype.createSpriteEditor = function(){ diff --git a/store.js b/store.js index 056767f1..6112c224 100644 --- a/store.js +++ b/store.js @@ -61,7 +61,7 @@ SyntaxElementMorph, Variable*/ // Global stuff //////////////////////////////////////////////////////// -modules.store = '2015-January-21'; +modules.store = '2015-July-27'; // XML_Serializer /////////////////////////////////////////////////////// @@ -320,7 +320,7 @@ SnapSerializer.prototype.loadProjectModel = function (xmlNode, ide) { var appInfo = xmlNode.attributes.app, app = appInfo ? appInfo.split(' ')[0] : null; - if (ide && app !== this.app.split(' ')[0]) { + if (ide && app && app !== this.app.split(' ')[0]) { ide.inform( app + ' Project', 'This project has been created by a different app:\n\n' + @@ -413,6 +413,8 @@ SnapSerializer.prototype.rawLoadProjectModel = function (xmlNode) { model.stage.attributes.threadsafe === 'true'; StageMorph.prototype.enableCodeMapping = model.stage.attributes.codify === 'true'; + StageMorph.prototype.enableInheritance = + model.stage.attributes.inheritance === 'true'; model.hiddenPrimitives = model.project.childNamed('hidden'); if (model.hiddenPrimitives) { @@ -459,9 +461,17 @@ SnapSerializer.prototype.rawLoadProjectModel = function (xmlNode) { myself.loadValue(model); }); - // restore nesting associations + // restore inheritance and nesting associations myself.project.stage.children.forEach(function (sprite) { - var anchor; + var exemplar, anchor; + if (sprite.inheritanceInfo) { // only sprites can inherit + exemplar = myself.project.sprites[ + sprite.inheritanceInfo.exemplar + ]; + if (exemplar) { + sprite.setExemplar(exemplar); + } + } if (sprite.nestingInfo) { // only sprites may have nesting info anchor = myself.project.sprites[sprite.nestingInfo.anchor]; if (anchor) { @@ -471,6 +481,7 @@ SnapSerializer.prototype.rawLoadProjectModel = function (xmlNode) { } }); myself.project.stage.children.forEach(function (sprite) { + delete sprite.inheritanceInfo; if (sprite.nestingInfo) { // only sprites may have nesting info sprite.nestingScale = +(sprite.nestingInfo.scale || sprite.scale); delete sprite.nestingInfo; @@ -531,8 +542,8 @@ SnapSerializer.prototype.rawLoadProjectModel = function (xmlNode) { } watcher.setStyle(model.attributes.style || 'normal'); if (watcher.style === 'slider') { - watcher.setSliderMin(model.attributes.min || '1'); - watcher.setSliderMax(model.attributes.max || '100'); + watcher.setSliderMin(model.attributes.min || '1', true); + watcher.setSliderMax(model.attributes.max || '100', true); } watcher.setPosition( project.stage.topLeft().add(new Point( @@ -639,9 +650,17 @@ SnapSerializer.prototype.loadSprites = function (xmlString, ide) { myself.loadObject(sprite, model); }); - // restore nesting associations + // restore inheritance and nesting associations project.stage.children.forEach(function (sprite) { - var anchor; + var exemplar, anchor; + if (sprite.inheritanceInfo) { // only sprites can inherit + exemplar = project.sprites[ + sprite.inheritanceInfo.exemplar + ]; + if (exemplar) { + sprite.setExemplar(exemplar); + } + } if (sprite.nestingInfo) { // only sprites may have nesting info anchor = project.sprites[sprite.nestingInfo.anchor]; if (anchor) { @@ -651,6 +670,7 @@ SnapSerializer.prototype.loadSprites = function (xmlString, ide) { } }); project.stage.children.forEach(function (sprite) { + delete sprite.inheritanceInfo; if (sprite.nestingInfo) { // only sprites may have nesting info sprite.nestingScale = +(sprite.nestingInfo.scale || sprite.scale); delete sprite.nestingInfo; @@ -699,6 +719,14 @@ SnapSerializer.prototype.loadObject = function (object, model) { this.loadScripts(object.scripts, model.require('scripts')); }; +SnapSerializer.prototype.loadInheritanceInfo = function (object, model) { + // private + var info = model.childNamed('inherit'); + if (info) { + object.inheritanceInfo = info.attributes; + } +}; + SnapSerializer.prototype.loadNestingInfo = function (object, model) { // private var info = model.childNamed('nest'); @@ -782,7 +810,7 @@ SnapSerializer.prototype.loadCustomBlocks = function ( names = definition.parseSpec(definition.spec).filter( function (str) { - return str.charAt(0) === '%'; + return str.charAt(0) === '%' && str.length > 1; } ).map(function (str) { return str.substr(1); @@ -977,7 +1005,11 @@ SnapSerializer.prototype.loadBlock = function (model, isReporter) { ); } if (!receiver) { - return this.obsoleteBlock(isReporter); + if (!isGlobal) { + receiver = this.project.stage; + } else { + return this.obsoleteBlock(isReporter); + } } if (isGlobal) { info = detect(receiver.globalBlocks, function (block) { @@ -1023,6 +1055,7 @@ SnapSerializer.prototype.loadBlock = function (model, isReporter) { this.loadInput(child, inputs[i], block); } }, this); + block.cachedInputs = null; return block; }; @@ -1403,6 +1436,7 @@ StageMorph.prototype.toXML = function (serializer) { 'costume="@" tempo="@" threadsafe="@" ' + 'lines="@" ' + 'codify="@" ' + + 'inheritance="@" ' + 'scheduled="@" ~>' + '$' + '%' + @@ -1430,6 +1464,7 @@ StageMorph.prototype.toXML = function (serializer) { this.isThreadSafe, SpriteMorph.prototype.useFlatLineEnds ? 'flat' : 'round', this.enableCodeMapping, + this.enableInheritance, StageMorph.prototype.frameRate !== 0, this.trailsCanvas.toDataURL('image/png'), serializer.store(this.costumes, this.name + '_cst'), @@ -1462,6 +1497,7 @@ SpriteMorph.prototype.toXML = function (serializer) { ' draggable="@"' + '%' + ' costume="@" color="@,@,@" pen="@" ~>' + + '%' + // inheritance info '%' + // nesting info '%' + '%' + @@ -1484,6 +1520,13 @@ SpriteMorph.prototype.toXML = function (serializer) { this.color.b, this.penPoint, + // inheritance info + this.exemplar + ? '' + : '', + // nesting info this.anchor ? '
1datamapmany1data lists
1
1
110i
1
cont
catchtag
cont
catchtag
\ No newline at end of file +
1datamapmany1data lists
1
1
110i
1
cont
catchtag
cont
catchtag
Sprite
Sprite
\ No newline at end of file diff --git a/widgets.js b/widgets.js index bb250a85..2bfb4ceb 100644 --- a/widgets.js +++ b/widgets.js @@ -7,7 +7,7 @@ written by Jens Mönig jens@moenig.org - Copyright (C) 2014 by Jens Mönig + Copyright (C) 2015 by Jens Mönig This file is part of Snap!. @@ -74,7 +74,7 @@ HTMLCanvasElement, fontHeight, SymbolMorph, localize, SpeechBubbleMorph, ArrowMorph, MenuMorph, isString, isNil, SliderMorph, MorphicPreferences, ScrollFrameMorph*/ -modules.widgets = '2014-February-13'; +modules.widgets = '2015-July-27'; var PushButtonMorph; var ToggleButtonMorph; @@ -560,12 +560,13 @@ ToggleButtonMorph.prototype.init = function ( // ToggleButtonMorph events ToggleButtonMorph.prototype.mouseEnter = function () { + var contents = this.hint instanceof Function ? this.hint() : this.hint; if (!this.state) { this.image = this.highlightImage; this.changed(); } - if (this.hint) { - this.bubbleHelp(this.hint); + if (contents) { + this.bubbleHelp(contents); } }; diff --git a/xml.js b/xml.js old mode 100644 new mode 100755 index fb612cec..b80f5200 --- a/xml.js +++ b/xml.js @@ -7,7 +7,7 @@ written by Jens Mönig jens@moenig.org - Copyright (C) 2014 by Jens Mönig + Copyright (C) 2015 by Jens Mönig This file is part of Snap!. @@ -57,15 +57,17 @@ Nathan Dinsmore contributed to the design and implemented a first working version of a complete XMLSerializer. I have taken much of the overall design and many of the functions and methods in this file from - Nathan's fine original prototype. + Nathan's fine original prototype. Recently Nathan has once again + worked his magic on the parser and optimized it by an order of + magnitude. */ -/*global modules, isString, detect, Node, isNil*/ +/*global modules, detect, Node, isNil*/ // Global stuff //////////////////////////////////////////////////////// -modules.xml = '2014-January-09'; +modules.xml = '2015-June-25'; // Declarations @@ -85,7 +87,8 @@ function ReadStream(arrayOrString) { // ReadStream constants: -ReadStream.prototype.space = /[\s]/; +ReadStream.prototype.nonSpace = /\S|$/g; +ReadStream.prototype.nonWord = /[\s\>\/\=]|$/g; // ReadStream accessing: @@ -115,46 +118,26 @@ ReadStream.prototype.atEnd = function () { // ReadStream accessing String contents: -ReadStream.prototype.upTo = function (regex) { - var i, start; - if (!isString(this.contents)) {return ''; } - i = this.contents.substr(this.index).search(regex); - if (i === -1) { - return ''; - } - start = this.index; - this.index += i; - return this.contents.substring(start, this.index); +ReadStream.prototype.upTo = function (str) { + var i = this.contents.indexOf(str, this.index); + return i === -1 ? '' : this.contents.slice(this.index, this.index = i); }; -ReadStream.prototype.peekUpTo = function (regex) { - if (!isString(this.contents)) {return ''; } - var i = this.contents.substr(this.index).search(regex); - if (i === -1) { - return ''; - } - return this.contents.substring(this.index, this.index + i); +ReadStream.prototype.peekUpTo = function (str) { + var i = this.contents.indexOf(str, this.index); + return i === -1 ? '' : this.contents.slice(this.index, i); }; ReadStream.prototype.skipSpace = function () { - if (!isString(this.contents)) {return ''; } - var ch = this.peek(); - while (this.space.test(ch) && ch !== '') { - this.skip(); - ch = this.peek(); - } + this.nonSpace.lastIndex = this.index; + var result = this.nonSpace.exec(this.contents); + if (result) this.index = result.index; }; ReadStream.prototype.word = function () { - var i, start; - if (!isString(this.contents)) {return ''; } - i = this.contents.substr(this.index).search(/[\s\>\/\=]|$/); - if (i === -1) { - return ''; - } - start = this.index; - this.index += i; - return this.contents.substring(start, this.index); + this.nonWord.lastIndex = this.index; + var result = this.nonWord.exec(this.contents); + return result ? this.contents.slice(this.index, this.index = result.index) : ''; }; // XML_Element /////////////////////////////////////////////////////////// @@ -166,7 +149,7 @@ ReadStream.prototype.word = function () { // XML_Element inherits from Node: -XML_Element.prototype = new Node(); +XML_Element.prototype = Object.create(Node.prototype); XML_Element.prototype.constructor = XML_Element; XML_Element.uber = Node.prototype; @@ -190,9 +173,7 @@ XML_Element.prototype.init = function (tag, contents, parent) { XML_Element.uber.init.call(this); // override inherited properties - if (parent instanceof XML_Element) { - parent.addChild(this); - } + if (parent) parent.addChild(this); }; // XML_Element DOM navigation: (aside from what's inherited from Node) @@ -318,51 +299,18 @@ XML_Element.prototype.escape = function (string, ignoreQuotes) { }; XML_Element.prototype.unescape = function (string) { - var stream = new ReadStream(string), - result = '', - ch, - esc; - - function nextPut(str) { - result += str; - stream.upTo(';'); - stream.skip(); - } - - while (!stream.atEnd()) { - ch = stream.next(); - if (ch === '&') { - esc = stream.peekUpTo(';'); - switch (esc) { - case 'apos': - nextPut('\''); - break; - case 'quot': - nextPut('\"'); - break; - case 'lt': - nextPut('<'); - break; - case 'gt': - nextPut('>'); - break; - case 'amp': - nextPut('&'); - break; - case '#xD': - nextPut('\n'); - break; - case '#126': - nextPut('~'); - break; - default: - result += ch; - } - } else { - result += ch; + return string.replace(/&(amp|apos|quot|lt|gt|#xD|#126);/g, function(_, name) { + switch (name) { + case 'amp': return '&'; + case 'apos': return '\''; + case 'quot': return '"'; + case 'lt': return '<'; + case 'gt': return '>'; + case '#xD': return '\n'; + case '#126': return '~'; + default: console.warn('unreachable'); } - } - return result; + }); }; // XML_Element parsing: @@ -375,10 +323,7 @@ XML_Element.prototype.parseString = function (string) { }; XML_Element.prototype.parseStream = function (stream) { - var key, - value, - ch, - child; + var key, value, ch, child; // tag: this.tag = stream.word(); @@ -395,9 +340,7 @@ XML_Element.prototype.parseStream = function (stream) { stream.skipSpace(); ch = stream.next(); if (ch !== '"' && ch !== "'") { - throw new Error( - 'Expected single- or double-quoted attribute value' - ); + throw new Error('Expected single- or double-quoted attribute value'); } value = stream.upTo(ch); stream.skip(1); @@ -407,7 +350,7 @@ XML_Element.prototype.parseStream = function (stream) { } // empty tag: - if (stream.peek() === '/') { + if (ch === '/') { stream.skip(); if (stream.next() !== '>') { throw new Error('Expected ">" after "/" in empty tag');