EPLAN

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|

BMK anpassen / ändern

Das sichtbare BMK anpassen… hört sich erstmal einfach an.

Ist aber leider nicht ganz so einfach in der API, zumindest wenn man nicht weiß wie. So ging es mir und dank dem grandiosen EPLAN API Support sind wir auch auf eine Lösung gekommen, welche meinen Anforderungen entspricht:

  • Optional: neues BMK zuweisen
  • BMK korrekt auflösen

Ist z.B. das BMK -MAA1 nicht korrekt eingegeben worden (z.B. alles im Feld Zähler) dann löst der Code das BMK korrekt auf (wie in der Oberfläche).

functionBase.VisibleName = functionBase.VisibleName; // Same device tag
new NameService(newPage).AdjustFullName(functionBase);
Von |2023-02-28T10:33:51+01:002023-02-28|EPLAN, EPLAN-API|
Nach oben