From d54e8103ea72b6027ebff7b02768d40deab739e6 Mon Sep 17 00:00:00 2001
From: Alexander Goussas
Date: Mon, 1 Jun 2026 22:32:19 -0500
Subject: [PATCH] feat: add support for multilang definitions
---
collections/larousse API/Define a word.yml | 5 +++-
collections/larousse API/Translate a word.yml | 5 +++-
.../java/net/frustratedfunctor/core/Lang.java | 28 ++++++++++++++++++
...va => FrenchWordDefinitionRepository.java} | 2 +-
.../LanguageAwareDefinitionsRepository.java | 29 +++++++++++++++++++
.../definitions/WordDefinitionResource.java | 12 ++++----
.../definitions/WordDefinitionService.java | 12 ++++----
.../net/frustratedfunctor/ui/UiResource.java | 7 +++--
.../resources/templates/pub/contributing.html | 3 +-
src/main/resources/templates/pub/index.html | 5 ++++
10 files changed, 88 insertions(+), 20 deletions(-)
create mode 100644 src/main/java/net/frustratedfunctor/core/Lang.java
rename src/main/java/net/frustratedfunctor/definitions/{JsoupWordDefinitionRepository.java => FrenchWordDefinitionRepository.java} (91%)
create mode 100644 src/main/java/net/frustratedfunctor/definitions/LanguageAwareDefinitionsRepository.java
diff --git a/collections/larousse API/Define a word.yml b/collections/larousse API/Define a word.yml
index 96fcef1..905fda1 100644
--- a/collections/larousse API/Define a word.yml
+++ b/collections/larousse API/Define a word.yml
@@ -5,8 +5,11 @@ info:
http:
method: GET
- url: "{{api.base_url}}/words/:word/definition"
+ url: "{{api.base_url}}/words/:word/definition?lang=de"
params:
+ - name: lang
+ value: de
+ type: query
- name: word
value: voiture
type: path
diff --git a/collections/larousse API/Translate a word.yml b/collections/larousse API/Translate a word.yml
index 9f08930..9e31518 100644
--- a/collections/larousse API/Translate a word.yml
+++ b/collections/larousse API/Translate a word.yml
@@ -5,8 +5,11 @@ info:
http:
method: GET
- url: "{{api.base_url}}/words/:word/translation"
+ url: "{{api.base_url}}/words/:word/translation?lang=de"
params:
+ - name: lang
+ value: de
+ type: query
- name: word
value: voiture
type: path
diff --git a/src/main/java/net/frustratedfunctor/core/Lang.java b/src/main/java/net/frustratedfunctor/core/Lang.java
new file mode 100644
index 0000000..a58a4ae
--- /dev/null
+++ b/src/main/java/net/frustratedfunctor/core/Lang.java
@@ -0,0 +1,28 @@
+package net.frustratedfunctor.core;
+
+import java.util.Optional;
+
+public enum Lang {
+ French("fr"),
+ German("de");
+
+ public final String code;
+
+ public final static Lang DEFAULT = French;
+
+ Lang(String code) {
+ this.code = code;
+ }
+
+ public static Optional parse(String s) {
+ return Optional.ofNullable(switch (s.toLowerCase()) {
+ case "fr" -> Lang.French;
+ case "de" -> Lang.German;
+ default -> null;
+ });
+ }
+
+ public static Lang parseOrDefault(String s) {
+ return parse(s).orElse(DEFAULT);
+ }
+}
diff --git a/src/main/java/net/frustratedfunctor/definitions/JsoupWordDefinitionRepository.java b/src/main/java/net/frustratedfunctor/definitions/FrenchWordDefinitionRepository.java
similarity index 91%
rename from src/main/java/net/frustratedfunctor/definitions/JsoupWordDefinitionRepository.java
rename to src/main/java/net/frustratedfunctor/definitions/FrenchWordDefinitionRepository.java
index 96e7d78..0b26252 100644
--- a/src/main/java/net/frustratedfunctor/definitions/JsoupWordDefinitionRepository.java
+++ b/src/main/java/net/frustratedfunctor/definitions/FrenchWordDefinitionRepository.java
@@ -10,7 +10,7 @@ import java.util.ArrayList;
import java.util.List;
@ApplicationScoped
-public class JsoupWordDefinitionRepository implements WordDefinitionRepository {
+public class FrenchWordDefinitionRepository implements WordDefinitionRepository {
@Override
public List definitionsForWord(String word) {
try {
diff --git a/src/main/java/net/frustratedfunctor/definitions/LanguageAwareDefinitionsRepository.java b/src/main/java/net/frustratedfunctor/definitions/LanguageAwareDefinitionsRepository.java
new file mode 100644
index 0000000..fd43308
--- /dev/null
+++ b/src/main/java/net/frustratedfunctor/definitions/LanguageAwareDefinitionsRepository.java
@@ -0,0 +1,29 @@
+package net.frustratedfunctor.definitions;
+
+import jakarta.annotation.Priority;
+import jakarta.enterprise.context.ApplicationScoped;
+import net.frustratedfunctor.core.Lang;
+
+import java.util.List;
+
+@Priority(1)
+@ApplicationScoped
+public class LanguageAwareDefinitionsRepository implements WordDefinitionRepository {
+ private final FrenchWordDefinitionRepository french;
+
+ public LanguageAwareDefinitionsRepository(FrenchWordDefinitionRepository french) {
+ this.french = french;
+ }
+
+ @Override
+ public List definitionsForWord(String word) {
+ return french.definitionsForWord(word);
+ }
+
+ public List definitionsForWord(String word, String lang) {
+ return switch (Lang.parseOrDefault(lang)) {
+ case French -> french.definitionsForWord(word);
+ case German -> List.of("OOPS! NOT IMPLEMENTED");
+ };
+ }
+}
diff --git a/src/main/java/net/frustratedfunctor/definitions/WordDefinitionResource.java b/src/main/java/net/frustratedfunctor/definitions/WordDefinitionResource.java
index 6f3b78d..7e9e9b1 100644
--- a/src/main/java/net/frustratedfunctor/definitions/WordDefinitionResource.java
+++ b/src/main/java/net/frustratedfunctor/definitions/WordDefinitionResource.java
@@ -1,9 +1,6 @@
package net.frustratedfunctor.definitions;
-import jakarta.ws.rs.GET;
-import jakarta.ws.rs.Path;
-import jakarta.ws.rs.PathParam;
-import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
@Path("/words")
@@ -18,8 +15,11 @@ public class WordDefinitionResource {
@Path("/{word}/definition")
@GET
@Produces(MediaType.APPLICATION_JSON)
- public WordDefinition definition(@PathParam("word") String word) {
- return definitions.define(word);
+ public WordDefinition definition(
+ @PathParam("word") String word,
+ @QueryParam("lang") String lang
+ ) {
+ return definitions.define(word, lang);
}
}
diff --git a/src/main/java/net/frustratedfunctor/definitions/WordDefinitionService.java b/src/main/java/net/frustratedfunctor/definitions/WordDefinitionService.java
index 44696e2..564aafa 100644
--- a/src/main/java/net/frustratedfunctor/definitions/WordDefinitionService.java
+++ b/src/main/java/net/frustratedfunctor/definitions/WordDefinitionService.java
@@ -5,17 +5,15 @@ import jakarta.enterprise.context.ApplicationScoped;
@ApplicationScoped
public class WordDefinitionService {
- private final WordDefinitionRepository definitions;
+ private final LanguageAwareDefinitionsRepository definitions;
- public WordDefinitionService(WordDefinitionRepository definitions) {
+ public WordDefinitionService(LanguageAwareDefinitionsRepository definitions) {
this.definitions = definitions;
}
- public WordDefinition define(String word) {
- return new WordDefinition(
- word,
- definitions.definitionsForWord(word)
- );
+ public WordDefinition define(String word, String lang) {
+ final var defs = definitions.definitionsForWord(word, lang);
+ return new WordDefinition(word, defs);
}
}
diff --git a/src/main/java/net/frustratedfunctor/ui/UiResource.java b/src/main/java/net/frustratedfunctor/ui/UiResource.java
index 0fe5dc2..00e688d 100644
--- a/src/main/java/net/frustratedfunctor/ui/UiResource.java
+++ b/src/main/java/net/frustratedfunctor/ui/UiResource.java
@@ -28,10 +28,13 @@ public class UiResource {
@Path("getTranslationsDefinitions")
@POST
@Produces(MediaType.TEXT_HTML)
- public TemplateInstance getTranslationsDefinitions(@FormParam("word") String word) {
+ public TemplateInstance getTranslationsDefinitions(
+ @FormParam("word") String word,
+ @FormParam("lang") String lang
+ ) {
final var data = new WordTranslationsDefinitions(
translations.translate(word).translations(),
- definitions.define(word).definitions()
+ definitions.define(word, lang).definitions()
);
return index.data("translationsDefinitions", data);
}
diff --git a/src/main/resources/templates/pub/contributing.html b/src/main/resources/templates/pub/contributing.html
index 78b98b3..80d1079 100644
--- a/src/main/resources/templates/pub/contributing.html
+++ b/src/main/resources/templates/pub/contributing.html
@@ -56,8 +56,7 @@
You can send me a patch implementing support for your language. Take a look at the codebase.
I think everything is pretty self-explanatory. You should create a new implementation of the
- WordDefinitionRepository and WordTranslationRepository interfaces and add it to the
- corresponding composite classes.
+ WordDefinitionRepository and WordTranslationRepository interfaces.
The patches should be sent over email with the subject [larousseapi] PATCH: description
diff --git a/src/main/resources/templates/pub/index.html b/src/main/resources/templates/pub/index.html
index 34bcd6f..69ad8cb 100644
--- a/src/main/resources/templates/pub/index.html
+++ b/src/main/resources/templates/pub/index.html
@@ -54,6 +54,11 @@