Skip to content

Commit

Permalink
[BUGS#1238] fix: check cache before asking engine when visit translat… (
Browse files Browse the repository at this point in the history
#884)

* [BUGS#1238] fix: check cache before asking engine when visit translated segment

Signed-off-by: Hiroshi Miura <[email protected]>

* fix: unused imports

Signed-off-by: Hiroshi Miura <[email protected]>

* docs: developer manual for MT engine connector

Signed-off-by: Hiroshi Miura <[email protected]>

* docs: update developer manual and comment

Signed-off-by: Hiroshi Miura <[email protected]>

* feat: add fake MT connector for test and devel_docs for it

Signed-off-by: Hiroshi Miura <[email protected]>

---------

Signed-off-by: Hiroshi Miura <[email protected]>
  • Loading branch information
miurahr authored Feb 10, 2024
1 parent f59958c commit c0b2a3f
Show file tree
Hide file tree
Showing 7 changed files with 263 additions and 9 deletions.
153 changes: 153 additions & 0 deletions docs_devel/docs/12.HowToMakeMTConnector.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
# How to make Machine Translation connector plugin

## What is MT connector

OmegaT can be extended with plugin. One of the popular categories of plugin is a Machine Translation (MT) connector.
There are many translation web services, thanks to the innovation of AI technologies.
OmegaT bundles some MT connectors that support popular services, such as Google, DeepL and IBM Watson.
There are also genuine and third party plugins for services;

- [Azure translate](https://github.com/omegat-org/azure-translate-plugin/releases)
- [Moses](https://github.com/omegat-org/moses-plugin/releases)
- [Autshumato MT](https://sourceforge.net/projects/autshumatoite/files/OmegaT-plugins-AutshumatoMT/)
- [Mirai translator](https://codeberg.org/miurahr/omegat-mirai/releases)
- [NICT TexTra](https://codeberg.org/miurahr/omegat-textra-plugin/releases)
- [Tencent translation](https://github.com/yoyicue/omegat-tencent-plugin)

## Getting started the project

OmegaT project provides a plugin project skeleton repository. You can start your project from
a skeleton project. Please go to the URL https://github.com/omegat-org/plugin-skeleton and
click "Use this template" button to start your project in GitHub.
When you use codeberg.org forge site, there is also a skeleton at https://codeberg.org/miurahr/omegat-plugin-skeleton

The skeleton project uses Gradle for a build system.
You can select Groovy DSL or Kotlin DSL for the configuration.
When you choose a Groovy DSL, please rename `build.gradle.disabled` to `build.gradle` and remove `build.gradle.kts`.

You should also modify a file
- Project.name in settings.gradle
- Properties: description, title, website and category
- Plugin Main class name in build.gradle(.kts).

Implementation should be placed at
- Source code: src/main/<lang>/*
- Test code: src/test/<lang>/* and src/test/resources/*

## OmegaT MT API

There is a main API that is `org.omegat.gui.exttrans.IMachineTranslation`.
All MT connectors should implement the API.

### `String getTranslation(Language sLang, Language tLang, String text) throws Exception`

It is a main method to override in your plugin project. The method receives a source text, translation from sLang to
tLang language, and return translation text.

### String getCachedTranslation(Language sLang, Language tLang, String text);

It is another method that you should override. If your plugin has a caching mechanism, and there is entry for the text,
return translation without accessing MT engine. Otherwise, return null.

> **_NOTE:_** You should not call the engine in the method, because OmegaT will call it even when the target
> segment has already translated, but configured as `MT only untranslated segment` is on or `automatically translate` is off.
### getName()

Human and machine-readable name of MT engine. OmegaT uses it for the index of results, and as a property value, and
logging purpose.

### `isEnabled()`/`setEnabled(boolean b)`

return and set an enabled status.

### `boolean isConfigurable()` / `void showConfigurationUI(Window parent)`

When the plugin return true for the method, `isConfigurable()` OmegaT will call `showConfigurationUI` when user
clicks a configuration UI button on `Tools > Preferences > MachineTranslation`.

## Convenience abstract class for plugins

There are two convenience class for plugins. You are recommended to use `org.omegat.core.
machinetranslators.BaseCachedTranslate`. It implements many necessary things, and you can concentrate into a logic to
access your MT engine API. There are only three methods you should override.

### `getName()`

Name of the engine as same as `IMachineTranslate`.

### `protected abstract String getPreferenceName()`

A preference key used in a user's configuration file. It will be like a "allow_<ENGINE NAME>_translate".

### `protected abstract String translate(Language sLang, Language tLang, String text) throws Exception`

Main method to return translation from source text.


## Common way to register your plugin

You can register your plugin through a Core method like as follows;

```java
public class ExamplePlugin {
public static void loadPlugins() {
Core.registerMachineTranslationClass(ExamplePlugin.class);
}

public static void unloadPlugins() {
}

public ExamplePlugin() {
// You can initialize internal resources here.
// Because the class will be instantiated in a dynamic way through
// Core.registerMachineTranslationClass API, only a default constructor
// can be used, and unable to expect static initialization of the class.
}
}
```

## Utility functions

You can use several utility functions to implement a feature.

### JSON and XML Parser

OmegaT 6.0 and later bundles Jackson JSON parser. You can use Jackson to create query JSON data and parse a response.
You can check details at Jackson document page; https://github.com/FasterXML/jackson-docs

> **_NOTE:_** There was `org.omegat.util.JsonParser#parse` utility method, but it is deprecated in OmegaT 5.8 and later.
OmegaT 6.1 and later bundles Jackson XML parser. You can use Jackson to create query XML data and parse a response XML.

> **_NOTE:_** `org.omegat.util.xml.XMLReader` is deprecated in OmegaT 6.1 and later
### HttpConnectionUtils

You can use `org.omegat.util.HttpConnectionUtils` to access your MT engine.
You may interested `get`, `post` and `postJSON` methods.

## Writing tests

### Unit test

When you write a connector, you will also want to write unit tests to check a parser of responses from MT engine.
At first, you will need to prepare examples of responses in XML or JSON file, and store it as test data.
It is better to test not only for a response of success case, but also for a response with error or an empty content.

### Connection test

You may want to use WireMock for test for http query and response.
You can learn about usage of the library to see a bundled connector test.

You can see an MT connector source code in the OmegaT project,
`machinetranslators/aperitium/src/test/java/org/omegat/machinetranslators.aperitium/ApertiumTranslateTest`

You can also see a plugin project Azure-translate-plugin to learn how to write a test.
`TestMicrosoftTranslatorAzure.java` implement a case to test http request and response.

## Publish

If you are willing to merge your connector into OmegaT genuine bundles, it is challenging for maintainers to test it
with actual MT engines, because we need to learn a target service, pay costs and conformance to its license.
You are recommended to publish your plugin and share its download link in OmegaT users mail list.
12 changes: 12 additions & 0 deletions docs_devel/docs/35.SpecificFeatureTests.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Test a specific features

Sometimes there are challenging targets to test when want to see the behavior of specific features in OmegaT.
There are several features that require resources, whether connecting to external services, or test data that is not
freely available in categories of machine translation, and dictionary.

## check the behavior of Machine Translation

We have a fake MT connector project in `machinetranslator/dummy` folder.
You can build the fake connector by running `./gradlew machinetranslators:dummy:jar` and copy `dummy.jar` from
`machinetranslator/dummy/build/libs/` to `.omegat/plugins` folder. It always produces a translation text such as
"Translated result from dummy engine.". You can check OmegaT core calls engine or not by looking on the MT pane.
2 changes: 2 additions & 0 deletions docs_devel/docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
* [Setup your plugin project](15.SetupPluginProject.md)
* [Loading Plugins](17.LoadingPlugins.md)
* [Plugin manifest](19.PluginManifest.md)
* [How to make Machine Translation connector plugin](12.HowToMakeMTConnector.md)

## Understanding OmegaT Internals

Expand All @@ -33,6 +34,7 @@

* [Test and coverage](33.TestAndCoverage.md)
* [Integration test](34.IntegrationTest.md)
* [Test a spcific features](35.SpecificFeatureTests.md)

## Documentation

Expand Down
18 changes: 18 additions & 0 deletions machinetranslators/dummy/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
plugins {
id 'java-library'
}

dependencies {
compileOnly(project.rootProject)
}

jar {
manifest {
attributes('License': 'GNU Public License version 3 or later',
'Implementation-Version': '1.0',
'OmegaT-Plugins': 'org.omegat.machinetranslators.dummy.Dummy',
'Plugin-Category': 'machinetranslator',
'Automatic-Module-Name': 'org.omegat.machinetranslators.dummy'
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/

package org.omegat.machinetranslators.dummy;

import org.omegat.core.Core;
import org.omegat.core.machinetranslators.BaseCachedTranslate;
import org.omegat.util.Language;

public class Dummy extends BaseCachedTranslate {

private static final String ENGINE_NAME = "dummy";
private static final String ALLOW_TRANSLATE = "allow_dummy_translate";
private static final String TRANSLATION = "Translated result from dummy engine.";

/**
* Register plugins into OmegaT.
*/
public static void loadPlugins() {
Core.registerMachineTranslationClass(Dummy.class);
}

public static void unloadPlugins() {
}

public Dummy() {
super();
}

@Override
public String getName() {
return ENGINE_NAME;
}

@Override
public String getPreferenceName() {
return ALLOW_TRANSLATE;
}

@Override
protected String translate(Language sLang, Language tLang, String text) {
return TRANSLATION;
}

@Override
public boolean isConfigurable() {
return false;
}
}
1 change: 1 addition & 0 deletions settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ include("machinetranslators:apertium",
"machinetranslators:ibmwatson",
"machinetranslators:mymemory",
"machinetranslators:yandex",
"machinetranslators:dummy",
"aligner",
"theme",
"spellchecker:hunspell-jmyspell",
Expand Down
15 changes: 6 additions & 9 deletions src/org/omegat/gui/exttrans/MachineTranslateTextArea.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@
import org.omegat.core.Core;
import org.omegat.core.data.ProjectProperties;
import org.omegat.core.data.SourceTextEntry;
import org.omegat.core.data.TMXEntry;
import org.omegat.core.machinetranslators.MachineTranslateError;
import org.omegat.core.machinetranslators.MachineTranslators;
import org.omegat.filters2.master.PluginUtils;
Expand Down Expand Up @@ -264,16 +263,14 @@ protected MachineTranslationInfo search() throws Exception {

private String getTranslation(Language source, Language target) {
if (!force) {
if (!Preferences.isPreferenceDefault(Preferences.MT_AUTO_FETCH, true)) {
return translator.getCachedTranslation(source, target, src);
}
if (Preferences.isPreference(Preferences.MT_ONLY_UNTRANSLATED)) {
TMXEntry entry = Core.getProject().getTranslationInfo(currentlyProcessedEntry);
if (entry.isTranslated()) {
return translator.getCachedTranslation(source, target, src);
}
String cached = translator.getCachedTranslation(source, target, src);
if (cached != null || !Preferences.isPreferenceDefault(Preferences.MT_AUTO_FETCH, false)
|| Preferences.isPreference(Preferences.MT_ONLY_UNTRANSLATED)
&& Core.getProject().getTranslationInfo(currentlyProcessedEntry).isTranslated()) {
return cached;
}
}
// Ask MT engine when forced, or visiting an untranslated entry.
try {
return translator.getTranslation(source, target, src);
} catch (MachineTranslateError e) {
Expand Down

0 comments on commit c0b2a3f

Please sign in to comment.