Repository navigation
Internationalization
How the draw.io user interface is translated: the resource files, their format, how the editor and the viewer choose and load a language, how to use strings in core code and in plugins, and how to contribute a translation fix. For developers who add UI text, write plugins, run their own deployment or fork the editor.
| Piece | Where | Role |
|---|---|---|
| English strings | resources/dia.txt |
Master list of keys (about 2,200) with English text |
| Translations | resources/dia_<code>.txt |
One file per language, same keys |
| Key reference | resources/dia_i18n.txt |
Maps every key to itself, used with ?lang=i18n
|
| Lookup | mxResources |
parse, get, add
|
| Language list |
mxLanguageMap in js/diagramly/Init.js
|
Codes and names shown in Extras > Language |
| Startup load |
App.main in js/diagramly/App.js
|
Loads one language file before the UI is created |
| Runtime switch |
EditorUi.prototype.setAndPersistLanguage in js/diagramly/EditorUi.js
|
Loads another file and fires languageChanged
|
All paths are relative to src/main/webapp/.
The resources folder holds dia.txt, 58 dia_<code>.txt files, and a README.md and CONTRIBUTING.md with notes about the folder.
Of the 58 files:
-
42 are languages offered by the editor. They are the entries of
mxLanguageMap:id,ms,bs,bg,ca,cs,da,de,et,es,eu,fil,fr,gl,it,hu,kl,lt,lv,nl,no,pl,pt-br,pt,ro,fi,sv,vi,tr,el,ru,sr,uk,he,ar,fa,th,ta,ko,ja,zh,zh-tw. English (en) is also in the map and usesdia.txt. -
15 have no entry in
mxLanguageMap:am,bn,eo,gu,hi,hr,kn,ml,mr,my,si,sk,sl,sw,te. The editor neither lists nor loads them as shipped; alangparameter with one of these codes gives English. -
dia_i18n.txtmaps each key to its own name (about=about). The map has ani18nentry with an empty display name, so it is not in the menu, but?lang=i18nloads it and the UI then shows resource keys instead of text. Use it to find the key behind a string.
copyOf=Copy of {1}
pageWithNumber=Page-{1}
timeAgo={1} ago
mxResources.parse reads the files line by line:
- The key is the text before the first
=. The value is everything after it, up to the end of the line; a trailing carriage return is removed. There is no trimming, so do not put spaces around=. - Lines that start with
#and lines without=are ignored. - Values are used verbatim.
mxResources.resourcesEncodedisfalse, so\uXXXXand%XXsequences are not decoded. Files are UTF-8; write characters directly. -
\nstays as two characters. A few consumers turn it into a line break (for examplemxGraph.prototype.getTooltipreplaces it with<br>for thecollapse-expandtooltip), so keep it wherever the English text has it. -
{1},{2}, ... are placeholders filled from theparamsarray ofmxResources.get. Translations may reorder them (dia_de.txthastimeAgo=Vor {1}) but must keep every one. - A key with an empty value (
key=) stores an empty string, andmxResources.getreturns it as is. An empty value does not fall back to English. - A couple of values contain an HTML link. Keep the markup unchanged in translations.
- Keys are camelCase, with two exceptions (
collapse-expand,draw.io). The order of the lines does not matter.
js/diagramly/Init.js sets the global mxLanguage. The first rule that gives a value wins:
-
window.mxLanguage, if it was already set beforeInit.jsruns, for example injs/PreConfig.js.bootstrap.jsloadsPreConfig.jsfirst in development mode, in the desktop app and on hosts other than*.draw.ioand*.diagrams.net. A value set here overrides everything below, including thelangparameter. - The
langURL parameter, for example?lang=de. - The language the user chose in Extras > Language, stored as
languagein the.drawio-configobject inlocalStorage(mxSettings.setLanguage). - In the desktop app, the system locale that the app passes as the
appLangURL parameter, lower-cased and without the region. - On a fixed list of official hosts in
Init.js, such as app.diagrams.net, the browser language (navigator.languagewithout the region), if it is supported. - Otherwise
mxLanguagestaysnulland the editor uses English.
Init.js also builds mxLanguages, the supported codes: every key of mxLanguageMap except en. mxClient.js copies these into mxClient.languages and mxClient.language; when mxLanguage is null, mxClient.language is the raw navigator.language. Like mxLanguage, both mxLanguageMap and mxLanguages are only set by Init.js if no earlier script has defined them.
Use the codes exactly as they appear in mxLanguageMap: lower case, with pt-br and zh-tw as the only regional codes. App.main passes mxLanguage to mxResources unchanged, so ?lang=pt-BR or ?lang=de-CH is not a supported code and loads English.
To give your own deployment a default language without overriding lang and the user's choice, check both before you set mxLanguage in PreConfig.js, as shown in Configuration. The Docker image has a DRAWIO_LANG variable for this; see its README. The full list of URL parameters is on drawio.com.
Before it creates the UI, App.main sets mxResources.loadDefaultBundle = false and loads exactly one file:
mxResources.loadDefaultBundle = false;
doLoad(mxResources.getDefaultBundle(RESOURCE_BASE, mxLanguage) ||
mxResources.getSpecialBundle(RESOURCE_BASE, mxLanguage));For a supported code this is resources/dia_<code>.txt; for English, null or an unsupported code it is resources/dia.txt. doLoad fetches the file and passes its text to mxResources.parse. If the file cannot be loaded, the page shows an error with a link that retries in English.
English is not loaded underneath a translation. js/grapheditor/Graph.js overrides mxResources.get so that a missing key returns the default value passed by the caller or, if there is none, the key itself. A key missing from dia_de.txt therefore shows up as its key name in a German UI, which is why new keys go into the translation files as well as into dia.txt.
RESOURCES_PATH (default resources) and RESOURCE_BASE (default RESOURCES_PATH + '/dia') are globals that Init.js only sets if they are undefined, so a deployment can serve the files from elsewhere by setting them in PreConfig.js. The extension comes from mxResourceExtension, which defaults to .txt.
Extras > Language calls EditorUi.prototype.setAndPersistLanguage(code). It saves the setting, sets mxClient.language, and calls mxResources.add(RESOURCE_BASE, null, callback) with loadDefaultBundle still false, which parses the new file over the current strings. It then closes open dialogs (their text is static), fires a languageChanged event on the EditorUi, and reopens the start dialog if no file is open. UI parts that build their own text update through EditorUi.prototype.dependsOnLanguage(fn), which calls fn now and on every languageChanged.
Language files are not precached. When the service worker is active (see Self-hosting), each file is cached the first time it is used. While the browser is offline, Extras > Language disables languages that are not cached (EditorUi.prototype.isLanguageAvailableOffline). The defaultLanguages configuration key installs a list of languages for offline use at startup; see Configuration.
The viewer bundles (viewer.min.js, viewer-static.min.js) compile dia.txt in: the app target of the Ant build generates Graph-Resources.js (a mxResources.parse call with the text of dia.txt) and includes it in the viewer. GraphViewer.loadLanguageResources then loads <base>_<code>.txt over it, so in the viewer a missing key falls back to English.
- The code comes from
GraphViewer.getLanguage:mxLanguage, elsemxClient.language(the browser language), reduced to a supported code. English needs no request. - The base comes from
GraphViewer.getResourceBase:RESOURCE_BASE, except that the viewer bundles, whoseSTYLE_PATHdefaults tohttps://viewer.diagrams.net/styles, load from theresources/dianext toSTYLE_PATH. - Load errors, for example a missing CORS header on your own host, are ignored and the viewer stays in English.
A page that embeds the viewer can force a language by setting window.mxLanguage before it loads the script. See Embedding.
Arabic (ar), Persian (fa) and Hebrew (he) values are mostly wrapped in Unicode bidirectional controls: U+202B (right-to-left embedding) before the text and U+202C (pop directional formatting) after it. They make the browser lay out the value as right-to-left text, including any punctuation and Latin words in it, inside the left-to-right UI. Copy the markers when you edit such a value.
The editor layout itself is not mirrored for these languages: there is no dir="rtl" handling in the UI code. The shape search strips these control characters before matching translated terms (Sidebar.js). Text direction inside diagram labels is a separate cell style, textDirection (see Styles).
To add UI text, add a key to dia.txt and look it up with mxResources.get(key, params, defaultValue):
// Plain lookup
mxUtils.write(hd, mxResources.get('properties'));
// {1}..{n} are filled from the array: "Copy of " + title in English
var name = mxResources.get('copyOf', [title]);
// Explicit default if the key may be missing
var text = mxResources.get('timeAgo', [str], '{1} ago');-
Actions and menus. An action registered with
ui.actions.addAction('myKey', fn)uses its key as its label.Action.prototype.getTitlelooks the label up withmxResources.getand, if the label ends in..., appends...after the translated text. AddmyKey=My Textto the resources. -
Escaping. Values are plain text, and placeholders often carry user data such as file or page names. Insert text with
mxUtils.writeortextContent. If you build HTML, escape the value, asDrawioFile.jsdoes withmxUtils.htmlEntities(mxResources.get('readOnly')). See Security. -
Language changes. Text you put into long-lived DOM goes stale when the user switches language. Set it inside
ui.dependsOnLanguage(function() { ... })or listen forlanguageChanged. Menu items are created each time a menu opens, so the labels of actions in menus need nothing extra. -
New keys in a fork. Because only one file is loaded, add a new key to
dia.txtand to everydia_<code>.txt, with the English text where you have no translation. Otherwise users of other languages see the key name.
Plugins add their own keys with mxResources.parse, which accepts the same key=value text as the files. This is what the bundled plugins do, for example plugins/anonymize.js:
Draw.loadPlugin(function(editorUi)
{
mxResources.parse('anonymizeCurrentPage=Anonymize Current Page');
editorUi.actions.addAction('anonymizeCurrentPage', function()
{
// ...
});
var menu = editorUi.menus.get('extras');
var oldFunct = menu.funct;
menu.funct = function(menu, parent)
{
oldFunct.apply(this, arguments);
editorUi.menus.addMenuItems(menu, ['-', 'anonymizeCurrentPage'], parent);
};
});Keys parsed by a plugin survive a language switch, because the language files do not contain them. To ship translations, choose the text by language code, as Editor.applyCustomResources does with mxClient.language, and parse it again on languageChanged. Prefix your keys so they cannot collide with core keys. See Plugins.
Without code, the resources key of the editor configuration overrides existing strings or adds new ones. Each value is a string, or an object with one entry per language code and main as the fallback:
{"resources": {"saveAs": {"main": "Save a Copy", "de": "Kopie speichern"}, "myKey": "My Text"}}Editor.configure stores the object in Editor.customResources, and js/diagramly/Editor.js wraps mxResources.parse so that these values are applied again after every parsed file, including after a language switch. They take precedence over the built-in files. See Configuration and the configuration reference.
The UI language and the text inside a diagram are separate. For multilingual diagrams, Graph.js can read a label from a language-specific attribute of the cell's XML value:
- With
Graph.translateDiagramon (?translate-diagram=1, or Extras > Diagram Language > Language Code), a cell showslabel_<code>instead oflabelif that attribute exists, for examplelabel_de. - The code is
Graph.diagramLanguage: thediagram-languageURL parameter, elsemxClient.language. - Tooltips (
tooltip_<code>) and placeholder attributes (<name>_<code>) are resolved the same way.
The user-facing guide is Enable in-diagram text translation. See Graph model for user objects and attributes.
Translation fixes are the one kind of pull request the project accepts. Edit dia_<code>.txt in a fork and open a pull request against dev, following resources/CONTRIBUTING.md: change values only, keep placeholders and markup, and keep the English text where you have no translation (an empty value is shown as empty text). To find the key, search for the current text in dia_<code>.txt or open the editor with ?lang=i18n. A new language needs an issue first. Details are in Contributing.
Describes the dev branch of jgraph/drawio as of release 32.3.0 (October 2026). Internal JavaScript APIs change between releases; check the code of the version you use. · Questions: Discussions · Bugs: Issues · Vulnerabilities: report privately · User docs: drawio.com/docs
Get started
Concepts
Guides
- Self-hosting
- Configuration
- Storage backends
- OneDrive app registration
- Embedding
- Diagrams in GitHub
- Plugins
- Extending the editor
- Shapes and stencils
- Import and export
- Desktop app
- Internationalization
Reference
Project
Elsewhere