Ich habe jetzt für meinen Anwendungsfall eine Lösung gefunden.
Als Erstes habe ich bei "Skripte > Globales Modul > Globaler Definitionsbereich" folgende Konstante angelegt:
Javascript:
const lang_path = "/home/industrial/last_language.txt";
Danach habe ich 2 Skripte angelegt ("Skripte > Globales Modul"):
LoadLanguage
Javascript:
export function LoadLanguage() {
function set_language(data) {
let lcid = parseInt(data, 10) >>> 0;
HMIRuntime.Trace("Set runtime language to " + lcid + "\n");
HMIRuntime.Language = lcid;
Tags("LangIndex").Write(lcid);
}
function error(err_msg) {
HMIRuntime.Trace("Could not read file '" + lang_path + "'\n" + err_msg);
}
function read_file() {
// it's an async function
// use .then().catch()
HMIRuntime.FileSystem.ReadFile(lang_path, "utf8").then(set_language).catch(error);
}
read_file();
}
UpdateLang
Javascript:
export function UpdateLang() {
function error(err_msg) {
HMIRuntime.Trace("Could not write to file '" + lang_path + "'\n" + err_msg);
}
function SaveNewLanguage() {
HMIRuntime.FileSystem.WriteFile(lang_path, String(HMIRuntime.Language), "utf8").catch(error);
}
UI.SysFct.ToggleLanguage();
Tags("LangIndex").Write(HMIRuntime.Language);
SaveNewLanguage();
HMIRuntime.Trace("Changed language to " + HMIRuntime.Language + "\n");
}
Die HMI-Variable
LangIndex anlegen. Kann auch intern sein.
Damit die Funktion
LoadLanguage geladen wird, muss für das Grundbild ein Ereignis angelegt werden:
Eigenschaften -> Ereignisse -> Aufgebaut > Globales Modul.LoadLanguage
Die Funktion
UpdateLang dient zum toggeln. Dann benötigt man nur ein Button, um durch alle vorhandenen Sprachen durchschalten zu können. Jedes mal, wenn der Button betätigt wird, wird auch die LCID in der
last_language.txt gespeichert.
Dazu ein Button anlegen und dann Eigenschaften -> Ereignisse > Drücken > Globales Modul.UpdateLang
(Taste Drücken ist falsch!)
Die Grafik des Buttons definiere ich über eine Ressourcen-Liste. Als HMI-Variable verwende ich
LangIndex und die Ressource heißt bei mir
Lang.
Folgende Sprache habe ich bis jetzt zugeordnet:
1031 - Deutsch
1033 - Englisch (US)
1045 - Polnisch
Dann ist mir noch aufgefallen, wenn HMIRuntime.Language = 0 gesetzt wird, wird die Standard-Sprache verwendet. Hilfreich ist das Tracing mit RTILtraceTool.exe und RTILtraceViewer.exe.
Ich habe ziemlich lange gebraucht, um zu verstehen, dass
HMIRuntime.FileSystem.ReadFile und
HMIRuntime.FileSystem.WriteFile asynchrone Funktionen sind, die ein Promise zurückgeben. Bei der Funktion zum Schreiben fällt das nicht auf, da der Wert entweder geschrieben wird oder nicht (Pfad z.B. falsch). Beim Lesen der Datei wird auch ein Promise zurückgeliefert und ich habe fälschlicherweise angenommen, dass es der gelesene Inhalt als string ist. Anstatt mit dem Rückgabewert der Funktion zu arbeiten, muss man nach dem Aufruf von
HMIRuntime.FileSystem.WriteFile().then(daten_bereit).catch(error) delegiert werden. Die Funktion daten_bereit wird aufgerufen, wenn die Datei erfolgreich gelesen worden ist und bei einem Fehler wird nur die Funktion error aufgerufen.
Ich werde mich jetzt weiter mit WinCC Unified quälen. Schade, dass Siemens kein Python integriert hat. So hätte zumindest ich viel effizienter arbeiten können. Woran momentan exzessiv gearbeitet wird, ist
PyScript mit Micropython als Runtime.