diff --git a/.classpath b/.classpath index 1eb6761..45ba4c8 100644 --- a/.classpath +++ b/.classpath @@ -41,17 +41,17 @@ - + - + - + diff --git a/build.xml b/build.xml index 75affdd..7884797 100644 --- a/build.xml +++ b/build.xml @@ -11,9 +11,9 @@ - - - + + + diff --git a/catalog/xliff2.1/catalog.xml b/catalog/xliff2.1/catalog.xml index a9678f5..4439012 100755 --- a/catalog/xliff2.1/catalog.xml +++ b/catalog/xliff2.1/catalog.xml @@ -11,7 +11,7 @@ - + diff --git a/catalog/xliff2.1/informativeCopiesOf3rdPartySchemas/readme.txt b/catalog/xliff2.1/informativeCopiesOf3rdPartySchemas/readme.txt new file mode 100644 index 0000000..6ffb5bc --- /dev/null +++ b/catalog/xliff2.1/informativeCopiesOf3rdPartySchemas/readme.txt @@ -0,0 +1,10 @@ +IMPORTANT WARNING +Schema copies in this sub-folder are provided solely for implementers convenience and are NOT a part of the OASIS multipart product. +These schemas belong to their respective owners and their use is governed by their owners' respective IPR policies. +The support schemas are organized in folders per owner/maintainer. +It is the implemnter's sole responsibility to ensure that their local copies of all schemas are the appropriate up to date versions. + +Included 3rd Party Support Schemas: +----------------------------------- +http://www.w3.org/2001/xml.xsd [http://www.w3.org/2009/01/xml.xsd] here under /w3c/xml.xsd +change_tracking.xsd here under /extensions/change_tracking.xsd \ No newline at end of file diff --git a/catalog/xliff2.1/informativeCopiesOf3rdPartySchemas/w3c/xml.xsd b/catalog/xliff2.1/informativeCopiesOf3rdPartySchemas/w3c/xml.xsd new file mode 100644 index 0000000..aea7d0d --- /dev/null +++ b/catalog/xliff2.1/informativeCopiesOf3rdPartySchemas/w3c/xml.xsd @@ -0,0 +1,287 @@ + + + + + + +
+

About the XML namespace

+ +
+

+ This schema document describes the XML namespace, in a form + suitable for import by other schema documents. +

+

+ See + http://www.w3.org/XML/1998/namespace.html and + + http://www.w3.org/TR/REC-xml for information + about this namespace. +

+

+ Note that local names in this namespace are intended to be + defined only by the World Wide Web Consortium or its subgroups. + The names currently defined in this namespace are listed below. + They should not be used with conflicting semantics by any Working + Group, specification, or document instance. +

+

+ See further below in this document for more information about how to refer to this schema document from your own + XSD schema documents and about the + namespace-versioning policy governing this schema document. +

+
+
+
+
+ + + + +
+ +

lang (as an attribute name)

+

+ denotes an attribute whose value + is a language code for the natural language of the content of + any element; its value is inherited. This name is reserved + by virtue of its definition in the XML specification.

+ +
+
+

Notes

+

+ Attempting to install the relevant ISO 2- and 3-letter + codes as the enumerated possible values is probably never + going to be a realistic possibility. +

+

+ See BCP 47 at + http://www.rfc-editor.org/rfc/bcp/bcp47.txt + and the IANA language subtag registry at + + http://www.iana.org/assignments/language-subtag-registry + for further information. +

+

+ The union allows for the 'un-declaration' of xml:lang with + the empty string. +

+
+
+
+ + + + + + + + + +
+ + + + +
+ +

space (as an attribute name)

+

+ denotes an attribute whose + value is a keyword indicating what whitespace processing + discipline is intended for the content of the element; its + value is inherited. This name is reserved by virtue of its + definition in the XML specification.

+ +
+
+
+ + + + + + +
+ + + +
+ +

base (as an attribute name)

+

+ denotes an attribute whose value + provides a URI to be used as the base for interpreting any + relative URIs in the scope of the element on which it + appears; its value is inherited. This name is reserved + by virtue of its definition in the XML Base specification.

+ +

+ See http://www.w3.org/TR/xmlbase/ + for information about this attribute. +

+
+
+
+
+ + + + +
+ +

id (as an attribute name)

+

+ denotes an attribute whose value + should be interpreted as if declared to be of type ID. + This name is reserved by virtue of its definition in the + xml:id specification.

+ +

+ See http://www.w3.org/TR/xml-id/ + for information about this attribute. +

+
+
+
+
+ + + + + + + + + + +
+ +

Father (in any context at all)

+ +
+

+ denotes Jon Bosak, the chair of + the original XML Working Group. This name is reserved by + the following decision of the W3C XML Plenary and + XML Coordination groups: +

+
+

+ In appreciation for his vision, leadership and + dedication the W3C XML Plenary on this 10th day of + February, 2000, reserves for Jon Bosak in perpetuity + the XML name "xml:Father". +

+
+
+
+
+
+ + + +
+

About this schema document

+ +
+

+ This schema defines attributes and an attribute group suitable + for use by schemas wishing to allow xml:base, + xml:lang, xml:space or + xml:id attributes on elements they define. +

+

+ To enable this, such a schema must import this schema for + the XML namespace, e.g. as follows: +

+
+          <schema . . .>
+           . . .
+           <import namespace="http://www.w3.org/XML/1998/namespace"
+                      schemaLocation="http://www.w3.org/2001/xml.xsd"/>
+     
+

+ or +

+
+           <import namespace="http://www.w3.org/XML/1998/namespace"
+                      schemaLocation="http://www.w3.org/2009/01/xml.xsd"/>
+     
+

+ Subsequently, qualified reference to any of the attributes or the + group defined below will have the desired effect, e.g. +

+
+          <type . . .>
+           . . .
+           <attributeGroup ref="xml:specialAttrs"/>
+     
+

+ will define a type which will schema-validate an instance element + with any of those attributes. +

+
+
+
+
+ + + +
+

Versioning policy for this schema document

+
+

+ In keeping with the XML Schema WG's standard versioning + policy, this schema document will persist at + + http://www.w3.org/2009/01/xml.xsd. +

+

+ At the date of issue it can also be found at + + http://www.w3.org/2001/xml.xsd. +

+

+ The schema document at that URI may however change in the future, + in order to remain compatible with the latest version of XML + Schema itself, or with the XML namespace itself. In other words, + if the XML Schema or XML namespaces change, the version of this + document at + http://www.w3.org/2001/xml.xsd + + will change accordingly; the version at + + http://www.w3.org/2009/01/xml.xsd + + will not change. +

+

+ Previous dated (and unchanging) versions of this schema + document are at: +

+ +
+
+
+
+ +
+ diff --git a/css/dark.css b/css/dark.css index 7387832..1863ee0 100644 --- a/css/dark.css +++ b/css/dark.css @@ -65,7 +65,7 @@ a:hover { position: absolute; top: 200px; left: calc(40% - 100px); - width: 200px; + /* width: 200px; */ margin: auto; background-color: var(--ClassicBlue90); color: var(--white); @@ -774,4 +774,18 @@ svg.stats { ::-webkit-scrollbar-button { border-radius: inherit; +} + +.arrow-down:after { + content: "\2193"; + display: inline-block; + vertical-align: text-bottom; + margin-left: 4px; +} + +.arrow-up:after { + content: "\2191"; + display: inline-block; + vertical-align: text-bottom; + margin-left: 4px; } \ No newline at end of file diff --git a/css/light.css b/css/light.css index ebd3bdb..db73dc8 100644 --- a/css/light.css +++ b/css/light.css @@ -65,7 +65,7 @@ a:hover { position: absolute; top: 200px; left: calc(40% - 100px); - width: 200px; + /* width: 200px; */ margin: auto; background-color: var(--ClassicBlue80); color: var(--white); @@ -770,4 +770,18 @@ svg.stats { ::-webkit-scrollbar-button { border-radius: inherit; +} + +.arrow-down:after { + content: "\2193"; + display: inline-block; + vertical-align: text-bottom; + margin-left: 4px; +} + +.arrow-up:after { + content: "\2191"; + display: inline-block; + vertical-align: text-bottom; + margin-left: 4px; } \ No newline at end of file diff --git a/jars/bcp47j.jar b/jars/bcp47j.jar index 7d8723d..a32adca 100644 Binary files a/jars/bcp47j.jar and b/jars/bcp47j.jar differ diff --git a/jars/slf4j-api-2.0.13.jar b/jars/slf4j-api-2.0.13.jar new file mode 100644 index 0000000..a800cc2 Binary files /dev/null and b/jars/slf4j-api-2.0.13.jar differ diff --git a/jars/slf4j-api-2.0.9.jar b/jars/slf4j-api-2.0.9.jar deleted file mode 100644 index 3796afe..0000000 Binary files a/jars/slf4j-api-2.0.9.jar and /dev/null differ diff --git a/jars/slf4j-nop-2.0.13.jar b/jars/slf4j-nop-2.0.13.jar new file mode 100644 index 0000000..e2e1122 Binary files /dev/null and b/jars/slf4j-nop-2.0.13.jar differ diff --git a/jars/slf4j-nop-2.0.9.jar b/jars/slf4j-nop-2.0.9.jar deleted file mode 100644 index 6a9403d..0000000 Binary files a/jars/slf4j-nop-2.0.9.jar and /dev/null differ diff --git a/jars/sqlite-jdbc-3.45.2.0.jar b/jars/sqlite-jdbc-3.45.3.0.jar similarity index 61% rename from jars/sqlite-jdbc-3.45.2.0.jar rename to jars/sqlite-jdbc-3.45.3.0.jar index 9b6e9db..4debbd4 100644 Binary files a/jars/sqlite-jdbc-3.45.2.0.jar and b/jars/sqlite-jdbc-3.45.3.0.jar differ diff --git a/package.json b/package.json index 4dbaf74..e1ded6a 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "swordfish", "productName": "Swordfish", - "version": "5.2.1", + "version": "5.3.0", "description": "Swordfish Translation Editor", "main": "js/Swordfish.js", "scripts": { @@ -20,12 +20,12 @@ "url": "https://github.com/rmraya/Swordfish.git" }, "devDependencies": { - "electron": "^29.3.0", + "electron": "^30.0.9", "typescript": "^5.4.5" }, "dependencies": { - "mtengines": "^1.3.3", - "typesxml": "^1.3.0", - "typesbcp47": "^1.3.0" + "mtengines": "^1.4.0", + "typesxml": "^1.3.1", + "typesbcp47": "^1.3.2" } } \ No newline at end of file diff --git a/src/com/maxprograms/swordfish/Constants.java b/src/com/maxprograms/swordfish/Constants.java index 50fc9d8..0cc8a1f 100644 --- a/src/com/maxprograms/swordfish/Constants.java +++ b/src/com/maxprograms/swordfish/Constants.java @@ -19,8 +19,8 @@ private Constants() { } public static final String APPNAME = "Swordfish"; - public static final String VERSION = "5.2.1"; - public static final String BUILD = "20240411_0935"; + public static final String VERSION = "5.3.0"; + public static final String BUILD = "20240602_1623"; public static final String REASON = "reason"; public static final String STATUS = "status"; diff --git a/src/com/maxprograms/swordfish/GlossariesHandler.java b/src/com/maxprograms/swordfish/GlossariesHandler.java index 01f270f..7dbd613 100644 --- a/src/com/maxprograms/swordfish/GlossariesHandler.java +++ b/src/com/maxprograms/swordfish/GlossariesHandler.java @@ -58,7 +58,6 @@ public class GlossariesHandler implements HttpHandler { private static Logger logger = System.getLogger(GlossariesHandler.class.getName()); - private static Map glossaries; private static Map engines; private static Map openTasks = new Hashtable<>(); @@ -159,24 +158,24 @@ private static JSONObject createGlossary(String request) throws IOException, SQL Memory mem = new Memory(json); ITmEngine engine = new SqliteDatabase(mem.getId(), getWorkFolder()); engine.close(); - if (glossaries == null) { - loadGlossariesList(); - } + Map glossaries = getGlossaries(); glossaries.put(mem.getId(), mem); ServicesHandler.addClient(json.getString("client")); ServicesHandler.addSubject(json.getString("subject")); ServicesHandler.addProject(json.getString("project")); - saveGlossariesList(); + saveGlossariesList(glossaries); return result; } - private static void loadGlossariesList() throws IOException { - glossaries = new Hashtable<>(); + private static Map getGlossaries() throws IOException { + Map glossaries = new Hashtable<>(); engines = new Hashtable<>(); File home = new File(getWorkFolder()); File list = new File(home, "glossaries.json"); if (!list.exists()) { - return; + JSONObject json = new JSONObject(); + TmsServer.writeJSON(list, json); + return glossaries; } JSONObject json = TmsServer.readJSON(list); Set keys = json.keySet(); @@ -186,9 +185,10 @@ private static void loadGlossariesList() throws IOException { JSONObject obj = json.getJSONObject(key); glossaries.put(key, new Memory(obj)); } + return glossaries; } - private static void saveGlossariesList() throws IOException { + private static synchronized void saveGlossariesList(Map glossaries) throws IOException { JSONObject json = new JSONObject(); Set keys = glossaries.keySet(); Iterator it = keys.iterator(); @@ -204,16 +204,18 @@ private static void saveGlossariesList() throws IOException { private static JSONObject listGlossaries() throws IOException { JSONObject result = new JSONObject(); - loadGlossariesList(); JSONArray array = new JSONArray(); result.put("glossaries", array); - Vector vector = new Vector<>(); - vector.addAll(glossaries.values()); - Collections.sort(vector); - Iterator it = vector.iterator(); - while (it.hasNext()) { - Memory m = it.next(); - array.put(m.toJSON()); + Map glossaries = getGlossaries(); + if (!glossaries.isEmpty()) { + Vector vector = new Vector<>(); + vector.addAll(glossaries.values()); + Collections.sort(vector); + Iterator it = vector.iterator(); + while (it.hasNext()) { + Memory m = it.next(); + array.put(m.toJSON()); + } } return result; } @@ -221,7 +223,6 @@ private static JSONObject listGlossaries() throws IOException { private static JSONObject deleteGlossary(String request) { JSONObject result = new JSONObject(); final JSONObject json = new JSONObject(request); - if (json.has("glossaries")) { final String process = "" + System.currentTimeMillis(); result.put("process", process); @@ -230,6 +231,7 @@ private static JSONObject deleteGlossary(String request) { openTasks.put(process, obj); Thread.ofVirtual().start(() -> { try { + Map glossaries = getGlossaries(); JSONArray array = json.getJSONArray("glossaries"); for (int i = 0; i < array.length(); i++) { Memory mem = glossaries.get(array.getString(i)); @@ -239,7 +241,7 @@ private static JSONObject deleteGlossary(String request) { } glossaries.remove(mem.getId()); } - saveGlossariesList(); + saveGlossariesList(glossaries); JSONObject completed = new JSONObject(); completed.put(Constants.PROGRESS, Constants.COMPLETED); openTasks.put(process, completed); @@ -286,9 +288,7 @@ private static JSONObject exportGlossary(String request) { openTasks.put(process, obj); Thread.ofVirtual().start(() -> { try { - if (glossaries == null) { - loadGlossariesList(); - } + Map glossaries = getGlossaries(); Memory mem = glossaries.get(json.getString("glossary")); openGlossary(mem); ITmEngine engine = getEngine(mem.getId()); @@ -320,30 +320,21 @@ private static JSONObject exportGlossary(String request) { } public static synchronized void openGlossary(String id) throws IOException, SQLException, URISyntaxException { - if (glossaries == null) { - loadGlossariesList(); - } + Map glossaries = getGlossaries(); openGlossary(glossaries.get(id)); } public static synchronized void openGlossary(Memory memory) throws IOException, SQLException, URISyntaxException { - if (glossaries == null) { - loadGlossariesList(); - } ITmEngine engine = memory.getType().equals(Memory.LOCAL) ? new SqliteDatabase(memory.getId(), getWorkFolder()) : new RemoteDatabase(memory.getServer(), memory.getUser(), memory.getPassword(), memory.getId()); engines.put(memory.getId(), engine); } public static ITmEngine getEngine(String id) throws IOException, SQLException, URISyntaxException { - if (glossaries == null) { - loadGlossariesList(); - } if (!engines.containsKey(id)) { openGlossary(id); } return engines.get(id); - } public static synchronized void closeGlossary(String id) throws IOException, SQLException, URISyntaxException { @@ -389,6 +380,7 @@ private JSONObject importGlossary(String request) { openTasks.put(process, obj); Thread.ofVirtual().start(() -> { try { + Map glossaries = getGlossaries(); openGlossary(glossaries.get(id)); File tempFile = null; String tmxFile = glossFile.getAbsolutePath(); @@ -430,21 +422,21 @@ private JSONObject importGlossary(String request) { return result; } - public static JSONArray getGlossaries() throws IOException { + public static synchronized JSONArray getGlossariesList() throws IOException { JSONArray result = new JSONArray(); - if (glossaries == null) { - loadGlossariesList(); - } - Vector vector = new Vector<>(); - vector.addAll(glossaries.values()); - Collections.sort(vector); - Iterator it = vector.iterator(); - while (it.hasNext()) { - Memory m = it.next(); - JSONArray array = new JSONArray(); - array.put(m.getId()); - array.put(m.getName()); - result.put(array); + Map glossaries = getGlossaries(); + if (!glossaries.isEmpty()) { + Vector vector = new Vector<>(); + vector.addAll(glossaries.values()); + Collections.sort(vector); + Iterator it = vector.iterator(); + while (it.hasNext()) { + Memory m = it.next(); + JSONArray array = new JSONArray(); + array.put(m.getId()); + array.put(m.getName()); + result.put(array); + } } return result; } @@ -505,6 +497,7 @@ private JSONObject addTerm(String request) { Element tgtSeg = new Element("seg"); tgtSeg.setText(json.getString("targetTerm")); tgtTuv.addContent(tgtSeg); + Map glossaries = getGlossaries(); openGlossary(glossaries.get(glossary)); ITmEngine engine = getEngine(glossary); engine.storeTu(tu); @@ -532,6 +525,7 @@ public static JSONObject searchTerm(String request) { String glossary = json.getString("glossary"); try { List matches = new Vector<>(); + Map glossaries = getGlossaries(); openGlossary(glossaries.get(glossary)); matches.addAll(getEngine(glossary).searchAll(searchStr, srcLang, similarity, caseSensitive)); closeGlossary(glossary); @@ -597,17 +591,13 @@ private static String parseTU(Element element, List languages) } public static String getGlossaryName(String id) throws IOException { - if (glossaries == null) { - loadGlossariesList(); - } + Map glossaries = getGlossaries(); return glossaries.get(id).getName(); } protected static void addGlossary(Memory memory) throws IOException { - if (glossaries == null) { - loadGlossariesList(); - } + Map glossaries = getGlossaries(); glossaries.put(memory.getId(), memory); - saveGlossariesList(); + saveGlossariesList(glossaries); } } diff --git a/src/com/maxprograms/swordfish/MemoriesHandler.java b/src/com/maxprograms/swordfish/MemoriesHandler.java index f54a871..1d75bb8 100644 --- a/src/com/maxprograms/swordfish/MemoriesHandler.java +++ b/src/com/maxprograms/swordfish/MemoriesHandler.java @@ -61,7 +61,6 @@ public class MemoriesHandler implements HttpHandler { private static Logger logger = System.getLogger(MemoriesHandler.class.getName()); - private static Map memories; private static Map engines; private static Map openTasks = new Hashtable<>(); private static Map localEngines = new Hashtable<>(); @@ -145,9 +144,6 @@ private static JSONObject getLanguages(String request) { openTasks.put(process, obj); Thread.ofVirtual().start(() -> { try { - if (memories == null) { - loadMemoriesList(); - } String memory = json.getString("memory"); open(memory); ITmEngine engine = getEngine(memory); @@ -324,9 +320,6 @@ private static JSONObject exportMemory(String request) { openTasks.put(process, obj); Thread.ofVirtual().start(() -> { try { - if (memories == null) { - loadMemoriesList(); - } String memory = json.getString("memory"); open(memory); ITmEngine engine = getEngine(memory); @@ -360,7 +353,6 @@ private static JSONObject exportMemory(String request) { private static JSONObject deleteMemory(String request) { JSONObject result = new JSONObject(); final JSONObject json = new JSONObject(request); - if (json.has("memories")) { final String process = "" + System.currentTimeMillis(); result.put("process", process); @@ -369,6 +361,7 @@ private static JSONObject deleteMemory(String request) { openTasks.put(process, obj); Thread.ofVirtual().start(() -> { try { + Map memories = getMemories(); JSONArray array = json.getJSONArray("memories"); for (int i = 0; i < array.length(); i++) { String id = array.getString(i); @@ -379,7 +372,7 @@ private static JSONObject deleteMemory(String request) { } memories.remove(id); } - saveMemoriesList(); + saveMemoriesList(memories); JSONObject completed = new JSONObject(); completed.put(Constants.PROGRESS, Constants.COMPLETED); openTasks.put(process, completed); @@ -406,27 +399,27 @@ private static void deleteMemoryFolder(String id) { } } - private static JSONObject listMemories() throws IOException { + protected static JSONObject listMemories() throws IOException { JSONObject result = new JSONObject(); - loadMemoriesList(); JSONArray array = new JSONArray(); result.put("memories", array); - Vector vector = new Vector<>(); - vector.addAll(memories.values()); - Collections.sort(vector); - Iterator it = vector.iterator(); - while (it.hasNext()) { - Memory m = it.next(); - array.put(m.toJSON()); + Map memories = getMemories(); + if (!memories.isEmpty()) { + Vector vector = new Vector<>(); + vector.addAll(memories.values()); + Collections.sort(vector); + Iterator it = vector.iterator(); + while (it.hasNext()) { + Memory m = it.next(); + array.put(m.toJSON()); + } } return result; } - public static JSONArray getMemories() throws IOException { + public static JSONArray getMemoriesList() throws IOException { JSONArray result = new JSONArray(); - if (memories == null) { - loadMemoriesList(); - } + Map memories = getMemories(); Vector vector = new Vector<>(); vector.addAll(memories.values()); Collections.sort(vector); @@ -453,24 +446,24 @@ private static JSONObject createMemory(String request) throws IOException, SQLEx Memory mem = new Memory(json); ITmEngine engine = new SqliteDatabase(mem.getId(), getWorkFolder()); engine.close(); - if (memories == null) { - loadMemoriesList(); - } + Map memories = getMemories(); memories.put(mem.getId(), mem); ServicesHandler.addClient(json.getString("client")); ServicesHandler.addSubject(json.getString("subject")); ServicesHandler.addProject(json.getString("project")); - saveMemoriesList(); + saveMemoriesList(memories); return result; } - private static synchronized void loadMemoriesList() throws IOException { - memories = new Hashtable<>(); + private static synchronized Map getMemories() throws IOException { + Map memories = new Hashtable<>(); engines = new Hashtable<>(); File home = new File(getWorkFolder()); File list = new File(home, "memories.json"); if (!list.exists()) { - return; + JSONObject json = new JSONObject(); + TmsServer.writeJSON(list, json); + return memories; } JSONObject json = TmsServer.readJSON(list); Set keys = json.keySet(); @@ -480,9 +473,10 @@ private static synchronized void loadMemoriesList() throws IOException { JSONObject obj = json.getJSONObject(key); memories.put(key, new Memory(obj)); } + return memories; } - private static synchronized void saveMemoriesList() throws IOException { + private static synchronized void saveMemoriesList(Map memories) throws IOException { JSONObject json = new JSONObject(); Set keys = memories.keySet(); Iterator it = keys.iterator(); @@ -505,10 +499,8 @@ public static String getWorkFolder() throws IOException { } public static synchronized void open(String id) throws IOException, SQLException, URISyntaxException { - if (memories == null) { - loadMemoriesList(); - } if (!engines.containsKey(id)) { + Map memories = getMemories(); Memory memory = memories.get(id); ITmEngine engine = memory.getType().equals(Memory.LOCAL) ? new SqliteDatabase(id, getWorkFolder()) : new RemoteDatabase(memory.getServer(), memory.getUser(), memory.getPassword(), id); @@ -536,9 +528,6 @@ public static synchronized void closeAll() throws IOException, SQLException, URI } public static ITmEngine getEngine(String id) throws IOException, SQLException, URISyntaxException { - if (memories == null) { - loadMemoriesList(); - } if (!engines.containsKey(id)) { open(id); } @@ -546,9 +535,7 @@ public static ITmEngine getEngine(String id) throws IOException, SQLException, U } public static String getName(String id) throws IOException { - if (memories == null) { - loadMemoriesList(); - } + Map memories = getMemories(); return memories.get(id).getName(); } @@ -685,10 +672,8 @@ public static String pureText(Element e) { } protected static void addMemory(Memory memory) throws IOException { - if (memories == null) { - loadMemoriesList(); - } + Map memories = getMemories(); memories.put(memory.getId(), memory); - saveMemoriesList(); + saveMemoriesList(memories); } } diff --git a/src/com/maxprograms/swordfish/ProjectsHandler.java b/src/com/maxprograms/swordfish/ProjectsHandler.java index f819080..a866deb 100644 --- a/src/com/maxprograms/swordfish/ProjectsHandler.java +++ b/src/com/maxprograms/swordfish/ProjectsHandler.java @@ -27,8 +27,6 @@ import java.sql.SQLException; import java.text.MessageFormat; import java.time.LocalDate; -import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; import java.util.Hashtable; import java.util.Iterator; @@ -37,6 +35,7 @@ import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; +import java.util.Vector; import java.util.zip.DataFormatException; import javax.xml.parsers.ParserConfigurationException; @@ -65,9 +64,7 @@ public class ProjectsHandler implements HttpHandler { private static Logger logger = System.getLogger(ProjectsHandler.class.getName()); - private static Map projects = new Hashtable<>(); private static Map processes = new Hashtable<>(); - protected JSONObject projectsList; private String srxFile; private String catalogFile; @@ -83,7 +80,6 @@ public void handle(HttpExchange exchange) throws IOException { try (InputStream is = exchange.getRequestBody()) { request = TmsServer.readRequestBody(is); } - loadProjectsList(); JSONObject response = processRequest(uri.toString(), request); byte[] bytes = response.toString().getBytes(StandardCharsets.UTF_8); exchange.sendResponseHeaders(200, bytes.length); @@ -97,7 +93,7 @@ public void handle(HttpExchange exchange) throws IOException { } } } - } catch (IOException | JSONException | SAXException | ParserConfigurationException e) { + } catch (IOException | JSONException e) { MessageFormat mf = new MessageFormat(Messages.getString("ProjectsHandler.0")); logger.log(Level.ERROR, mf.format(new String[] { exchange.getRequestURI().toString() }), e); } @@ -238,29 +234,37 @@ private JSONObject setMTMatches(String request) JSONObject result = new JSONObject(); JSONObject json = new JSONObject(request); String project = json.getString("project"); + Map projects = getProjects(); if (!projects.containsKey(project)) { - result.put(Constants.REASON, Messages.getString("ProjectsHandler.2")); + MessageFormat mf = new MessageFormat(Messages.getString("ProjectsHandler.2")); + result.put(Constants.REASON, mf.format(new String[] { project })); return result; } projectStores.get(project).setMTMatches(json); return result; } - private JSONObject getProject(String request) throws IOException, JSONException { + private JSONObject getProject(String request) + throws IOException, JSONException, SAXException, ParserConfigurationException { JSONObject json = new JSONObject(request); + Map projects = getProjects(); if (!projects.containsKey(json.getString("project"))) { JSONObject result = new JSONObject(); - result.put(Constants.REASON, Messages.getString("ProjectsHandler.2")); + MessageFormat mf = new MessageFormat(Messages.getString("ProjectsHandler.2")); + result.put(Constants.REASON, mf.format(new String[] { json.getString("project") })); return result; } return projects.get(json.getString("project")).toJSON(); } - private JSONObject getProjectFiles(String request) { + private JSONObject getProjectFiles(String request) + throws JSONException, IOException, SAXException, ParserConfigurationException { JSONObject result = new JSONObject(); JSONObject json = new JSONObject(request); + Map projects = getProjects(); if (!projects.containsKey(json.getString("project"))) { - result.put(Constants.REASON, Messages.getString("ProjectsHandler.2")); + MessageFormat mf = new MessageFormat(Messages.getString("ProjectsHandler.2")); + result.put(Constants.REASON, mf.format(new String[] { json.getString("project") })); return result; } Project project = projects.get(json.getString("project")); @@ -292,6 +296,7 @@ private JSONObject exportTranslations(String request) { String output = json.getString("output"); if (!projectStores.containsKey(project)) { try { + Map projects = getProjects(); Project prj = projects.get(project); XliffStore store = new XliffStore(prj.getXliff(), prj.getSourceLang().getCode(), prj.getTargetLang().getCode()); @@ -334,6 +339,7 @@ private JSONObject export(String request) { String output = json.getString("output"); if (!projectStores.containsKey(project)) { try { + Map projects = getProjects(); Project prj = projects.get(project); XliffStore store = new XliffStore(prj.getXliff(), prj.getSourceLang().getCode(), prj.getTargetLang().getCode()); @@ -376,6 +382,7 @@ private JSONObject exportTMX(String request) { String output = json.getString("output"); if (!projectStores.containsKey(project)) { try { + Map projects = getProjects(); Project prj = projects.get(project); XliffStore store = new XliffStore(prj.getXliff(), prj.getSourceLang().getCode(), prj.getTargetLang().getCode()); @@ -394,6 +401,7 @@ private JSONObject exportTMX(String request) { try { Thread.ofVirtual().start(() -> { try { + Map projects = getProjects(); Project prj = projects.get(project); projectStores.get(project).exportTMX(output, prj.getDescription(), prj.getClient(), prj.getSubject()); @@ -419,6 +427,7 @@ private JSONObject deleteProjects(String request) { try { JSONObject json = new JSONObject(request); JSONArray array = json.getJSONArray("projects"); + Map projects = getProjects(); for (int i = 0; i < array.length(); i++) { String project = array.getString(i); if (projectStores.containsKey(project)) { @@ -427,77 +436,65 @@ private JSONObject deleteProjects(String request) { projectStores.remove(project); } TmsServer.deleteFolder(new File(getWorkFolder(), project)); - removeFromList(project); + projects.remove(project); } - saveProjectsList(); - } catch (IOException | SQLException e) { + saveProjectsList(projects); + } catch (IOException | SQLException | JSONException | SAXException | ParserConfigurationException e) { logger.log(Level.ERROR, e); result.put(Constants.REASON, e.getMessage()); } return result; } - private void removeFromList(String id) { - JSONArray array = projectsList.getJSONArray("projects"); - for (int i = 0; i < array.length(); i++) { - JSONObject project = array.getJSONObject(i); - if (project.get("id").equals(id)) { - array.remove(i); - break; - } - } - } - private JSONObject listProjects() throws IOException, JSONException, SAXException, ParserConfigurationException { JSONObject result = new JSONObject(); - loadProjectsList(); - JSONArray array = projectsList.getJSONArray("projects"); - for (int i = 0; i < array.length(); i++) { - int status = array.getJSONObject(i).getInt("status"); - array.getJSONObject(i).put("svg", XliffUtils.makeSVG(status)); - } + JSONArray array = new JSONArray(); result.put("projects", array); + Map projects = getProjects(); + if (!projects.isEmpty()) { + Vector list = new Vector<>(projects.values()); + for (int i = 0; i < list.size(); i++) { + Project project = list.get(i); + int status = project.getStatus(); + JSONObject obj = project.toJSON(); + obj.put("svg", XliffUtils.makeSVG(status)); + array.put(obj); + } + } return result; } - private void loadProjectsList() throws IOException, JSONException, SAXException, ParserConfigurationException { - projects.clear(); + private static synchronized Map getProjects() + throws IOException, JSONException, SAXException, ParserConfigurationException { + Map projects = new Hashtable<>(); File home = getWorkFolder(); File list = new File(home, "projects.json"); if (!list.exists()) { JSONObject json = new JSONObject(); json.put("projects", new JSONArray()); TmsServer.writeJSON(list, json); + return projects; } - projectsList = TmsServer.readJSON(list); - sortProjects(); - } - - private void sortProjects() throws IOException, JSONException, SAXException, ParserConfigurationException { + JSONObject projectsList = TmsServer.readJSON(list); JSONArray array = projectsList.getJSONArray("projects"); - List list = new ArrayList<>(); for (int i = 0; i < array.length(); i++) { Project project = new Project(array.getJSONObject(i)); - list.add(project); - } - Collections.sort(list, (o1, o2) -> { - Long long1 = Long.parseLong(o1.getId()); - Long long2 = Long.parseLong(o2.getId()); - return Long.compare(long2, long1); - }); - array = new JSONArray(); - for (int i = 0; i < list.size(); i++) { - Project project = list.get(i); projects.put(project.getId(), project); - array.put(project.toJSON()); } - projectsList.put("projects", array); + return projects; } - private synchronized void saveProjectsList() throws IOException { + private synchronized void saveProjectsList(Map projects) throws IOException { + JSONObject json = new JSONObject(); + JSONArray array = new JSONArray(); + Iterator it = projects.values().iterator(); + while (it.hasNext()) { + array.put(it.next().toJSON()); + } + json.put("projects", array); File home = getWorkFolder(); File list = new File(home, "projects.json"); - byte[] bytes = projectsList.toString(2).getBytes(StandardCharsets.UTF_8); + byte[] bytes = json.toString(2).getBytes(StandardCharsets.UTF_8); try (FileOutputStream out = new FileOutputStream(list)) { out.write(bytes); } @@ -514,6 +511,7 @@ private JSONObject getSegmentSource(String request) { } if (!projectStores.containsKey(project)) { try { + Map projects = getProjects(); Project prj = projects.get(project); XliffStore store = new XliffStore(prj.getXliff(), prj.getSourceLang().getCode(), prj.getTargetLang().getCode()); @@ -545,6 +543,7 @@ private JSONObject getSegments(String request) { if (!projectStores.containsKey(project)) { try { + Map projects = getProjects(); Project prj = projects.get(project); XliffStore store = new XliffStore(prj.getXliff(), prj.getSourceLang().getCode(), prj.getTargetLang().getCode()); @@ -593,6 +592,7 @@ private JSONObject getSegmentsCount(String request) { String project = json.getString("project"); if (!projectStores.containsKey(project)) { try { + Map projects = getProjects(); Project prj = projects.get(project); XliffStore store = new XliffStore(prj.getXliff(), prj.getSourceLang().getCode(), prj.getTargetLang().getCode()); @@ -649,10 +649,10 @@ private JSONObject createProject(String request) { File projectFolder = new File(getWorkFolder(), id); Files.createDirectories(projectFolder.toPath()); - List sourceFiles = new ArrayList<>(); + List sourceFiles = new Vector<>(); Thread.ofVirtual().start(() -> { try { - List xliffs = new ArrayList<>(); + List xliffs = new Vector<>(); for (int i = 0; i < files.length(); i++) { JSONObject file = files.getJSONObject(i); String fullName = file.getString("file"); @@ -694,7 +694,7 @@ private JSONObject createProject(String request) { List res = Convert.run(params); if ("0".equals(res.get(0))) { - res = ToXliff2.run(xliff, catalogFile, "2.0"); + res = ToXliff2.run(xliff, catalogFile, "2.1"); if (mustResegment && "0".equals(res.get(0))) { res = Resegmenter.run(xliff.getAbsolutePath(), srxFile, json.getString("srcLang"), new Catalog(catalogFile)); @@ -731,10 +731,9 @@ private JSONObject createProject(String request) { ServicesHandler.addProject(p.getDescription()); } p.setFiles(sourceFiles); + Map projects = getProjects(); projects.put(id, p); - projectsList.getJSONArray("projects").put(p.toJSON()); - sortProjects(); - saveProjectsList(); + saveProjectsList(projects); if (applyTM) { XliffStore store = new XliffStore(p.getXliff(), p.getSourceLang().getCode(), p.getTargetLang().getCode()); @@ -780,10 +779,6 @@ public static File getWorkFolder() throws IOException { private JSONObject closeProject(String request) { JSONObject result = new JSONObject(); - if (projects == null) { - result.put(Constants.REASON, Messages.getString("ProjectsHandler.12")); - return result; - } if (projectStores == null) { result.put(Constants.REASON, Messages.getString("ProjectsHandler.13")); return result; @@ -852,19 +847,14 @@ private JSONObject saveSource(String request) { return result; } - private void updateProjectStatus(String projectId, int status) throws IOException { - JSONArray array = projectsList.getJSONArray("projects"); - for (int i = 0; i < array.length(); i++) { - JSONObject project = array.getJSONObject(i); - if (project.getString("id").equals(projectId)) { - int value = project.getInt("status"); - if (value != status) { - array.getJSONObject(i).put("status", status); - projectsList.put("projects", array); - saveProjectsList(); - } - break; - } + private void updateProjectStatus(String projectId, int status) + throws IOException, JSONException, SAXException, ParserConfigurationException { + Map projects = getProjects(); + Project project = projects.get(projectId); + int value = project.getStatus(); + if (value != status) { + project.setStatus(status); + saveProjectsList(projects); } } @@ -924,6 +914,7 @@ private JSONObject assembleMatchesAll(String request) { String project = json.getString("project"); if (!projectStores.containsKey(project)) { + Map projects = getProjects(); Project prj = projects.get(project); XliffStore store = new XliffStore(prj.getXliff(), prj.getSourceLang().getCode(), prj.getTargetLang().getCode()); @@ -964,6 +955,7 @@ private JSONObject tmTranslateAll(String request) { String memory = json.getString("memory"); int penalization = json.has("penalization") ? json.getInt("penalization") : 0; if (!projectStores.containsKey(project)) { + Map projects = getProjects(); Project prj = projects.get(project); XliffStore store = new XliffStore(prj.getXliff(), prj.getSourceLang().getCode(), prj.getTargetLang().getCode()); @@ -996,13 +988,17 @@ private JSONObject tmTranslateAll(String request) { return result; } - private JSONObject getProjectMemories(String request) { + private JSONObject getProjectMemories(String request) + throws JSONException, IOException, SAXException, ParserConfigurationException { JSONObject result = new JSONObject(); JSONObject json = new JSONObject(request); + String projectId = json.getString("project"); + Map projects = getProjects(); + Project project = projects.get(projectId); + String memory = project.getMemory(); + result.put("default", memory); try { - result.put("memories", MemoriesHandler.getMemories()); - String memory = projects.get(json.getString("project")).getMemory(); - result.put("default", memory != null ? memory : ""); + result.put("memories", MemoriesHandler.getMemoriesList()); } catch (IOException e) { logger.log(Level.ERROR, e); result.put(Constants.REASON, e.getMessage()); @@ -1010,13 +1006,17 @@ private JSONObject getProjectMemories(String request) { return result; } - private JSONObject getProjectGlossaries(String request) { + private JSONObject getProjectGlossaries(String request) + throws JSONException, IOException, SAXException, ParserConfigurationException { JSONObject result = new JSONObject(); JSONObject json = new JSONObject(request); + String projectId = json.getString("project"); + Map projects = getProjects(); + Project project = projects.get(projectId); + String glossary = project.getGlossary(); + result.put("default", glossary); try { - result.put("glossaries", GlossariesHandler.getGlossaries()); - String glossary = projects.get(json.getString("project")).getGlossary(); - result.put("default", glossary != null ? glossary : ""); + result.put("glossaries", GlossariesHandler.getGlossariesList()); } catch (IOException e) { logger.log(Level.ERROR, e); result.put(Constants.REASON, e.getMessage()); @@ -1024,22 +1024,16 @@ private JSONObject getProjectGlossaries(String request) { return result; } - private JSONObject setProjectMemory(String request) { + private JSONObject setProjectMemory(String request) + throws JSONException, SAXException, ParserConfigurationException { JSONObject result = new JSONObject(); try { JSONObject json = new JSONObject(request); String project = json.getString("project"); String memory = json.getString("memory"); + Map projects = getProjects(); projects.get(project).setMemory(memory); - JSONArray list = projectsList.getJSONArray("projects"); - for (int i = 0; i < list.length(); i++) { - JSONObject obj = list.getJSONObject(i); - if (project.equals(obj.getString("id"))) { - obj.put("memory", memory); - break; - } - } - saveProjectsList(); + saveProjectsList(projects); } catch (IOException e) { logger.log(Level.ERROR, e); result.put(Constants.REASON, e.getMessage()); @@ -1047,22 +1041,16 @@ private JSONObject setProjectMemory(String request) { return result; } - private JSONObject setProjectGlossary(String request) { + private JSONObject setProjectGlossary(String request) + throws JSONException, SAXException, ParserConfigurationException { JSONObject result = new JSONObject(); try { JSONObject json = new JSONObject(request); String project = json.getString("project"); String glossary = json.getString("glossary"); + Map projects = getProjects(); projects.get(project).setMemory(glossary); - JSONArray list = projectsList.getJSONArray("projects"); - for (int i = 0; i < list.length(); i++) { - JSONObject obj = list.getJSONObject(i); - if (project.equals(obj.getString("id"))) { - obj.put("glossary", glossary); - break; - } - } - saveProjectsList(); + saveProjectsList(projects); } catch (IOException e) { logger.log(Level.ERROR, e); result.put(Constants.REASON, e.getMessage()); @@ -1106,9 +1094,9 @@ private JSONObject importXliff(String request) { p.setStatus(status.getInt("percentage")); ServicesHandler.addClient(json.getString("client")); ServicesHandler.addSubject(json.getString("subject")); + Map projects = getProjects(); projects.put(id, p); - projectsList.getJSONArray("projects").put(p.toJSON()); - saveProjectsList(); + saveProjectsList(projects); obj.put(Constants.PROGRESS, Constants.COMPLETED); processes.put(id, obj); } catch (IOException | SAXException | ParserConfigurationException | URISyntaxException @@ -1201,7 +1189,7 @@ private JSONObject unconfirmTranslations(String request) { result.put("statistics", status); updateProjectStatus(project, status.getInt("percentage")); } - } catch (SQLException | JSONException | IOException e) { + } catch (SQLException | JSONException | IOException | SAXException | ParserConfigurationException e) { logger.log(Level.ERROR, e); result.put(Constants.REASON, e.getMessage()); } @@ -1305,6 +1293,7 @@ private JSONObject generateStatistics(String request) { String project = json.getString("project"); if (!projectStores.containsKey(project)) { try { + Map projects = getProjects(); Project prj = projects.get(project); XliffStore store = new XliffStore(prj.getXliff(), prj.getSourceLang().getCode(), prj.getTargetLang().getCode()); @@ -1331,6 +1320,7 @@ private JSONObject exportHTML(String request) { try { JSONObject json = new JSONObject(request); String project = json.getString("project"); + Map projects = getProjects(); Project prj = projects.get(project); if (!projectStores.containsKey(project)) { try { @@ -1459,6 +1449,7 @@ private JSONObject getProjectTerms(String request) { try { String project = json.getString("project"); if (!projectStores.containsKey(project)) { + Map projects = getProjects(); Project prj = projects.get(project); XliffStore store = new XliffStore(prj.getXliff(), prj.getSourceLang().getCode(), prj.getTargetLang().getCode()); diff --git a/src/com/maxprograms/swordfish/ServicesHandler.java b/src/com/maxprograms/swordfish/ServicesHandler.java index c2c2102..7553998 100644 --- a/src/com/maxprograms/swordfish/ServicesHandler.java +++ b/src/com/maxprograms/swordfish/ServicesHandler.java @@ -29,7 +29,6 @@ import java.text.MessageFormat; import java.text.ParseException; import java.text.SimpleDateFormat; -import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.Iterator; @@ -37,6 +36,7 @@ import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; +import java.util.Vector; import javax.xml.parsers.ParserConfigurationException; @@ -218,7 +218,7 @@ private JSONObject getXmlFilters(String request) { File appFolder = new File(json.getString("path")); File xmlFiltersFolder = new File(appFolder, "xmlfilter"); JSONArray array = new JSONArray(); - List list = new ArrayList<>(); + List list = new Vector<>(); String[] files = xmlFiltersFolder.list(); for (int i = 0; i < files.length; i++) { if (files[i].endsWith(".xml")) { @@ -399,7 +399,7 @@ private JSONObject removeElements(String request) Document doc = builder.build(configFile); Element root = doc.getRootElement(); List tags = root.getChildren("tag"); - List newList = new ArrayList<>(); + List newList = new Vector<>(); Iterator it = tags.iterator(); while (it.hasNext()) { Element tag = it.next(); @@ -592,7 +592,7 @@ public static void addProject(String project) throws IOException { private static JSONArray insertString(String string, JSONArray array) { JSONArray result = new JSONArray(); - List list = new ArrayList<>(); + List list = new Vector<>(); list.add(string); for (int i = 0; i < array.length(); i++) { list.add(array.getString(i)); diff --git a/src/com/maxprograms/swordfish/TmsServer.java b/src/com/maxprograms/swordfish/TmsServer.java index 978c545..a488363 100644 --- a/src/com/maxprograms/swordfish/TmsServer.java +++ b/src/com/maxprograms/swordfish/TmsServer.java @@ -90,7 +90,7 @@ private void run() { server.createContext("/glossaries", new GlossariesHandler()); server.createContext("/services", new ServicesHandler()); server.createContext("/", this); - server.setExecutor(new ThreadPoolExecutor(4, 8, 30, TimeUnit.SECONDS, new ArrayBlockingQueue<>(100))); + server.setExecutor(new ThreadPoolExecutor(4, 20, 2, TimeUnit.HOURS, new ArrayBlockingQueue<>(200))); server.start(); if (debug) { logger.log(Level.INFO, Messages.getString("TmsServer.2")); diff --git a/src/com/maxprograms/swordfish/models/Project.java b/src/com/maxprograms/swordfish/models/Project.java index d458b99..eca3fec 100644 --- a/src/com/maxprograms/swordfish/models/Project.java +++ b/src/com/maxprograms/swordfish/models/Project.java @@ -15,9 +15,9 @@ import java.io.File; import java.io.IOException; import java.time.LocalDate; -import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import java.util.Vector; import javax.xml.parsers.ParserConfigurationException; @@ -79,7 +79,7 @@ public Project(JSONObject json) throws IOException, JSONException, SAXException, client = json.has("client") ? json.getString("client") : ""; subject = json.has("subject") ? json.getString("subject") : ""; creationDate = LocalDate.parse(json.getString("creationDate")); - files = new ArrayList<>(); + files = new Vector<>(); JSONArray filesArray = json.getJSONArray("files"); for (int i = 0; i < filesArray.length(); i++) { SourceFile sourceFile = new SourceFile(filesArray.getJSONObject(i)); @@ -174,7 +174,7 @@ public void setFiles(List files) { } public void setFiles(JSONArray array) { - files = new ArrayList<>(); + files = new Vector<>(); for (int i = 0; i < array.length(); i++) { files.add(new SourceFile(array.getJSONObject(i))); } diff --git a/src/com/maxprograms/swordfish/swordfish.properties b/src/com/maxprograms/swordfish/swordfish.properties index 09bd155..516deda 100644 --- a/src/com/maxprograms/swordfish/swordfish.properties +++ b/src/com/maxprograms/swordfish/swordfish.properties @@ -42,7 +42,7 @@ ProjectsHandler.14=Project is not open ProjectsHandler.15=no open projects ProjectsHandler.16=Projects closed ProjectsHandler.17=XLIFF file does not exist -ProjectsHandler.2=Project does not exist +ProjectsHandler.2=Project {0} does not exist ProjectsHandler.3=Error creating project store ProjectsHandler.4=Error exporting translations ProjectsHandler.5=Error creating project store diff --git a/src/com/maxprograms/swordfish/xliff/Split.java b/src/com/maxprograms/swordfish/xliff/Split.java index 1d5eb74..a794a84 100644 --- a/src/com/maxprograms/swordfish/xliff/Split.java +++ b/src/com/maxprograms/swordfish/xliff/Split.java @@ -16,13 +16,13 @@ import java.io.FileOutputStream; import java.io.IOException; import java.nio.file.Files; -import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; +import java.util.Vector; import javax.xml.parsers.ParserConfigurationException; @@ -43,7 +43,7 @@ private Split() { public static List split(String xliff, String outputFolder) throws SAXException, IOException, ParserConfigurationException { - List result = new ArrayList<>(); + List result = new Vector<>(); SAXBuilder builder = new SAXBuilder(); Document doc = builder.build(xliff); Element root = doc.getRootElement(); diff --git a/src/com/maxprograms/swordfish/xliff/XliffUtils.java b/src/com/maxprograms/swordfish/xliff/XliffUtils.java index 174f0fe..2903a4f 100644 --- a/src/com/maxprograms/swordfish/xliff/XliffUtils.java +++ b/src/com/maxprograms/swordfish/xliff/XliffUtils.java @@ -18,7 +18,6 @@ import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; -import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -187,10 +186,10 @@ public static String unquote(String string) { } public static List harvestTags(String source) { - List result = new ArrayList<>(); + List result = new Vector<>(); int index = source.indexOf(" currentTags = new ArrayList<>(); + List currentTags = new Vector<>(); while (index >= 0) { String start = source.substring(0, index); String rest = source.substring(index + 1); diff --git a/src/module-info.java b/src/module-info.java index cae5277..e35b89d 100644 --- a/src/module-info.java +++ b/src/module-info.java @@ -31,4 +31,5 @@ requires transitive json; requires java.logging; requires org.xerial.sqlitejdbc; + requires org.slf4j.nop; } \ No newline at end of file diff --git a/ts/Swordfish.ts b/ts/Swordfish.ts index 69d32ed..eb5258a 100644 --- a/ts/Swordfish.ts +++ b/ts/Swordfish.ts @@ -4163,7 +4163,6 @@ export class Swordfish { if (Swordfish.currentStatus.progress === Swordfish.COMPLETED) { clearInterval(intervalObject); Swordfish.mainWindow.webContents.send('set-status', 'Translating...'); - let exportedFile: string = Swordfish.path.join(Swordfish.appHome, 'projects', arg.project, 'applymt.xlf'); if (!existsSync(exportedFile)) { Swordfish.mainWindow.webContents.send('end-waiting'); @@ -4171,14 +4170,23 @@ export class Swordfish { Swordfish.showMessage({ type: 'error', message: 'Unable to find exported file' }); return; } - - let mtManager: MTManager = new MTManager(this.currentPreferences, arg.srcLang, arg.tgtLang); - mtManager.translateProject(arg.project, exportedFile); - unlinkSync(exportedFile); - - Swordfish.mainWindow.webContents.send('end-waiting'); - Swordfish.mainWindow.webContents.send('set-status', ''); - Swordfish.mainWindow.webContents.send('reload-page', { project: arg.project }); + try { + let mtManager: MTManager = new MTManager(this.currentPreferences, arg.srcLang, arg.tgtLang); + mtManager.translateProject(arg.project, exportedFile, arg.currentSegment); + unlinkSync(exportedFile); + Swordfish.mainWindow.webContents.send('end-waiting'); + Swordfish.mainWindow.webContents.send('set-status', ''); + Swordfish.mainWindow.webContents.send('reload-page', { project: arg.project }); + } catch (e) { + Swordfish.mainWindow.webContents.send('end-waiting'); + Swordfish.mainWindow.webContents.send('set-status', ''); + if (e instanceof Error) { + Swordfish.showMessage({ type: 'error', message: e.message }); + } else { + Swordfish.showMessage({ type: 'error', message: 'Unknown error applying MT' }); + console.error(e); + } + } return; } else if (Swordfish.currentStatus.progress === Swordfish.PROCESSING) { // it's OK, keep waiting diff --git a/ts/glossaries.ts b/ts/glossaries.ts index 00292d5..683dee6 100644 --- a/ts/glossaries.ts +++ b/ts/glossaries.ts @@ -20,6 +20,11 @@ class GlossariesView { tableContainer: HTMLDivElement; selected: Map; + glossaries: Memory[] + + glossariesSortFielD: string = 'name'; + glossariesSortAscending: boolean = true; + constructor(div: HTMLDivElement) { this.selected = new Map(); this.container = div; @@ -103,22 +108,136 @@ class GlossariesView { glossariesTable.classList.add('discover'); this.tableContainer.appendChild(glossariesTable); - glossariesTable.innerHTML = - '' + - ' ' + - 'Name' + - 'Type' + - 'Project' + - 'Client' + - 'Subject' + - 'Created' + - ''; + let header: HTMLTableSectionElement = document.createElement('thead'); + glossariesTable.appendChild(header); + + let headerRow: HTMLTableRowElement = document.createElement('tr'); + header.appendChild(headerRow); + + let headerCell: HTMLTableCellElement = document.createElement('th'); + headerCell.innerHTML = ' '; + headerRow.appendChild(headerCell); + + headerCell = document.createElement('th'); + headerCell.classList.add('noWrap'); + headerCell.innerText = 'Name'; + headerCell.id = 'glossary-name'; + headerCell.addEventListener('click', () => { + (document.getElementById('glossary-' + this.glossariesSortFielD) as HTMLTableCellElement).classList.remove('arrow-down'); + (document.getElementById('glossary-' + this.glossariesSortFielD) as HTMLTableCellElement).classList.remove('arrow-up'); + if (this.glossariesSortFielD === 'name') { + this.glossariesSortAscending = !this.glossariesSortAscending; + } else { + this.glossariesSortFielD = 'name'; + this.glossariesSortAscending = true; + } + this.displayGlossaries(); + }); + headerCell.style.paddingLeft = '4px'; + headerCell.style.paddingRight = '4px'; + headerRow.appendChild(headerCell); + + headerCell = document.createElement('th'); + headerCell.classList.add('noWrap'); + headerCell.innerText = 'Type'; + headerCell.id = 'glossary-type'; + headerCell.addEventListener('click', () => { + (document.getElementById('glossary-' + this.glossariesSortFielD) as HTMLTableCellElement).classList.remove('arrow-down'); + (document.getElementById('glossary-' + this.glossariesSortFielD) as HTMLTableCellElement).classList.remove('arrow-up'); + if (this.glossariesSortFielD === 'type') { + this.glossariesSortAscending = !this.glossariesSortAscending; + } else { + this.glossariesSortFielD = 'type'; + this.glossariesSortAscending = true; + } + this.displayGlossaries(); + }); + headerCell.style.paddingLeft = '4px'; + headerCell.style.paddingRight = '4px'; + headerRow.appendChild(headerCell); + + headerCell = document.createElement('th'); + headerCell.classList.add('noWrap'); + headerCell.innerText = 'Project'; + headerCell.id = 'glossary-project'; + headerCell.addEventListener('click', () => { + (document.getElementById('glossary-' + this.glossariesSortFielD) as HTMLTableCellElement).classList.remove('arrow-down'); + (document.getElementById('glossary-' + this.glossariesSortFielD) as HTMLTableCellElement).classList.remove('arrow-up'); + if (this.glossariesSortFielD === 'project') { + this.glossariesSortAscending = !this.glossariesSortAscending; + } else { + this.glossariesSortFielD = 'project'; + this.glossariesSortAscending = true; + } + this.displayGlossaries(); + }); + headerCell.style.paddingLeft = '4px'; + headerCell.style.paddingRight = '4px'; + headerRow.appendChild(headerCell); + + headerCell = document.createElement('th'); + headerCell.classList.add('noWrap'); + headerCell.innerText = 'Client'; + headerCell.id = 'glossary-client'; + headerCell.addEventListener('click', () => { + (document.getElementById('glossary-' + this.glossariesSortFielD) as HTMLTableCellElement).classList.remove('arrow-down'); + (document.getElementById('glossary-' + this.glossariesSortFielD) as HTMLTableCellElement).classList.remove('arrow-up'); + if (this.glossariesSortFielD === 'client') { + this.glossariesSortAscending = !this.glossariesSortAscending; + } else { + this.glossariesSortFielD = 'client'; + this.glossariesSortAscending = true; + } + this.displayGlossaries(); + }); + headerCell.style.paddingLeft = '4px'; + headerCell.style.paddingRight = '4px'; + headerRow.appendChild(headerCell); + + headerCell = document.createElement('th'); + headerCell.classList.add('noWrap'); + headerCell.innerText = 'Subject'; + headerCell.id = 'glossary-subject'; + headerCell.addEventListener('click', () => { + (document.getElementById('glossary-' + this.glossariesSortFielD) as HTMLTableCellElement).classList.remove('arrow-down'); + (document.getElementById('glossary-' + this.glossariesSortFielD) as HTMLTableCellElement).classList.remove('arrow-up'); + if (this.glossariesSortFielD === 'subject') { + this.glossariesSortAscending = !this.glossariesSortAscending; + } else { + this.glossariesSortFielD = 'subject'; + this.glossariesSortAscending = true; + } + this.displayGlossaries(); + }); + headerCell.style.paddingLeft = '4px'; + headerCell.style.paddingRight = '4px'; + headerRow.appendChild(headerCell); + + headerCell = document.createElement('th'); + headerCell.classList.add('noWrap'); + headerCell.innerText = 'Created'; + headerCell.id = 'glossary-created'; + headerCell.addEventListener('click', () => { + (document.getElementById('glossary-' + this.glossariesSortFielD) as HTMLTableCellElement).classList.remove('arrow-down'); + (document.getElementById('glossary-' + this.glossariesSortFielD) as HTMLTableCellElement).classList.remove('arrow-up'); + if (this.glossariesSortFielD === 'created') { + this.glossariesSortAscending = !this.glossariesSortAscending; + } else { + this.glossariesSortFielD = 'created'; + this.glossariesSortAscending = true; + } + this.displayGlossaries(); + }); + headerCell.style.paddingLeft = '4px'; + headerCell.style.paddingRight = '4px'; + headerRow.appendChild(headerCell); this.tbody = document.createElement('tbody'); glossariesTable.appendChild(this.tbody); this.electron.ipcRenderer.on('set-glossaries', (event: Electron.IpcRendererEvent, arg: any) => { - this.displayGlossaries(arg); + this.glossaries = arg; + this.displayGlossaries(); }); this.loadGlossaries(); @@ -196,20 +315,81 @@ class GlossariesView { this.electron.ipcRenderer.send('get-glossaries'); } - displayGlossaries(glossaries: Memory[]) { + displayGlossaries() { + if (this.glossariesSortAscending) { + (document.getElementById('glossary-' + this.glossariesSortFielD) as HTMLTableCellElement).classList.add('arrow-up'); + } else { + (document.getElementById('glossary-' + this.glossariesSortFielD) as HTMLTableCellElement).classList.add('arrow-down'); + } + this.glossaries.sort((a: Memory, b: Memory) => { + if (this.glossariesSortFielD === 'name') { + if (a.name.toLocaleLowerCase() < b.name.toLocaleLowerCase()) { + return this.glossariesSortAscending ? -1 : 1; + } + if (a.name.toLocaleLowerCase() > b.name.toLocaleLowerCase()) { + return this.glossariesSortAscending ? 1 : -1; + } + return 0; + } + if (this.glossariesSortFielD === 'type') { + if (a.type < b.type) { + return this.glossariesSortAscending ? -1 : 1; + } + if (a.type > b.type) { + return this.glossariesSortAscending ? 1 : -1; + } + return 0; + } + if (this.glossariesSortFielD === 'project') { + if (a.project.toLocaleLowerCase() < b.project.toLocaleLowerCase()) { + return this.glossariesSortAscending ? -1 : 1; + } + if (a.project.toLocaleLowerCase() > b.project.toLocaleLowerCase()) { + return this.glossariesSortAscending ? 1 : -1; + } + return 0; + } + if (this.glossariesSortFielD === 'client') { + if (a.client.toLocaleLowerCase() < b.client.toLocaleLowerCase()) { + return this.glossariesSortAscending ? -1 : 1; + } + if (a.client.toLocaleLowerCase() > b.client.toLocaleLowerCase()) { + return this.glossariesSortAscending ? 1 : -1; + } + return 0; + } + if (this.glossariesSortFielD === 'subject') { + if (a.subject.toLocaleLowerCase() < b.subject.toLocaleLowerCase()) { + return this.glossariesSortAscending ? -1 : 1; + } + if (a.subject.toLocaleLowerCase() > b.subject.toLocaleLowerCase()) { + return this.glossariesSortAscending ? 1 : -1; + } + return 0; + } + if (this.glossariesSortFielD === 'created') { + if (a.creationDate < b.creationDate) { + return this.glossariesSortAscending ? -1 : 1; + } + if (a.creationDate > b.creationDate) { + return this.glossariesSortAscending ? 1 : -1; + } + return 0; + } + }); this.tbody.innerHTML = ''; - let length = glossaries.length; + let length = this.glossaries.length; for (let i = 0; i < length; i++) { - let p: Memory = glossaries[i]; + let gloss: Memory = this.glossaries[i]; let checkBox: HTMLInputElement = document.createElement('input'); - checkBox.id = 'ck_' + p.id; + checkBox.id = 'ck_' + gloss.id; checkBox.type = 'checkbox'; let tr: HTMLTableRowElement = document.createElement('tr'); - tr.id = p.id; + tr.id = gloss.id; tr.addEventListener('click', (event: MouseEvent) => { - this.clicked(tr, p, checkBox); + this.clicked(tr, gloss, checkBox); }); this.tbody.appendChild(tr); @@ -223,13 +403,13 @@ class GlossariesView { td = document.createElement('td'); td.classList.add('noWrap'); td.classList.add('middle'); - td.innerText = p.name; + td.innerText = gloss.name; tr.append(td); td = document.createElement('td'); td.classList.add('middle'); td.classList.add('center'); - td.innerText = p.type; + td.innerText = gloss.type; tr.append(td); td = document.createElement('td'); @@ -237,7 +417,7 @@ class GlossariesView { td.classList.add('middle'); td.classList.add('center'); td.style.minWidth = '170px'; - td.innerText = p.project; + td.innerText = gloss.project; tr.append(td); td = document.createElement('td'); @@ -245,7 +425,7 @@ class GlossariesView { td.classList.add('middle'); td.classList.add('center'); td.style.minWidth = '170px'; - td.innerText = p.client; + td.innerText = gloss.client; tr.append(td); td = document.createElement('td'); @@ -253,7 +433,7 @@ class GlossariesView { td.classList.add('middle'); td.classList.add('center'); td.style.minWidth = '170px'; - td.innerText = p.subject; + td.innerText = gloss.subject; tr.append(td); td = document.createElement('td'); @@ -261,7 +441,7 @@ class GlossariesView { td.classList.add('middle'); td.classList.add('center'); td.style.minWidth = '170px'; - td.innerText = p.creationString; + td.innerText = gloss.creationString; tr.append(td); } this.selected.clear(); diff --git a/ts/locations.ts b/ts/locations.ts index cabf1ae..8d5c857 100644 --- a/ts/locations.ts +++ b/ts/locations.ts @@ -38,6 +38,10 @@ export class Locations { this.locations.set(key, new Point((value as any).x, (value as any).y)); } } catch (err: any) { + if (err instanceof Error ) { + console.error(err.message); + return; + } console.log(err); } } diff --git a/ts/memories.ts b/ts/memories.ts index 9e45d9b..133c36c 100644 --- a/ts/memories.ts +++ b/ts/memories.ts @@ -33,6 +33,11 @@ class MemoriesView { tbody: HTMLTableSectionElement; selected: Map; + memories: Memory[] + + memoriesSortFielD: string = 'name'; + memoriesSortAscending: boolean = true; + constructor(div: HTMLDivElement) { this.selected = new Map(); this.container = div; @@ -108,22 +113,136 @@ class MemoriesView { memoriesTable.classList.add('discover'); this.tableContainer.appendChild(memoriesTable); - memoriesTable.innerHTML = - '' + - ' ' + - 'Name' + - 'Type' + - 'Project' + - 'Client' + - 'Subject' + - 'Created' + - ''; + let header: HTMLTableSectionElement = document.createElement('thead'); + memoriesTable.appendChild(header); + + let headerRow: HTMLTableRowElement = document.createElement('tr'); + header.appendChild(headerRow); + + let headerCell: HTMLTableCellElement = document.createElement('th'); + headerCell.innerHTML = ' '; + headerRow.appendChild(headerCell); + + headerCell = document.createElement('th'); + headerCell.classList.add('noWrap'); + headerCell.innerText = 'Name'; + headerCell.id = 'memory-name'; + headerCell.addEventListener('click', () => { + (document.getElementById('memory-' + this.memoriesSortFielD) as HTMLTableCellElement).classList.remove('arrow-down'); + (document.getElementById('memory-' + this.memoriesSortFielD) as HTMLTableCellElement).classList.remove('arrow-up'); + if (this.memoriesSortFielD === 'name') { + this.memoriesSortAscending = !this.memoriesSortAscending; + } else { + this.memoriesSortFielD = 'name'; + this.memoriesSortAscending = true; + } + this.displayMemories(); + }); + headerCell.style.paddingLeft = '4px'; + headerCell.style.paddingRight = '4px'; + headerRow.appendChild(headerCell); + + headerCell = document.createElement('th'); + headerCell.classList.add('noWrap'); + headerCell.innerText = 'Type'; + headerCell.id = 'memory-type'; + headerCell.addEventListener('click', () => { + (document.getElementById('memory-' + this.memoriesSortFielD) as HTMLTableCellElement).classList.remove('arrow-down'); + (document.getElementById('memory-' + this.memoriesSortFielD) as HTMLTableCellElement).classList.remove('arrow-up'); + if (this.memoriesSortFielD === 'type') { + this.memoriesSortAscending = !this.memoriesSortAscending; + } else { + this.memoriesSortFielD = 'type'; + this.memoriesSortAscending = true; + } + this.displayMemories(); + }); + headerCell.style.paddingLeft = '4px'; + headerCell.style.paddingRight = '4px'; + headerRow.appendChild(headerCell); + + headerCell = document.createElement('th'); + headerCell.classList.add('noWrap'); + headerCell.innerText = 'Project'; + headerCell.id = 'memory-project'; + headerCell.addEventListener('click', () => { + (document.getElementById('memory-' + this.memoriesSortFielD) as HTMLTableCellElement).classList.remove('arrow-down'); + (document.getElementById('memory-' + this.memoriesSortFielD) as HTMLTableCellElement).classList.remove('arrow-up'); + if (this.memoriesSortFielD === 'project') { + this.memoriesSortAscending = !this.memoriesSortAscending; + } else { + this.memoriesSortFielD = 'project'; + this.memoriesSortAscending = true; + } + this.displayMemories(); + }); + headerCell.style.paddingLeft = '4px'; + headerCell.style.paddingRight = '4px'; + headerRow.appendChild(headerCell); + + headerCell = document.createElement('th'); + headerCell.classList.add('noWrap'); + headerCell.innerText = 'Client'; + headerCell.id = 'memory-client'; + headerCell.addEventListener('click', () => { + (document.getElementById('memory-' + this.memoriesSortFielD) as HTMLTableCellElement).classList.remove('arrow-down'); + (document.getElementById('memory-' + this.memoriesSortFielD) as HTMLTableCellElement).classList.remove('arrow-up'); + if (this.memoriesSortFielD === 'client') { + this.memoriesSortAscending = !this.memoriesSortAscending; + } else { + this.memoriesSortFielD = 'client'; + this.memoriesSortAscending = true; + } + this.displayMemories(); + }); + headerCell.style.paddingLeft = '4px'; + headerCell.style.paddingRight = '4px'; + headerRow.appendChild(headerCell); + + headerCell = document.createElement('th'); + headerCell.classList.add('noWrap'); + headerCell.innerText = 'Subject'; + headerCell.id = 'memory-subject'; + headerCell.addEventListener('click', () => { + (document.getElementById('memory-' + this.memoriesSortFielD) as HTMLTableCellElement).classList.remove('arrow-down'); + (document.getElementById('memory-' + this.memoriesSortFielD) as HTMLTableCellElement).classList.remove('arrow-up'); + if (this.memoriesSortFielD === 'subject') { + this.memoriesSortAscending = !this.memoriesSortAscending; + } else { + this.memoriesSortFielD = 'subject'; + this.memoriesSortAscending = true; + } + this.displayMemories(); + }); + headerCell.style.paddingLeft = '4px'; + headerCell.style.paddingRight = '4px'; + headerRow.appendChild(headerCell); + + headerCell = document.createElement('th'); + headerCell.classList.add('noWrap'); + headerCell.innerText = 'Created'; + headerCell.id = 'memory-created'; + headerCell.addEventListener('click', () => { + (document.getElementById('memory-' + this.memoriesSortFielD) as HTMLTableCellElement).classList.remove('arrow-down'); + (document.getElementById('memory-' + this.memoriesSortFielD) as HTMLTableCellElement).classList.remove('arrow-up'); + if (this.memoriesSortFielD === 'created') { + this.memoriesSortAscending = !this.memoriesSortAscending; + } else { + this.memoriesSortFielD = 'created'; + this.memoriesSortAscending = true; + } + this.displayMemories(); + }); + headerCell.style.paddingLeft = '4px'; + headerCell.style.paddingRight = '4px'; + headerRow.appendChild(headerCell); this.tbody = document.createElement('tbody'); memoriesTable.appendChild(this.tbody); this.electron.ipcRenderer.on('set-memories', (event: Electron.IpcRendererEvent, arg: any) => { - this.displayMemories(arg); + this.memories = arg; + this.displayMemories(); }); this.loadMemories(); @@ -201,20 +320,81 @@ class MemoriesView { this.electron.ipcRenderer.send('export-memories', memories); } - displayMemories(memories: Memory[]) { + displayMemories() { + if (this.memoriesSortAscending) { + (document.getElementById('memory-' + this.memoriesSortFielD) as HTMLTableCellElement).classList.add('arrow-up'); + } else { + (document.getElementById('memory-' + this.memoriesSortFielD) as HTMLTableCellElement).classList.add('arrow-down'); + } + this.memories.sort((a: Memory, b: Memory) => { + if (this.memoriesSortFielD === 'name') { + if (a.name.toLocaleLowerCase() < b.name.toLocaleLowerCase()) { + return this.memoriesSortAscending ? -1 : 1; + } + if (a.name.toLocaleLowerCase() > b.name.toLocaleLowerCase()) { + return this.memoriesSortAscending ? 1 : -1; + } + return 0; + } + if (this.memoriesSortFielD === 'type') { + if (a.type < b.type) { + return this.memoriesSortAscending ? -1 : 1; + } + if (a.type > b.type) { + return this.memoriesSortAscending ? 1 : -1; + } + return 0; + } + if (this.memoriesSortFielD === 'project') { + if (a.project.toLocaleLowerCase() < b.project.toLocaleLowerCase()) { + return this.memoriesSortAscending ? -1 : 1; + } + if (a.project.toLocaleLowerCase() > b.project.toLocaleLowerCase()) { + return this.memoriesSortAscending ? 1 : -1; + } + return 0; + } + if (this.memoriesSortFielD === 'client') { + if (a.client.toLocaleLowerCase() < b.client.toLocaleLowerCase()) { + return this.memoriesSortAscending ? -1 : 1; + } + if (a.client.toLocaleLowerCase() > b.client.toLocaleLowerCase()) { + return this.memoriesSortAscending ? 1 : -1; + } + return 0; + } + if (this.memoriesSortFielD === 'subject') { + if (a.subject.toLocaleLowerCase() < b.subject.toLocaleLowerCase()) { + return this.memoriesSortAscending ? -1 : 1; + } + if (a.subject.toLocaleLowerCase() > b.subject.toLocaleLowerCase()) { + return this.memoriesSortAscending ? 1 : -1; + } + return 0; + } + if (this.memoriesSortFielD === 'created') { + if (a.creationDate < b.creationDate) { + return this.memoriesSortAscending ? -1 : 1; + } + if (a.creationDate > b.creationDate) { + return this.memoriesSortAscending ? 1 : -1; + } + return 0; + } + }); this.tbody.innerHTML = ''; - let length = memories.length; + let length = this.memories.length; for (let i = 0; i < length; i++) { - let p = memories[i]; + let mem = this.memories[i]; let checkBox: HTMLInputElement = document.createElement('input'); - checkBox.id = 'ck_' + p.id; + checkBox.id = 'ck_' + mem.id; checkBox.type = 'checkbox'; let tr: HTMLTableRowElement = document.createElement('tr'); - tr.id = p.id; + tr.id = mem.id; tr.addEventListener('click', (event: MouseEvent) => { - this.clicked(tr, p, checkBox); + this.clicked(tr, mem, checkBox); }); this.tbody.appendChild(tr); @@ -228,13 +408,13 @@ class MemoriesView { td = document.createElement('td'); td.classList.add('noWrap'); td.classList.add('middle'); - td.innerText = p.name; + td.innerText = mem.name; tr.append(td); td = document.createElement('td'); td.classList.add('middle'); td.classList.add('center'); - td.innerText = p.type; + td.innerText = mem.type; tr.append(td); td = document.createElement('td'); @@ -242,7 +422,7 @@ class MemoriesView { td.classList.add('middle'); td.classList.add('center'); td.style.minWidth = '170px'; - td.innerText = p.project; + td.innerText = mem.project; tr.append(td); td = document.createElement('td'); @@ -250,7 +430,7 @@ class MemoriesView { td.classList.add('middle'); td.classList.add('center'); td.style.minWidth = '170px'; - td.innerText = p.client; + td.innerText = mem.client; tr.append(td); td = document.createElement('td'); @@ -258,7 +438,7 @@ class MemoriesView { td.classList.add('middle'); td.classList.add('center'); td.style.minWidth = '170px'; - td.innerText = p.subject; + td.innerText = mem.subject; tr.append(td); td = document.createElement('td'); @@ -266,7 +446,7 @@ class MemoriesView { td.classList.add('middle'); td.classList.add('center'); td.style.minWidth = '170px'; - td.innerText = p.creationString; + td.innerText = mem.creationString; tr.append(td); } this.selected.clear(); diff --git a/ts/mtManager.ts b/ts/mtManager.ts index 37fd934..29aa867 100644 --- a/ts/mtManager.ts +++ b/ts/mtManager.ts @@ -46,6 +46,7 @@ export class MTManager { tgtLangs: ["azb", "tk", "tl", "de", "ace", "azj", "li", "ti", "lg", "tg", "th", "tum", "bho", "te", "hne", "dz", "la", "ta", "lb", "tw", "lv", "min", "zsm", "ts", "lt", "tt", "tr", "lo", "ln", "tn", "bs", "bug", "dyu", "prs", "cs", "kk", "sk", "ki", "si", "kg", "sg", "sd", "cy", "ca", "sc", "ka", "sa", "da", "ky", "sv", "ast", "zh-TW", "sw", "st", "su", "sr", "ks", "ss", "sq", "kn", "sn", "ko", "so", "be", "ceb", "sl", "km", "sm", "nn", "bjn", "nl", "vi", "ne", "ga", "nb", "gd", "ilo", "khk", "ltg", "zh-CN", "ny", "mni", "uzn", "fj", "fi", "awa", "fo", "fr", "ml", "et", "mk", "uk", "mi", "ba", "cjk", "mg", "ug", "taq", "vec", "mos", "tpi", "ee", "my", "mt", "bg", "ckb", "el", "mr", "ur", "eo", "ms", "en", "es-ES", "mn", "knc", "pt-PT", "hy", "pl", "xh", "id", "ig", "pa", "hi", "hr", "ps", "ht", "hu", "wo", "az", "crh", "als", "ayr", "ha", "oc", "he", "gl", "gn", "or", "kmr", "plt", "gu", "ro", "rn", "kmb", "war", "rw", "ru", "zu", "jv", "af", "dik", "yo", "diq", "ja", "ydd", "is", "it", "kea", "pag", "es-419", "pap", "bm", "bn", "bo", "pbt", "ban", "ak", "tzm", "gaz", "pes", "am", "bem", "ar", "as", "umb", "pt-BR", "quy", "fon", "kas", "kam", "kab", "kac", "fur", "kbp", "fuv", "lij", "lmo", "es", "luo", "lus", "lua", "lvs", "nso", "sat", "mag", "mai", "scn", "shn", "szl", "nus", "zh", "pt"] } }; + currentSegment: any; constructor(preferences: Preferences, srcLang: string, tgtLang: string) { this.mtEngines = []; @@ -89,7 +90,8 @@ export class MTManager { } } - translateProject(project: string, exportedFile: string) { + translateProject(project: string, exportedFile: string, currentSegment: any) { + this.currentSegment = currentSegment; let parser: SAXParser = new SAXParser(); let handler: MTContentHandler = new MTContentHandler(this, project); parser.setContentHandler(handler); @@ -119,14 +121,21 @@ export class MTManager { segment: segment, srcLang: this.srcLang, tgtLang: this.tgtLang, - translations: translations + translations: translations, + currentSegment: this.currentSegment }); + }, (reason: any) => { if (reason instanceof Error) { - console.log(reason.message); + console.error(reason.message); throw reason; } throw new Error(reason); + }).catch((error: any) => { + if (error instanceof Error) { + console.error(error.message); + throw error; + } }); } @@ -148,6 +157,7 @@ export class MTManager { translations.push(value); } params.translations = translations; + params.reload = true; this.setMTMatches(params); Swordfish.mainWindow.webContents.send('end-waiting'); Swordfish.mainWindow.webContents.send('set-status', ''); @@ -158,6 +168,13 @@ export class MTManager { throw reason; } throw new Error(reason); + }).catch((error: any) => { + Swordfish.mainWindow.webContents.send('end-waiting'); + Swordfish.mainWindow.webContents.send('set-status', ''); + if (error instanceof Error) { + throw error; + } + throw new Error(error); }); }, (reason: any) => { Swordfish.mainWindow.webContents.send('end-waiting'); @@ -177,15 +194,14 @@ export class MTManager { "Content-Type": "application/json" }, body: JSON.stringify(params) - }).then((response: Response) => { + }).then(async (response: Response) => { if (response.ok) { - response.json().then((result: any) => { - if (result.status === 'Success') { - resolve(result); - return; - } - reject(result.reason); - }); + let result: any = await response.json(); + if (result.status === 'Success') { + resolve(result); + return; + } + reject(result.reason); } else { throw new Error("Error getting source segment"); } @@ -205,22 +221,26 @@ export class MTManager { "Content-Type": "application/json" }, body: JSON.stringify(params) - }).then((response: Response) => { + }).then(async (response: Response) => { if (response.ok) { - response.json().then((result: any) => { - if (result.status === 'Success') { + let json: any = await response.json(); + if (json.status !== 'Success') { + console.error("Received " + JSON.stringify(json)); + throw new Error(json.reason); + } + if (params.currentSegment) { + let current: any = params.currentSegment; + if (current.file === params.file && current.unit === params.unit && current.id === params.segment) { Swordfish.getMatches({ project: params.project, file: params.file, unit: params.unit, segment: params.segment }); - } else { - throw new Error(result.reason); } - }); + } } else { - throw new Error("Error setting MT matches"); + throw new Error("Error setting MT matches: " + response.statusText); } }).catch((error: any) => { if (error instanceof Error) { diff --git a/ts/projects.ts b/ts/projects.ts index 72f453b..ba30bb8 100644 --- a/ts/projects.ts +++ b/ts/projects.ts @@ -44,6 +44,9 @@ class ProjectsView { projects: Project[]; shouldOpen: string; + projectSortFielD: string = 'created'; + projectSortAscending: boolean = false; + constructor(div: HTMLDivElement) { this.shouldOpen = ''; this.container = div; @@ -151,16 +154,142 @@ class ProjectsView { projectsTable.classList.add('discover'); this.tableContainer.appendChild(projectsTable); - projectsTable.innerHTML = - '' + - ' ' + - 'NameStatus' + - 'Src.Lang.' + - 'Tgt.Lang.' + - 'Created' + - 'Client' + - 'Subject' + - ''; + let tableHeader: HTMLTableSectionElement = document.createElement('thead'); + projectsTable.appendChild(tableHeader); + let headerRow: HTMLTableRowElement = document.createElement('tr'); + tableHeader.appendChild(headerRow); + + let th: HTMLTableCellElement = document.createElement('th'); + th.innerHTML = ' '; + headerRow.appendChild(th); + + th = document.createElement('th'); + th.classList.add('noWrap'); + th.innerHTML = 'Name'; + th.id = 'project-name'; + th.addEventListener('click', () => { + (document.getElementById('project-' + this.projectSortFielD) as HTMLTableCellElement).classList.remove('arrow-down'); + (document.getElementById('project-' + this.projectSortFielD) as HTMLTableCellElement).classList.remove('arrow-up'); + if (this.projectSortFielD === 'name') { + this.projectSortAscending = !this.projectSortAscending; + } else { + this.projectSortFielD = 'name'; + this.projectSortAscending = true; + } + this.displayProjects(); + }); + headerRow.appendChild(th); + + th = document.createElement('th'); + th.classList.add('noWrap'); + th.innerHTML = 'Status'; + th.id = 'project-status'; + th.addEventListener('click', () => { + (document.getElementById('project-' + this.projectSortFielD) as HTMLTableCellElement).classList.remove('arrow-down'); + (document.getElementById('project-' + this.projectSortFielD) as HTMLTableCellElement).classList.remove('arrow-up'); + if (this.projectSortFielD === 'status') { + this.projectSortAscending = !this.projectSortAscending; + } else { + this.projectSortFielD = 'status'; + this.projectSortAscending = true; + } + this.displayProjects(); + }); + headerRow.appendChild(th); + + th = document.createElement('th'); + th.classList.add('noWrap'); + th.innerHTML = 'Src.Lang.'; + th.id = 'project-srcLang'; + th.addEventListener('click', () => { + (document.getElementById('project-' + this.projectSortFielD) as HTMLTableCellElement).classList.remove('arrow-down'); + (document.getElementById('project-' + this.projectSortFielD) as HTMLTableCellElement).classList.remove('arrow-up'); + if (this.projectSortFielD === 'srcLang') { + this.projectSortAscending = !this.projectSortAscending; + } else { + this.projectSortFielD = 'srcLang'; + this.projectSortAscending = true; + } + this.displayProjects(); + }); + th.style.paddingLeft = '4px'; + th.style.paddingRight = '4px'; + headerRow.appendChild(th); + + th = document.createElement('th'); + th.classList.add('noWrap'); + th.innerHTML = 'Tgt.Lang.'; + th.id = 'project-tgtLang'; + th.addEventListener('click', () => { + (document.getElementById('project-' + this.projectSortFielD) as HTMLTableCellElement).classList.remove('arrow-down'); + (document.getElementById('project-' + this.projectSortFielD) as HTMLTableCellElement).classList.remove('arrow-up'); + if (this.projectSortFielD === 'tgtLang') { + this.projectSortAscending = !this.projectSortAscending; + } else { + this.projectSortFielD = 'tgtLang'; + this.projectSortAscending = true; + } + this.displayProjects(); + }); + th.style.paddingLeft = '4px'; + th.style.paddingRight = '4px'; + headerRow.appendChild(th); + + th = document.createElement('th'); + th.classList.add('noWrap'); + th.innerHTML = 'Created'; + th.id = 'project-created'; + th.addEventListener('click', () => { + (document.getElementById('project-' + this.projectSortFielD) as HTMLTableCellElement).classList.remove('arrow-down'); + (document.getElementById('project-' + this.projectSortFielD) as HTMLTableCellElement).classList.remove('arrow-up'); + if (this.projectSortFielD === 'created') { + this.projectSortAscending = !this.projectSortAscending; + } else { + this.projectSortFielD = 'created'; + this.projectSortAscending = true; + } + this.displayProjects(); + }); + th.classList.add('arrow-down'); + th.style.paddingLeft = '4px'; + th.style.paddingRight = '4px'; + headerRow.appendChild(th); + + th = document.createElement('th'); + th.innerHTML = 'Client'; + th.id = 'project-client'; + th.addEventListener('click', () => { + (document.getElementById('project-' + this.projectSortFielD) as HTMLTableCellElement).classList.remove('arrow-down'); + (document.getElementById('project-' + this.projectSortFielD) as HTMLTableCellElement).classList.remove('arrow-up'); + if (this.projectSortFielD === 'client') { + this.projectSortAscending = !this.projectSortAscending; + } else { + this.projectSortFielD = 'client'; + this.projectSortAscending = true; + } + this.displayProjects(); + }); + th.style.paddingLeft = '4px'; + th.style.paddingRight = '4px'; + headerRow.appendChild(th); + + th = document.createElement('th'); + th.innerHTML = 'Subject'; + th.id = 'project-subject'; + th.addEventListener('click', () => { + (document.getElementById('project-' + this.projectSortFielD) as HTMLTableCellElement).classList.remove('arrow-down'); + (document.getElementById('project-' + this.projectSortFielD) as HTMLTableCellElement).classList.remove('arrow-up'); + if (this.projectSortFielD === 'subject') { + this.projectSortAscending = !this.projectSortAscending; + } else { + this.projectSortFielD = 'subject'; + this.projectSortAscending = true; + } + this.displayProjects(); + }); + th.style.paddingLeft = '4px'; + th.style.paddingRight = '4px'; + headerRow.appendChild(th); this.tbody = document.createElement('tbody'); projectsTable.appendChild(this.tbody); @@ -372,6 +501,76 @@ class ProjectsView { } displayProjects() { + if (this.projectSortAscending) { + (document.getElementById('project-' + this.projectSortFielD) as HTMLTableCellElement).classList.add('arrow-up'); + } else { + (document.getElementById('project-' + this.projectSortFielD) as HTMLTableCellElement).classList.add('arrow-down'); + } + this.projects.sort((a: Project, b: Project) => { + if (this.projectSortFielD === 'name') { + if (a.description.toLocaleLowerCase() < b.description.toLocaleLowerCase()) { + return this.projectSortAscending ? -1 : 1; + } + if (a.description.toLocaleLowerCase() > b.description.toLocaleLowerCase()) { + return this.projectSortAscending ? 1 : -1; + } + return 0; + } + if (this.projectSortFielD === 'status') { + if (a.status < b.status) { + return this.projectSortAscending ? -1 : 1; + } + if (a.status > b.status) { + return this.projectSortAscending ? 1 : -1; + } + return 0; + } + if (this.projectSortFielD === 'srcLang') { + if (a.sourceLang < b.sourceLang) { + return this.projectSortAscending ? -1 : 1; + } + if (a.sourceLang > b.sourceLang) { + return this.projectSortAscending ? 1 : -1; + } + return 0; + } + if (this.projectSortFielD === 'tgtLang') { + if (a.targetLang < b.targetLang) { + return this.projectSortAscending ? -1 : 1; + } + if (a.targetLang > b.targetLang) { + return this.projectSortAscending ? 1 : -1; + } + return 0; + } + if (this.projectSortFielD === 'created') { + if (a.creationDate < b.creationDate) { + return this.projectSortAscending ? -1 : 1; + } + if (a.creationDate > b.creationDate) { + return this.projectSortAscending ? 1 : -1; + } + return 0; + } + if (this.projectSortFielD === 'client') { + if (a.client.toLocaleLowerCase() < b.client.toLocaleLowerCase()) { + return this.projectSortAscending ? -1 : 1; + } + if (a.client.toLocaleLowerCase() > b.client.toLocaleLowerCase()) { + return this.projectSortAscending ? 1 : -1; + } + return 0; + } + if (this.projectSortFielD === 'subject') { + if (a.subject.toLocaleLowerCase() < b.subject.toLocaleLowerCase()) { + return this.projectSortAscending ? -1 : 1; + } + if (a.subject.toLocaleLowerCase() > b.subject.toLocaleLowerCase()) { + return this.projectSortAscending ? 1 : -1; + } + return 0; + } + }); this.tbody.innerHTML = ''; let length = this.projects.length; for (let i = 0; i < length; i++) { diff --git a/ts/translation.ts b/ts/translation.ts index fd8e2ec..e267e00 100644 --- a/ts/translation.ts +++ b/ts/translation.ts @@ -113,7 +113,7 @@ class TranslationView { memSelect: HTMLSelectElement; glossSelect: HTMLSelectElement; - returnTo: any = { file: '', unit: '', segment: '' }; + returnTo: SegmentId = { file: '', unit: '', id: '' }; returnNumber: number = -1; notesVisible: boolean = false; @@ -984,7 +984,7 @@ class TranslationView { tr.addEventListener('click', (event: MouseEvent) => this.rowClickListener(event)); this.tbody.appendChild(tr); - if (row.file === this.returnTo.file && row.unit === this.returnTo.unit && row.segment === this.returnTo.segment) { + if (row.file === this.returnTo.file && row.unit === this.returnTo.unit && row.segment === this.returnTo.id) { returnRow = tr; } @@ -1091,15 +1091,15 @@ class TranslationView { this.setColumnWidths(); - let rows: HTMLCollection = this.tbody.rows; + let rows: HTMLCollectionOf = this.tbody.rows; this.currentId = { id: '', file: '', unit: '' }; if (returnRow) { this.selectRow(returnRow); - this.returnTo = { file: '', unit: '', segment: '' }; + this.returnTo = { file: '', unit: '', id: '' }; this.returnNumber = -1; return; } - this.selectRow((rows[0] as HTMLTableRowElement)); + this.selectRow(rows[0]); } static isBiDi(code: string): boolean { @@ -1151,7 +1151,12 @@ class TranslationView { unit: this.currentId.unit, segment: this.currentId.id, srcLang: this.srcLang, - tgtLang: this.tgtLang + tgtLang: this.tgtLang, + currentSegment: { + file: this.currentId.file, + unit: this.currentId.unit, + id: this.currentId.id + } }); } @@ -1381,8 +1386,6 @@ class TranslationView { let file: string = this.currentRow.getAttribute('data-file'); let unit: string = this.currentRow.getAttribute('data-unit'); - let sameRow: boolean = (id === this.currentId.id && file === this.currentId.file && unit === this.currentId.unit); - this.currentId = { id: id, file: file, unit: unit }; let source: HTMLTableCellElement = this.currentRow.getElementsByClassName('source')[0] as HTMLTableCellElement; this.sourceTags = this.getTags(source); @@ -1398,27 +1401,22 @@ class TranslationView { this.currentCell.classList.add('editing'); } - if (!sameRow) { - this.tmMatches.clear(); - this.mtMatches.clear(); - this.termsPanel.clear(); + this.tmMatches.clear(); + this.mtMatches.clear(); + this.termsPanel.clear(); - this.electron.ipcRenderer.send('get-matches', { - project: this.projectId, - file: this.currentId.file, - unit: this.currentId.unit, - segment: this.currentId.id - }); - this.electron.ipcRenderer.send('get-terms', { - project: this.projectId, - file: this.currentId.file, - unit: this.currentId.unit, - segment: this.currentId.id - }); - if (this.notesVisible) { - this.showNotes(); - } + let params: any = { + project: this.projectId, + file: this.currentId.file, + unit: this.currentId.unit, + segment: this.currentId.id + }; + this.electron.ipcRenderer.send('get-matches', params); + this.electron.ipcRenderer.send('get-terms', params); + if (this.notesVisible) { + this.showNotes(); } + this.centerRow(this.currentRow); this.currentCell.focus(); } @@ -1704,7 +1702,7 @@ class TranslationView { this.returnTo = { file: this.currentId.file, unit: this.currentId.unit, - segment: this.currentId.id + id: this.currentId.id } this.electron.ipcRenderer.send('show-apply-tm', { project: this.projectId, memory: this.memSelect.value }); } @@ -1713,7 +1711,7 @@ class TranslationView { this.returnTo = { file: this.currentId.file, unit: this.currentId.unit, - segment: this.currentId.id + id: this.currentId.id } this.electron.ipcRenderer.send('remove-translations', { project: this.projectId }); } @@ -1722,7 +1720,7 @@ class TranslationView { this.returnTo = { file: this.currentId.file, unit: this.currentId.unit, - segment: this.currentId.id + id: this.currentId.id } this.electron.ipcRenderer.send('remove-all-matches', { project: this.projectId }); } @@ -1731,7 +1729,7 @@ class TranslationView { this.returnTo = { file: this.currentId.file, unit: this.currentId.unit, - segment: this.currentId.id + id: this.currentId.id } this.electron.ipcRenderer.send('remove-machine-translations', { project: this.projectId }); } @@ -1740,7 +1738,7 @@ class TranslationView { this.returnTo = { file: this.currentId.file, unit: this.currentId.unit, - segment: this.currentId.id + id: this.currentId.id } this.electron.ipcRenderer.send('unconfirm-translations', { project: this.projectId }); } @@ -1753,7 +1751,7 @@ class TranslationView { this.returnTo = { file: this.currentId.file, unit: this.currentId.unit, - segment: this.currentId.id + id: this.currentId.id } this.electron.ipcRenderer.send('copy-sources', { project: this.projectId }); } @@ -1762,7 +1760,7 @@ class TranslationView { this.returnTo = { file: this.currentId.file, unit: this.currentId.unit, - segment: this.currentId.id + id: this.currentId.id } this.electron.ipcRenderer.send('confirm-translations', { project: this.projectId, memory: this.memSelect.value }); } @@ -1771,7 +1769,7 @@ class TranslationView { this.returnTo = { file: this.currentId.file, unit: this.currentId.unit, - segment: this.currentId.id + id: this.currentId.id } this.electron.ipcRenderer.send('accept-100-matches', { project: this.projectId }); } @@ -1834,9 +1832,15 @@ class TranslationView { this.returnTo = { file: this.currentId.file, unit: this.currentId.unit, - segment: this.currentId.id + id: this.currentId.id } - this.electron.ipcRenderer.send('apply-mt-all', { project: this.projectId, srcLang: this.srcLang, tgtLang: this.tgtLang }); + this.electron.ipcRenderer.send('apply-mt-all', { + project: this.projectId, srcLang: this.srcLang, tgtLang: this.tgtLang, currentSegment: { + file: this.currentId.file, + unit: this.currentId.unit, + id: this.currentId.id + } + }); } assembleMatchesAll(): void { @@ -1851,7 +1855,7 @@ class TranslationView { this.returnTo = { file: this.currentId.file, unit: this.currentId.unit, - segment: this.currentId.id + id: this.currentId.id } this.electron.ipcRenderer.send('assemble-matches-all', { project: this.projectId, @@ -1868,7 +1872,7 @@ class TranslationView { this.returnTo = { file: this.currentId.file, unit: this.currentId.unit, - segment: this.currentId.id + id: this.currentId.id } this.electron.ipcRenderer.send('accept-mt-all', { project: this.projectId }); } @@ -1925,7 +1929,7 @@ class TranslationView { this.returnTo = { file: this.currentId.file, unit: this.currentId.unit, - segment: this.currentId.id + id: this.currentId.id } this.electron.ipcRenderer.send('get-project-terms', { project: this.projectId, glossary: this.glossSelect.value }); } @@ -2178,7 +2182,7 @@ class TranslationView { this.returnTo = { file: this.currentId.file, unit: this.currentId.unit, - segment: this.currentId.id + '-1' + id: this.currentId.id + '-1' } this.electron.ipcRenderer.send('split-at', { project: this.projectId, @@ -2217,7 +2221,7 @@ class TranslationView { this.returnTo = { file: this.currentId.file, unit: this.currentId.unit, - segment: this.currentId.id + id: this.currentId.id } this.electron.ipcRenderer.send('merge-at', { project: this.projectId,