LT_LANGUAGE_CLASSES = new HashMap<>();
+
+ private LanguageManager() {
+ }
+
+ public static void registerLTLanguage(String lang, String fqcn) {
+ LT_LANGUAGE_CLASSES.put(lang, fqcn);
+ }
+
+ /**
+ * Get LanguageTool language.
+ *
+ * This code made side effect to load LT modules eventually.
+ * It loads a specified language-country.
+ * It also loads a variant of countries, such as "en-US" for "en-AU".
+ * And also it loads language code module such as "en".
+ * It is because some language definition depends on another language,
+ * for example, en-AU depends on en-US.
+ * When loading only en-AU language module class, it failed to load
+ * with an error, not-found "en-US".
+ *
+ * @param lang OmegaT language code.
+ * @return LanguageTool's Language object.
+ */
+ public static Language getLTLanguage(org.omegat.util.Language lang) {
+ Language result = null;
+ if (lang == null) {
+ return null;
+ }
+ // search for language-country code.
+ String fqcn = LT_LANGUAGE_CLASSES.get(lang.getLanguage().replace("_", "-"));
+ if (fqcn != null) {
+ result = Languages.getOrAddLanguageByClassName(fqcn);
+ }
+ // Search for language code
+ fqcn = LT_LANGUAGE_CLASSES.get(lang.getLanguageCode());
+ if (fqcn != null) {
+ // when exists, load it.
+ Language language = Languages.getOrAddLanguageByClassName(fqcn);
+ if (result == null) {
+ result = language;
+ }
+ }
+ // Search for just language code match but allow country difference
+ String languageCode;
+ for (Map.Entry entry : LT_LANGUAGE_CLASSES.entrySet()) {
+ if (entry.getKey().contains("-")) {
+ languageCode = entry.getKey().substring(0, entry.getKey().indexOf('-'));
+ } else {
+ languageCode = entry.getKey();
+ }
+ if (languageCode.equals(lang.getLanguageCode())) {
+ // when exists, load it.
+ Language language = Languages.getOrAddLanguageByClassName(entry.getValue());
+ if (result == null) {
+ result = language;
+ }
+ }
+ }
+ return result;
+ }
+
+ static Language getLTLanguage() {
+ if (Core.getProject() == null) {
+ return null;
+ }
+ ProjectProperties prop = Core.getProject().getProjectProperties();
+ if (prop == null) {
+ return null;
+ }
+ org.omegat.util.Language omLang = prop.getTargetLanguage();
+ if (omLang == null) {
+ return null;
+ }
+ Language lang = getLTLanguage(omLang);
+ if (lang == null) {
+ lang = getLTLanguage(new org.omegat.util.Language("en-US"));
+ }
+ return lang;
+ }
+}
diff --git a/src/org/omegat/languagetools/LanguageToolNativeBridge.java b/src/org/omegat/languagetools/LanguageToolNativeBridge.java
index e12892ffb2..770590794a 100644
--- a/src/org/omegat/languagetools/LanguageToolNativeBridge.java
+++ b/src/org/omegat/languagetools/LanguageToolNativeBridge.java
@@ -26,7 +26,6 @@
**************************************************************************/
package org.omegat.languagetools;
-import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
@@ -39,6 +38,7 @@
import org.languagetool.rules.RuleMatch;
import org.languagetool.rules.bitext.BitextRule;
import org.languagetool.tools.Tools;
+
import org.omegat.util.Log;
public class LanguageToolNativeBridge extends BaseLanguageToolBridge {
@@ -135,34 +135,6 @@ List getRuleMatches(String sourceText, String translationText) throws
* getLanguageForLanguageNameOnly
in {@link Languages}.
*/
public static Language getLTLanguage(org.omegat.util.Language lang) {
- List ltLangs = Languages.get();
-
- // Search for full xx-YY match
- String omLang = lang.getLanguageCode();
- String omCountry = lang.getCountryCode();
- for (Language ltLang : ltLangs) {
- if (omLang.equalsIgnoreCase(ltLang.getShortCode())) {
- List countries = Arrays.asList(ltLang.getCountries());
- if (countries.contains(omCountry)) {
- return ltLang;
- }
- }
- }
-
- // Search for just xx match
- for (Language ltLang : ltLangs) {
- if (omLang.equalsIgnoreCase(ltLang.getShortCode()) && ltLang.hasVariant()) {
- Language defaultVariant = ltLang.getDefaultLanguageVariant();
- if (defaultVariant != null) {
- return ltLang;
- }
- }
- }
- for (Language ltLang : ltLangs) {
- if (omLang.equalsIgnoreCase(ltLang.getShortCode()) && !ltLang.hasVariant()) {
- return ltLang;
- }
- }
- return null;
+ return LanguageManager.getLTLanguage(lang);
}
}
diff --git a/src/org/omegat/logger.properties b/src/org/omegat/logger.properties
index 6808566195..cd7ab32c1d 100644
--- a/src/org/omegat/logger.properties
+++ b/src/org/omegat/logger.properties
@@ -8,16 +8,24 @@ org.omegat.level = ALL
java.util.logging.ConsoleHandler.level = ALL
org.omegat.util.logging.OmegaTFileHandler.level = ALL
-org.omegat.util.logging.OmegaTLogFormatter.mask=$mark: $level: $text $key
+org.omegat.util.logging.OmegaTLogFormatter.mask=$time: $level: $text $key
#org.omegat.util.logging.OmegaTLogFormatter.mask=$time: $threadName [$level] $key $text
+#org.omegat.util.logging.OmegaTLogFormatter.mask=$mark: $level: $text $key
-#org.omegat.util.logging.OmegaTLogFormatter.timeFormat=HH:mm:ss,SSSS
+org.omegat.util.logging.OmegaTLogFormatter.timeFormat=HH:mm:ss.SSS
java.util.logging.ConsoleHandler.formatter = org.omegat.util.logging.OmegaTLogFormatter
org.omegat.util.logging.OmegaTFileHandler.formatter = org.omegat.util.logging.OmegaTLogFormatter
+
+# maximum log file size, which triggers rotation
org.omegat.util.logging.OmegaTFileHandler.size=1048576
-org.omegat.util.logging.OmegaTFileHandler.count=10
+
+# retention policy: maximum 30 files
+org.omegat.util.logging.OmegaTFileHandler.count=30
+# retention policy; remove older than specified duration.
+# 20 days * 24 hours * 60 min * 60 sec = 1,020,000 seconds
+org.omegat.util.logging.OmegaTFileHandler.retention=1020000
# precise control of log levels, please change when debug
org.omegat.core.data.level = INFO
diff --git a/src/org/omegat/util/FunctionalAction.java b/src/org/omegat/util/FunctionalAction.java
new file mode 100644
index 0000000000..fb3d175f0c
--- /dev/null
+++ b/src/org/omegat/util/FunctionalAction.java
@@ -0,0 +1,54 @@
+/**************************************************************************
+ OmegaT - Computer Assisted Translation (CAT) tool
+ with fuzzy matching, translation memory, keyword search,
+ glossaries, and translation leveraging into updated projects.
+
+ Copyright (C) 2024 Hiroshi Miura
+ Home page: https://www.omegat.org/
+ Support center: https://omegat.org/support
+
+ This file is part of OmegaT.
+
+ OmegaT is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ OmegaT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+ **************************************************************************/
+
+package org.omegat.util;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.AbstractAction;
+
+public class FunctionalAction extends AbstractAction {
+ private static final long serialVersionUID = 1L;
+
+ ActionListener action;
+
+ public FunctionalAction(ActionListener action) {
+ this.action = action;
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ action.actionPerformed(e);
+ }
+
+ public ActionListener getAction() {
+ return action;
+ }
+
+ public void setAction(ActionListener newAction) {
+ this.action = newAction;
+ }
+}
diff --git a/src/org/omegat/util/Log.java b/src/org/omegat/util/Log.java
index 050f66ff7b..4ae381383a 100644
--- a/src/org/omegat/util/Log.java
+++ b/src/org/omegat/util/Log.java
@@ -34,7 +34,9 @@
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.time.ZonedDateTime;
import java.util.Properties;
+import java.util.concurrent.ThreadLocalRandom;
import java.util.logging.Formatter;
import java.util.logging.Handler;
import java.util.logging.Level;
@@ -56,19 +58,38 @@
*/
public final class Log {
- private static final ILogger LOGGER = LoggerFactory.getLogger(ILogger.ROOT_LOGGER_NAME,
- OStrings.getResourceBundle());
+ private static final ILogger LOGGER;
+
+ // Line mark is day-of-the-year and five-character random number
+ private static final String SESSION_ID;
+ private static final ZonedDateTime SESSION_START_DATETIME;
private Log() {
}
static {
+ SESSION_ID = String.format("%05d", ThreadLocalRandom.current().nextInt(100000));
+ SESSION_START_DATETIME = ZonedDateTime.now();
+ LOGGER = LoggerFactory.getLogger(ILogger.ROOT_LOGGER_NAME,
+ OStrings.getResourceBundle());
+ init();
+ }
+
+ public static String getSessionId() {
+ return SESSION_ID;
+ }
+
+ public static ZonedDateTime getSessionStartDateTime() {
+ return SESSION_START_DATETIME;
+ }
+
+ private static void init() {
boolean loaded = false;
// Ask slf4j-format-jdk14 to append (KEY) to log message.
// When you switch to backend other than slf4j-jdk14(aka. JUL),
// you should set to false. Otherwise, you may get duplicated key
- // in message.
+ // in a message.
System.setProperty(LoggerDecorator.LOCALISATION_KEY_APPENDER, "true");
String customLogConfig = System.getProperty("java.util.logging.config.file");
diff --git a/src/org/omegat/util/Preferences.java b/src/org/omegat/util/Preferences.java
index ff0ef8b3dd..d05e6e98d9 100644
--- a/src/org/omegat/util/Preferences.java
+++ b/src/org/omegat/util/Preferences.java
@@ -187,6 +187,8 @@ public final class Preferences {
public static final String MARK_WHITESPACE = "mark_whitespace";
/** Mark Bidi controls as symbols */
public static final String MARK_BIDI = "mark_bidi";
+ /** Mark alternative translations */
+ public static final String MARK_ALT_TRANSLATIONS = "mark_alt_translations";
/** Do aggressive font fallback */
public static final String FONT_FALLBACK = "font_fallback";
diff --git a/src/org/omegat/util/gui/CustomDockingUISettings.java b/src/org/omegat/util/gui/CustomDockingUISettings.java
new file mode 100644
index 0000000000..1295c8e2eb
--- /dev/null
+++ b/src/org/omegat/util/gui/CustomDockingUISettings.java
@@ -0,0 +1,125 @@
+/**************************************************************************
+ OmegaT - Computer Assisted Translation (CAT) tool
+ with fuzzy matching, translation memory, keyword search,
+ glossaries, and translation leveraging into updated projects.
+
+ Copyright (C) 2024 Hiroshi Miura
+ Home page: https://www.omegat.org/
+ Support center: https://omegat.org/support
+
+ This file is part of OmegaT.
+
+ OmegaT is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ OmegaT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+ **************************************************************************/
+
+package org.omegat.util.gui;
+
+import java.awt.Color;
+import java.awt.Image;
+
+import javax.swing.ImageIcon;
+import javax.swing.UIDefaults;
+import javax.swing.UIManager;
+import javax.swing.plaf.ColorUIResource;
+
+import org.omegat.util.OStrings;
+
+import com.vlsolutions.swing.docking.ui.DockingUISettings;
+
+public class CustomDockingUISettings extends DockingUISettings {
+
+ public CustomDockingUISettings() {
+ super();
+ }
+
+ @Override
+ protected UIDefaults getDefaults(UIDefaults config) {
+ // UI strings
+ config.put("DockViewTitleBar.minimizeButtonText", OStrings.getString("DOCKING_HINT_MINIMIZE"));
+ config.put("DockViewTitleBar.maximizeButtonText", OStrings.getString("DOCKING_HINT_MAXIMIZE"));
+ config.put("DockViewTitleBar.restoreButtonText", OStrings.getString("DOCKING_HINT_RESTORE"));
+ config.put("DockViewTitleBar.attachButtonText", OStrings.getString("DOCKING_HINT_DOCK"));
+ config.put("DockViewTitleBar.floatButtonText", OStrings.getString("DOCKING_HINT_UNDOCK"));
+ config.put("DockViewTitleBar.closeButtonText", "");
+ config.put("DockTabbedPane.minimizeButtonText", OStrings.getString("DOCKING_HINT_MINIMIZE"));
+ config.put("DockTabbedPane.maximizeButtonText", OStrings.getString("DOCKING_HINT_MAXIMIZE"));
+ config.put("DockTabbedPane.restoreButtonText", OStrings.getString("DOCKING_HINT_RESTORE"));
+ config.put("DockTabbedPane.floatButtonText", OStrings.getString("DOCKING_HINT_UNDOCK"));
+ config.put("DockTabbedPane.closeButtonText", "");
+
+ // Fonts
+ config.put("DockViewTitleBar.titleFont", UIManager.getFont("Label.font"));
+
+ config.put("DockViewTitleBar.isCloseButtonDisplayed", false);
+
+ // Disused icons
+ config.put("DockViewTitleBar.menu.close", getIcon("empty.gif"));
+ config.put("DockTabbedPane.close", getIcon("empty.gif"));
+ config.put("DockTabbedPane.close.rollover", getIcon("empty.gif"));
+ config.put("DockTabbedPane.close.pressed", getIcon("empty.gif"));
+ config.put("DockTabbedPane.menu.close", getIcon("empty.gif"));
+
+ // Panel notification (blinking tabs/headers) settings
+ config.put("DockingDesktop.notificationBlinkCount", 2);
+ config.put("DockingDesktop.notificationColor",
+ Styles.EditorColor.COLOR_NOTIFICATION_MAX.getColor());
+
+ // to ensure DockViewTitleBar title readability
+ Color textColor = UIManager.getColor("InternalFrame.inactiveTitleForeground");
+ Color backColor = UIManager.getColor("Panel.background");
+ // One of these could be null
+ if (textColor != null && backColor != null) {
+ if (textColor.equals(backColor)) {
+ float[] hsb = Color.RGBtoHSB(textColor.getRed(), textColor.getGreen(), textColor.getBlue(),
+ null);
+ float brightness = hsb[2]; // darkest 0.0f <--> 1.0f brightest
+ if (brightness >= 0.5f) {
+ brightness -= 0.5f; // to darker
+ } else {
+ brightness += 0.5f; // to brighter
+ }
+ int rgb = Color.HSBtoRGB(hsb[0], hsb[1], brightness);
+ ColorUIResource res = new ColorUIResource(rgb);
+ config.put("InternalFrame.inactiveTitleForeground", res);
+ }
+ }
+
+ config.put("DockingDesktop.notificationBlinkCount", 2);
+ config.put("DockingDesktop.notificationColor",
+ Styles.EditorColor.COLOR_NOTIFICATION_MAX.getColor());
+
+ super.getDefaults(config);
+
+ // Override by null for accelerators to disable
+ // This should be placed after `super.getDefaults` call.
+ config.put("DockingDesktop.closeActionAccelerator", null);
+ config.put("DockingDesktop.maximizeActionAccelerator", null);
+ config.put("DockingDesktop.dockActionAccelerator", null);
+ config.put("DockingDesktop.floatActionAccelerator", null);
+
+ return config;
+ }
+
+ /**
+ * Load icon from classpath.
+ *
+ * @param iconName
+ * icon file name
+ * @return icon instance
+ */
+ private ImageIcon getIcon(String iconName) {
+ Image image = ResourcesUtil.getBundledImage(iconName);
+ return image == null ? null : new ImageIcon(image);
+ }
+}
diff --git a/src/org/omegat/util/gui/MenuExtender.java b/src/org/omegat/util/gui/MenuExtender.java
index 784b729140..3e83b05884 100644
--- a/src/org/omegat/util/gui/MenuExtender.java
+++ b/src/org/omegat/util/gui/MenuExtender.java
@@ -42,7 +42,7 @@ public enum MenuKey {
/**
* Project menu.
*/
- PROJECT("project", 21),
+ PROJECT("project", 18),
/**
* Edit menu.
*/
@@ -54,7 +54,7 @@ public enum MenuKey {
/**
* View menu.
*/
- VIEW("view", 13),
+ VIEW("view", 14),
/**
* Tools menu.
*/
diff --git a/src/org/omegat/util/gui/StaticUIUtils.java b/src/org/omegat/util/gui/StaticUIUtils.java
index df31fca87a..8a382d6f89 100644
--- a/src/org/omegat/util/gui/StaticUIUtils.java
+++ b/src/org/omegat/util/gui/StaticUIUtils.java
@@ -6,6 +6,7 @@
Copyright (C) 2006 Henry Pijffers
2013 Yu Tang
2014-2015 Aaron Madlon-Kay
+ 2024 Hiroshi Miura
Home page: https://www.omegat.org/
Support center: https://omegat.org/support
@@ -36,7 +37,6 @@
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.Window;
-import java.awt.event.ActionEvent;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.FocusAdapter;
@@ -47,12 +47,12 @@
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Predicate;
-import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JComponent;
import javax.swing.JDialog;
@@ -67,7 +67,8 @@
import org.omegat.core.Core;
import org.omegat.gui.main.DockableScrollPane;
-import org.omegat.util.Java8Compat;
+import org.omegat.gui.main.IMainWindow;
+import org.omegat.util.FunctionalAction;
import org.omegat.util.Platform;
import org.omegat.util.Preferences;
import org.omegat.util.StringUtil;
@@ -93,9 +94,10 @@ private StaticUIUtils() {
* {@link JDialog#dispose()} will be called.
*
* @param dialog
+ * to configure.
*/
public static void setEscapeClosable(JDialog dialog) {
- setEscapeAction(dialog.getRootPane(), makeCloseAction(dialog));
+ setEscapeAction(dialog.getRootPane(), new FunctionalAction(e -> closeWindowByEvent(dialog)));
}
/**
@@ -103,19 +105,10 @@ public static void setEscapeClosable(JDialog dialog) {
* will be called.
*
* @param frame
+ * to configure.
*/
public static void setEscapeClosable(JFrame frame) {
- setEscapeAction(frame.getRootPane(), makeCloseAction(frame));
- }
-
- @SuppressWarnings("serial")
- public static Action makeCloseAction(final Window window) {
- return new AbstractAction() {
- @Override
- public void actionPerformed(ActionEvent e) {
- closeWindowByEvent(window);
- }
- };
+ setEscapeAction(frame.getRootPane(), new FunctionalAction(e -> closeWindowByEvent(frame)));
}
/**
@@ -130,7 +123,9 @@ public static void closeWindowByEvent(Window window) {
* Associate a custom action to be called when the Esc key is pressed.
*
* @param dialog
+ * target dialog.
* @param action
+ * object to set.
*/
public static void setEscapeAction(JDialog dialog, Action action) {
setEscapeAction(dialog.getRootPane(), action);
@@ -140,7 +135,9 @@ public static void setEscapeAction(JDialog dialog, Action action) {
* Associate a custom action to be called when the Esc key is pressed.
*
* @param frame
+ * target frame.
* @param action
+ * object to set.
*/
public static void setEscapeAction(JFrame frame, Action action) {
setEscapeAction(frame.getRootPane(), action);
@@ -150,7 +147,9 @@ public static void setEscapeAction(JFrame frame, Action action) {
* Associate a custom action to be called when the Esc key is pressed.
*
* @param pane
+ * target UI pane.
* @param action
+ * object to set.
*/
public static void setEscapeAction(JRootPane pane, Action action) {
// Handle escape key to close the window
@@ -215,8 +214,7 @@ public static String truncateToFit(String text, JComponent comp, int margin) {
}
if (chomp != null) {
- text = text.substring(0, chompStart) + StringUtil.TRUNCATE_CHAR
- + text.substring(chompEnd, text.length());
+ text = text.substring(0, chompStart) + StringUtil.TRUNCATE_CHAR + text.substring(chompEnd);
}
return text;
}
@@ -319,6 +317,14 @@ public static void visitHierarchy(Component parent, Predicate filter,
}
}
+ /**
+ * list hierarchy for debug.
+ *
+ * @param parent
+ * component to determine.
+ * @return list of components.
+ */
+ @SuppressWarnings("unused")
public static List listHierarchy(Component parent) {
List cs = new ArrayList<>();
visitHierarchy(parent, cs::add);
@@ -374,7 +380,7 @@ public void componentResized(ComponentEvent e) {
public static void setWindowIcon(Window window) {
List icons;
if (Platform.isMacOSX()) {
- icons = Arrays.asList(OSXIntegration.APP_ICON_MAC);
+ icons = Collections.singletonList(OSXIntegration.APP_ICON_MAC);
} else {
icons = Arrays.asList(ResourcesUtil.APP_ICON_16X16, ResourcesUtil.APP_ICON_32X32);
}
@@ -431,34 +437,29 @@ public static String getKeyStrokeText(KeyStroke ks) {
return sb.toString();
}
- @SuppressWarnings("serial")
public static void makeUndoable(JTextComponent comp) {
UndoManager manager = new UndoManager();
comp.getDocument().addUndoableEditListener(manager);
// Handle undo (Ctrl/Cmd+Z);
- KeyStroke undo = KeyStroke.getKeyStroke(KeyEvent.VK_Z, Java8Compat.getMenuShortcutKeyMaskEx(), false);
- Action undoAction = new AbstractAction() {
- public void actionPerformed(ActionEvent e) {
- if (manager.canUndo()) {
- manager.undo();
- }
- }
- };
+ KeyStroke undo = KeyStroke.getKeyStroke(KeyEvent.VK_Z,
+ Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx(), false);
comp.getInputMap().put(undo, "UNDO");
- comp.getActionMap().put("UNDO", undoAction);
+ comp.getActionMap().put("UNDO", new FunctionalAction(e -> {
+ if (manager.canUndo()) {
+ manager.undo();
+ }
+ }));
// Handle redo (Ctrl/Cmd+Y);
- KeyStroke redo = KeyStroke.getKeyStroke(KeyEvent.VK_Y, Java8Compat.getMenuShortcutKeyMaskEx(), false);
- Action redoAction = new AbstractAction() {
- public void actionPerformed(ActionEvent e) {
- if (manager.canRedo()) {
- manager.redo();
- }
- }
- };
+ KeyStroke redo = KeyStroke.getKeyStroke(KeyEvent.VK_Y,
+ Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx(), false);
comp.getInputMap().put(redo, "REDO");
- comp.getActionMap().put("REDO", redoAction);
+ comp.getActionMap().put("REDO", new FunctionalAction(e -> {
+ if (manager.canRedo()) {
+ manager.redo();
+ }
+ }));
}
/**
@@ -471,4 +472,12 @@ public static void requestVisible(DockableScrollPane scrollPane) {
desktop.setAutoHide(dockable, false);
}
}
+
+ /**
+ * Whether run on GUI or not.
+ */
+ public static boolean isGUI() {
+ IMainWindow mainWindow = Core.getMainWindow();
+ return mainWindow != null && mainWindow.getApplicationFrame() != null;
+ }
}
diff --git a/src/org/omegat/util/gui/Styles.java b/src/org/omegat/util/gui/Styles.java
index e38c2b8cb2..c7635dbcae 100644
--- a/src/org/omegat/util/gui/Styles.java
+++ b/src/org/omegat/util/gui/Styles.java
@@ -110,7 +110,7 @@ public enum EditorColor {
COLOR_PARAGRAPH_START(UIManager.getColor("OmegaT.paragraphStart")),
- COLOR_MARK_COMES_FROM_TM(UIManager.getColor("OmegaT.markComesFromTm")),
+ COLOR_MARK_COMES_FROM_TM_MT(UIManager.getColor("OmegaT.markComesFromTmMt")),
COLOR_MARK_COMES_FROM_TM_XICE(UIManager.getColor("OmegaT.markComesFromTmXice")),
@@ -120,6 +120,8 @@ public enum EditorColor {
COLOR_MARK_COMES_FROM_TM_XENFORCED(UIManager.getColor("OmegaT.markComesFromTmXenforced")),
+ COLOR_MARK_ALT_TRANSLATION(UIManager.getColor("OmegaT.markAltTranslations")),
+
COLOR_REPLACE(UIManager.getColor("OmegaT.replace")),
COLOR_LANGUAGE_TOOLS(UIManager.getColor("OmegaT.languageTools")),
diff --git a/src/org/omegat/util/gui/UIDesignManager.java b/src/org/omegat/util/gui/UIDesignManager.java
index 281f24d921..14610e641e 100644
--- a/src/org/omegat/util/gui/UIDesignManager.java
+++ b/src/org/omegat/util/gui/UIDesignManager.java
@@ -45,12 +45,10 @@
import javax.swing.LookAndFeel;
import javax.swing.UIDefaults;
import javax.swing.UIManager;
-import javax.swing.plaf.ColorUIResource;
import org.omegat.gui.main.BaseMainWindowMenu;
import org.omegat.gui.preferences.IMenuPreferece;
import org.omegat.util.Log;
-import org.omegat.util.OStrings;
import org.omegat.util.Platform;
import org.omegat.util.Preferences;
import org.omegat.util.StringUtil;
@@ -177,7 +175,7 @@ private static ClassLoader getClassLoader() {
*/
public static void initialize() throws IOException {
// Install VLDocking defaults
- DockingUISettings.getInstance().installUI();
+ DockingUISettings.setInstance(new CustomDockingUISettings());
DockableContainerFactory.setFactory(new CustomContainerFactory());
// Set Look And Feel
@@ -211,71 +209,10 @@ public static void initialize() throws IOException {
// Enable animated popup when mousing over minimized tab
AutoHidePolicy.getPolicy().setExpandMode(ExpandMode.EXPAND_ON_ROLLOVER);
- // UI strings
- UIManager.put("DockViewTitleBar.minimizeButtonText", OStrings.getString("DOCKING_HINT_MINIMIZE"));
- UIManager.put("DockViewTitleBar.maximizeButtonText", OStrings.getString("DOCKING_HINT_MAXIMIZE"));
- UIManager.put("DockViewTitleBar.restoreButtonText", OStrings.getString("DOCKING_HINT_RESTORE"));
- UIManager.put("DockViewTitleBar.attachButtonText", OStrings.getString("DOCKING_HINT_DOCK"));
- UIManager.put("DockViewTitleBar.floatButtonText", OStrings.getString("DOCKING_HINT_UNDOCK"));
- UIManager.put("DockViewTitleBar.closeButtonText", "");
- UIManager.put("DockTabbedPane.minimizeButtonText", OStrings.getString("DOCKING_HINT_MINIMIZE"));
- UIManager.put("DockTabbedPane.maximizeButtonText", OStrings.getString("DOCKING_HINT_MAXIMIZE"));
- UIManager.put("DockTabbedPane.restoreButtonText", OStrings.getString("DOCKING_HINT_RESTORE"));
- UIManager.put("DockTabbedPane.floatButtonText", OStrings.getString("DOCKING_HINT_UNDOCK"));
- UIManager.put("DockTabbedPane.closeButtonText", "");
-
// Fonts
Font defaultFont = UIManager.getFont("Label.font");
- UIManager.put("DockViewTitleBar.titleFont", defaultFont);
UIManager.put("JTabbedPaneSmartIcon.font", defaultFont);
UIManager.put("AutoHideButton.font", defaultFont);
-
- // UI settings
- UIManager.put("DockViewTitleBar.isCloseButtonDisplayed", false);
- UIManager.put("DockingDesktop.closeActionAccelerator", null);
- UIManager.put("DockingDesktop.maximizeActionAccelerator", null);
- UIManager.put("DockingDesktop.dockActionAccelerator", null);
- UIManager.put("DockingDesktop.floatActionAccelerator", null);
-
- // Disused icons
- UIManager.put("DockViewTitleBar.menu.close", getIcon("empty.gif"));
- UIManager.put("DockTabbedPane.close", getIcon("empty.gif"));
- UIManager.put("DockTabbedPane.close.rollover", getIcon("empty.gif"));
- UIManager.put("DockTabbedPane.close.pressed", getIcon("empty.gif"));
- UIManager.put("DockTabbedPane.menu.close", getIcon("empty.gif"));
-
- // Panel notification (blinking tabs/headers) settings
- UIManager.put("DockingDesktop.notificationBlinkCount", 2);
- UIManager.put("DockingDesktop.notificationColor",
- Styles.EditorColor.COLOR_NOTIFICATION_MAX.getColor());
-
- ensureTitlebarReadability();
- }
-
- private static void ensureTitlebarReadability() {
- // to ensure DockViewTitleBar title readability
- Color textColor = UIManager.getColor("InternalFrame.inactiveTitleForeground");
- Color backColor = UIManager.getColor("Panel.background");
- // One of these could be null
- if (textColor != null && backColor != null) {
- if (textColor.equals(backColor)) {
- float[] hsb = Color.RGBtoHSB(textColor.getRed(), textColor.getGreen(), textColor.getBlue(),
- null);
- float brightness = hsb[2]; // darkest 0.0f <--> 1.0f brightest
- if (brightness >= 0.5f) {
- brightness -= 0.5f; // to darker
- } else {
- brightness += 0.5f; // to brighter
- }
- int rgb = Color.HSBtoRGB(hsb[0], hsb[1], brightness);
- ColorUIResource res = new ColorUIResource(rgb);
- UIManager.put("InternalFrame.inactiveTitleForeground", res);
- }
- }
-
- UIManager.put("DockingDesktop.notificationBlinkCount", 2);
- UIManager.put("DockingDesktop.notificationColor",
- Styles.EditorColor.COLOR_NOTIFICATION_MAX.getColor());
}
/**
diff --git a/src/org/omegat/util/logging/OmegaTFileHandler.java b/src/org/omegat/util/logging/OmegaTFileHandler.java
index 4977eb52c6..f145dddb8b 100644
--- a/src/org/omegat/util/logging/OmegaTFileHandler.java
+++ b/src/org/omegat/util/logging/OmegaTFileHandler.java
@@ -5,6 +5,7 @@
Copyright (C) 2008 Alex Buloichik
2013 Didier Briel
+ 2024 Hiroshi Miura
Home page: https://www.omegat.org/
Support center: https://omegat.org/support
@@ -27,20 +28,22 @@
package org.omegat.util.logging;
import java.io.File;
-import java.io.FileFilter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
-import java.text.SimpleDateFormat;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.time.format.DateTimeFormatter;
import java.util.Arrays;
-import java.util.Comparator;
-import java.util.Date;
import java.util.logging.ErrorManager;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.LogRecord;
import java.util.logging.StreamHandler;
+import org.omegat.util.Log;
import org.omegat.util.OStrings;
import org.omegat.util.StaticUtils;
@@ -61,10 +64,12 @@
*/
public class OmegaTFileHandler extends StreamHandler {
private String logFileName;
+ private File logFile;
private File lockFile;
private FileOutputStream lockStream;
private final long maxSize;
private final int count;
+ private final long retention;
public OmegaTFileHandler() throws IOException {
LogManager manager = LogManager.getLogManager();
@@ -86,10 +91,17 @@ public OmegaTFileHandler() throws IOException {
if (countStr != null) {
count = Integer.parseInt(countStr);
} else {
- count = 10;
+ count = 30;
}
- openFiles(new File(StaticUtils.getConfigDir(), "logs"));
+ String retentionStr = manager.getProperty(cname + ".retention");
+ if (retentionStr != null) {
+ retention = Integer.parseInt(retentionStr) * 1000L;
+ } else {
+ retention = 20 * 24 * 60 * 60 * 1000L;
+ }
+
+ openFiles(getLogDirectory());
}
/**
@@ -99,16 +111,27 @@ public String getLogFileName() {
return logFileName + ".log";
}
+ private File getLogDirectory() {
+ return new File(StaticUtils.getConfigDir(), "logs");
+ }
+
/**
* Open log file and lock.
*/
@SuppressWarnings("resource")
private void openFiles(final File dir) throws IOException {
- dir.mkdirs();
+ boolean ignored = dir.mkdirs();
for (int instanceIndex = 0; instanceIndex < 100; instanceIndex++) {
- String fileName = OStrings.getApplicationName()
+ String fileName = String.format("%s_%s_%s%s", OStrings.getApplicationName(),
+ DateTimeFormatter.ofPattern("yyyy-MM-dd_HH-mm").format(Log.getSessionStartDateTime()),
+ Log.getSessionId(),
// Instance index
- + (instanceIndex > 0 ? ("-" + instanceIndex) : "");
+ instanceIndex > 0 ? ("-" + instanceIndex) : "");
+
+ logFile = new File(dir, fileName + ".log");
+ if (logFile.exists()) {
+ continue;
+ }
lockFile = new File(dir, fileName + ".log.lck");
logFileName = fileName;
@@ -116,9 +139,9 @@ private void openFiles(final File dir) throws IOException {
// try to create lock file
lockStream = new FileOutputStream(lockFile);
if (lockStream.getChannel().tryLock() != null) {
- rotate(dir, fileName);
+ cleanOldLogFiles(dir);
setEncoding(StandardCharsets.UTF_8.name());
- setOutputStream(new FileOutputStream(new File(dir, fileName + ".log"), true));
+ setOutputStream(new FileOutputStream(logFile, true));
break;
}
}
@@ -131,48 +154,60 @@ public synchronized void close() throws SecurityException {
super.close();
try {
lockStream.close();
- lockFile.delete();
+ boolean ignored = lockFile.delete();
} catch (Exception ex) {
// shouldn't happen
- ex.printStackTrace();
+ Log.log(ex);
}
}
- /**
- * Rotate log files if need.
- */
- private void rotate(final File dir, final String fileName) {
- File logFile = new File(dir, fileName + ".log");
- if (!logFile.exists() || logFile.length() < maxSize) {
- // do not need to rotate
- return;
+ @Override
+ public synchronized void publish(LogRecord record) {
+ if (isLoggable(record)) {
+ super.publish(record);
+ flush();
}
- String suffix = new SimpleDateFormat("yyyyMMdd.HHmm").format(new Date());
- File destFile = new File(dir, fileName + '.' + suffix + ".log");
- logFile.renameTo(destFile);
- File[] oldLogs = dir.listFiles(new FileFilter() {
- public boolean accept(File pathname) {
- return pathname.getName().startsWith(fileName + '.') && pathname.getName().endsWith(".log");
- }
- });
- if (oldLogs != null) {
- Arrays.sort(oldLogs, new Comparator() {
- public int compare(File o1, File o2) {
- return o2.getName().compareToIgnoreCase(o1.getName());
- }
- });
- for (int i = count; i < oldLogs.length; i++) {
- oldLogs[i].delete();
+ if (logFile.length() > maxSize) {
+ try {
+ close();
+ openFiles(getLogDirectory());
+ } catch (IOException e) {
+ Log.log(e);
}
}
}
- @Override
- public synchronized void publish(LogRecord record) {
- if (isLoggable(record)) {
- super.publish(record);
- flush();
+ private void cleanOldLogFiles(File dir) {
+ if (!dir.exists() || !dir.isDirectory()) {
+ return;
+ }
+
+ File[] files = dir.listFiles((d, name) -> name.startsWith(OStrings.getApplicationName())
+ && name.endsWith(".log"));
+ if (files == null) {
+ return;
+ }
+
+ long cutoffTime = System.currentTimeMillis() - retention;
+
+ Arrays.sort(files, (o1, o2) -> o2.getName().compareToIgnoreCase(o1.getName()));
+
+ for (int i = count; i < files.length; i++) {
+ final File file = files[i];
+ Path filePath = Paths.get(file.getAbsolutePath());
+ try {
+ if (retention <= 0L) {
+ Files.delete(filePath);
+ } else {
+ BasicFileAttributes attrs = Files.readAttributes(filePath, BasicFileAttributes.class);
+ if (attrs.creationTime().toMillis() < cutoffTime) {
+ Files.delete(filePath);
+ }
+ }
+ } catch (IOException e) {
+ Log.log("Failed to delete old log file: " + file.getAbsolutePath());
+ }
}
}
}
diff --git a/src/org/omegat/util/logging/OmegaTLogFormatter.java b/src/org/omegat/util/logging/OmegaTLogFormatter.java
index 222e5573ac..90931479f7 100644
--- a/src/org/omegat/util/logging/OmegaTLogFormatter.java
+++ b/src/org/omegat/util/logging/OmegaTLogFormatter.java
@@ -30,12 +30,12 @@
import java.io.StringWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
-import java.util.concurrent.ThreadLocalRandom;
import java.util.logging.Formatter;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.LogRecord;
+import org.omegat.util.Log;
import org.omegat.util.OStrings;
import org.omegat.util.StringUtil;
@@ -47,17 +47,17 @@
*/
public class OmegaTLogFormatter extends Formatter {
- // Line mark is a five-character random number
- protected static final String LINE_MARK = String.format("%05d", ThreadLocalRandom.current().nextInt(100000));
+ // Line mark is five-character random number
+ protected final String LINE_MARK;
private String logMask;
- private boolean isMaskContainsMark;
- private boolean isMaskContainsThreadName;
- private boolean isMaskContainsLevel;
- private boolean isMaskContainsText;
- private boolean isMaskContainsKey;
- private boolean isMaskContainsLoggerName;
- private boolean isMaskContainsTime;
+ private final boolean isMaskContainsMark;
+ private final boolean isMaskContainsThreadName;
+ private final boolean isMaskContainsLevel;
+ private final boolean isMaskContainsText;
+ private final boolean isMaskContainsKey;
+ private final boolean isMaskContainsLoggerName;
+ private final boolean isMaskContainsTime;
private String defaultTimeFormat = "HH:mm:ss";
@@ -65,7 +65,7 @@ public class OmegaTLogFormatter extends Formatter {
* We have to use ThreadLocal for formatting time because DateFormat is not
* thread safe.
*/
- private ThreadLocal timeFormatter = new ThreadLocal() {
+ private final ThreadLocal timeFormatter = new ThreadLocal() {
@Override
protected SimpleDateFormat initialValue() {
return new SimpleDateFormat(defaultTimeFormat);
@@ -79,6 +79,8 @@ public OmegaTLogFormatter() {
LogManager manager = LogManager.getLogManager();
String cname = getClass().getName();
+ LINE_MARK = Log.getSessionId();
+
logMask = manager.getProperty(cname + ".mask");
if (logMask == null) {
logMask = "$mark: $level: $text $key";
diff --git a/test-acceptance/src/org/omegat/TestMainInitializer.java b/test-acceptance/src/org/omegat/TestMainInitializer.java
index d70ab6746e..7d7ff07fab 100644
--- a/test-acceptance/src/org/omegat/TestMainInitializer.java
+++ b/test-acceptance/src/org/omegat/TestMainInitializer.java
@@ -2,16 +2,15 @@
import javax.swing.UIManager;
+import org.omegat.filters2.master.PluginUtils;
+
public final class TestMainInitializer {
private TestMainInitializer() {
}
public static void initClassloader() {
- ClassLoader cl = ClassLoader.getSystemClassLoader();
- MainClassLoader mainClassLoader = (cl instanceof MainClassLoader) ? (MainClassLoader) cl
- : new MainClassLoader(cl);
- UIManager.put("ClassLoader", mainClassLoader);
+ UIManager.put("ClassLoader", PluginUtils.getThemeClassLoader());
}
}
diff --git a/test-acceptance/src/org/omegat/gui/editor/EditorTextAreaTest.java b/test-acceptance/src/org/omegat/gui/editor/EditorTextAreaTest.java
new file mode 100644
index 0000000000..c9eba5bcb2
--- /dev/null
+++ b/test-acceptance/src/org/omegat/gui/editor/EditorTextAreaTest.java
@@ -0,0 +1,20 @@
+package org.omegat.gui.editor;
+
+import org.junit.Test;
+
+import org.omegat.gui.main.TestCoreGUI;
+import org.omegat.util.OStrings;
+
+public class EditorTextAreaTest extends TestCoreGUI {
+
+ @Test
+ public void testIntroPaneExist() {
+ window.panel(OStrings.getString("DOCKING_FIRST_STEPS_TITLE")).requireEnabled();
+ window.panel(OStrings.getString("DOCKING_FIRST_STEPS_TITLE")).scrollPane("EditorScrollPane").requireEnabled();
+ window.panel(OStrings.getString("DOCKING_FIRST_STEPS_TITLE")).scrollPane("EditorScrollPane")
+ .verticalScrollBar().requireVisible();
+ window.panel(OStrings.getString("DOCKING_FIRST_STEPS_TITLE")).scrollPane("EditorScrollPane")
+ .horizontalScrollBar().requireNotVisible();
+ }
+
+}
diff --git a/test-acceptance/src/org/omegat/gui/main/TestMainWindow.java b/test-acceptance/src/org/omegat/gui/main/TestMainWindow.java
index 8e7f1a6a2d..ca3c4b3558 100644
--- a/test-acceptance/src/org/omegat/gui/main/TestMainWindow.java
+++ b/test-acceptance/src/org/omegat/gui/main/TestMainWindow.java
@@ -196,6 +196,8 @@ public void initializeScreenLayout() {
Rectangle defaultWindowSize = new Rectangle(omegatLeftPosition, 0, omegatWidth, omegatHeight);
applicationFrame.setBounds(defaultWindowSize);
+
+ MainWindowUI.initializeScreenLayout(TestMainWindow.this);
}
@Override
diff --git a/test-acceptance/src/org/omegat/gui/main/TestMainWindowMenuHandler.java b/test-acceptance/src/org/omegat/gui/main/TestMainWindowMenuHandler.java
index 2cbeb9267e..4a8d7a22a2 100644
--- a/test-acceptance/src/org/omegat/gui/main/TestMainWindowMenuHandler.java
+++ b/test-acceptance/src/org/omegat/gui/main/TestMainWindowMenuHandler.java
@@ -35,7 +35,7 @@
import org.omegat.core.data.SourceTextEntry;
import org.omegat.core.data.TMXEntry;
import org.omegat.gui.dialogs.AboutDialog;
-import org.omegat.gui.dialogs.LogDialog;
+import org.omegat.gui.dialogs.LogDialogController;
import org.omegat.gui.editor.EditorUtils;
import org.omegat.gui.editor.SegmentExportImport;
import org.omegat.gui.exttrans.MachineTranslationInfo;
@@ -379,7 +379,7 @@ public void optionsAccessConfigDirMenuItemActionPerformed() {
* Show log
*/
public void helpLogMenuItemActionPerformed() {
- new LogDialog(mainWindow.getApplicationFrame()).setVisible(true);
+ LogDialogController.show(Core.getMainWindow().getApplicationFrame());
}
public void helpAboutMenuItemActionPerformed() {
diff --git a/test-integration/docker/client/Dockerfile b/test-integration/docker/client/Dockerfile
index 015aa11bfa..251ff66f42 100644
--- a/test-integration/docker/client/Dockerfile
+++ b/test-integration/docker/client/Dockerfile
@@ -3,7 +3,7 @@
# with fuzzy matching, translation memory, keyword search,
# glossaries, and translation leveraging into updated projects.
#
-# Copyright (C) 2022,2023 Hiroshi Miura
+# Copyright (C) 2022-2024 Hiroshi Miura
# Home page: https://www.omegat.org/
# Support center: https://omegat.org/support
#
@@ -24,13 +24,13 @@
# **************************************************************************/
#
-FROM debian:bullseye-slim
-ARG CAVER=1.0.2-1
+FROM debian:bookworm-slim
+ARG CAVER=1.0.3-1
ARG JAVA=11
-ARG JDKVER=jdk_11.0.20.1.0+1
-ARG GRADLE=8.4
+ARG JDKVER=jdk_11.0.23.0.0+9
+ARG GRADLE=8.8
RUN apt-get -y update && apt-get upgrade -y && apt-get install -y openssh-client git inotify-tools curl subversion unzip rsync \
- java-common libasound2 libfontconfig1 libfreetype6 libxi6 libxrender1 libxtst6 p11-kit
+ java-common libasound2 libfontconfig1 libfreetype6 libxi6 libxrender1 libxtst6 p11-kit openjdk-17-jdk
RUN adduser --disabled-password --gecos "" --home /home/omegat --shell /bin/bash omegat && mkdir -p /home/omegat/.ssh
RUN chown -R omegat.omegat /home/omegat
COPY --chown=omegat ssh_config /home/omegat/.ssh/config
diff --git a/test-integration/src/org/omegat/core/data/TestTeamIntegration.java b/test-integration/src/org/omegat/core/data/TestTeamIntegration.java
index ba841f2c89..3442695c38 100644
--- a/test-integration/src/org/omegat/core/data/TestTeamIntegration.java
+++ b/test-integration/src/org/omegat/core/data/TestTeamIntegration.java
@@ -29,6 +29,7 @@
import java.io.InputStream;
import java.lang.management.ManagementFactory;
import java.nio.file.Files;
+import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
@@ -409,8 +410,10 @@ static class Run extends Thread {
if (!new File(DIR + "/" + source + "/omegat/").mkdirs()) {
throw new Exception("Impossible to create test dir");
}
+ // Get `java` command path from java.home
+ Path javaBin = Paths.get(System.getProperty("java.home")).resolve("bin/java");
List cmd = new ArrayList<>();
- cmd.add("java");
+ cmd.add(javaBin.toString());
cmd.add("-Duser.name=" + source);
if (logConfig != null) {
cmd.add("-Djava.util.logging.config.file=" + logConfig);
diff --git a/test-integration/src/org/omegat/core/data/TestTeamIntegrationChild.java b/test-integration/src/org/omegat/core/data/TestTeamIntegrationChild.java
index aeada09dd3..603734aff0 100644
--- a/test-integration/src/org/omegat/core/data/TestTeamIntegrationChild.java
+++ b/test-integration/src/org/omegat/core/data/TestTeamIntegrationChild.java
@@ -678,6 +678,10 @@ public DockingDesktop getDesktop() {
return null;
}
+ @Override
+ public void resetDesktopLayout() {
+ }
+
public Cursor getCursor() {
return null;
}
diff --git a/test/data/filters/resourceBundle/file-ResourceBundleFilter-UnicodeEscaped.properties b/test/data/filters/resourceBundle/file-ResourceBundleFilter-UnicodeEscaped.properties
new file mode 100644
index 0000000000..760a9f7285
--- /dev/null
+++ b/test/data/filters/resourceBundle/file-ResourceBundleFilter-UnicodeEscaped.properties
@@ -0,0 +1,2 @@
+#
+Unicode=\u30E6\u30CB\u30B3\u30FC\u30C9
diff --git a/test/data/filters/resourceBundle/file-ResourceBundleFilter-UnicodeUTF8.properties b/test/data/filters/resourceBundle/file-ResourceBundleFilter-UnicodeUTF8.properties
new file mode 100644
index 0000000000..a40ac93d5f
--- /dev/null
+++ b/test/data/filters/resourceBundle/file-ResourceBundleFilter-UnicodeUTF8.properties
@@ -0,0 +1,2 @@
+#
+Unicode=ユニコード
diff --git a/test/data/mark/alternative.tmx b/test/data/mark/alternative.tmx
new file mode 100644
index 0000000000..83be1c7464
--- /dev/null
+++ b/test/data/mark/alternative.tmx
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+ Edit
+
+
+ default
+
+
+
+ file1
+ 1_1
+ prev1
+ next1
+
+ Edit
+
+
+ alternative
+
+
+
+
\ No newline at end of file
diff --git a/test/data/tmx/mt/mt1.tmx b/test/data/tmx/mt/mt1.tmx
new file mode 100644
index 0000000000..cbea88002f
--- /dev/null
+++ b/test/data/tmx/mt/mt1.tmx
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+ source
+
+
+ target
+
+
+
+
diff --git a/test/fixtures/org/omegat/core/TestCore.java b/test/fixtures/org/omegat/core/TestCore.java
index bda24d9a09..ae30b89485 100644
--- a/test/fixtures/org/omegat/core/TestCore.java
+++ b/test/fixtures/org/omegat/core/TestCore.java
@@ -386,6 +386,15 @@ public boolean isMarkBidi() {
public void setMarkBidi(boolean markBidi) {
}
+ @Override
+ public boolean isMarkAltTranslations() {
+ return false;
+ }
+
+ @Override
+ public void setMarkAltTranslations(final boolean markAltTranslations) {
+ }
+
@Override
public boolean isAutoSpellChecking() {
return false;
diff --git a/test/fixtures/org/omegat/core/TestCoreInitializer.java b/test/fixtures/org/omegat/core/TestCoreInitializer.java
index 5af7f61f64..28396a304b 100644
--- a/test/fixtures/org/omegat/core/TestCoreInitializer.java
+++ b/test/fixtures/org/omegat/core/TestCoreInitializer.java
@@ -30,7 +30,6 @@
import org.omegat.gui.glossary.IGlossaries;
import org.omegat.gui.main.ConsoleWindow;
import org.omegat.gui.main.IMainWindow;
-import org.omegat.gui.main.MainWindow;
/**
* Core initializer for unit tests.
@@ -56,11 +55,7 @@ public static void initMainWindow(IMainWindow mainWindow) throws Exception {
if (mainWindow instanceof ConsoleWindow) {
return;
}
-
- // FIXME: IMainWindow on GUI environment should be initialized
- if (mainWindow instanceof MainWindow) {
- Core.initializeGUIimpl((MainWindow) mainWindow);
- }
+ Core.initializeGUIimpl(mainWindow);
}
public static void initGlossary(IGlossaries glossaries) {
diff --git a/test/src/org/omegat/core/statistics/CalcMatchStatisticsTest.java b/test/src/org/omegat/core/statistics/CalcMatchStatisticsTest.java
index 647a5a0479..34c7bfbaf6 100644
--- a/test/src/org/omegat/core/statistics/CalcMatchStatisticsTest.java
+++ b/test/src/org/omegat/core/statistics/CalcMatchStatisticsTest.java
@@ -375,18 +375,24 @@ static class CalcMatchStatisticsMock extends CalcMatchStatistics {
"RowMatch85", "RowMatch75", "RowMatch50", "RowNoMatch", "Total" };
private MatchStatCounts result;
+ private final IStatsConsumer callback;
CalcMatchStatisticsMock(IStatsConsumer callback) {
super(callback, false);
+ this.callback = callback;
}
@Override
public void run() {
entriesToProcess = Core.getProject().getAllEntries().size();
result = calcTotal(false);
+ callback.finishData();
}
public String[][] getTable() {
+ if (result == null) {
+ return null;
+ }
return result.calcTable(rowsTotal, i -> i != 1);
}
}
diff --git a/test/src/org/omegat/filters/ResourceBundleFilterTest.java b/test/src/org/omegat/filters/ResourceBundleFilterTest.java
index f6a16ad779..2d9f14b587 100644
--- a/test/src/org/omegat/filters/ResourceBundleFilterTest.java
+++ b/test/src/org/omegat/filters/ResourceBundleFilterTest.java
@@ -113,6 +113,48 @@ public void testDoNotEscapeUnicodeLiterals() throws Exception {
translateText(filter, f, options);
}
+ /**
+ * Test Unicode case.
+ * @throws Exception when error occurred.
+ */
+ @Test
+ public void testNonEscapeUnicode() throws Exception {
+ String f = "test/data/filters/resourceBundle/file-ResourceBundleFilter-UnicodeUTF8.properties";
+ ResourceBundleFilter filter = new ResourceBundleFilter();
+ context.setOutEncoding("UTF-8");
+ IProject.FileInfo fi = loadSourceFiles(filter, f);
+
+ checkMultiStart(fi, f);
+ checkMulti("\u30E6\u30CB\u30B3\u30FC\u30C9", "Unicode", null, null, null, "#");
+ checkMultiEnd();
+
+ translateText(filter, f);
+ }
+
+ /**
+ * Test Unicode case, when the filter configured not to force escape
+ * and output encoding context is US-ASCII.
+ * Check loaded Unicode literals are in code points out of ASCII,
+ * then check the output file is escaped.
+ * @throws Exception when error occurred.
+ */
+ @Test
+ public void testEscapeUnicodeWhenASCII() throws Exception {
+ String f = "test/data/filters/resourceBundle/file-ResourceBundleFilter-UnicodeEscaped.properties";
+ ResourceBundleFilter filter = new ResourceBundleFilter();
+ context.setOutEncoding("US-ASCII");
+ Map options = new HashMap<>();
+ options.put(ResourceBundleFilter.OPTION_DONT_UNESCAPE_U_LITERALS, "false");
+ options.put(ResourceBundleFilter.OPTION_FORCE_JAVA8_LITERALS_ESCAPE, "false");
+ IProject.FileInfo fi = loadSourceFiles(filter, f, options);
+
+ checkMultiStart(fi, f);
+ checkMulti("\u30E6\u30CB\u30B3\u30FC\u30C9", "Unicode", null, null, null, "#");
+ checkMultiEnd();
+
+ translateText(filter, f, options);
+ }
+
@Test
public void testBadUnicodeLiterals() throws Exception {
String base = "test/data/filters/resourceBundle/";
diff --git a/test/src/org/omegat/filters/TestFilterBase.java b/test/src/org/omegat/filters/TestFilterBase.java
index e2c4df32ef..e8af4a8043 100644
--- a/test/src/org/omegat/filters/TestFilterBase.java
+++ b/test/src/org/omegat/filters/TestFilterBase.java
@@ -50,6 +50,8 @@
import org.junit.Rule;
import org.junit.rules.TestName;
import org.w3c.dom.Document;
+import org.xmlunit.diff.DefaultNodeMatcher;
+import org.xmlunit.diff.ElementSelectors;
import org.omegat.core.Core;
import org.omegat.core.TestCore;
@@ -72,8 +74,6 @@
import org.omegat.tokenizer.DefaultTokenizer;
import org.omegat.util.Language;
import org.omegat.util.TMXReader2;
-import org.xmlunit.diff.DefaultNodeMatcher;
-import org.xmlunit.diff.ElementSelectors;
/**
* Base class for testing filter parsing.
@@ -421,6 +421,11 @@ public static void compareBinary(File f1, File f2) throws Exception {
protected void compareTMX(File f1, File f2) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
+ factory.setValidating(false);
+ factory.setFeature("http://xml.org/sax/features/namespaces", true);
+ factory.setFeature("http://xml.org/sax/features/validation", false);
+ factory.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false);
+ factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
DocumentBuilder builder = factory.newDocumentBuilder();
builder.setEntityResolver(TMXReader2.TMX_DTD_RESOLVER);
@@ -440,6 +445,12 @@ protected void compareXML(File f1, File f2) throws Exception {
protected void compareXML(URL f1, URL f2) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setNamespaceAware(false);
+ factory.setValidating(false);
+ factory.setFeature("http://xml.org/sax/features/namespaces", false);
+ factory.setFeature("http://xml.org/sax/features/validation", false);
+ factory.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false);
+ factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
DocumentBuilder builder = factory.newDocumentBuilder();
var doc1 = builder.parse(f1.toExternalForm());
var doc2 = builder.parse(f2.toExternalForm());
diff --git a/test/src/org/omegat/gui/editor/mark/AltTranslationsMarkerTest.java b/test/src/org/omegat/gui/editor/mark/AltTranslationsMarkerTest.java
new file mode 100644
index 0000000000..730d2bf5d8
--- /dev/null
+++ b/test/src/org/omegat/gui/editor/mark/AltTranslationsMarkerTest.java
@@ -0,0 +1,122 @@
+/**************************************************************************
+ OmegaT - Computer Assisted Translation (CAT) tool
+ with fuzzy matching, translation memory, keyword search,
+ glossaries, and translation leveraging into updated projects.
+
+ Copyright (C) 2024 Lev Abashkin
+ 2024 Hiroshi Miura
+ Home page: https://www.omegat.org/
+ Support center: https://omegat.org/support
+
+ This file is part of OmegaT.
+
+ OmegaT is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ OmegaT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+ **************************************************************************/
+package org.omegat.gui.editor.mark;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.nio.file.Paths;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.omegat.core.Core;
+import org.omegat.core.TestCoreInitializer;
+import org.omegat.core.data.EntryKey;
+import org.omegat.core.data.NotLoadedProject;
+import org.omegat.core.data.ProjectProperties;
+import org.omegat.core.data.ProjectTMX;
+import org.omegat.core.data.SourceTextEntry;
+import org.omegat.core.data.TMXEntry;
+import org.omegat.core.segmentation.SRX;
+import org.omegat.core.segmentation.Segmenter;
+import org.omegat.util.Language;
+
+public class AltTranslationsMarkerTest extends MarkerTestBase {
+
+ private ProjectTMX projectTMX;
+
+ @Before
+ public void preUp() throws Exception {
+ TestCoreInitializer.initEditor(editor);
+ Core.setSegmenter(new Segmenter(SRX.getDefault()));
+ projectTMX = new ProjectTMX(new Language("en"), new Language("fr"), true,
+ Paths.get("test/data/mark/alternative.tmx").toFile(), null);
+ Core.setProject(new NotLoadedProject() {
+ @Override
+ public boolean isProjectLoaded() {
+ return true;
+ }
+
+ @Override
+ public ProjectProperties getProjectProperties() {
+ return new ProjectProperties() {
+ @Override
+ public Language getSourceLanguage() {
+ return new Language("en");
+ }
+
+ @Override
+ public Language getTargetLanguage() {
+ return new Language("fr");
+ }
+ };
+ }
+
+ @Override
+ public TMXEntry getTranslationInfo(SourceTextEntry ste) {
+ if (ste == null || projectTMX == null) {
+ return EMPTY_TRANSLATION;
+ }
+ TMXEntry r = projectTMX.getMultipleTranslation(ste.getKey());
+ if (r == null) {
+ r = projectTMX.getDefaultTranslation(ste.getSrcText());
+ }
+ if (r == null) {
+ r = EMPTY_TRANSLATION;
+ }
+ return r;
+ }
+
+ });
+ }
+
+ @Test
+ public void testAltTranslationsMarker() throws Exception {
+ IMarker marker = new AltTranslationsMarker();
+ Core.getEditor().getSettings().setMarkAltTranslations(true);
+ String sourceText = "Edit";
+ String translationText = "default";
+ // default entry: file and
+ EntryKey key0 = new EntryKey("file0", sourceText, "1_0", "prev0", "next0", "path");
+ SourceTextEntry ste0 = new SourceTextEntry(key0, 1, new String[0], sourceText,
+ Collections.emptyList());
+ List result = marker.getMarksForEntry(ste0, sourceText, translationText, true);
+ assertNull(result);
+ // alternative entry: file and 1_0
+ translationText = "alternative";
+ EntryKey key1 = new EntryKey("file1", sourceText, "1_1", "prev1", "next1", null);
+ SourceTextEntry ste1 = new SourceTextEntry(key1, 1, new String[0], sourceText,
+ Collections.emptyList());
+ result = marker.getMarksForEntry(ste1, sourceText, translationText, true);
+ assertNotNull(result);
+ assertEquals(1, result.size());
+ // TODO: further checks
+ }
+}
diff --git a/test/src/org/omegat/gui/editor/mark/ComesFromMTMarkerTest.java b/test/src/org/omegat/gui/editor/mark/ComesFromMTMarkerTest.java
new file mode 100644
index 0000000000..62b9e286be
--- /dev/null
+++ b/test/src/org/omegat/gui/editor/mark/ComesFromMTMarkerTest.java
@@ -0,0 +1,161 @@
+/*
+ * OmegaT - Computer Assisted Translation (CAT) tool
+ * with fuzzy matching, translation memory, keyword search,
+ * glossaries, and translation leveraging into updated projects.
+ *
+ * Copyright (C) 2024 Hiroshi Miura.
+ * Home page: https://www.omegat.org/
+ * Support center: https://omegat.org/support
+ *
+ * This file is part of OmegaT.
+ *
+ * OmegaT is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OmegaT is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.omegat.gui.editor.mark;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.omegat.core.Core;
+import org.omegat.core.TestCoreInitializer;
+import org.omegat.core.data.DataUtils;
+import org.omegat.core.data.EntryKey;
+import org.omegat.core.data.NotLoadedProject;
+import org.omegat.core.data.ProjectProperties;
+import org.omegat.core.data.ProjectTMX;
+import org.omegat.core.data.SourceTextEntry;
+import org.omegat.core.data.TMXEntry;
+import org.omegat.core.matching.NearString;
+import org.omegat.core.segmentation.SRX;
+import org.omegat.core.segmentation.Segmenter;
+import org.omegat.util.Language;
+
+public class ComesFromMTMarkerTest extends MarkerTestBase {
+
+ private ProjectTMX projectTMX;
+ private Path tmroot;
+ private Path project;
+
+ @Before
+ public void preUp() throws Exception {
+ tmroot = Paths.get("test/data/tmx/");
+ project = tmroot.resolve("mt/mt1.tmx"); // should under 'mt'
+ TestCoreInitializer.initEditor(editor);
+ Core.setSegmenter(new Segmenter(SRX.getDefault()));
+ projectTMX = new ProjectTMX(new Language("en"), new Language("fr"), true,
+ project.toFile(), null);
+ Core.setProject(new NotLoadedProject() {
+ @Override
+ public boolean isProjectLoaded() {
+ return true;
+ }
+
+ @Override
+ public ProjectProperties getProjectProperties() {
+ return new ProjectProperties() {
+ @Override
+ public Language getSourceLanguage() {
+ return new Language("en");
+ }
+
+ @Override
+ public Language getTargetLanguage() {
+ return new Language("fr");
+ }
+
+ @Override
+ public String getTMRoot() {
+ return tmroot.toString();
+ }
+
+ };
+ }
+
+ @Override
+ public TMXEntry getTranslationInfo(SourceTextEntry ste) {
+ if (ste == null || projectTMX == null) {
+ return EMPTY_TRANSLATION;
+ }
+ TMXEntry r = projectTMX.getMultipleTranslation(ste.getKey());
+ if (r == null) {
+ r = projectTMX.getDefaultTranslation(ste.getSrcText());
+ }
+ if (r == null) {
+ r = EMPTY_TRANSLATION;
+ }
+ return r;
+ }
+
+ });
+ }
+
+ @Test
+ public void testMarkersDisabled() throws Exception {
+ IMarker marker = new ComesFromMTMarker();
+ assertThat(marker.getMarksForEntry(null, null, null, true))
+ .describedAs("marker should return null when ste, sourceText and translationText is null")
+ .isNull();
+ }
+
+ @Test
+ public void testMarkersNotActive() throws Exception {
+ IMarker marker = new ComesFromMTMarker();
+ final String sourceText = "source";
+ final String targetText = "target";
+ EntryKey key = new EntryKey("file", sourceText, "id", "prev", "next", "path");
+ SourceTextEntry ste = new SourceTextEntry(key, 1, new String[0], sourceText, Collections.emptyList());
+ assertThat(marker.getMarksForEntry(ste, sourceText, targetText, false))
+ .describedAs("marker should return null when ste is not active")
+ .isNull();
+ }
+
+ @Test
+ public void testMarkersMT() {
+ ComesFromMTMarker marker = new ComesFromMTMarker();
+ final String sourceText = "source";
+ final String targetText = "target";
+ EntryKey key = new EntryKey("file", sourceText, "id", "prev", "next", "path");
+ SourceTextEntry ste = new SourceTextEntry(key, 1, new String[0], sourceText, Collections.emptyList());
+ marker.setMark(ste, targetText);
+ List result = marker.getMarksForEntry(ste, sourceText, targetText, true);
+ assertNotNull(result);
+ assertEquals(1, result.size());
+ assertEquals(0, result.get(0).startOffset);
+ assertEquals(6, result.get(0).endOffset);
+ assertEquals("TRANSLATION", result.get(0).entryPart.toString());
+ }
+
+ @Test
+ public void testNearString() {
+ final String sourceText = "source";
+ final String targetText = "target";
+ final String user = "translator";
+ final int score = 75;
+ final byte[] nearData = null;
+ final long date = 10000L;
+ EntryKey key = new EntryKey("file", sourceText, "id", "prev", "next", "path");
+ NearString near = new NearString(key, sourceText, targetText, NearString.MATCH_SOURCE.TM, false,
+ score, score, score, nearData, project.toString(), user, date, user, date, Collections.emptyList());
+ assertThat(DataUtils.isFromMTMemory(near)).isTrue();
+ }
+}
diff --git a/test/src/org/omegat/gui/editor/mark/MarkerTestBase.java b/test/src/org/omegat/gui/editor/mark/MarkerTestBase.java
index 1282b08a62..cb2509ab0a 100644
--- a/test/src/org/omegat/gui/editor/mark/MarkerTestBase.java
+++ b/test/src/org/omegat/gui/editor/mark/MarkerTestBase.java
@@ -63,6 +63,7 @@ public static class MockEditorSettings implements IEditorSettings {
private boolean markGlossaryMatches;
private boolean markLanguageChecker;
private boolean doFontFallback;
+ private boolean markAlt;
@Override
public boolean isUseTabForAdvance() {
@@ -164,6 +165,16 @@ public void setMarkBidi(boolean markBidi) {
this.markBidi = markBidi;
}
+ @Override
+ public boolean isMarkAltTranslations() {
+ return markAlt;
+ }
+
+ @Override
+ public void setMarkAltTranslations(final boolean markAltTranslations) {
+ markAlt = markAltTranslations;
+ }
+
@Override
public boolean isAutoSpellChecking() {
return autoSpellChecking;
diff --git a/test/src/org/omegat/languagetools/FalseFriendsTest.java b/test/src/org/omegat/languagetools/FalseFriendsTest.java
index 71523f7d65..bf470c53f6 100644
--- a/test/src/org/omegat/languagetools/FalseFriendsTest.java
+++ b/test/src/org/omegat/languagetools/FalseFriendsTest.java
@@ -4,6 +4,7 @@
glossaries, and translation leveraging into updated projects.
Copyright (C) 2010-2013 Alex Buloichik
+ 2024 Hiroshi Miura
Home page: https://www.omegat.org/
Support center: https://omegat.org/support
@@ -32,7 +33,10 @@
import java.util.Map;
import org.junit.Before;
+import org.junit.BeforeClass;
import org.junit.Test;
+import org.languagetool.JLanguageTool;
+
import org.omegat.core.Core;
import org.omegat.core.TestCore;
import org.omegat.core.data.EntryKey;
@@ -54,6 +58,17 @@
* @author Alex Buloichik (alex73mail@gmail.com)
*/
public class FalseFriendsTest extends TestCore {
+
+ @BeforeClass
+ public static void setUpClass() {
+ JLanguageTool.setClassBrokerBroker(new LanguageClassBroker());
+ JLanguageTool.setDataBroker(new LanguageDataBroker());
+ LanguageManager.registerLTLanguage("en", "org.languagetool.language.English");
+ LanguageManager.registerLTLanguage("en-US", "org.languagetool.language.AmericanEnglish");
+ LanguageManager.registerLTLanguage("en-CA", "org.languagetool.language.CanadianEnglish");
+ LanguageManager.registerLTLanguage("pl-PL", "org.languagetool.language.Polish");
+ }
+
@Before
public final void setUp() {
final ProjectProperties props = new ProjectProperties() {
@@ -188,8 +203,8 @@ public void commitSourceFiles() throws Exception {
}
@Override
- public void compileProjectAndCommit(String sourcePattern, boolean doPostProcessing, boolean commitTargetFiles)
- throws Exception {
+ public void compileProjectAndCommit(String sourcePattern, boolean doPostProcessing,
+ boolean commitTargetFiles) throws Exception {
}
});
LanguageToolWrapper.setBridgeFromCurrentProject();
@@ -216,7 +231,8 @@ public boolean isEnabled() {
};
};
- List marks = marker.getMarksForEntry(null, "This is some long text without translation.", "", true);
+ List marks = marker.getMarksForEntry(null, "This is some long text without translation.", "",
+ true);
assertEquals(0, marks.size());
marks = marker.getMarksForEntry(null, "This is text with the same translation.",
diff --git a/test/src/org/omegat/languagetools/LanguageToolTest.java b/test/src/org/omegat/languagetools/LanguageToolTest.java
index 1bff75fb60..212627089e 100644
--- a/test/src/org/omegat/languagetools/LanguageToolTest.java
+++ b/test/src/org/omegat/languagetools/LanguageToolTest.java
@@ -4,6 +4,7 @@
glossaries, and translation leveraging into updated projects.
Copyright (C) 2010-2013 Alex Buloichik
+ 2024 Hiroshi Miura
Home page: https://www.omegat.org/
Support center: https://omegat.org/support
@@ -27,24 +28,26 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
+import java.io.IOException;
+import java.net.ServerSocket;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import org.junit.Before;
+import org.junit.BeforeClass;
import org.junit.Test;
import org.languagetool.JLanguageTool;
-import org.languagetool.language.AmericanEnglish;
-import org.languagetool.language.CanadianEnglish;
-import org.languagetool.language.English;
-import org.languagetool.language.French;
+import org.languagetool.Languages;
import org.languagetool.rules.RuleMatch;
import org.languagetool.rules.patterns.PatternRule;
import org.languagetool.server.HTTPServer;
+import org.languagetool.server.HTTPServerConfig;
import org.omegat.util.Language;
import org.omegat.util.Preferences;
@@ -57,19 +60,29 @@ public class LanguageToolTest {
private static final Language SOURCE_LANG = new Language(Locale.FRENCH);
private static final Language TARGET_LANG = new Language(Locale.ENGLISH);
+ @BeforeClass
+ public static void setUpClass() {
+ JLanguageTool.setClassBrokerBroker(new LanguageClassBroker());
+ JLanguageTool.setDataBroker(new LanguageDataBroker());
+ LanguageManager.registerLTLanguage("en", "org.languagetool.language.English");
+ LanguageManager.registerLTLanguage("en-US", "org.languagetool.language.AmericanEnglish");
+ LanguageManager.registerLTLanguage("en-CA", "org.languagetool.language.CanadianEnglish");
+ LanguageManager.registerLTLanguage("be-BE", "org.languagetool.language.Belarusian");
+ LanguageManager.registerLTLanguage("fr-FR", "org.languagetool.language.French");
+ }
+
@Before
public final void setUp() throws Exception {
TestPreferencesInitializer.init();
}
@Test
- @SuppressWarnings("deprecation")
public void testExecuteLanguageToolCheck() throws Exception {
- JLanguageTool lt = new JLanguageTool(new org.languagetool.language.Belarusian());
+ JLanguageTool lt = new JLanguageTool(Languages.getLanguageForShortCode("be"));
// The test string is Belarusian; originally it was actual UTF-8,
- // but that causes the test to fail when environment encodings aren't set
- // correctly, so we are now using Unicode literals.
+ // but that causes the test to fail when environment encodings aren't
+ // set correctly, so we are now using Unicode literals.
List matches = lt.check("\u0441\u043F\u0440\u0430\u0443\u0434\u0437\u0456\u043C.");
assertEquals(1, matches.size());
assertTrue(matches.get(0).getRule() instanceof PatternRule);
@@ -77,9 +90,10 @@ public void testExecuteLanguageToolCheck() throws Exception {
@Test
public void testFrench() throws Exception {
- JLanguageTool lt = new JLanguageTool(new French());
+ JLanguageTool lt = new JLanguageTool(Languages.getLanguageForShortCode("fr"));
- // example from https://github.com/languagetool-org/languagetool/issues/2852
+ // example from
+ // https://github.com/languagetool-org/languagetool/issues/2852
List matches = lt.check("Il est par cons\u00E9quent perdue.");
assertEquals(1, matches.size());
assertTrue(matches.get(0).getRule() instanceof PatternRule);
@@ -87,29 +101,46 @@ public void testFrench() throws Exception {
@Test
public void testEnglish() throws Exception {
- JLanguageTool lt = new JLanguageTool(new AmericanEnglish());
+ JLanguageTool lt = new JLanguageTool(Languages.getLanguageForLocale(new Locale("en", "US")));
List matches = lt.check("Check test");
assertEquals(0, matches.size());
}
+ private static final int[] FREE_PORT_RANGE = {8081, 10080, 10081, 10082, 10083, 10084, 10085, 10086};
+
+ private int getFreePort() {
+ for (int p : FREE_PORT_RANGE) {
+ try (ServerSocket serverSocket = new ServerSocket(p)) {
+ return serverSocket.getLocalPort();
+ } catch (IOException ignored) {
+ }
+ }
+ return -1;
+ }
+
@Test
public void testRemoteServer() throws Exception {
- HTTPServer server = new HTTPServer();
+ int port = getFreePort();
+ assertNotEquals("Port has been already used.", -1, port);
+ HTTPServerConfig config = new HTTPServerConfig(port);
+ HTTPServer server = new HTTPServer(config);
try {
server.run();
+ String urlBase = "http://localhost:" + port;
+
assertThrows("URL not specifying API actions should fail due to missing argument.",
java.lang.Exception.class,
- () -> new LanguageToolNetworkBridge(SOURCE_LANG, TARGET_LANG, "http://localhost:8081")
- );
+ () -> new LanguageToolNetworkBridge(SOURCE_LANG, TARGET_LANG, urlBase));
ILanguageToolBridge bridge = new LanguageToolNetworkBridge(SOURCE_LANG, TARGET_LANG,
- "http://localhost:8081/v2/check");
+ urlBase + "/v2/check");
- // Set some rules to prevent the server from looking at config files.
- // User config files can specify languages we aren't providing at test
- // runtime, in which case queries will fail.
+ // Set some rules to prevent the server from looking at config
+ // files.
+ // User config files can specify languages we aren't providing at
+ // test runtime, in which case queries will fail.
bridge.applyRuleFilters(Collections.singleton("FOO"), Collections.emptySet(),
Collections.emptySet());
@@ -141,44 +172,31 @@ public void testWrapperInit() throws Exception {
assertTrue(bridge instanceof LanguageToolNativeBridge);
// Bad URL: fall back to local implementation
- Preferences.setPreference(Preferences.LANGUAGETOOL_BRIDGE_TYPE, LanguageToolWrapper.BridgeType.REMOTE_URL);
+ Preferences.setPreference(Preferences.LANGUAGETOOL_BRIDGE_TYPE,
+ LanguageToolWrapper.BridgeType.REMOTE_URL);
Preferences.setPreference(Preferences.LANGUAGETOOL_REMOTE_URL, "blah");
bridge = LanguageToolWrapper.createBridgeFromPrefs(SOURCE_LANG, TARGET_LANG);
assertTrue(bridge instanceof LanguageToolNativeBridge);
}
@Test
- @SuppressWarnings("deprecation")
public void testLanguageMapping() {
- {
- org.languagetool.Language lang = LanguageToolNativeBridge.getLTLanguage(new Language("en-US"));
- assertEquals(AmericanEnglish.class, lang.getClass());
- }
- {
- org.languagetool.Language lang = LanguageToolNativeBridge.getLTLanguage(new Language("en-CA"));
- assertEquals(CanadianEnglish.class, lang.getClass());
- }
- {
- org.languagetool.Language lang = LanguageToolNativeBridge.getLTLanguage(new Language("en"));
- assertEquals(English.class, lang.getClass());
- }
- {
- // Unknown region--fall back to generic class
- org.languagetool.Language lang = LanguageToolNativeBridge.getLTLanguage(new Language("en-JA"));
- assertEquals(English.class, lang.getClass());
- }
- {
- org.languagetool.Language lang = LanguageToolNativeBridge.getLTLanguage(new Language("be-BY"));
- assertEquals(org.languagetool.language.Belarusian.class, lang.getClass());
- }
- {
- // Belarusian is offered in be-BY only; ensure hit with just "be"
- org.languagetool.Language lang = LanguageToolNativeBridge.getLTLanguage(new Language("be"));
- assertEquals(org.languagetool.language.Belarusian.class, lang.getClass());
- }
- {
- org.languagetool.Language lang = LanguageToolNativeBridge.getLTLanguage(new Language("xyz"));
- assertNull(lang);
- }
+ org.languagetool.Language lang;
+ lang = LanguageToolNativeBridge.getLTLanguage(new Language("en-US"));
+ assertEquals(Languages.getLanguageForLocale(new Locale("en", "US")).getClass(), lang.getClass());
+ lang = LanguageToolNativeBridge.getLTLanguage(new Language("en-CA"));
+ assertEquals(Languages.getLanguageForLocale(new Locale("en", "CA")).getClass(), lang.getClass());
+ lang = LanguageToolNativeBridge.getLTLanguage(new Language("en"));
+ assertEquals(Languages.getLanguageForShortCode("en").getClass(), lang.getClass());
+ // Unknown region--fall back to generic class
+ lang = LanguageToolNativeBridge.getLTLanguage(new Language("en-JA"));
+ assertEquals(Languages.getLanguageForShortCode("en").getClass(), lang.getClass());
+ lang = LanguageToolNativeBridge.getLTLanguage(new Language("be-BY"));
+ assertEquals(Languages.getLanguageForShortCode("be").getClass(), lang.getClass());
+ // Belarusian is offered in be-BY only; ensure hit with just "be"
+ lang = LanguageToolNativeBridge.getLTLanguage(new Language("be"));
+ assertEquals(Languages.getLanguageForShortCode("be").getClass(), lang.getClass());
+ lang = LanguageToolNativeBridge.getLTLanguage(new Language("xyz"));
+ assertNull(lang);
}
}
diff --git a/test/src/org/omegat/util/gui/StaticUIUtilsTest.java b/test/src/org/omegat/util/gui/StaticUIUtilsTest.java
index 00ddc12f3c..a372443014 100644
--- a/test/src/org/omegat/util/gui/StaticUIUtilsTest.java
+++ b/test/src/org/omegat/util/gui/StaticUIUtilsTest.java
@@ -26,14 +26,26 @@
package org.omegat.util.gui;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import java.awt.Color;
import java.util.stream.IntStream;
+import org.junit.Before;
import org.junit.Test;
+import org.omegat.core.TestCoreInitializer;
+import org.omegat.gui.main.ConsoleWindow;
+import org.omegat.gui.main.IMainWindow;
+
public class StaticUIUtilsTest {
+ @Before
+ public void setUp() throws Exception {
+ IMainWindow mainWindow = new ConsoleWindow();
+ TestCoreInitializer.initMainWindow(mainWindow);
+ }
+
@Test
public void testGetHighlightColor() {
// Don't make an invalid color even with big or edge-casey adjustment values
@@ -44,4 +56,9 @@ public void testGetHighlightColor() {
assertEquals(new Color(245, 245, 245), StaticUIUtils.getHighlightColor(Color.WHITE, 10));
assertEquals(new Color(245, 245, 245), StaticUIUtils.getHighlightColor(Color.WHITE, -10));
}
+
+ @Test
+ public void testIsGUI() {
+ assertFalse("Run with ConsoleWindow", StaticUIUtils.isGUI());
+ }
}
diff --git a/theme/build.gradle b/theme/build.gradle
index 2657312fda..bbe1d6de77 100644
--- a/theme/build.gradle
+++ b/theme/build.gradle
@@ -4,8 +4,8 @@ plugins {
dependencies {
compileOnly(project.rootProject)
- if (providedLibsDir.directory) {
- compileOnly fileTree(dir: providedLibsDir, include: '**/flatlaf*.jar')
+ if (providedModuleLibsDir.directory) {
+ compileOnly fileTree(dir: providedModuleLibsDir, include: '**/flatlaf*.jar')
} else {
// platform independent dark theme
implementation(libs.flatlaf)
diff --git a/tipoftheday/build.gradle b/tipoftheday/build.gradle
index 92cc07dd1d..b2159b1927 100644
--- a/tipoftheday/build.gradle
+++ b/tipoftheday/build.gradle
@@ -18,16 +18,22 @@ sourceSets {
dependencies {
compileOnly(project.rootProject)
- if (providedLibsDir.directory) {
- compileOnly fileTree(dir: providedLibsDir, includes: ['**/jackson*.jar'])
- implementation fileTree(dir: providedLibsDir, includes: ['**/tipoftheday-*.jar'])
+ if (providedCoreLibsDir.directory) {
+ compileOnly fileTree(dir: providedCoreLibsDir, includes: ['**/commons-lang3-*.jar', '**/jackson*.jar',
+ '**/icu4j-*.jar'])
+ implementation fileTree(dir: providedModuleLibsDir, includes: ['**/tipoftheday-*.jar'])
} else {
// runtime dependencies should be in main project
- implementation(libs.tipoftheday)
+ implementation(libs.tipoftheday) {
+ exclude module: 'commons-lang3'
+ exclude module: 'commons-io'
+ }
+ compileOnly(libs.commons.lang3)
constraints {
implementation(libs.icj4j)
}
- implementation(libs.jackson.yaml)
+ // jackson-databind-yaml is dependency of languagetool-core
+ compileOnly(libs.jackson.yaml)
}
testImplementation(testFixtures(project.rootProject))
testImplementation(libs.commons.io)