Repository: abhi-kr-2100/Lingetic
Pull request #278: Add JapaneseModifiedHepburn language to the backend
Author: login: abhi-kr-2100
Created: 2025-05-08T15:13:32Z | Merged: 2025-05-08T17:44:39Z


    
<!-- This is an auto-generated description by mrge. -->

## Summary by mrge
Added support for the JapaneseModifiedHepburn language to the backend, including language model, database migration, and tests.

- **New Features**
  - Implemented JapaneseModifiedHepburnLanguageModel with macron support.
  - Added database entry and unit tests for the new language.

<!-- End of auto-generated description by mrge. -->



<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **New Features**
  - Added support for Japanese Modified Hepburn romanization as a new language option.
  - Included new example prompts and question templates using Japanese Modified Hepburn romanization.
- **Bug Fixes**
  - Enhanced recognition of accented Latin characters (ā, ī, ū, ē, ō) for improved text processing.
- **Tests**
  - Added comprehensive tests validating tokenization and equivalence of Japanese Modified Hepburn romanized text.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->


Diff:
diff --git a/lingetic-nextjs-frontend/app/languages/constants.ts b/lingetic-nextjs-frontend/app/languages/constants.ts
index bcfcd0a4..13b6f6bc 100644
--- a/lingetic-nextjs-frontend/app/languages/constants.ts
+++ b/lingetic-nextjs-frontend/app/languages/constants.ts
@@ -48,9 +48,15 @@ export const languages: LanguageProperty[] = [
     image: "/img/languages/portuguese-flag.png",
     isSupported: false,
   },
+  {
+    id: "JapaneseModifiedHepburn",
+    name: "Japanese 1",
+    image: "/img/languages/japanese-flag.png",
+    isSupported: true,
+  },
   {
     id: "Japanese",
-    name: "Japanese",
+    name: "Japanese 2",
     image: "/img/languages/japanese-flag.png",
     isSupported: true,
   },
@@ -95,6 +101,7 @@ export const languageNameToCode: Record<string, string> = {
   Italian: "it",
   Portuguese: "pt",
   Japanese: "ja",
+  JapaneseModifiedHepburn: "ja-hepburn",
   Korean: "ko",
   Chinese: "zh",
   Russian: "ru",
diff --git a/lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/Language.java b/lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/Language.java
index 34827e6f..d57529e2 100644
--- a/lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/Language.java
+++ b/lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/Language.java
@@ -7,4 +7,5 @@ public enum Language {
     Turkish,
     Swedish,
     Japanese,
+    JapaneseModifiedHepburn,
 }
diff --git a/lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/JapaneseModifiedHepburnLanguageModel.java b/lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/JapaneseModifiedHepburnLanguageModel.java
new file mode 100644
index 00000000..4d794aa3
--- /dev/null
+++ b/lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/JapaneseModifiedHepburnLanguageModel.java
@@ -0,0 +1,26 @@
+package com.munetmo.lingetic.LanguageService.Entities.LanguageModels;
+
+import com.munetmo.lingetic.LanguageService.Entities.Language;
+import com.munetmo.lingetic.LanguageService.Entities.Token;
+
+import java.util.List;
+import java.util.Locale;
+
+public final class JapaneseModifiedHepburnLanguageModel implements LanguageModel {
+    private static final LatinScriptLanguageModelHelper helper = new LatinScriptLanguageModelHelper(Locale.JAPAN);
+
+    @Override
+    public Language getLanguage() {
+        return Language.JapaneseModifiedHepburn;
+    }
+
+    @Override
+    public boolean areEquivalent(String s1, String s2) {
+        return helper.areEquivalent(s1, s2);
+    }
+
+    @Override
+    public List<Token> tokenize(String input) {
+        return helper.tokenize(input);
+    }
+}
diff --git a/lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/LanguageModel.java b/lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/LanguageModel.java
index 856376d2..6a6e2fbd 100644
--- a/lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/LanguageModel.java
+++ b/lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/LanguageModel.java
@@ -6,7 +6,8 @@
 import java.util.List;
 import java.util.Map;
 
-public sealed interface LanguageModel permits EnglishLanguageModel, FrenchLanguageModel, TurkishLanguageModel, SwedishLanguageModel, JapaneseLanguageModel {
+public sealed interface LanguageModel permits EnglishLanguageModel, FrenchLanguageModel, TurkishLanguageModel,
+        SwedishLanguageModel, JapaneseLanguageModel, JapaneseModifiedHepburnLanguageModel {
     Language getLanguage();
 
     boolean areEquivalent(String s1, String s2);
@@ -18,7 +19,8 @@ Language.English, new EnglishLanguageModel(),
             Language.French, new FrenchLanguageModel(),
             Language.Turkish, new TurkishLanguageModel(),
             Language.Swedish, new SwedishLanguageModel(),
-            Language.Japanese, new JapaneseLanguageModel()
+            Language.Japanese, new JapaneseLanguageModel(),
+            Language.JapaneseModifiedHepburn, new JapaneseModifiedHepburnLanguageModel()
     );
 
     static LanguageModel getLanguageModel(Language language) {
diff --git a/lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/LatinScriptLanguageModelHelper.java b/lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/LatinScriptLanguageModelHelper.java
index 28cba017..fba9ac86 100644
--- a/lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/LatinScriptLanguageModelHelper.java
+++ b/lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/LatinScriptLanguageModelHelper.java
@@ -12,7 +12,7 @@
 
 public final class LatinScriptLanguageModelHelper {
     private static final String TERMINAL_PUNCTUATION = ".?!;,:-";
-    private static final String SPECIFIC_CHARACTERS = "àâäæçéèêëîïôœùûüÿçğıöşüåäö";
+    private static final String SPECIFIC_CHARACTERS = "àâäæçéèêëîïôœùûüÿçğıöşüåäöāīūēō";
     private static final String SURROUNDING_PUNCTUATION = "'\"«»";
 
     private static final Pattern LEADING_PUNCTUATION_PATTERN = Pattern.compile(
diff --git a/lingetic-spring-backend/src/main/resources/META-INF/native-image/com.munetmo/lingetic/reachability-metadata.json b/lingetic-spring-backend/src/main/resources/META-INF/native-image/com.munetmo/lingetic/reachability-metadata.json
index 267ee94e..c4fe1d69 100644
--- a/lingetic-spring-backend/src/main/resources/META-INF/native-image/com.munetmo/lingetic/reachability-metadata.json
+++ b/lingetic-spring-backend/src/main/resources/META-INF/native-image/com.munetmo/lingetic/reachability-metadata.json
@@ -8410,6 +8410,9 @@
     {
       "glob": "db/migration/V6__Add_Japanese_Language.sql"
     },
+    {
+      "glob": "db/migration/V7__Add_Japanese_Modified_Hepburn_Language.sql"
+    },
     {
       "glob": "dictionaries/system_full.dic"
     },
diff --git a/lingetic-spring-backend/src/main/resources/db/migration/V7__Add_Japanese_Modified_Hepburn_Language.sql b/lingetic-spring-backend/src/main/resources/db/migration/V7__Add_Japanese_Modified_Hepburn_Language.sql
new file mode 100644
index 00000000..31d4ad89
--- /dev/null
+++ b/lingetic-spring-backend/src/main/resources/db/migration/V7__Add_Japanese_Modified_Hepburn_Language.sql
@@ -0,0 +1,2 @@
+-- Add JapaneseModifiedHepburn to supported languages
+INSERT INTO languages (name) VALUES ('JapaneseModifiedHepburn');
diff --git a/lingetic-spring-backend/src/test/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/JapaneseModifiedHepburnLanguageModelTest.java b/lingetic-spring-backend/src/test/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/JapaneseModifiedHepburnLanguageModelTest.java
new file mode 100644
index 00000000..41516239
--- /dev/null
+++ b/lingetic-spring-backend/src/test/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/JapaneseModifiedHepburnLanguageModelTest.java
@@ -0,0 +1,255 @@
+package com.munetmo.lingetic.LanguageService.Entities.LanguageModels;
+
+import com.munetmo.lingetic.LanguageService.Entities.Language;
+import com.munetmo.lingetic.LanguageService.Entities.TokenType;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class JapaneseModifiedHepburnLanguageModelTest {
+    private JapaneseModifiedHepburnLanguageModel model;
+
+    @BeforeEach
+    void setUp() {
+        model = new JapaneseModifiedHepburnLanguageModel();
+    }
+
+    @Test
+    void getLanguageShouldReturnJapaneseModifiedHepburn() {
+        assertEquals(Language.JapaneseModifiedHepburn, model.getLanguage());
+    }
+
+    @Test
+    void tokenizeShouldHandleEmptyStrings() {
+        assertTrue(model.tokenize("").isEmpty());
+        assertTrue(model.tokenize(" ").isEmpty());
+    }
+
+    @Test
+    void areEquivalentShouldHandleEmptyStrings() {
+        assertTrue(model.areEquivalent("", ""));
+        assertTrue(model.areEquivalent(" ", " "));
+        assertTrue(model.areEquivalent(" ", ""));
+    }
+
+    @Test
+    void areEquivalentShouldMatchRomanizedForms() {
+        assertTrue(model.areEquivalent("inu", "inu"));
+    }
+
+    @Test
+    void areEquivalentShouldIgnorePunctuation() {
+        assertTrue(model.areEquivalent("inu!", "inu"));
+    }
+
+    @Test
+    void areEquivalentShouldWorkWithMacronA() {
+        assertTrue(model.areEquivalent("kādo", "kādo")); // card
+        assertFalse(model.areEquivalent("kādo", "kaado"));
+        assertTrue(model.areEquivalent("KĀDO", "kādo")); // case insensitive
+        assertFalse(model.areEquivalent("kado", "kādo")); // different meaning
+    }
+
+    @Test
+    void areEquivalentShouldWorkWithMacronI() {
+        assertTrue(model.areEquivalent("onīsan", "onīsan")); // older brother
+        assertFalse(model.areEquivalent("onīsan", "oniisan"));
+        assertTrue(model.areEquivalent("ONĪSAN", "onīsan")); // case insensitive
+        assertFalse(model.areEquivalent("onisan", "onīsan")); // different meaning
+    }
+
+    @Test
+    void areEquivalentShouldWorkWithMacronU() {
+        assertTrue(model.areEquivalent("yūki", "yūki")); // courage
+        assertFalse(model.areEquivalent("yūki", "yuuki"));
+        assertTrue(model.areEquivalent("YŪKI", "yūki")); // case insensitive
+        assertFalse(model.areEquivalent("yuki", "yūki")); // different meaning (snow vs courage)
+    }
+
+    @Test
+    void areEquivalentShouldWorkWithMacronE() {
+        assertTrue(model.areEquivalent("onēsan", "onēsan")); // older sister
+        assertFalse(model.areEquivalent("onēsan", "oneesan"));
+        assertTrue(model.areEquivalent("ONĒSAN", "onēsan")); // case insensitive
+        assertFalse(model.areEquivalent("onesan", "onēsan")); // different meaning
+    }
+
+    @Test
+    void areEquivalentShouldWorkWithMacronO() {
+        assertTrue(model.areEquivalent("tōkyō", "tōkyō")); // Tokyo
+        assertFalse(model.areEquivalent("tōkyō", "toukyou"));
+        assertTrue(model.areEquivalent("TŌKYŌ", "tōkyō")); // case insensitive
+        assertFalse(model.areEquivalent("tokyo", "tōkyō")); // incorrect romanization
+    }
+
+    @Test
+    void areEquivalentShouldWorkWithMultipleMacrons() {
+        assertTrue(model.areEquivalent("tōkyō", "tōkyō")); // Tokyo
+        assertTrue(model.areEquivalent("kyōsō", "kyōsō")); // competition
+        assertTrue(model.areEquivalent("shōchū", "shōchū")); // distilled spirits
+        assertTrue(model.areEquivalent("kōkōsei", "kōkōsei")); // high school student
+    }
+
+    @Test
+    void areEquivalentShouldHandleMacronsWithPunctuation() {
+        assertTrue(model.areEquivalent("Tōkyō!", "tōkyō"));
+        assertTrue(model.areEquivalent("Tōkyō?", "tōkyō"));
+        assertTrue(model.areEquivalent("Tōkyō...", "tōkyō"));
+    }
+
+    @Test
+    void areEquivalentShouldHandleMacronsWithSpaces() {
+        assertTrue(model.areEquivalent("  tōkyō  ", "tōkyō"));
+        assertFalse(model.areEquivalent("Tōkyō-to", "tōkyō to")); // Tokyo metropolis
+        assertTrue(model.areEquivalent("Tōkyō\tto", "tōkyō to"));
+    }
+
+    @Test
+    void tokenizeShouldHandleTokenTypes() {
+        var tokens = model.tokenize("Watashi wa 25-sai desu.");
+
+        assertEquals(5, tokens.size());
+
+        assertEquals(TokenType.Word, tokens.get(0).type());
+        assertEquals("Watashi", tokens.get(0).value());
+
+        assertEquals(TokenType.Word, tokens.get(1).type());
+        assertEquals("wa", tokens.get(1).value());
+
+        assertEquals(TokenType.Word, tokens.get(2).type());
+        assertEquals("25-sai", tokens.get(2).value());
+
+        assertEquals(TokenType.Word, tokens.get(3).type());
+        assertEquals("desu", tokens.get(3).value());
+
+        assertEquals(TokenType.Punctuation, tokens.get(4).type());
+        assertEquals(".", tokens.get(4).value());
+    }
+
+    @Test
+    void tokenizeShouldHandleMacronsInWords() {
+        var tokens = model.tokenize("Tōkyō wa ōkii desu.");
+
+        assertEquals(5, tokens.size());
+
+        assertEquals(TokenType.Word, tokens.get(0).type());
+        assertEquals("Tōkyō", tokens.get(0).value());
+
+        assertEquals(TokenType.Word, tokens.get(1).type());
+        assertEquals("wa", tokens.get(1).value());
+
+        assertEquals(TokenType.Word, tokens.get(2).type());
+        assertEquals("ōkii", tokens.get(2).value());
+
+        assertEquals(TokenType.Word, tokens.get(3).type());
+        assertEquals("desu", tokens.get(3).value());
+
+        assertEquals(TokenType.Punctuation, tokens.get(4).type());
+        assertEquals(".", tokens.get(4).value());
+    }
+
+    @Test
+    void tokenizeShouldHandleJapaneseQuotations() {
+        var tokens = model.tokenize("Sensei wa \"Konnichiwa\" to iimashita.");
+
+        assertEquals(8, tokens.size());
+
+        assertEquals(TokenType.Word, tokens.get(0).type());
+        assertEquals("Sensei", tokens.get(0).value());
+
+        assertEquals(TokenType.Word, tokens.get(1).type());
+        assertEquals("wa", tokens.get(1).value());
+
+        assertEquals(TokenType.Punctuation, tokens.get(2).type());
+        assertEquals("\"", tokens.get(2).value());
+
+        assertEquals(TokenType.Word, tokens.get(3).type());
+        assertEquals("Konnichiwa", tokens.get(3).value());
+
+        assertEquals(TokenType.Punctuation, tokens.get(4).type());
+        assertEquals("\"", tokens.get(4).value());
+
+        assertEquals(TokenType.Word, tokens.get(5).type());
+        assertEquals("to", tokens.get(5).value());
+
+        assertEquals(TokenType.Word, tokens.get(6).type());
+        assertEquals("iimashita", tokens.get(6).value());
+
+        assertEquals(TokenType.Punctuation, tokens.get(7).type());
+        assertEquals(".", tokens.get(7).value());
+    }
+
+    @Test
+    void tokenizeShouldHandleNumbers() {
+        var tokens = model.tokenize("Kurasu ni 42-nin imasu.");
+        assertEquals(5, tokens.size());
+
+        assertEquals(TokenType.Word, tokens.get(0).type());
+        assertEquals("Kurasu", tokens.get(0).value());
+
+        assertEquals(TokenType.Word, tokens.get(1).type());
+        assertEquals("ni", tokens.get(1).value());
+
+        assertEquals(TokenType.Word, tokens.get(2).type());
+        assertEquals("42-nin", tokens.get(2).value());
+
+        assertEquals(TokenType.Word, tokens.get(3).type());
+        assertEquals("imasu", tokens.get(3).value());
+
+        assertEquals(TokenType.Punctuation, tokens.get(4).type());
+        assertEquals(".", tokens.get(4).value());
+    }
+
+    @Test
+    void tokenizeShouldHandleComplexPunctuation() {
+        var tokens = model.tokenize("Sugoi...! Hontō?!");
+
+        assertEquals(8, tokens.size());
+
+        assertEquals(TokenType.Word, tokens.get(0).type());
+        assertEquals("Sugoi", tokens.get(0).value());
+
+        assertEquals(TokenType.Punctuation, tokens.get(1).type());
+        assertEquals(".", tokens.get(1).value());
+
+        assertEquals(TokenType.Punctuation, tokens.get(2).type());
+        assertEquals(".", tokens.get(2).value());
+
+        assertEquals(TokenType.Punctuation, tokens.get(3).type());
+        assertEquals(".", tokens.get(3).value());
+
+        assertEquals(TokenType.Punctuation, tokens.get(4).type());
+        assertEquals("!", tokens.get(4).value());
+
+        assertEquals(TokenType.Word, tokens.get(5).type());
+        assertEquals("Hontō", tokens.get(5).value());
+
+        assertEquals(TokenType.Punctuation, tokens.get(6).type());
+        assertEquals("?", tokens.get(6).value());
+
+        assertEquals(TokenType.Punctuation, tokens.get(7).type());
+        assertEquals("!", tokens.get(7).value());
+    }
+
+    @Test
+    void tokenizeShouldKeepNumbersAndLettersSeparate() {
+        var tokens = model.tokenize("Room 101A wa doko desu ka?");
+
+        assertEquals(7, tokens.size());
+        assertEquals(TokenType.Word, tokens.get(0).type());
+        assertEquals("Room", tokens.get(0).value());
+        assertEquals(TokenType.Word, tokens.get(1).type());
+        assertEquals("101A", tokens.get(1).value());
+        assertEquals(TokenType.Word, tokens.get(2).type());
+        assertEquals("wa", tokens.get(2).value());
+        assertEquals(TokenType.Word, tokens.get(3).type());
+        assertEquals("doko", tokens.get(3).value());
+        assertEquals(TokenType.Word, tokens.get(4).type());
+        assertEquals("desu", tokens.get(4).value());
+        assertEquals(TokenType.Word, tokens.get(5).type());
+        assertEquals("ka", tokens.get(5).value());
+        assertEquals(TokenType.Punctuation, tokens.get(6).type());
+        assertEquals("?", tokens.get(6).value());
+    }
+}
diff --git a/scripts/scripts/course.py b/scripts/scripts/course.py
index 6f34ad75..0d6c3cb3 100644
--- a/scripts/scripts/course.py
+++ b/scripts/scripts/course.py
@@ -131,6 +131,34 @@
     }
 ]
 }
+""",
+    "JapaneseModifiedHepburn": """
+Example:
+
+Theme: Basic verbs, Level: Intermediate, Number: 2
+
+Output:
+
+{
+"data": [
+    {
+        "text": "Watashi wa shitte imasu!",
+        "translations": [
+            {
+                "text": "I know!"
+            }
+        ]
+    },
+    {
+        "text": "Tomu ga katteimasu.",
+        "translations": [
+            {
+                "text": "Tom is winning."
+            }
+        ]
+    }
+]
+}
 """,
 }
 
diff --git a/scripts/scripts/questions.py b/scripts/scripts/questions.py
index 83f3b690..4049666a 100644
--- a/scripts/scripts/questions.py
+++ b/scripts/scripts/questions.py
@@ -79,6 +79,28 @@
 Reason: Both words `駅` (station) and `へ` (direction particle) are relevant to the theme and instructions, as they deal with locations and particles used for indicating direction.
         """,
     },
+    "JapaneseModifiedHepburn": {
+        "sentence": "gakusei wa toshokan de benkyou shimasu",
+        "word1": "de",
+        "word2": ["gakusei", "toshokan"],
+        "blank1": "gakusei wa toshokan ____ benkyou shimasu",
+        "blank2": [
+            "_____ wa toshokan de benkyou shimasu",
+            "gakusei wa _____ de benkyou shimasu",
+        ],
+        "example": """
+Example:
+Words: [{{"type":"Word","value":"watashi","sequenceNumber":1}},{{"type":"Word","value":"wa","sequenceNumber":2}},{{"type":"Word","value":"eki","sequenceNumber":3}},{{"type":"Word","value":"e","sequenceNumber":4}},{{"type":"Word","value":"ikimasu","sequenceNumber":5}}]
+
+Theme: Basic Locations and Transportation
+Instructions: Teach basic location particles (e, ni, de) and verbs of motion (iku, kuru). Focus on simple sentence structures using basic particles. Average sentence length: 3-5 words.
+
+Output:
+{{ "selectedWordsSequenceNumbers": [3, 4] }}
+
+Reason: Both words `eki` (station) and `e` (direction particle) are relevant to the theme and instructions, as they deal with locations and particles used for indicating direction.
+        """,
+    },
 }
 
 PROMPT_TEMPLATE = """Your job is to create fill-in-the-blank questions. To create a fill-in-the-blank question, start with a set of words: "{sentence}" Then choose a word to hide, say, "{word1}". The fill-in-the-blank question becomes: "{blank1}"
diff --git a/scripts/scripts/tts.py b/scripts/scripts/tts.py
index 049860f2..d2a502ae 100644
--- a/scripts/scripts/tts.py
+++ b/scripts/scripts/tts.py
@@ -16,6 +16,7 @@
     "Turkish": "tr",
     "Swedish": "sv",
     "Japanese": "ja",
+    "JapaneseModifiedHepburn": "ja",
 }
 
 


Reviews:
user: login: gemini-code-assist[bot]
body: Hello @abhi-kr-2100, I'm Gemini Code Assist[^1]! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

## Summary of Changes
This pull request adds support for the `JapaneseModifiedHepburn` language to the backend. This includes adding the language to the `Language` enum, creating a corresponding `LanguageModel`, updating the database migration script, and adding unit tests. The `LatinScriptLanguageModelHelper` is also updated to include additional characters.

### Highlights
* **Language Support**: Adds `JapaneseModifiedHepburn` to the `Language` enum to represent the new language.
* **Language Model**: Creates a `JapaneseModifiedHepburnLanguageModel` that implements the `LanguageModel` interface, leveraging `LatinScriptLanguageModelHelper` for tokenization and equivalence checks.
* **Database Migration**: Includes a database migration script to add `JapaneseModifiedHepburn` to the `languages` table.
* **Unit Tests**: Adds unit tests for the `JapaneseModifiedHepburnLanguageModel` to ensure correct behavior, especially around macrons and punctuation.
* **Character Support**: Extends `LatinScriptLanguageModelHelper` to include macrons (āīūēō) in the list of specific characters.

### Changelog
<details>
<summary>Click here to see the changelog</summary>

* **lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/Language.java**
  * Added `JapaneseModifiedHepburn` to the `Language` enum.
* **lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/JapaneseModifiedHepburnLanguageModel.java**
  * Created `JapaneseModifiedHepburnLanguageModel` to handle tokenization and equivalence checks for the new language.
  * Implements the `LanguageModel` interface.
* **lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/LanguageModel.java**
  * Added `JapaneseModifiedHepburnLanguageModel` to the `permits` list for the `LanguageModel` sealed interface.
  * Updated the `languageModels` map to include `JapaneseModifiedHepburn` and its corresponding model.
* **lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/LatinScriptLanguageModelHelper.java**
  * Added macron characters (āīūēō) to the `SPECIFIC_CHARACTERS` constant.
* **lingetic-spring-backend/src/main/resources/db/migration/V7__Add_Japanese_Modified_Hepburn_Language.sql**
  * Added a SQL script to insert `JapaneseModifiedHepburn` into the `languages` table.
* **lingetic-spring-backend/src/test/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/JapaneseModifiedHepburnLanguageModelTest.java**
  * Created unit tests for `JapaneseModifiedHepburnLanguageModel` to verify correct behavior, including handling of macrons, punctuation, and empty strings.

</details>


<details>

<summary><b>Using Gemini Code Assist</b></summary>
<br>

The full guide for Gemini Code Assist can be found on our [documentation page](https://developers.google.com/gemini-code-assist/docs/review-github-code), here are some quick tips.

<b>Invoking Gemini</b>

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either `/gemini <command>` or `@gemini-code-assist <command>`. Below is a summary of the supported commands.

Feature | Command | Description
--- | --- | ---
Code Review | `/gemini review` | Performs a code review for the current pull request in its current state.
Pull Request Summary | `/gemini summary` | Provides a summary of the current pull request in its current state.
Comment | @gemini-code-assist | Responds in comments when explicitly tagged, both in issue comments and review comments.
Help | `/gemini help` | Displays a list of available commands.

<b>Customization</b>

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a `.gemini/` folder in the base of the repository. Detailed instructions can be found [here](https://developers.google.com/gemini-code-assist/docs/customize-gemini-behavior-github).

<b>Limitations & Feedback</b>

Gemini Code Assist is currently in preview and may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with :thumbsup: and :thumbsdown: on @gemini-code-assist comments to provide feedback.

</details>

<b>You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the [Gemini Code Assist IDE Extension](https://cloud.google.com/products/gemini/code-assist).</b>


[^1]: Review the [Privacy Notices](https://policies.google.com/privacy), [Generative AI Prohibited Use Policy](https://policies.google.com/terms/generative-ai/use-policy), [Terms of Service](https://policies.google.com/terms), and learn how to configure Gemini Code Assist in GitHub [here](https://developers.google.com/gemini-code-assist/docs/review-github-code). Gemini can make mistakes, so double check it and [use code with caution](https://support.google.com/legal/answer/13505487).

---

> Hepburn's script, now in code,
> Macrons dance, a lighter load.
> Tests all pass,
> A welcome class,
> Backend's reach, a wider road.


state: COMMENTED
author_association: NONE
submitted_at: 2025-05-08T15:13:44Z
user: login: gemini-code-assist[bot]
body: ## Code Review
This pull request introduces support for the Japanese Modified Hepburn language to the backend. The changes include adding the language to the `Language` enum, creating a language model, updating the database, and adding unit tests. Overall, the changes seem well-structured and cover the necessary aspects for integrating the new language.

### Merge Readiness
The pull request appears to be well-structured and includes necessary components for adding the new language. I am unable to directly approve the pull request, and recommend that others review and approve this code before merging. There are no critical or high severity issues, so the pull request is likely ready to be merged once other reviewers have had a chance to look at it.
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-08T15:13:58Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 3**

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: ASSERTIVE**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between b2f6112bc3b24c6f7a5bdc29578fa21830c654af and c69e2470d8f64c05161d012fc915c058bdbc6c40.

</details>

<details>
<summary>📒 Files selected for processing (6)</summary>

* `lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/Language.java` (1 hunks)
* `lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/JapaneseModifiedHepburnLanguageModel.java` (1 hunks)
* `lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/LanguageModel.java` (2 hunks)
* `lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/LatinScriptLanguageModelHelper.java` (1 hunks)
* `lingetic-spring-backend/src/main/resources/db/migration/V7__Add_Japanese_Modified_Hepburn_Language.sql` (1 hunks)
* `lingetic-spring-backend/src/test/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/JapaneseModifiedHepburnLanguageModelTest.java` (1 hunks)

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (3)</summary>

* GitHub Check: Codacy Static Code Analysis
* GitHub Check: mrge · AI code reviewer
* GitHub Check: Socket Security: Pull Request Alerts

</details>

<details>
<summary>🔇 Additional comments (8)</summary><blockquote>

<details>
<summary>lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/LatinScriptLanguageModelHelper.java (1)</summary>

`15-15`: **LGTM: Well-implemented character set extension**

Adding the macronized vowels "āīūēō" to the SPECIFIC_CHARACTERS constant is necessary to properly support Japanese Modified Hepburn romanization, which uses these macrons to indicate long vowels.

</details>
<details>
<summary>lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/Language.java (1)</summary>

`10-10`: **LGTM: Clean enum addition**

The JapaneseModifiedHepburn enum value is correctly added to the Language enum, maintaining the same naming convention as other languages.

</details>
<details>
<summary>lingetic-spring-backend/src/main/resources/db/migration/V7__Add_Japanese_Modified_Hepburn_Language.sql (1)</summary>

`1-2`: **LGTM: Proper migration script**

The SQL migration properly adds JapaneseModifiedHepburn to the languages table, with appropriate commenting and formatting.

</details>
<details>
<summary>lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/LanguageModel.java (2)</summary>

`9-10`: **LGTM: Properly updated sealed interface**

The sealed interface declaration is correctly updated to permit the new JapaneseModifiedHepburnLanguageModel implementation.

---

`22-23`: **LGTM: Proper language model registration**

The static map is appropriately updated to include the new language model, mapping the JapaneseModifiedHepburn enum to its implementation.

</details>
<details>
<summary>lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/JapaneseModifiedHepburnLanguageModel.java (1)</summary>

`9-26`: **Implementation looks good!**

The implementation follows the established pattern for language models in the codebase. It correctly delegates to the `LatinScriptLanguageModelHelper` initialized with the Japanese locale, which keeps the code DRY and maintainable.

</details>
<details>
<summary>lingetic-spring-backend/src/test/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/JapaneseModifiedHepburnLanguageModelTest.java (2)</summary>

`40-43`: **Good punctuation test**

This test correctly verifies that punctuation is ignored when checking for equivalence.

---

`45-105`: **Comprehensive macron testing**

The tests thoroughly cover all macron characters (ā, ī, ū, ē, ō) with good edge cases. They correctly verify:
1. Case insensitivity
2. Distinction between macronized and non-macronized vowels
3. Multiple macrons in a single word
4. Interaction with punctuation and spaces
5. Correct handling of hyphenation vs. spaces for compound words

This comprehensive testing helps ensure the language model's robustness.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-08T15:15:53Z
user: login: cubic-dev-ai[bot]
body: mrge found 4 issues across 6 files. Review them in [mrge.io](https://mrge.io/pr/abhi-kr-2100/Lingetic/pull/278)
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-08T15:16:10Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 3**

<details>
<summary>♻️ Duplicate comments (8)</summary><blockquote>

<details>
<summary>lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/JapaneseModifiedHepburnLanguageModel.java (1)</summary><blockquote>

`9-25`: _🧹 Nitpick (assertive)_

**Add JavaDoc to explain purpose and behavior of the class.**

The implementation looks good, but consider adding JavaDoc comments to explain what Japanese Modified Hepburn romanization is and how it differs from the regular Japanese language model. This would help other developers understand the purpose and usage of this class.

</blockquote></details>
<details>
<summary>lingetic-spring-backend/src/test/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/JapaneseModifiedHepburnLanguageModelTest.java (7)</summary><blockquote>

`11-11`: **The test class doesn't verify integration with the LatinScriptLanguageModelHelper**

The implementation likely delegates key functionality to LatinScriptLanguageModelHelper, but the tests don't explicitly verify this integration works correctly.

---

`23-27`: **Test method doesn't verify tokenization of actual Japanese text or romanized Japanese with macrons**

The tokenization tests only verify empty string handling, but don't test actual Japanese Modified Hepburn text with macrons, which is the main feature of this model.

---

`36-39`: **This test doesn't actually verify Japanese-specific functionality**

This test doesn't verify that the model correctly handles Japanese characters or words, as it's just testing the same romanized string against itself.

---

`78-84`: _🛠️ Refactor suggestion_

**Add tests for actual Japanese characters with macron o**

Add validation for Japanese character equivalence with romanized form using macron o, particularly for Tokyo which is a common example.

```diff
 void areEquivalentShouldWorkWithMacronO() {
     assertTrue(model.areEquivalent("tōkyō", "tōkyō")); // Tokyo
     assertFalse(model.areEquivalent("tōkyō", "toukyou"));
     assertTrue(model.areEquivalent("TŌKYŌ", "tōkyō")); // case insensitive
     assertFalse(model.areEquivalent("tokyo", "tōkyō")); // incorrect romanization
+    // Test with actual Japanese characters
+    assertTrue(model.areEquivalent("東京", "tōkyō")); // Japanese to romanized
 }
```

---

`62-68`: _🛠️ Refactor suggestion_

**Good distinction between semantically different words**

The test effectively demonstrates the semantic importance of macrons by contrasting "yuki" (snow) with "yūki" (courage), but should also test with actual Japanese characters.


```diff
 void areEquivalentShouldWorkWithMacronU() {
     assertTrue(model.areEquivalent("yūki", "yūki")); // courage
     assertFalse(model.areEquivalent("yūki", "yuuki"));
     assertTrue(model.areEquivalent("YŪKI", "yūki")); // case insensitive
     assertFalse(model.areEquivalent("yuki", "yūki")); // different meaning (snow vs courage)
+    // Test with actual Japanese characters
+    assertTrue(model.areEquivalent("勇気", "yūki")); // courage in Japanese
+    assertTrue(model.areEquivalent("雪", "yuki")); // snow in Japanese
 }
```

---

`54-60`: _🛠️ Refactor suggestion_

**Add tests for actual Japanese characters with macron i**

Similar to the macron A test, add validation for Japanese character equivalence with romanized form using macron i.

```diff
 void areEquivalentShouldWorkWithMacronI() {
     assertTrue(model.areEquivalent("onīsan", "onīsan")); // older brother
     assertFalse(model.areEquivalent("onīsan", "oniisan"));
     assertTrue(model.areEquivalent("ONĪSAN", "onīsan")); // case insensitive
     assertFalse(model.areEquivalent("onisan", "onīsan")); // different meaning
+    // Test with actual Japanese characters
+    assertTrue(model.areEquivalent("お兄さん", "onīsan")); // Japanese to romanized
 }
```

---

`70-76`: _🛠️ Refactor suggestion_

**Add tests for actual Japanese characters with macron e**

Similar to other macron tests, add validation for Japanese character equivalence with romanized form using macron e.

```diff
 void areEquivalentShouldWorkWithMacronE() {
     assertTrue(model.areEquivalent("onēsan", "onēsan")); // older sister
     assertFalse(model.areEquivalent("onēsan", "oneesan"));
     assertTrue(model.areEquivalent("ONĒSAN", "onēsan")); // case insensitive
     assertFalse(model.areEquivalent("onesan", "onēsan")); // different meaning
+    // Test with actual Japanese characters
+    assertTrue(model.areEquivalent("お姉さん", "onēsan")); // Japanese to romanized
 }
```

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: ASSERTIVE**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between c69e2470d8f64c05161d012fc915c058bdbc6c40 and e35bfd24bf355cefbfd0c6666a1213ce14d804a5.

</details>

<details>
<summary>📒 Files selected for processing (6)</summary>

* `lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/Language.java` (1 hunks)
* `lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/JapaneseModifiedHepburnLanguageModel.java` (1 hunks)
* `lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/LanguageModel.java` (2 hunks)
* `lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/LatinScriptLanguageModelHelper.java` (1 hunks)
* `lingetic-spring-backend/src/main/resources/db/migration/V7__Add_Japanese_Modified_Hepburn_Language.sql` (1 hunks)
* `lingetic-spring-backend/src/test/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/JapaneseModifiedHepburnLanguageModelTest.java` (1 hunks)

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (1)</summary>

* GitHub Check: Codacy Static Code Analysis

</details>

<details>
<summary>🔇 Additional comments (14)</summary><blockquote>

<details>
<summary>lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/LatinScriptLanguageModelHelper.java (1)</summary>

`15-15`: **Appropriate extension of supported characters for Japanese Modified Hepburn.**

The addition of macron vowels "āīūēō" to `SPECIFIC_CHARACTERS` enables proper handling of Japanese Modified Hepburn romanization, which requires these special characters for long vowels.

</details>
<details>
<summary>lingetic-spring-backend/src/main/resources/db/migration/V7__Add_Japanese_Modified_Hepburn_Language.sql (1)</summary>

`1-2`: **Database migration for new language looks good.**

The SQL statement correctly adds the JapaneseModifiedHepburn language to the languages table, which is necessary for the backend to recognize and use this language.

</details>
<details>
<summary>lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/Language.java (1)</summary>

`10-10`: **Appropriate addition of new language enum.**

The JapaneseModifiedHepburn enum constant has been correctly added to the Language enum, which is necessary for the new language model to be identified within the system.

</details>
<details>
<summary>lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/LanguageModel.java (2)</summary>

`9-10`: **Correct integration of new language model in sealed interface.**

The JapaneseModifiedHepburnLanguageModel has been properly added to the permits clause of the sealed interface, which is required for it to be recognized as a valid implementation.

---

`22-23`: **Appropriate registration of new language model.**

The new JapaneseModifiedHepburnLanguageModel is correctly registered in the languageModels map, allowing it to be retrieved via the getLanguageModel method.

</details>
<details>
<summary>lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/JapaneseModifiedHepburnLanguageModel.java (1)</summary>

`10-10`: **Verify the locale choice for Modified Hepburn romanization.**

The use of `Locale.JAPAN` is generally appropriate, but consider explaining why this specific locale works for Modified Hepburn romanization, which uses Latin characters with macrons rather than Japanese characters.

</details>
<details>
<summary>lingetic-spring-backend/src/test/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/JapaneseModifiedHepburnLanguageModelTest.java (8)</summary>

`18-21`: **Good verification of language model identity**

This test correctly ensures that the model returns the appropriate language enum value, which is a critical aspect of the language model interface contract.

---

`109-128`: **Good tokenization test with mixed content**

This test effectively verifies that the tokenizer correctly handles mixed content with words and punctuation, including age expressions.

---

`130-150`: **Comprehensive test for macrons in tokenization**

This test properly verifies that words containing macrons are tokenized correctly, which is essential for the Modified Hepburn romanization system.

---

`152-181`: **Good test for quotation handling**

This test effectively verifies that Japanese quotations are tokenized correctly, separating the punctuation from the words.

---

`183-202`: **Good test for number handling**

This test effectively verifies that numbers within Japanese text are tokenized correctly, particularly with the counter suffix.

---

`204-233`: **Excellent test for complex punctuation**

This test thoroughly verifies that complex punctuation sequences like ellipses and multiple punctuation marks are correctly tokenized.

---

`235-254`: **Good verification of alphanumeric tokens**

This test correctly verifies that mixed alphanumeric tokens like room numbers are properly handled during tokenization.

---

`46-52`: <details>
<summary>❌ Incorrect review comment</summary>

**Test doesn't verify that the model correctly handles the Japanese characters**

While testing macron handling is important, the test should also verify that Japanese characters are correctly romanized to macron forms. For example, testing that "カード" is equivalent to "kādo".



```diff
 void areEquivalentShouldWorkWithMacronA() {
     assertTrue(model.areEquivalent("kādo", "kādo")); // card
     assertFalse(model.areEquivalent("kādo", "kaado"));
     assertTrue(model.areEquivalent("KĀDO", "kādo")); // case insensitive
     assertFalse(model.areEquivalent("kado", "kādo")); // different meaning
+    // Test with actual Japanese characters
+    assertTrue(model.areEquivalent("カード", "kādo")); // Japanese to romanized
 }
```

---

🌐 Web query:

```web
What are the Japanese characters for kādo (card in Japanese)?
```

💡 Result:

The Japanese word for “card” is カード, written in katakana as:  
**カード** (kādo)[2][4].

- カ (ka)
- ー (long vowel mark)
- ド (do)

This is the standard way to write "card" in Japanese, especially for things like credit cards, ID cards, SIM cards, and playing cards. Japanese typically uses katakana to represent foreign words, and “card” is a loanword from English[2][4].

There is no common kanji for "card" in this context; it is not written using kanji characters. If you see the word written in kanji, such as 在留カード (zairyū kādo, “residence card”), only the explanatory part like 在留 (residence) is in kanji, while カード remains in katakana[10].

So, the Japanese characters for kādo (card) are:  
**カード**

Citations:

- 1: https://www.youtube.com/watch?v=DRByIrIZgnc
- 2: https://www.nihongomaster.com/japanese/dictionary/word/3346/ka%E3%83%BCdo-%E3%82%AB%E3%83%BC%E3%83%89
- 3: https://www.memrise.com/en-us/learn-japanese/japanese-course/phrasebook/65637480268034/how-to-say-card-in-japanese
- 4: https://www.wordhippo.com/what-is/the-meaning-of/japanese-word-ab1110fbbc0768f90dd793122ba6b229e9ca194b.html
- 5: https://www.japan-experience.com/plan-your-trip/to-know/japanese-language/kanji-japanese-characters
- 6: https://nihongoichiban.com/2011/06/04/%E8%A7%92/
- 7: https://www.nihongoshark.com/post/kanji-by-sight
- 8: https://hinative.com/questions/17707233
- 9: https://en.wikipedia.org/wiki/Honorific_speech_in_Japanese
- 10: https://www.japan-guide.com/forum/quereadisplay.html?0+111997

---

🏁 Script executed:

```shell
#!/bin/bash
# Locate the implementation of areEquivalent in the JapaneseModifiedHepburnLanguageModel
rg -n "class JapaneseModifiedHepburnLanguageModel" -A50 -B0 lingetic-spring-backend
rg -n "areEquivalent" -A5 -B5 lingetic-spring-backend
```

Length of output: 107420

---

🏁 Script executed:

```shell
#!/bin/bash
# Display the normalize implementation in LatinScriptLanguageModelHelper
rg -n "String normalize" -A20 -B5 lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/LatinScriptLanguageModelHelper.java
```

Length of output: 1114

---



</details>

**Ignore Japanese script input in Romanization tests**  
The JapaneseModifiedHepburnLanguageModel is designed to compare romanized (Japanese Modified Hepburn) strings only, not to transliterate or normalize raw Japanese characters. The conversion of “カード”→“kādo” should happen upstream (e.g. via a dedicated transliteration component or the JapaneseLanguageModel), not in this model’s `areEquivalent` logic.  
No changes needed to this test class.  


> Likely an incorrect or invalid review comment.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-08T15:45:32Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 1**

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: ASSERTIVE**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 0b7bb411e8f441f3749b1847708237d8bc5f8d3c and d07dfe7c5d6e5e29fa28c363dcff7f54a2b69c8e.

</details>

<details>
<summary>📒 Files selected for processing (3)</summary>

* `scripts/scripts/course.py` (1 hunks)
* `scripts/scripts/questions.py` (1 hunks)
* `scripts/scripts/tts.py` (1 hunks)

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (1)</summary>

* GitHub Check: Codacy Static Code Analysis

</details>

<details>
<summary>🔇 Additional comments (3)</summary><blockquote>

<details>
<summary>scripts/scripts/tts.py (1)</summary>

`19-19`: **New language mapping added – looks good.**

The `"JapaneseModifiedHepburn": "ja"` entry correctly maps the new variant to the existing Japanese language code. This ensures `gTTS` will accept it and that `main()`’s supported-language check will pass.

</details>
<details>
<summary>scripts/scripts/course.py (1)</summary>

`134-162`: **New example for JapaneseModifiedHepburn is well-formed.**

The added `"JapaneseModifiedHepburn"` entry in `EXAMPLES` matches the structure of the other language examples, with proper triple-quoted strings and a closing comma. This integrates seamlessly with `generate_prompt()` and the language-support checks.

</details>
<details>
<summary>scripts/scripts/questions.py (1)</summary>

`82-90`: **New PROMPT_EXAMPLES entry added correctly.**

The `"JapaneseModifiedHepburn"` key and its fields (`sentence`, `word1`, `word2`, `blank1`, `blank2`) mirror the existing pattern for other languages. This will be picked up by `generate_prompt()` and the selection logic without further changes.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-08T17:22:07Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 2**

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: ASSERTIVE**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between d07dfe7c5d6e5e29fa28c363dcff7f54a2b69c8e and f105473c8e5691480d306439615e13989461dd51.

</details>

<details>
<summary>📒 Files selected for processing (1)</summary>

* `lingetic-nextjs-frontend/app/languages/constants.ts` (2 hunks)

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (1)</summary>

* GitHub Check: Codacy Static Code Analysis

</details>

<details>
<summary>🔇 Additional comments (1)</summary><blockquote>

<details>
<summary>lingetic-nextjs-frontend/app/languages/constants.ts (1)</summary>

`104-104`: **Good language code choice**

Using "ja-hepburn" as the language code for JapaneseModifiedHepburn is an appropriate choice and follows conventional language code patterns.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-08T17:40:08Z

Review comments:
diff_hunk: @@ -0,0 +1,26 @@
+package com.munetmo.lingetic.LanguageService.Entities.LanguageModels;
+
+import com.munetmo.lingetic.LanguageService.Entities.Language;
+import com.munetmo.lingetic.LanguageService.Entities.Token;
+
+import java.util.List;
+import java.util.Locale;
+
+public final class JapaneseModifiedHepburnLanguageModel implements LanguageModel {
+    private static final LatinScriptLanguageModelHelper helper = new LatinScriptLanguageModelHelper(Locale.JAPAN);
+
+    @Override
+    public Language getLanguage() {
+        return Language.JapaneseModifiedHepburn;
+    }
+
+    @Override
+    public boolean areEquivalent(String s1, String s2) {
+        return helper.areEquivalent(s1, s2);
+    }
+
+    @Override
+    public List<Token> tokenize(String input) {
+        return helper.tokenize(input);
+    }
path: lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/JapaneseModifiedHepburnLanguageModel.java
user: login: gemini-code-assist[bot]
body: ![medium](https://img.shields.io/badge/priority-medium-yellow)

The `JapaneseModifiedHepburnLanguageModel` class seems well-implemented, leveraging the `LatinScriptLanguageModelHelper`. Consider adding JavaDoc to the class and methods to explain their purpose and usage.
created_at: 2025-05-08T15:13:58Z
author_association: NONE
diff_hunk: @@ -0,0 +1,106 @@
+package com.munetmo.lingetic.LanguageService.Entities.LanguageModels;
+
+import com.munetmo.lingetic.LanguageService.Entities.Language;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class JapaneseModifiedHepburnLanguageModelTest {
+    private JapaneseModifiedHepburnLanguageModel model;
+
+    @BeforeEach
+    void setUp() {
+        model = new JapaneseModifiedHepburnLanguageModel();
+    }
+
+    @Test
+    void getLanguageShouldReturnJapaneseModifiedHepburn() {
+        assertEquals(Language.JapaneseModifiedHepburn, model.getLanguage());
+    }
+
+    @Test
+    void tokenizeShouldHandleEmptyStrings() {
+        assertTrue(model.tokenize("").isEmpty());
+        assertTrue(model.tokenize(" ").isEmpty());
+    }
+
+    @Test
+    void areEquivalentShouldHandleEmptyStrings() {
+        assertTrue(model.areEquivalent("", ""));
+        assertTrue(model.areEquivalent(" ", " "));
+        assertTrue(model.areEquivalent(" ", ""));
+    }
+
+    @Test
+    void areEquivalentShouldMatchBothJapaneseAndRomanizedForms() {
+        assertTrue(model.areEquivalent("inu", "inu"));
+    }
path: lingetic-spring-backend/src/test/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/JapaneseModifiedHepburnLanguageModelTest.java
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**Test name doesn't match implementation**

The test method name `areEquivalentShouldMatchBothJapaneseAndRomanizedForms` suggests that it's testing both Japanese and romanized forms, but the test only checks romanized Japanese against itself (`"inu", "inu"`). Consider either updating the test name or extending the test to include actual Japanese characters (e.g., "犬" vs "inu").

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-08T15:15:52Z
author_association: NONE
diff_hunk: @@ -0,0 +1,106 @@
+package com.munetmo.lingetic.LanguageService.Entities.LanguageModels;
+
+import com.munetmo.lingetic.LanguageService.Entities.Language;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class JapaneseModifiedHepburnLanguageModelTest {
+    private JapaneseModifiedHepburnLanguageModel model;
+
+    @BeforeEach
+    void setUp() {
+        model = new JapaneseModifiedHepburnLanguageModel();
+    }
+
+    @Test
+    void getLanguageShouldReturnJapaneseModifiedHepburn() {
+        assertEquals(Language.JapaneseModifiedHepburn, model.getLanguage());
+    }
+
+    @Test
+    void tokenizeShouldHandleEmptyStrings() {
+        assertTrue(model.tokenize("").isEmpty());
+        assertTrue(model.tokenize(" ").isEmpty());
+    }
+
+    @Test
+    void areEquivalentShouldHandleEmptyStrings() {
+        assertTrue(model.areEquivalent("", ""));
+        assertTrue(model.areEquivalent(" ", " "));
+        assertTrue(model.areEquivalent(" ", ""));
+    }
+
+    @Test
+    void areEquivalentShouldMatchBothJapaneseAndRomanizedForms() {
+        assertTrue(model.areEquivalent("inu", "inu"));
+    }
+
+    @Test
+    void areEquivalentShouldIgnorePunctuation() {
+        assertTrue(model.areEquivalent("inu!", "inu"));
+    }
+
+    @Test
+    void areEquivalentShouldWorkWithMacronA() {
+        assertTrue(model.areEquivalent("kādo", "kādo")); // card
+        assertFalse(model.areEquivalent("kādo", "kaado"));
+        assertTrue(model.areEquivalent("KĀDO", "kādo")); // case insensitive
+        assertFalse(model.areEquivalent("kado", "kādo")); // different meaning
+    }
+
+    @Test
+    void areEquivalentShouldWorkWithMacronI() {
+        assertTrue(model.areEquivalent("onīsan", "onīsan")); // older brother
+        assertFalse(model.areEquivalent("onīsan", "oniisan"));
+        assertTrue(model.areEquivalent("ONĪSAN", "onīsan")); // case insensitive
+        assertFalse(model.areEquivalent("onisan", "onīsan")); // different meaning
+    }
+
+    @Test
+    void areEquivalentShouldWorkWithMacronU() {
+        assertTrue(model.areEquivalent("yūki", "yūki")); // courage
+        assertFalse(model.areEquivalent("yūki", "yuuki"));
+        assertTrue(model.areEquivalent("YŪKI", "yūki")); // case insensitive
+        assertFalse(model.areEquivalent("yuki", "yūki")); // different meaning (snow vs courage)
+    }
+
+    @Test
+    void areEquivalentShouldWorkWithMacronE() {
+        assertTrue(model.areEquivalent("onēsan", "onēsan")); // older sister
+        assertFalse(model.areEquivalent("onēsan", "oneesan"));
+        assertTrue(model.areEquivalent("ONĒSAN", "onēsan")); // case insensitive
+        assertFalse(model.areEquivalent("onesan", "onēsan")); // different meaning
+    }
+
+    @Test
+    void areEquivalentShouldWorkWithMacronO() {
+        assertTrue(model.areEquivalent("tōkyō", "tōkyō")); // Tokyo
+        assertFalse(model.areEquivalent("tōkyō", "toukyou"));
+        assertTrue(model.areEquivalent("TŌKYŌ", "tōkyō")); // case insensitive
+        assertFalse(model.areEquivalent("tokyo", "tōkyō")); // incorrect romanization
+    }
+
+    @Test
+    void areEquivalentShouldWorkWithMultipleMacrons() {
+        assertTrue(model.areEquivalent("tōkyō", "tōkyō")); // Tokyo
+        assertTrue(model.areEquivalent("kyōsō", "kyōsō")); // competition
+        assertTrue(model.areEquivalent("shōchū", "shōchū")); // distilled spirits
+        assertTrue(model.areEquivalent("kōkōsei", "kōkōsei")); // high school student
+    }
+
+    @Test
+    void areEquivalentShouldHandleMacronsWithPunctuation() {
+        assertTrue(model.areEquivalent("Tōkyō!", "tōkyō"));
+        assertTrue(model.areEquivalent("Tōkyō?", "tōkyō"));
+        assertTrue(model.areEquivalent("Tōkyō...", "tōkyō"));
+    }
+
+    @Test
+    void areEquivalentShouldHandleMacronsWithSpaces() {
+        assertTrue(model.areEquivalent("  tōkyō  ", "tōkyō"));
+        assertFalse(model.areEquivalent("Tōkyō-to", "tōkyō to")); // Tokyo metropolis
+        assertTrue(model.areEquivalent("Tōkyō\tto", "tōkyō to"));
+    }
+}
path: lingetic-spring-backend/src/test/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/JapaneseModifiedHepburnLanguageModelTest.java
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**Consider adding JavaDoc comments**

Adding JavaDoc comments to the test class and test methods would improve documentation and clarify the purpose of each test, especially for those unfamiliar with Japanese language nuances. This could include explanations of Modified Hepburn romanization rules being tested and the semantic differences between similarly spelled words (like the snow/courage distinction for yuki/yūki).

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-08T15:15:52Z
author_association: NONE
diff_hunk: @@ -0,0 +1,106 @@
+package com.munetmo.lingetic.LanguageService.Entities.LanguageModels;
+
+import com.munetmo.lingetic.LanguageService.Entities.Language;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class JapaneseModifiedHepburnLanguageModelTest {
+    private JapaneseModifiedHepburnLanguageModel model;
+
+    @BeforeEach
+    void setUp() {
+        model = new JapaneseModifiedHepburnLanguageModel();
+    }
+
+    @Test
+    void getLanguageShouldReturnJapaneseModifiedHepburn() {
+        assertEquals(Language.JapaneseModifiedHepburn, model.getLanguage());
+    }
+
+    @Test
+    void tokenizeShouldHandleEmptyStrings() {
+        assertTrue(model.tokenize("").isEmpty());
+        assertTrue(model.tokenize(" ").isEmpty());
+    }
path: lingetic-spring-backend/src/test/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/JapaneseModifiedHepburnLanguageModelTest.java
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**Consider adding more tokenization tests**

The current tests only verify tokenization behavior for empty and whitespace strings. Consider adding tests that validate the tokenization of actual Japanese Modified Hepburn text, including words with macrons and various word boundaries.

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-08T15:15:52Z
author_association: NONE
diff_hunk: @@ -0,0 +1,106 @@
+package com.munetmo.lingetic.LanguageService.Entities.LanguageModels;
+
+import com.munetmo.lingetic.LanguageService.Entities.Language;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class JapaneseModifiedHepburnLanguageModelTest {
+    private JapaneseModifiedHepburnLanguageModel model;
+
+    @BeforeEach
+    void setUp() {
+        model = new JapaneseModifiedHepburnLanguageModel();
+    }
+
+    @Test
+    void getLanguageShouldReturnJapaneseModifiedHepburn() {
+        assertEquals(Language.JapaneseModifiedHepburn, model.getLanguage());
+    }
+
+    @Test
+    void tokenizeShouldHandleEmptyStrings() {
+        assertTrue(model.tokenize("").isEmpty());
+        assertTrue(model.tokenize(" ").isEmpty());
+    }
+
+    @Test
+    void areEquivalentShouldHandleEmptyStrings() {
+        assertTrue(model.areEquivalent("", ""));
+        assertTrue(model.areEquivalent(" ", " "));
+        assertTrue(model.areEquivalent(" ", ""));
+    }
+
+    @Test
+    void areEquivalentShouldMatchBothJapaneseAndRomanizedForms() {
+        assertTrue(model.areEquivalent("inu", "inu"));
path: lingetic-spring-backend/src/test/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/JapaneseModifiedHepburnLanguageModelTest.java
user: login: cubic-dev-ai[bot]
body: <!-- metadata:{"confidence":9,"steps":[{"text":"I'll review the changed lines in the JapaneseModifiedHepburnLanguageModelTest.java file for potential issues. Let me analyze the code systematically.","toolCalls":[{"args":{"pattern":"**/JapaneseModifiedHepburnLanguageModel.java"},"toolName":"listFiles"}]},{"text":"Let me examine the implementation of the JapaneseModifiedHepburnLanguageModel class to better understand what's being tested:","toolCalls":[{"args":{"command":"cat lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/JapaneseModifiedHepburnLanguageModel.java"},"toolName":"executeCommand"}]},{"text":"Let me also check the LatinScriptLanguageModelHelper class since it's used by the JapaneseModifiedHepburnLanguageModel:","toolCalls":[{"args":{"command":"cat lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/LatinScriptLanguageModelHelper.java"},"toolName":"executeCommand"}]},{"text":"Let me also check the Language enum to understand the JapaneseModifiedHepburn language definition:","toolCalls":[{"args":{"command":"cat lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/Language.java"},"toolName":"executeCommand"}]}]} -->
This test doesn't actually verify Japanese-specific functionality as it's just testing the same string against itself
created_at: 2025-05-08T15:16:10Z
author_association: NONE
diff_hunk: @@ -0,0 +1,106 @@
+package com.munetmo.lingetic.LanguageService.Entities.LanguageModels;
+
+import com.munetmo.lingetic.LanguageService.Entities.Language;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class JapaneseModifiedHepburnLanguageModelTest {
+    private JapaneseModifiedHepburnLanguageModel model;
+
+    @BeforeEach
+    void setUp() {
+        model = new JapaneseModifiedHepburnLanguageModel();
+    }
+
+    @Test
+    void getLanguageShouldReturnJapaneseModifiedHepburn() {
+        assertEquals(Language.JapaneseModifiedHepburn, model.getLanguage());
+    }
+
+    @Test
+    void tokenizeShouldHandleEmptyStrings() {
+        assertTrue(model.tokenize("").isEmpty());
+        assertTrue(model.tokenize(" ").isEmpty());
+    }
+
+    @Test
+    void areEquivalentShouldHandleEmptyStrings() {
+        assertTrue(model.areEquivalent("", ""));
+        assertTrue(model.areEquivalent(" ", " "));
+        assertTrue(model.areEquivalent(" ", ""));
+    }
+
+    @Test
+    void areEquivalentShouldMatchBothJapaneseAndRomanizedForms() {
+        assertTrue(model.areEquivalent("inu", "inu"));
+    }
+
+    @Test
+    void areEquivalentShouldIgnorePunctuation() {
+        assertTrue(model.areEquivalent("inu!", "inu"));
+    }
+
+    @Test
+    void areEquivalentShouldWorkWithMacronA() {
path: lingetic-spring-backend/src/test/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/JapaneseModifiedHepburnLanguageModelTest.java
user: login: cubic-dev-ai[bot]
body: <!-- metadata:{"confidence":9,"steps":[{"text":"I'll review the changed lines in the JapaneseModifiedHepburnLanguageModelTest.java file for potential issues. Let me analyze the code systematically.","toolCalls":[{"args":{"pattern":"**/JapaneseModifiedHepburnLanguageModel.java"},"toolName":"listFiles"}]},{"text":"Let me examine the implementation of the JapaneseModifiedHepburnLanguageModel class to better understand what's being tested:","toolCalls":[{"args":{"command":"cat lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/JapaneseModifiedHepburnLanguageModel.java"},"toolName":"executeCommand"}]},{"text":"Let me also check the LatinScriptLanguageModelHelper class since it's used by the JapaneseModifiedHepburnLanguageModel:","toolCalls":[{"args":{"command":"cat lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/LatinScriptLanguageModelHelper.java"},"toolName":"executeCommand"}]},{"text":"Let me also check the Language enum to understand the JapaneseModifiedHepburn language definition:","toolCalls":[{"args":{"command":"cat lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/Language.java"},"toolName":"executeCommand"}]}]} -->
Test doesn't verify that the model correctly handles the Japanese characters that would be romanized to macron forms
created_at: 2025-05-08T15:16:10Z
author_association: NONE
diff_hunk: @@ -0,0 +1,106 @@
+package com.munetmo.lingetic.LanguageService.Entities.LanguageModels;
+
+import com.munetmo.lingetic.LanguageService.Entities.Language;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class JapaneseModifiedHepburnLanguageModelTest {
+    private JapaneseModifiedHepburnLanguageModel model;
path: lingetic-spring-backend/src/test/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/JapaneseModifiedHepburnLanguageModelTest.java
user: login: cubic-dev-ai[bot]
body: <!-- metadata:{"confidence":8,"steps":[{"text":"I'll review the changed lines in the JapaneseModifiedHepburnLanguageModelTest.java file for potential issues. Let me analyze the code systematically.","toolCalls":[{"args":{"pattern":"**/JapaneseModifiedHepburnLanguageModel.java"},"toolName":"listFiles"}]},{"text":"Let me examine the implementation of the JapaneseModifiedHepburnLanguageModel class to better understand what's being tested:","toolCalls":[{"args":{"command":"cat lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/JapaneseModifiedHepburnLanguageModel.java"},"toolName":"executeCommand"}]},{"text":"Let me also check the LatinScriptLanguageModelHelper class since it's used by the JapaneseModifiedHepburnLanguageModel:","toolCalls":[{"args":{"command":"cat lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/LatinScriptLanguageModelHelper.java"},"toolName":"executeCommand"}]},{"text":"Let me also check the Language enum to understand the JapaneseModifiedHepburn language definition:","toolCalls":[{"args":{"command":"cat lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/Language.java"},"toolName":"executeCommand"}]}]} -->
The test class doesn't verify integration with the LatinScriptLanguageModelHelper that the implementation depends on
created_at: 2025-05-08T15:16:10Z
author_association: NONE
diff_hunk: @@ -0,0 +1,106 @@
+package com.munetmo.lingetic.LanguageService.Entities.LanguageModels;
+
+import com.munetmo.lingetic.LanguageService.Entities.Language;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class JapaneseModifiedHepburnLanguageModelTest {
+    private JapaneseModifiedHepburnLanguageModel model;
+
+    @BeforeEach
+    void setUp() {
+        model = new JapaneseModifiedHepburnLanguageModel();
+    }
+
+    @Test
+    void getLanguageShouldReturnJapaneseModifiedHepburn() {
+        assertEquals(Language.JapaneseModifiedHepburn, model.getLanguage());
+    }
+
+    @Test
+    void tokenizeShouldHandleEmptyStrings() {
path: lingetic-spring-backend/src/test/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/JapaneseModifiedHepburnLanguageModelTest.java
user: login: cubic-dev-ai[bot]
body: <!-- metadata:{"confidence":10,"steps":[{"text":"I'll review the changed lines in the JapaneseModifiedHepburnLanguageModelTest.java file for potential issues. Let me analyze the code systematically.","toolCalls":[{"args":{"pattern":"**/JapaneseModifiedHepburnLanguageModel.java"},"toolName":"listFiles"}]},{"text":"Let me examine the implementation of the JapaneseModifiedHepburnLanguageModel class to better understand what's being tested:","toolCalls":[{"args":{"command":"cat lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/JapaneseModifiedHepburnLanguageModel.java"},"toolName":"executeCommand"}]},{"text":"Let me also check the LatinScriptLanguageModelHelper class since it's used by the JapaneseModifiedHepburnLanguageModel:","toolCalls":[{"args":{"command":"cat lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/LatinScriptLanguageModelHelper.java"},"toolName":"executeCommand"}]},{"text":"Let me also check the Language enum to understand the JapaneseModifiedHepburn language definition:","toolCalls":[{"args":{"command":"cat lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/Language.java"},"toolName":"executeCommand"}]}]} -->
Test method doesn't verify tokenization of actual Japanese text or romanized Japanese with macrons
created_at: 2025-05-08T15:16:10Z
author_association: NONE
diff_hunk: @@ -0,0 +1,255 @@
+package com.munetmo.lingetic.LanguageService.Entities.LanguageModels;
+
+import com.munetmo.lingetic.LanguageService.Entities.Language;
+import com.munetmo.lingetic.LanguageService.Entities.TokenType;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class JapaneseModifiedHepburnLanguageModelTest {
path: lingetic-spring-backend/src/test/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/JapaneseModifiedHepburnLanguageModelTest.java
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**Consider adding JavaDoc to the test class to explain its purpose**

The test class would benefit from a class-level JavaDoc explaining the purpose of the Japanese Modified Hepburn romanization model, what features it's expected to support (especially macrons), and how it differs from other romanization systems.

```java
/**
 * Tests for the JapaneseModifiedHepburnLanguageModel which handles the Modified Hepburn romanization system.
 * The Modified Hepburn system uses macrons (ā, ī, ū, ē, ō) to represent long vowels in romanized Japanese,
 * which distinguishes words with different meanings but similar pronunciation (e.g., "yuki" (snow) vs "yūki" (courage)).
 */
```

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-08T15:45:32Z
author_association: NONE
diff_hunk: @@ -0,0 +1,255 @@
+package com.munetmo.lingetic.LanguageService.Entities.LanguageModels;
+
+import com.munetmo.lingetic.LanguageService.Entities.Language;
+import com.munetmo.lingetic.LanguageService.Entities.TokenType;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class JapaneseModifiedHepburnLanguageModelTest {
+    private JapaneseModifiedHepburnLanguageModel model;
+
+    @BeforeEach
+    void setUp() {
+        model = new JapaneseModifiedHepburnLanguageModel();
+    }
+
+    @Test
+    void getLanguageShouldReturnJapaneseModifiedHepburn() {
+        assertEquals(Language.JapaneseModifiedHepburn, model.getLanguage());
+    }
+
+    @Test
+    void tokenizeShouldHandleEmptyStrings() {
+        assertTrue(model.tokenize("").isEmpty());
+        assertTrue(model.tokenize(" ").isEmpty());
+    }
+
+    @Test
+    void areEquivalentShouldHandleEmptyStrings() {
+        assertTrue(model.areEquivalent("", ""));
+        assertTrue(model.areEquivalent(" ", " "));
+        assertTrue(model.areEquivalent(" ", ""));
+    }
+
+    @Test
+    void areEquivalentShouldMatchRomanizedForms() {
+        assertTrue(model.areEquivalent("inu", "inu"));
+    }
+
+    @Test
+    void areEquivalentShouldIgnorePunctuation() {
+        assertTrue(model.areEquivalent("inu!", "inu"));
+    }
path: lingetic-spring-backend/src/test/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/JapaneseModifiedHepburnLanguageModelTest.java
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**Enhance this test with multiple varieties of punctuation**

While this test correctly verifies that punctuation is ignored in equivalence checks, consider testing more complex cases with multiple punctuation marks and in different positions.

```diff
-    void areEquivalentShouldIgnorePunctuation() {
-        assertTrue(model.areEquivalent("inu!", "inu"));
+    void areEquivalentShouldIgnorePunctuation() {
+        assertTrue(model.areEquivalent("inu!", "inu"));
+        assertTrue(model.areEquivalent("!inu", "inu"));
+        assertTrue(model.areEquivalent("i!nu", "inu"));
+        assertTrue(model.areEquivalent("i.n,u!", "inu"));
```

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-08T15:45:32Z
author_association: NONE
diff_hunk: @@ -0,0 +1,255 @@
+package com.munetmo.lingetic.LanguageService.Entities.LanguageModels;
+
+import com.munetmo.lingetic.LanguageService.Entities.Language;
+import com.munetmo.lingetic.LanguageService.Entities.TokenType;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class JapaneseModifiedHepburnLanguageModelTest {
+    private JapaneseModifiedHepburnLanguageModel model;
+
+    @BeforeEach
+    void setUp() {
+        model = new JapaneseModifiedHepburnLanguageModel();
+    }
+
+    @Test
+    void getLanguageShouldReturnJapaneseModifiedHepburn() {
+        assertEquals(Language.JapaneseModifiedHepburn, model.getLanguage());
+    }
+
+    @Test
+    void tokenizeShouldHandleEmptyStrings() {
+        assertTrue(model.tokenize("").isEmpty());
+        assertTrue(model.tokenize(" ").isEmpty());
+    }
+
+    @Test
+    void areEquivalentShouldHandleEmptyStrings() {
+        assertTrue(model.areEquivalent("", ""));
+        assertTrue(model.areEquivalent(" ", " "));
+        assertTrue(model.areEquivalent(" ", ""));
+    }
+
+    @Test
+    void areEquivalentShouldMatchRomanizedForms() {
+        assertTrue(model.areEquivalent("inu", "inu"));
+    }
+
+    @Test
+    void areEquivalentShouldIgnorePunctuation() {
+        assertTrue(model.areEquivalent("inu!", "inu"));
+    }
+
+    @Test
+    void areEquivalentShouldWorkWithMacronA() {
+        assertTrue(model.areEquivalent("kādo", "kādo")); // card
+        assertFalse(model.areEquivalent("kādo", "kaado"));
+        assertTrue(model.areEquivalent("KĀDO", "kādo")); // case insensitive
+        assertFalse(model.areEquivalent("kado", "kādo")); // different meaning
+    }
+
+    @Test
+    void areEquivalentShouldWorkWithMacronI() {
+        assertTrue(model.areEquivalent("onīsan", "onīsan")); // older brother
+        assertFalse(model.areEquivalent("onīsan", "oniisan"));
+        assertTrue(model.areEquivalent("ONĪSAN", "onīsan")); // case insensitive
+        assertFalse(model.areEquivalent("onisan", "onīsan")); // different meaning
+    }
+
+    @Test
+    void areEquivalentShouldWorkWithMacronU() {
+        assertTrue(model.areEquivalent("yūki", "yūki")); // courage
+        assertFalse(model.areEquivalent("yūki", "yuuki"));
+        assertTrue(model.areEquivalent("YŪKI", "yūki")); // case insensitive
+        assertFalse(model.areEquivalent("yuki", "yūki")); // different meaning (snow vs courage)
+    }
+
+    @Test
+    void areEquivalentShouldWorkWithMacronE() {
+        assertTrue(model.areEquivalent("onēsan", "onēsan")); // older sister
+        assertFalse(model.areEquivalent("onēsan", "oneesan"));
+        assertTrue(model.areEquivalent("ONĒSAN", "onēsan")); // case insensitive
+        assertFalse(model.areEquivalent("onesan", "onēsan")); // different meaning
+    }
+
+    @Test
+    void areEquivalentShouldWorkWithMacronO() {
+        assertTrue(model.areEquivalent("tōkyō", "tōkyō")); // Tokyo
+        assertFalse(model.areEquivalent("tōkyō", "toukyou"));
+        assertTrue(model.areEquivalent("TŌKYŌ", "tōkyō")); // case insensitive
+        assertFalse(model.areEquivalent("tokyo", "tōkyō")); // incorrect romanization
+    }
+
+    @Test
+    void areEquivalentShouldWorkWithMultipleMacrons() {
+        assertTrue(model.areEquivalent("tōkyō", "tōkyō")); // Tokyo
+        assertTrue(model.areEquivalent("kyōsō", "kyōsō")); // competition
+        assertTrue(model.areEquivalent("shōchū", "shōchū")); // distilled spirits
+        assertTrue(model.areEquivalent("kōkōsei", "kōkōsei")); // high school student
+    }
+
+    @Test
+    void areEquivalentShouldHandleMacronsWithPunctuation() {
+        assertTrue(model.areEquivalent("Tōkyō!", "tōkyō"));
+        assertTrue(model.areEquivalent("Tōkyō?", "tōkyō"));
+        assertTrue(model.areEquivalent("Tōkyō...", "tōkyō"));
+    }
+
+    @Test
+    void areEquivalentShouldHandleMacronsWithSpaces() {
+        assertTrue(model.areEquivalent("  tōkyō  ", "tōkyō"));
+        assertFalse(model.areEquivalent("Tōkyō-to", "tōkyō to")); // Tokyo metropolis
+        assertTrue(model.areEquivalent("Tōkyō\tto", "tōkyō to"));
+    }
+
+    @Test
+    void tokenizeShouldHandleTokenTypes() {
+        var tokens = model.tokenize("Watashi wa 25-sai desu.");
+
+        assertEquals(5, tokens.size());
+
+        assertEquals(TokenType.Word, tokens.get(0).type());
+        assertEquals("Watashi", tokens.get(0).value());
+
+        assertEquals(TokenType.Word, tokens.get(1).type());
+        assertEquals("wa", tokens.get(1).value());
+
+        assertEquals(TokenType.Word, tokens.get(2).type());
+        assertEquals("25-sai", tokens.get(2).value());
+
+        assertEquals(TokenType.Word, tokens.get(3).type());
+        assertEquals("desu", tokens.get(3).value());
+
+        assertEquals(TokenType.Punctuation, tokens.get(4).type());
+        assertEquals(".", tokens.get(4).value());
+    }
+
+    @Test
+    void tokenizeShouldHandleMacronsInWords() {
+        var tokens = model.tokenize("Tōkyō wa ōkii desu.");
+
+        assertEquals(5, tokens.size());
+
+        assertEquals(TokenType.Word, tokens.get(0).type());
+        assertEquals("Tōkyō", tokens.get(0).value());
+
+        assertEquals(TokenType.Word, tokens.get(1).type());
+        assertEquals("wa", tokens.get(1).value());
+
+        assertEquals(TokenType.Word, tokens.get(2).type());
+        assertEquals("ōkii", tokens.get(2).value());
+
+        assertEquals(TokenType.Word, tokens.get(3).type());
+        assertEquals("desu", tokens.get(3).value());
+
+        assertEquals(TokenType.Punctuation, tokens.get(4).type());
+        assertEquals(".", tokens.get(4).value());
+    }
+
+    @Test
+    void tokenizeShouldHandleJapaneseQuotations() {
+        var tokens = model.tokenize("Sensei wa \"Konnichiwa\" to iimashita.");
+
+        assertEquals(8, tokens.size());
+
+        assertEquals(TokenType.Word, tokens.get(0).type());
+        assertEquals("Sensei", tokens.get(0).value());
+
+        assertEquals(TokenType.Word, tokens.get(1).type());
+        assertEquals("wa", tokens.get(1).value());
+
+        assertEquals(TokenType.Punctuation, tokens.get(2).type());
+        assertEquals("\"", tokens.get(2).value());
+
+        assertEquals(TokenType.Word, tokens.get(3).type());
+        assertEquals("Konnichiwa", tokens.get(3).value());
+
+        assertEquals(TokenType.Punctuation, tokens.get(4).type());
+        assertEquals("\"", tokens.get(4).value());
+
+        assertEquals(TokenType.Word, tokens.get(5).type());
+        assertEquals("to", tokens.get(5).value());
+
+        assertEquals(TokenType.Word, tokens.get(6).type());
+        assertEquals("iimashita", tokens.get(6).value());
+
+        assertEquals(TokenType.Punctuation, tokens.get(7).type());
+        assertEquals(".", tokens.get(7).value());
+    }
+
+    @Test
+    void tokenizeShouldHandleNumbers() {
+        var tokens = model.tokenize("Kurasu ni 42-nin imasu.");
+        assertEquals(5, tokens.size());
+
+        assertEquals(TokenType.Word, tokens.get(0).type());
+        assertEquals("Kurasu", tokens.get(0).value());
+
+        assertEquals(TokenType.Word, tokens.get(1).type());
+        assertEquals("ni", tokens.get(1).value());
+
+        assertEquals(TokenType.Word, tokens.get(2).type());
+        assertEquals("42-nin", tokens.get(2).value());
+
+        assertEquals(TokenType.Word, tokens.get(3).type());
+        assertEquals("imasu", tokens.get(3).value());
+
+        assertEquals(TokenType.Punctuation, tokens.get(4).type());
+        assertEquals(".", tokens.get(4).value());
+    }
+
+    @Test
+    void tokenizeShouldHandleComplexPunctuation() {
+        var tokens = model.tokenize("Sugoi...! Hontō?!");
+
+        assertEquals(8, tokens.size());
+
+        assertEquals(TokenType.Word, tokens.get(0).type());
+        assertEquals("Sugoi", tokens.get(0).value());
+
+        assertEquals(TokenType.Punctuation, tokens.get(1).type());
+        assertEquals(".", tokens.get(1).value());
+
+        assertEquals(TokenType.Punctuation, tokens.get(2).type());
+        assertEquals(".", tokens.get(2).value());
+
+        assertEquals(TokenType.Punctuation, tokens.get(3).type());
+        assertEquals(".", tokens.get(3).value());
+
+        assertEquals(TokenType.Punctuation, tokens.get(4).type());
+        assertEquals("!", tokens.get(4).value());
+
+        assertEquals(TokenType.Word, tokens.get(5).type());
+        assertEquals("Hontō", tokens.get(5).value());
+
+        assertEquals(TokenType.Punctuation, tokens.get(6).type());
+        assertEquals("?", tokens.get(6).value());
+
+        assertEquals(TokenType.Punctuation, tokens.get(7).type());
+        assertEquals("!", tokens.get(7).value());
+    }
+
+    @Test
+    void tokenizeShouldKeepNumbersAndLettersSeparate() {
+        var tokens = model.tokenize("Room 101A wa doko desu ka?");
+
+        assertEquals(7, tokens.size());
+        assertEquals(TokenType.Word, tokens.get(0).type());
+        assertEquals("Room", tokens.get(0).value());
+        assertEquals(TokenType.Word, tokens.get(1).type());
+        assertEquals("101A", tokens.get(1).value());
+        assertEquals(TokenType.Word, tokens.get(2).type());
+        assertEquals("wa", tokens.get(2).value());
+        assertEquals(TokenType.Word, tokens.get(3).type());
+        assertEquals("doko", tokens.get(3).value());
+        assertEquals(TokenType.Word, tokens.get(4).type());
+        assertEquals("desu", tokens.get(4).value());
+        assertEquals(TokenType.Word, tokens.get(5).type());
+        assertEquals("ka", tokens.get(5).value());
+        assertEquals(TokenType.Punctuation, tokens.get(6).type());
+        assertEquals("?", tokens.get(6).value());
+    }
+}
path: lingetic-spring-backend/src/test/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/JapaneseModifiedHepburnLanguageModelTest.java
user: login: coderabbitai[bot]
body: _💡 Verification agent_

<details>
<summary>🧩 Analysis chain</summary>

**Add unit tests for bidirectional conversion**

While the current tests verify various aspects of the language model, they don't comprehensively test bidirectional conversion between Japanese text and romanized forms. Adding tests that convert from Japanese to romanized and back would ensure the model works correctly in both directions.



```java
@Test
void testBidirectionalConversion() {
    // Test Japanese to romanized
    assertTrue(model.areEquivalent("東京", "tōkyō"));
    assertTrue(model.areEquivalent("お兄さん", "onīsan"));
    
    // Test with sentences containing multiple elements
    assertTrue(model.areEquivalent("東京は大きい都市です。", "Tōkyō wa ōkii toshi desu."));
}
```

---

🏁 Script executed:

```shell
#!/bin/bash
# Find and examine the implementation of JapaneseModifiedHepburnLanguageModel
cat lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/JapaneseModifiedHepburnLanguageModel.java
```

Length of output: 927

---



</details>

**Introduce explicit conversion methods before adding bidirectional‐conversion tests**

The current `LanguageModel` interface (and its `JapaneseModifiedHepburnLanguageModel` implementation) only provides `areEquivalent(String, String)` and `tokenize(String)`—there is no way to directly convert Japanese script into its romanized form (or vice versa). Before writing tests that verify round-trip conversion, please:

• Extend `LanguageModel` with two new methods, for example:  
  • `String toRoman(String nativeText)`  
  • `String toNative(String romanText)`

• Delegate these in `JapaneseModifiedHepburnLanguageModel` to the underlying `LatinScriptLanguageModelHelper` (or implement the conversions yourself).

• Then add unit tests such as:  
```java
@Test
void testBidirectionalConversion() {
    // Japanese ⇒ Romanized
    assertEquals("tōkyō", model.toRoman("東京"));
    // Romanized ⇒ Japanese
    assertEquals("東京", model.toNative("tōkyō"));
    // Round-trip on a sentence
    String sentence = "東京は大きい都市です。";
    String roman   = "Tōkyō wa ōkii toshi desu.";
    assertEquals(roman, model.toRoman(sentence));
    assertEquals(sentence, model.toNative(roman));
}
```

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-08T15:45:32Z
author_association: NONE
diff_hunk: @@ -79,6 +79,28 @@
 Reason: Both words `駅` (station) and `へ` (direction particle) are relevant to the theme and instructions, as they deal with locations and particles used for indicating direction.
         """,
     },
+    "JapaneseModifiedHepburn": {
+        "sentence": "gakusei wa toshokan de benkyou shimasu",
+        "word1": "de",
+        "word2": ["gakusei", "toshokan"],
+        "blank1": "gakusei wa toshokan ____ benkyou shimasu",
+        "blank2": [
+            "_____ wa toshokan de benkyou shimasu",
+            "gakusei wa _____ de benkyou shimasu",
+        ],
+        "example": """
+Example:
+Words: [{{"type":"Word","value":"watashi","sequenceNumber":1}},{{"type":"Word","value":"wa","sequenceNumber":2}},{{"type":"Word","value":"eki","sequenceNumber":3}},{{"type":"Word","value":"e","sequenceNumber":4}},{{"type":"Word","value":"ikimasu","sequenceNumber":5}}]
+
+Theme: Basic Locations and Transportation
+Instructions: Teach basic location particles (e, ni, de) and verbs of motion (iku, kuru). Focus on simple sentence structures using basic particles. Average sentence length: 3-5 words.
+
+Output:
+{{ "selectedWordsSequenceNumbers": [3, 4] }}
+
+Reason: Both words `eki` (station) and `e` (direction particle) are relevant to the theme and instructions, as they deal with locations and particles used for indicating direction.
+        """,
+    },
path: scripts/scripts/questions.py
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Fix inconsistent example tokens for JapaneseModifiedHepburn.**

The `sentence` field is `"gakusei wa toshokan de benkyou shimasu"`, but the `example` block still lists tokens for `"watashi wa eki e ikimasu"`. This mismatch can confuse both humans and the model. Update the token list to reflect the new sentence:

```diff
-Example:
-Words: [{{"type":"Word","value":"watashi","sequenceNumber":1}},{{"type":"Word","value":"wa","sequenceNumber":2}},{{"type":"Word","value":"eki","sequenceNumber":3}},{{"type":"Word","value":"e","sequenceNumber":4}},{{"type":"Word","value":"ikimasu","sequenceNumber":5}}]
+Example:
+Words: [{{"type":"Word","value":"gakusei","sequenceNumber":1}},{{"type":"Word","value":"wa","sequenceNumber":2}},{{"type":"Word","value":"toshokan","sequenceNumber":3}},{{"type":"Word","value":"de","sequenceNumber":4}},{{"type":"Word","value":"benkyou","sequenceNumber":5}},{{"type":"Word","value":"shimasu","sequenceNumber":6}}]
```



<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
        "example": """
Example:
Words: [{{"type":"Word","value":"gakusei","sequenceNumber":1}},{{"type":"Word","value":"wa","sequenceNumber":2}},{{"type":"Word","value":"toshokan","sequenceNumber":3}},{{"type":"Word","value":"de","sequenceNumber":4}},{{"type":"Word","value":"benkyou","sequenceNumber":5}},{{"type":"Word","value":"shimasu","sequenceNumber":6}}]

Theme: Basic Locations and Transportation
Instructions: Teach basic location particles (e, ni, de) and verbs of motion (iku, kuru). Focus on simple sentence structures using basic particles. Average sentence length: 3-5 words.

Output:
{{ "selectedWordsSequenceNumbers": [3, 4] }}

Reason: Both words `eki` (station) and `e` (direction particle) are relevant to the theme and instructions, as they deal with locations and particles used for indicating direction.
        """,
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-08T17:22:06Z
author_association: NONE
diff_hunk: @@ -48,9 +48,15 @@ export const languages: LanguageProperty[] = [
     image: "/img/languages/portuguese-flag.png",
     isSupported: false,
   },
+  {
+    id: "JapaneseModifiedHepburn",
+    name: "Japanese 1",
+    image: "/img/languages/japanese-flag.png",
+    isSupported: true,
+  },
path: lingetic-nextjs-frontend/app/languages/constants.ts
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Consider using more descriptive language names**

The new "Japanese 1" display name doesn't clearly indicate that this is the Japanese Modified Hepburn romanization system. Users may be confused about the difference between "Japanese 1" and "Japanese 2". Consider using more descriptive names like "Japanese (Modified Hepburn)" and "Japanese (Standard)" to make the distinction clearer.

```diff
  {
    id: "JapaneseModifiedHepburn",
-    name: "Japanese 1",
+    name: "Japanese (Modified Hepburn)",
    image: "/img/languages/japanese-flag.png",
    isSupported: true,
  },
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
  {
    id: "JapaneseModifiedHepburn",
    name: "Japanese (Modified Hepburn)",
    image: "/img/languages/japanese-flag.png",
    isSupported: true,
  },
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-08T17:40:08Z
author_association: NONE
diff_hunk: @@ -48,9 +48,15 @@ export const languages: LanguageProperty[] = [
     image: "/img/languages/portuguese-flag.png",
     isSupported: false,
   },
+  {
+    id: "JapaneseModifiedHepburn",
+    name: "Japanese 1",
+    image: "/img/languages/japanese-flag.png",
+    isSupported: true,
+  },
   {
     id: "Japanese",
-    name: "Japanese",
+    name: "Japanese 2",
path: lingetic-nextjs-frontend/app/languages/constants.ts
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Update Japanese naming for consistency**

For consistency with the suggestion above, consider renaming this to be more descriptive about what type of Japanese romanization this represents.

```diff
-    name: "Japanese 2",
+    name: "Japanese (Standard)",
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
    name: "Japanese (Standard)",
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-08T17:40:08Z
author_association: NONE

PR comments:
user: login: vercel[bot]
created_at: 2025-05-08T15:13:33Z
body: [vc]: #LVvo6LA9q4RlmlN5LsD7cH6cOPDTln/P/h0Xy6jjhIY=:eyJpc01vbm9yZXBvIjp0cnVlLCJ0eXBlIjoiZ2l0aHViIiwicHJvamVjdHMiOlt7Im5hbWUiOiJsaW5nZXRpYyIsImluc3BlY3RvclVybCI6Imh0dHBzOi8vdmVyY2VsLmNvbS9hYmhpa3IyMTAwcy1wcm9qZWN0cy9saW5nZXRpYy83WlNBNm9iZFFhcm04UXlNNm10eUNzQVFCdFFIIiwicHJldmlld1VybCI6ImxpbmdldGljLWdpdC0wNS0wOC1hZGRhcm9tYWppLWJhc2VkLTZkZDE4YS1hYmhpa3IyMTAwcy1wcm9qZWN0cy52ZXJjZWwuYXBwIiwibmV4dENvbW1pdFN0YXR1cyI6IkRFUExPWUVEIiwibGl2ZUZlZWRiYWNrIjp7InJlc29sdmVkIjowLCJ1bnJlc29sdmVkIjowLCJ0b3RhbCI6MCwibGluayI6ImxpbmdldGljLWdpdC0wNS0wOC1hZGRhcm9tYWppLWJhc2VkLTZkZDE4YS1hYmhpa3IyMTAwcy1wcm9qZWN0cy52ZXJjZWwuYXBwIn0sInJvb3REaXJlY3RvcnkiOiJsaW5nZXRpYy1uZXh0anMtZnJvbnRlbmQifV19
**The latest updates on your projects**. Learn more about [Vercel for Git ↗︎](https://vercel.link/github-learn-more)

| Name | Status | Preview | Comments | Updated (UTC) |
| :--- | :----- | :------ | :------- | :------ |
| **lingetic** | ✅ Ready ([Inspect](https://vercel.com/abhikr2100s-projects/lingetic/7ZSA6obdQarm8QyM6mtyCsAQBtQH)) | [Visit Preview](https://lingetic-git-05-08-addaromaji-based-6dd18a-abhikr2100s-projects.vercel.app) | 💬 [**Add feedback**](https://vercel.live/open-feedback/lingetic-git-05-08-addaromaji-based-6dd18a-abhikr2100s-projects.vercel.app?via=pr-comment-feedback-link) | May 8, 2025 5:45pm |


author_association: NONE
user: login: coderabbitai[bot]
created_at: 2025-05-08T15:13:38Z
body: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- This is an auto-generated comment: failure by coderabbit.ai -->

> [!CAUTION]
> ## Review failed
> 
> The pull request is closed.

<!-- end of auto-generated comment: failure by coderabbit.ai -->
<!-- walkthrough_start -->

"""
## Walkthrough

A new language, "JapaneseModifiedHepburn," was integrated into the backend system. This includes updates to the language enum, the addition of a dedicated language model class, adjustments to the sealed interface and its language model registry, an extension of recognized Latin characters, a database migration script for the new language, and comprehensive unit tests.

## Changes

| File(s)                                                                                      | Change Summary                                                                                           |
|---------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------|
| .../Entities/Language.java                                                                   | Added `JapaneseModifiedHepburn` to the `Language` enum.                                                 |
| .../Entities/LanguageModels/JapaneseModifiedHepburnLanguageModel.java                        | Introduced `JapaneseModifiedHepburnLanguageModel` class implementing `LanguageModel` for the new enum.  |
| .../Entities/LanguageModels/LanguageModel.java                                               | Added `JapaneseModifiedHepburnLanguageModel` to permits clause and registered it in the languageModels map. |
| .../Entities/LanguageModels/LatinScriptLanguageModelHelper.java                              | Appended "āīūēō" to the `SPECIFIC_CHARACTERS` constant.                                                 |
| .../resources/db/migration/V7__Add_Japanese_Modified_Hepburn_Language.sql                   | Added SQL migration to insert 'JapaneseModifiedHepburn' into the `languages` table.                     |
| .../Entities/LanguageModels/JapaneseModifiedHepburnLanguageModelTest.java                    | Added unit tests for `JapaneseModifiedHepburnLanguageModel`, covering tokenization and equivalence logic.|
| .../resources/META-INF/native-image/.../reachability-metadata.json                          | Added new migration script file to native image reachability metadata resources.                        |
| scripts/scripts/course.py                                                                    | Added "JapaneseModifiedHepburn" example prompt template with sample Japanese verb sentences in romanization. |
| scripts/scripts/questions.py                                                                 | Added "JapaneseModifiedHepburn" language example with fill-in-the-blank question templates.             |
| scripts/scripts/tts.py                                                                       | Added `"JapaneseModifiedHepburn": "ja"` mapping to `LANGUAGE_TO_CODE` dictionary.                       |
| lingetic-nextjs-frontend/app/languages/constants.ts                                         | Added new language entry "JapaneseModifiedHepburn" as "Japanese 1" and renamed existing Japanese to "Japanese 2". Added mapping for "ja-hepburn". |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant Client
    participant LanguageModelRegistry
    participant JapaneseModifiedHepburnLanguageModel
    participant LatinScriptLanguageModelHelper

    Client->>LanguageModelRegistry: Get LanguageModel for JapaneseModifiedHepburn
    LanguageModelRegistry-->>Client: JapaneseModifiedHepburnLanguageModel instance

    Client->>JapaneseModifiedHepburnLanguageModel: areEquivalent(s1, s2)
    JapaneseModifiedHepburnLanguageModel->>LatinScriptLanguageModelHelper: areEquivalent(s1, s2)
    LatinScriptLanguageModelHelper-->>JapaneseModifiedHepburnLanguageModel: Result
    JapaneseModifiedHepburnLanguageModel-->>Client: Result

    Client->>JapaneseModifiedHepburnLanguageModel: tokenize(input)
    JapaneseModifiedHepburnLanguageModel->>LatinScriptLanguageModelHelper: tokenize(input)
    LatinScriptLanguageModelHelper-->>JapaneseModifiedHepburnLanguageModel: Token list
    JapaneseModifiedHepburnLanguageModel-->>Client: Token list
```

## Possibly related PRs

- #196: Adds support for the French language model with similar enum, class, and test additions, paralleling the structure of this PR but targeting a different language.

## Poem

> In Hepburn’s name, a change arrives,  
> With macrons long, the language thrives.  
> A model new, with tests to show,  
> That ō and ū now truly glow.  
> The database learns a word anew—  
> Japanese romanized, crisp and true!  
> 🐇✨
"""

<!-- walkthrough_end -->
<!-- internal state start -->


<!-- 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 -->

<!-- internal state end -->

---

<details>
<summary>📜 Recent review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: ASSERTIVE**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between f105473c8e5691480d306439615e13989461dd51 and 30e9ea963962d6d9ed92318529112b3068021843.

</details>

<details>
<summary>📒 Files selected for processing (11)</summary>

* `lingetic-nextjs-frontend/app/languages/constants.ts` (2 hunks)
* `lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/Language.java` (1 hunks)
* `lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/JapaneseModifiedHepburnLanguageModel.java` (1 hunks)
* `lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/LanguageModel.java` (2 hunks)
* `lingetic-spring-backend/src/main/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/LatinScriptLanguageModelHelper.java` (1 hunks)
* `lingetic-spring-backend/src/main/resources/META-INF/native-image/com.munetmo/lingetic/reachability-metadata.json` (1 hunks)
* `lingetic-spring-backend/src/main/resources/db/migration/V7__Add_Japanese_Modified_Hepburn_Language.sql` (1 hunks)
* `lingetic-spring-backend/src/test/java/com/munetmo/lingetic/LanguageService/Entities/LanguageModels/JapaneseModifiedHepburnLanguageModelTest.java` (1 hunks)
* `scripts/scripts/course.py` (1 hunks)
* `scripts/scripts/questions.py` (1 hunks)
* `scripts/scripts/tts.py` (1 hunks)

</details>

</details>
<!-- finishing_touch_checkbox_start -->

<details open="true">
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

<details>
<summary>❤️ Share</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)

</details>

<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=abhi-kr-2100/Lingetic&utm_content=278):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Generate unit testing code for this file.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai generate unit testing code for this file.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and generate unit testing code.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

### Support

Need help? Create a ticket on our [support page](https://www.coderabbit.ai/contact-us/support) for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai generate sequence diagram` to generate a sequence diagram of the changes in this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
author_association: NONE
user: login: abhi-kr-2100
created_at: 2025-05-08T15:13:47Z
body: * **#278** <a href="https://app.graphite.dev/github/pr/abhi-kr-2100/Lingetic/278?utm_source=stack-comment-icon" target="_blank"><img src="https://static.graphite.dev/graphite-32x32-black.png" alt="Graphite" width="10px" height="10px"/></a> 👈 <a href="https://app.graphite.dev/github/pr/abhi-kr-2100/Lingetic/278?utm_source=stack-comment-view-in-graphite" target="_blank">(View in Graphite)</a>
* **#277** <a href="https://app.graphite.dev/github/pr/abhi-kr-2100/Lingetic/277?utm_source=stack-comment-icon" target="_blank"><img src="https://static.graphite.dev/graphite-32x32-black.png" alt="Graphite" width="10px" height="10px"/></a>
* `main`


<h2></h2>

This stack of pull requests is managed by <a href="https://graphite.dev?utm-source=stack-comment"><b>Graphite</b></a>. Learn more about <a href="https://stacking.dev/?utm_source=stack-comment">stacking</a>.
<!-- Current dependencies on/for this PR: -->
author_association: OWNER
user: login: abhi-kr-2100
created_at: 2025-05-08T17:42:37Z
body: ### Merge activity

* **May 8, 1:42 PM EDT**: A user started a stack merge that includes this pull request via [Graphite](https://app.graphite.dev/github/pr/abhi-kr-2100/Lingetic/278).
* **May 8, 1:43 PM EDT**: [Graphite](https://app.graphite.dev/github/pr/abhi-kr-2100/Lingetic/278) rebased this pull request as part of a merge.
* **May 8, 1:44 PM EDT**: @abhi-kr-2100 merged this pull request with [Graphite](https://app.graphite.dev/github/pr/abhi-kr-2100/Lingetic/278).

author_association: OWNER