Is there a migration tool for resource bundles

Question on behalf of @theodossios-steep-crest:

Is there a tool to migrate a resource bundle from the old structure into the new tree structure?

For example, the old structure:

const resourceBundle = {
    de: {
        "view.customer.name": "Name",
        "view.customer.age": "Alter",
    },
}; 

The new structure:

const resourceBundle: LocalizationTreeMap = {
    de: {
        view: {
             customer: {
                 name: "Name",
                 age: "Alter",
             }
     }
}; 
  • Here is the script that can make the job done.
    the script with .js extension

  • (The content of the script is down below :point_down: )

const fs = require("fs");

const keys = {
  "application.title": "Your-Project-Name",
  "veto.title": "Vorgang abbrechen",
  "veto.message":
    "Sind Sie sicher, dass Sie den Vorgang abbrechen möchten? Bitte beachten Sie, dass getätigte Eingaben verworfen werden.",
  "veto.buttonDiscard": "Ja, Vorgang abbrechen",
  "veto.buttonAbort": "Nein, zurück zum Formular",
  "veto.unsavedOrLockedActivties": "",
  "error.INTERNAL_CLIENT_ERROR": "Interner Client Fehler",
  "error.VALIDATION_ERROR": "Validierungsfehler",
  "error.PAGE_NOT_FOUND_ERROR": "Seite nicht gefunden",
  "error.SAVING_FAILED_ERROR": "Speichern fehlgeschlagen",
  "error.HTTP_ERROR": "HTTP Fehler",
  "error.UNKNOWN_ERROR": "Interner Fehler",

  "externalEnumeration.EmailBetreff.0.label": "Warten auf BiFi-Abrechnung",
  "externalEnumeration.EmailBetreff.1.label": "Informationen angefordert",

  "application.header.userinfo.labels.loggedInAs": "Angemeldet als",
  "application.header.userinfo.labels.logoutButton": "Ausloggen",
  "features.notification.title.success": "Erfolg",
  "features.notification.title.info": "Info",
  "features.notification.title.warning": "Warnung",
  "features.notification.title.error": "Fehler",
  "features.notification.content": "{message}",
  "wf.general.actions.cancel": "Abbrechen",
  "wf.general.actions.start": "Starten",
  "wf.sidemenu.startProcess.label": "Prozess starten",
  "wf.sidemenu.mytasks.label": "Meine Aufgaben",
  "wf.sidemenu.availabletasks.label": "Verfügbare Aufgaben",
  "wf.sidemenu.alltasks.label": "Alle Aufgaben",
  "wf.sidemenu.completedprocesses.label": "Abgeschlossene Prozesse",
  "wf.startprocess.title": "Prozess auswählen",
  "wf.startprocess.dropdown.title": "Verfügbare Prozesse",
  "wf.startprocess.selecteddocuments.id": "Dokument ID",
  "wf.startprocess.selecteddocuments.type": "Dokumententyp",
  "wf.startprocess.selecteddocuments.name": "Dokumentenname",
  "wf.startprocess.selecteddocuments.unselect": "Entfernen",
  "wf.notification.success.startprocess":
    "Instanz von {processDefinitionName} erfolgreich gestartet.",
  "wf.notification.error.startprocess":
    "Konnte keine Instanz von {processDefinitionName} starten.",
  "wf.notification.error.updatetask": "Task konnte nicht gespeichert werden.",
  "wf.notification.error.completetask":
    "Task konnte nicht erfolgreich beendet werden. Sind Sie diesem Task zugewiesen?",
  "wf.notification.error.showdiagram":
    "Processdiagramm für {processDefinitionName} kann nicht angezeigt werden.",
};

const REMOVE_VALUES = true;
const tree = {};

Object.keys(keys).forEach((key) => {
  const parts = key.split(".");
  const lastIndex = parts.length - 1;
  let node = tree;

  parts.forEach((part, index) => {
    const isLast = index === lastIndex;
    const next = node[part];

    if (!next) {
      if (isLast) {
        node[part] = REMOVE_VALUES ? "" : keys[key];
      } else {
        node[part] = {};
      }
    }

    node = node[part];
  });
});

fs.writeFileSync("./keys.json", JSON.stringify(tree, null, 4));