mo4islona / node-blockly

Blockly for Node.js and Browser via CommonJS module
133 stars 81 forks source link

Blocks do not always translate #19

Open NAllred91 opened 6 years ago

NAllred91 commented 6 years ago

You can reproduce this in your live demo, http://mo4islona.github.io/blockly/

First, load the page and change the language to french. Open the the Loops flyout to see that the while block has been translated to french. Then close the flyout and translate back to english. Check the Loops flyout again and still see french in the While block.

It seems like these blocks are getting stuck on whatever language they are set to when you first look at them.

NAllred91 commented 6 years ago

I've got a hacky way I think I can fix this in my own fork of node-blockly. I'm not sure how what the correct way to fix this is yet.

mo4islona commented 6 years ago

I know about this problem and think the problem is inside Blockly. Some blocks translates back correctly some not. For example Test translates correctly in english after french.

They fixed some blocks – in earlier versions of Blockly no one blocks translated back.

NAllred91 commented 6 years ago

Ah yea... At first I thought it was only drop downs but now I see its all pretty random. I'll take a look at blockly at some point and see if I can do a PR there.

For the time being I'm working around this in my application by creating a blocklyStore.js:

module.exports = {
    Blockly: require('node-blockly/browser'),
    reset: function() {
        delete require.cache[require.resolve('node-blockly/browser')]
        delete require.cache[require.resolve('node-blockly/lib/blockly_compressed_browser')]
        delete require.cache[require.resolve('node-blockly/lib/blocks_compressed_browser')]
        this.Blockly = require('node-blockly/browser')
    },
}

Then to use Blockly I do:

var BS = require('blocklyStore')

BS.Blockly.inject(...

Then whenever I change languages I call BS.reset().

This seems to work fine as a work around for now.

NAllred91 commented 6 years ago

Turns out my work around wasn't quite enough...

This line causes problems.. https://github.com/mo4islona/node-blockly/blob/master/browser.js#L12

Since setLocale is always called initially with english, so even when you clear the require cache it still gets called with english from the start and that messes up some blocks.

I'm not sure if my current solution is good enough for a PR, but I changed browser.js to this

var getBlockly = function(languageCode) {
  delete require.cache[require.resolve('node-blockly/lib/blockly_compressed_browser')]
  delete require.cache[require.resolve('node-blockly/lib/blocks_compressed_browser')]
  var Blockly = require('./lib/blockly_compressed_browser');

  Blockly._setLocale = function(locale) {
    Blockly.Msg = Object.assign(locale, Blockly.Msg);
    Blockly.Msg = Blockly.Msg();
  }

  Blockly.utils.getMessageArray_ = function () {
    return Blockly.Msg
  }

  Blockly._setLocale(require('./lib/i18n/' + languageCode))

  Blockly.Blocks = Object.assign(Blockly.Blocks, require('./lib/blocks_compressed_browser')(Blockly));

  Blockly.JavaScript = require('./lib/javascript_compressed')(Blockly);
  Blockly.Lua = require('./lib/lua_compressed')(Blockly);
  Blockly.Dart = require('./lib/dart_compressed')(Blockly);
  Blockly.PHP = require('./lib/php_compressed')(Blockly);
  Blockly.Python = require('./lib/python_compressed')(Blockly);

  return Blockly
}

class Blockly {
  constructor() {
      Object.assign(this, getBlockly('en'))
  }

  setLanguage = (languageCode) => {
      Object.assign(this, getBlockly(languageCode))
  }
}

module.exports =  new Blockly()

Then, to change the language I do this

import Blockly from 'node-blockly/browser'

var changeLanguage = (languageCode) => {
    Blockly.setLanguage(languageCode)
    var currentXML = this._getWorkspaceXML()
    this._workspace.dispose()
    this._workspace = Blockly.inject(config.blocklyElementId, {
                toolbox: getToolbox(this._appManager),
                grid: config.blocklyGridOptions,
            })
    this._setWorkspaceXML(currentXML)
}

With this solution, Blockly._setLocale only ever gets called on a given instance of Blockly once.

NAllred91 commented 6 years ago

But this solution is nice because I can change the language without doing the weird cache invalidation in my own code.

If I made a PR using this pattern and cleaned it up some keeping Blockly.setLocale as the public method, I don't think it would break existing code that uses setLocale? Let me know if you're interested in a PR with this pattern.