EPLAN-Scripts

EPLAN DeepL: Projekt übersetzen

Es hat genau einen Tag gedauert, seit EPLAN Newtonsoft.Json unterstützt, bis mein grandioser Kollege Daniel ein Script für EPLAN gebastelt hat, dass die fehlenden Übersetzungen im Wörterbuch mit DeepL übersetzt.

Das Script exportiert erstmal alle fehlenden Übersetzungen im Projekt (Quellsprache Deutsch).
Frägt dann die pro Eintrag die DeepL API nach einer Übersetzung (English).
Die Ergebnisse werden dann in einer XML-Datei gespeichert und angezeigt.

Diese Datei kann dann ins Wörterbuch importiert werden.

Vorraussetzung ist ein API-Key, welcher in der Windows Variable DEEPL_API_KEY gespeichert ist.

Orginal-Script findet Ihr auf GitHub.
Vielen Dank Daniel 💖

using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using System.Net.Http;
using System.Windows.Forms;
using System.Xml.Serialization;
using Eplan.EplApi.ApplicationFramework;
using Eplan.EplApi.Base;
using Eplan.EplApi.Scripting;

namespace TranslateWithDeepl
{
  public class TranslateWithDeepl
  {
    private readonly string _apiKey;
    private readonly string _url = "https://api-free.deepl.com/v2/translate";
    private readonly HttpClient _httpClient;

    [Start]
    public async void Execute(ActionCallingContext context)
    {
      var missingTerms = GetMissingTerms();
      await TranslateTerms(missingTerms);
    }

    private async Task TranslateTerms(EplanLanguageDbRoot missingTerms)
    {
      var requestDto = new RequestDto();
      requestDto.TargetLang = "EN";
      requestDto.Text = missingTerms.TextSection.MT.SelectMany(mt => mt.T).Where(t => t.Lang == "de_DE").Select(t => t.Text).ToArray();
      var translate = await Translate(requestDto);
      
      for(int i = 0; i < missingTerms.TextSection.MT.Length; i++)
      {
        missingTerms.TextSection.MT[i].T.First(t => t.Lang == "en_US").Text = translate.Translations[i].Text;
      }
      
      var projectDoc = PathMap.SubstitutePath("$(DOC)");
      var fileName = Path.Combine(projectDoc, "TranslatedTerms.xml");
      var serializer = new XmlSerializer(typeof(EplanLanguageDbRoot));
      using (var writer = new StreamWriter(fileName))
      {
        serializer.Serialize(writer, missingTerms);
      }
      
      Process.Start(fileName);
    }

    public EplanLanguageDbRoot GetMissingTerms()
    {
      var xmlFile = Path.GetTempFileName();
      var context = new ActionCallingContext();
      context.AddParameter("TYPE", "EXPORTMISSINGTRANSLATIONS");
      context.AddParameter("LANGUAGE", "en_US");
      context.AddParameter("EXPORTFILE", xmlFile);
      context.AddParameter("CONVERTER", "XTrLanguageDbXmlConverterImpl");
      new CommandLineInterpreter().Execute("translate", context);
      
      var serializer = new XmlSerializer(typeof(EplanLanguageDbRoot));
      EplanLanguageDbRoot eplanLanguageDbRoot = null;
      
      using (var reader = new StreamReader(xmlFile))
      {
        eplanLanguageDbRoot = (EplanLanguageDbRoot)serializer.Deserialize(reader);
      }
      return eplanLanguageDbRoot;
    }

    public TranslateWithDeepl()
    {
      // get api key from %DEEPL_API_KEY% environment variable
      _apiKey = System.Environment.GetEnvironmentVariable("DEEPL_API_KEY");
      _httpClient = new HttpClient();
    }

    private async Task<string> Translate(string text, string targetLang)
    {
      var translateDto = new RequestDto
      {
        Text = new string[] { text },
        TargetLang = targetLang
      };

      ResponseDto responseDto = await Translate(translateDto);
      return responseDto.Translations[0].Text;
    }

    private async Task<ResponseDto> Translate(RequestDto translateDto)
    {
      var json = JsonConvert.SerializeObject(translateDto);
      var data = new StringContent(json, Encoding.UTF8, "application/json");

      _httpClient.DefaultRequestHeaders.Add("Authorization", string.Format("DeepL-Auth-Key {0}", _apiKey));

      var response = await _httpClient.PostAsync(_url, data);
      var result = await response.Content.ReadAsStringAsync();
      ResponseDto responseDto = JsonConvert.DeserializeObject<ResponseDto>(result);

      return responseDto;
    }
  }

  public class ResponseDto
  {
    [JsonProperty("translations")]
    public TranslationDto[] Translations { get; set; }
  }

  public class TranslationDto
  {
    [JsonProperty("detected_source_language")]
    public string DetectedSourceLanguage { get; set; }

    [JsonProperty("text")]
    public string Text { get; set; }
  }

  public class RequestDto
  {
    [JsonProperty("text")]
    public string[] Text { get; set; }

    [JsonProperty("target_lang")]
    public string TargetLang { get; set; }
  }

  [XmlRoot(ElementName = "EplanLanguageDbRoot")]
  public class EplanLanguageDbRoot
  {
    [XmlAttribute(AttributeName = "Languages")]
    public string Languages { get; set; }

    [XmlAttribute(AttributeName = "numTexts")]
    public int NumTexts { get; set; }

    [XmlAttribute(AttributeName = "numTerms")]
    public int NumTerms { get; set; }

    [XmlAttribute(AttributeName = "numNonTranslate")]
    public int NumNonTranslate { get; set; }

    [XmlElement(ElementName = "TextSection")]
    public TextSection TextSection { get; set; }
  }

  public class TextSection
  {
    [XmlElement(ElementName = "MT")]
    public MT[] MT { get; set; }
  }

  public class MT
  {
    [XmlElement(ElementName = "T")]
    public T[] T { get; set; }
  }

  public class T
  {
    [XmlAttribute(AttributeName = "xml:lang")]
    public string Lang { get; set; }

    [XmlText]
    public string Text { get; set; }
  }
}

 

Von |2024-03-13T09:27:15+01:002024-03-08|EPLAN, EPLAN-Scripts|

Newtonsoft.Json in EPLAN Scripting

Still und leise kam ein neuer Namespace zum Scripting mit dem EPLAN 2024 Update 2 hinzu: Newtonsoft.Json

Nun kann man im Scripting auch mit REST-APIs oder JSON-Dateien direkt arbeiten und so z.B. Daten aus der EPLAN Cloud abrufen.
Leider setzt EPLAN hier auf eine sehr alte (2015) Version 6.0.8, welche mit der Installation mitkommt.

Anbei mal Beispiele um mit JSON zu arbeiten.

Serialize
Product product = new Product();
product.Name = "Apple";
product.Expiry = new DateTime(2008, 12, 28);
product.Sizes = new string[] { "Small" };

string json = JsonConvert.SerializeObject(product);
// {
//   "Name": "Apple",
//   "Expiry": "2008-12-28T00:00:00",
//   "Sizes": [
//     "Small"
//   ]
// }
Deserialize
string json = @"{
  'Name': 'Bad Boys',
  'ReleaseDate': '1995-4-7T00:00:00',
  'Genres': [
    'Action',
    'Comedy'
  ]
}";

Movie m = JsonConvert.DeserializeObject<Movie>(json);

string name = m.Name;
// Bad Boys
Von |2024-03-06T14:41:24+01:002024-03-06|EPLAN, EPLAN-Scripts|

EPLAN Ribbon mit Built-In Befehlen & RibbonCreator

Seit EPLAN 2022 war der Wunsch bei vielen Usern da, auch bestehende Commands von EPLAN in einer Registerkarte zu nutzen. Mit EPLAN 2024 ist dies nun möglich… Leider aber nur per Scripting / API.

Mit der Methode AddCommandWithId() kann eine “Command ID” übergeben werden, welcher der von EPLAN entspricht.

Beispiel für Strukturkennzeichenverwaltung:

const int commandMenuId = 35089;
var tab = ribbonBar.AddTab("CustomTab");
var commandGroup = tab.AddCommandGroup("Group1");
var commandAction = commandGroup.AddCommandWithId(commandMenuId);

Sind Buttons z.B. Drop-Down-Buttons vorhanden, wie bei der Artikelverwaltung, werden diese auch so übernommen:

Die Command ID bekommt Ihr über den Diagnose-Dialog (STRG+^):

Leider sind derzeit nicht alle Commands auch mit IDs im Diagnose-Dialog versehen (z.B. Artikelverwaltung):

Darum haben wir eine Auflistung aller Commands mit deren ID aus dem EPLAN Standard Ribbon exportiert und im ShopForProcess.com für euch frei zugänglich aufgelistet (unter “Anleitung” zu finden).

 

Denn wir haben diese Funktionalität gleich in ein fertiges Produkt gekippt: RibbonCreator

  • Einfaches Verteilen von Ribbons
  • Rechteverwaltung pro Ribbon
  • Simple UI um Ribbons zu konfigurieren
  • EPLAN Commands
  • Custom Actions

Von |2024-03-13T09:27:25+01:002024-02-06|EPLAN, EPLAN-Scripts|

PopUpMenu

In meinem Beitrag zum Erstellen eines Ribbons in EPLAN, gab es mehrfach den Wunsch eigene Untermenüs zu definieren.
Das ist leider so nicht direkt möglich.

Ich habe ein Script gebaut, dass man per Befehl im Menüband aufrufen kann.

 

Befehlszeile:

PopUpMenu /Items:"Item 1;TestAction;Tooltip 1|Item 2;TestAction;Tooltip 2|Item 3;TestAction;Tooltip 3"

Es werden alle Menü-Einträge übergeben, mit Text;Action;Tooltip. In meinem Beispiel drei.

using System.Windows.Forms;
using Eplan.EplApi.ApplicationFramework;
using Eplan.EplApi.Base;
using Eplan.EplApi.Scripting;

internal class PopUpMenu
{
  [DeclareAction("PopUpMenu")]
  public bool ActionPopUpMenu(ActionCallingContext acc)
  {
    // Get items
    string itemsString = null;
    acc.GetParameter("Items", ref itemsString);

    if (string.IsNullOrEmpty(itemsString))
    {
      return false;
    }

    ContextMenuStrip menu = new ContextMenuStrip();
    var itemsSplit = itemsString.Split('|');
    foreach (var itemSplit in itemsSplit)
    {
      var split = itemSplit.Split(';');
      if (split.Length < 2)
      {
        new Decider().Decide(EnumDecisionType.eOkDecision, "Wrong parameter value.", "PopUpMenu",
                             EnumDecisionReturn.eOK, EnumDecisionReturn.eOK, "PopUpMenu", false,
                             EnumDecisionIcon.eFATALERROR);
        return false;
      }

      // Create item
      ToolStripMenuItem menuItem = new ToolStripMenuItem();
      string text = split[0];
      menuItem.Text = text;

      // Action
      string action = split[1];
      menuItem.Click += (sender, args) => { new CommandLineInterpreter().Execute(action); };

      // Tooltip
      if (split.Length > 2)
      {
        string tooltipText = split[2];
        menuItem.ToolTipText = tooltipText;
      }

      menu.Items.Add(menuItem);
    }

    menu.Show(Cursor.Position);

    return true;
  }

  [DeclareAction("TestAction")]
  public void ActionTest()
  {
    MessageBox.Show("Hello!");
  }
}
Von |2022-11-30T16:55:35+01:002022-11-30|EPLAN, EPLAN-Scripts|
Nach oben