Multilanguage label dashboard

Hello everybody,
there is some support for internationalization (i18n) of the node-red-dashboard?
In order to use multilanguage label instead of fixed label in run-time dashboard (localhost/ui/xxx).

As alternative, is it possible to use dynamic text (as {{}} or {{}}) as label inside dashboard node?

Thanks in advance

I don't think there are any fixed language labels in the dashboard ? You can set them how you like. And yes a lot of the labels can be dynamic by setting them like {{msg xxx}} as you suggest.

If there are any fixed ones please let us know.

Thank you dceejay for the prompt answer.

Probably I said that badly.
With "fixed label" I mean typed text inside label attribute in node property.

If it's possible to use dynamic text inside typed text (please refer to attached images)

for me it should be enough.

I checked documentation but I didn't find which msg field is used to fill this attribute at run-time.
Please, could you help me indicating which field ( or is used to set dynamically these labels?

Thanks in advance

did you try some ? as it's a variable you can use whatever you like {{}}

Thank you dceejay.

I tried something and it wasn't working.
Now I'm repeating tests with more "knowledge of the cause" with all dashboard nodes.

Your suggestion works well with numeric node.
I'm able to use dynamic label and tooltip (i.e. {{label}} for label and {{tooltip}} for tooltip, without to indicate entirely {{msg.label}}).
It seems update dashboard page label only after a page refresh (probably this could be one of my initial troubles) but it's acceptable.

With form node it seems not works: I have moustache string (i.e. {{label.p1}}) in dashboard page label, instead of dynamic text.

I'll investigate deeply repeating test for all nodes and I'll let you know.

Thanks and

Yes - good point - I wouldn't expect it to work for form.

Thank you dcejaay and sorry for the late of this response.

All is working properly, except the form that isn't working as per your expectations.

Hello, I'm bouncing on your post :smiley:
I also want to make my dashboard multi-languages.
Would it be possible to share a piece of your flow as an example?

If I understood, you give for example the variable {{label}} in a lable field of a UI node. So you fill it just before with a Change Node for example?
Moreover you do a test just before the Change Node to check which language you will use. Doesn't that slow down the process too much?

More generally, if you have ideas on how to make a NR application multi-language it's welcome.


Well, I tested the above proposal and it works for the label. Here is the example.

But how to dynamically change the names of Tabs & Groups?
Ideas or another way are welcome :thinking:

It is possible to do for group names.

[{"id":"e709dc02.32591","type":"inject","z":"dee586f8.76a168","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"5","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":170,"y":1300,"wires":[["5da40c4d.c054a4"]]},{"id":"c560959d.897b38","type":"ui_template","z":"dee586f8.76a168","group":"e44fafb9.27f56","name":"fading text","order":7,"width":"6","height":1,"format":"<style>\n    .fadingtext{\n        margin: auto 15px auto 0px;\n        font-size:18px;\n    }\n    .fadingtext span:not(:last-child){\n        position: relative;\n        padding-right: 10px;\n        padding-left: 1px;\n        font-size: 22px;\n        top: 1px\n    }\n\n</style>\n<div class=\"fadingtext\" >\n    <span><i class=\"fa fa-credit-card\" aria-hidden=\"true\"></i></span><span id=\"{{'my_'+$id}}\"></span>\n</div>\n\n<script>\n(function(scope) {\n    scope.visible = document.visibilityState === 'visible'\n    document.addEventListener(\"visibilitychange\", function() {\n        if (document.visibilityState === 'visible') {\n            scope.visible = true;\n        } else {\n            scope.visible = false;\n        }\n    });\n    scope.$watch('msg', function(msg) {\n        if (msg) {\n            if(scope.visible){\n                $(\"#my_\"+scope.$id).fadeOut(function() {\n                    $(this).text(msg.payload)\n                }\n            ).fadeIn();\n        }\n        else{\n            $(\"#my_\"+scope.$id).text(msg.payload)   \n        }\n    }\n  });\n})(scope);\n\n\n</script>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","x":530,"y":1300,"wires":[[]]},{"id":"5da40c4d.c054a4","type":"function","z":"dee586f8.76a168","name":"","func":"var str = (msg.payload +Math.floor(Math.random()*1000000)).toString()\nmsg.payload = str.substring(str.length - 8);\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":340,"y":1300,"wires":[["c560959d.897b38"]]},{"id":"9ba5d5ff.551988","type":"ui_template","z":"dee586f8.76a168","group":"e44fafb9.27f56","name":"Home tab group names","order":14,"width":0,"height":0,"format":"<script>\n(function(scope) {\n  scope.$watch('msg', function(msg) {\n    if (msg) {\n        $('#Home_Default > div > p').text(msg.payload.default)\n    }\n  });\n})(scope);\n</script>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","x":590,"y":1060,"wires":[[]]},{"id":"e39f180e.b69e88","type":"ui_ui_control","z":"dee586f8.76a168","name":"","events":"change","x":140,"y":980,"wires":[["a0b6aadd.2a64c8"]]},{"id":"ce3fb1e8.2cc1f","type":"ui_template","z":"dee586f8.76a168","group":"d8f1e676.bd2948","name":"Away tab group names","order":14,"width":0,"height":0,"format":"<script>\n(function(scope) {\n  scope.$watch('msg', function(msg) {\n    if (msg) {\n        $('#Away_Default > div > p').text(msg.payload.default)\n        $('#Away_Other > div > p').text(msg.payload.other)\n    }\n  });\n})(scope);\n</script>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","x":580,"y":1100,"wires":[[]]},{"id":"25b41e96.17e4c2","type":"ui_button","z":"dee586f8.76a168","name":"","group":"53a306bb.7c2a18","order":0,"width":0,"height":0,"passthru":false,"label":"button","tooltip":"","color":"","bgcolor":"","icon":"","payload":"","payloadType":"str","topic":"","x":510,"y":1240,"wires":[[]]},{"id":"56f0c5a2.2ac5bc","type":"link in","z":"dee586f8.76a168","name":"","links":["a0b6aadd.2a64c8","d246ab3c.76d768"],"x":175,"y":1080,"wires":[["a2c66fe5.0c062","6611144.45393ec"]]},{"id":"a0b6aadd.2a64c8","type":"link out","z":"dee586f8.76a168","name":"","links":["56f0c5a2.2ac5bc"],"x":235,"y":980,"wires":[]},{"id":"e3def0b8.45dc7","type":"ui_dropdown","z":"dee586f8.76a168","name":"","label":"Language","tooltip":"","place":"Select option","group":"e44fafb9.27f56","order":2,"width":0,"height":0,"passthru":true,"multiple":false,"options":[{"label":"Estonian","value":"ET","type":"str"},{"label":"English","value":"EN","type":"str"}],"payload":"","topic":"","x":180,"y":1180,"wires":[["45234361.885eac"]]},{"id":"a2c66fe5.0c062","type":"function","z":"dee586f8.76a168","name":"select by language","func":"var groups = {\n    EN:{\n        default:\"Default\",\n        other:\"Other\"\n    },\n    ET:{\n        default:\"Tavaline\",\n        other:\"Miski muu\"\n    }\n}\nvar lang = global.get('language') || 'EN'\nmsg.payload = {\n    default:groups[lang].default,\n    other:groups[lang].other\n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":350,"y":1100,"wires":[["ce3fb1e8.2cc1f"]]},{"id":"45234361.885eac","type":"change","z":"dee586f8.76a168","name":"","rules":[{"t":"set","p":"language","pt":"global","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":350,"y":1180,"wires":[["d246ab3c.76d768"]]},{"id":"6611144.45393ec","type":"function","z":"dee586f8.76a168","name":"select by language","func":"var groups = {\n    EN:{\n        default:\"Default\"\n    },\n    ET:{\n        default:\"Tavaline\"\n       \n    }\n}\nvar lang = global.get('language') || 'EN'\nmsg.payload = {\n    default:groups[lang].default\n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":350,"y":1060,"wires":[["9ba5d5ff.551988"]]},{"id":"d246ab3c.76d768","type":"link out","z":"dee586f8.76a168","name":"","links":["56f0c5a2.2ac5bc"],"x":475,"y":1180,"wires":[]},{"id":"6d4ebc31.407504","type":"ui_button","z":"dee586f8.76a168","name":"","group":"d8f1e676.bd2948","order":0,"width":0,"height":0,"passthru":false,"label":"button","tooltip":"","color":"","bgcolor":"","icon":"","payload":"","payloadType":"str","topic":"","x":630,"y":1240,"wires":[[]]},{"id":"e44fafb9.27f56","type":"ui_group","name":"Default","tab":"1a6cce21.8ac4d2","order":1,"disp":true,"width":"6","collapse":true},{"id":"d8f1e676.bd2948","type":"ui_group","name":"Default","tab":"84350e6b.7f5f3","order":1,"disp":true,"width":"6","collapse":false},{"id":"53a306bb.7c2a18","type":"ui_group","name":"Other","tab":"84350e6b.7f5f3","order":2,"disp":true,"width":"6","collapse":true},{"id":"1a6cce21.8ac4d2","type":"ui_tab","name":"Home","icon":"dashboard","disabled":false,"hidden":false},{"id":"84350e6b.7f5f3","type":"ui_tab","name":"Away","icon":"dashboard","disabled":false,"hidden":false}]

But for tab names it goes too deep so I didn't find any good solution. I don't say it is not possible, I just ran out of time.


Hi all,
I'm sorry for delay of my answer.

I leaved dashboard and I use uibuilder, in order to execute work in client side (multilanguage also could be easily manage in all page fields).
So unfortunately I didn't go deep in dashboard multilanguage, I'm sorry.


Sorry for the delay, I was very busy but thank you very much for your answer. I tested it and it's great.

To sum up, we know how to dynamically change labels, groups but not Tabs.

So I used another approach - solution which is the following:

Modify the settings.js file and validate the following options:

  • flowFilePretty: true (this makes it easy to read it again with Excell)

  • flowFile: 'flows.json (which removes the name of the computer attached to the name of the flows file)

Completely finalize the program !

Make copies of the flows.json file into flows_En.json, flows_Du.json, flows_It.json, etc...

Translate these new files created into the desired language.
Then, in the dashboard, create a button to choose the desired language, which will trigger:

  • A copy of for example flows_En.json to flows.json
  • Restarts Node Red.

And there we are with the flows in English :slightly_smiling_face:

It's quite heavy and constraining but it works well.

The trouble is that when you change something then you have to do it in all other versions as well.

totally agree, it's not the easiest.
Fortunately, I can use powerquery in excel to automate a bit.
If there are other solutions, I'm always interested :wink:

Salut Jean-Luc,

I am working also for a multiple languages dashboard. So far I am using a DB and I put my strings in table. When Dashboard open, it validating the default selected language by the user, make a query with the selected value and save the data into a json file, . Then the items requiring to be translated are numbered and I do a search into the Json for the required label.. I didn't find a way to make a traditional ressources file as in Visual Studio.. I believe all ideas might be better than mine



Hello @ylechasseur
Have a look here, Maybe another simple solution ?!


Merci Jean-Luc.. I'll give a look ..

Bonne journée

Salut JL,
the idea is not bad and I gonna think about it, my process with my language reference table is going not bad and so far speed wise, didn't see an impact yet ..

thanks for the suggestion