feat(dictionary): Japanese cut into words and looked up on the device

Once the person agrees, the device holds MeCab's IPADIC and the
instance's JMdict and cuts lines as Jisho.org does, so their text never
leaves it (ADR 0012). MeCab comes through mecab_for_dart, whose build
hook compiles it; its tokens are grouped by Ve's rules, written anew in
Dart, with に kept a word of its own. Each word is found as it stands or
as a form of a word, else by its dictionary form, else as the longest
words it holds from token to token; longer words over token boundaries
are offered as before.

The curator packs Ubuntu's compiled IPADIC beside the dictionary files
(curate ipadic, and every update run). The server exports its JMdict
from its tables, so the device finds the same keys and keeps the same
versions, and serves both at /device-dictionaries/, named in
dictionary.deviceFiles('ja') with their hashes; Caddy forwards the path.

The app checks each file against its hash, unpacks IPADIC, builds a
SQLite database from the export on an isolate, and asks the instance
for newer files every 30 days, downloading only what changed. The Watch
screen offers the download once per device with its size (34 MB, some
150 MB once set up); Settings downloads and removes them. Without them,
or should cutting on the device fail, lines go to the instance as
before. MeCab's, IPADIC's and Ve's licences join the licence list.

Every build now needs a C++ compiler; mecab_for_dart holds code_assets
at 1.x.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
Tizian 「ティツィアーン」 2026-10-15 21:55:00 +02:00
commit 1d2011a676
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64

View file

@ -7064,7 +7064,62 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get jellyfinPrivacy =>
'Die Adresse deines Servers und deine Anmeldung bleiben auf diesem Gerät, und was du mit einem Lernset verbindest, folgt dir als IDs, nie als Titel. Um die Wörter einer Zeile zu finden, fragt die App die Instanz nach ihrem Text; sie antwortet und speichert ihn nicht. Wörter, die du hinzufügst, bekommen Tags, wo du ihnen begegnet bist, gespeichert mit deinen Karteikarten wie jeder Tag.';
'Die Adresse deines Servers und deine Anmeldung bleiben auf diesem Gerät, und was du mit einem Lernset verbindest, folgt dir als IDs, nie als Titel. Um die Wörter einer Zeile zu finden, fragt die App die Instanz nach ihrem Text; sie antwortet und speichert ihn nicht, außer die japanischen Wörterbücher sind auf diesem Gerät (Einstellungen): Dann schlägt die App sie hier nach. Wörter, die du hinzufügst, bekommen Tags, wo du ihnen begegnet bist, gespeichert mit deinen Karteikarten wie jeder Tag.';
@override
String get deviceDictionaryOfferTitle =>
'Wörter auf diesem Gerät nachschlagen?';
@override
String deviceDictionaryOfferBody(String size) {
return 'Lade die japanischen Wörterbücher einmal herunter ($size, eingerichtet mehr), um Zeilen hier in Wörter zu zerlegen, wie Jisho.org es tut. Ihr Text verlässt dieses Gerät dann nicht mehr.';
}
@override
String get deviceDictionaryOfferDownload => 'Herunterladen';
@override
String get deviceDictionaryOfferLater => 'Nicht jetzt';
@override
String deviceDictionaryDownloading(String received, String total) {
return 'Wird heruntergeladen: $received von $total';
}
@override
String get deviceDictionaryPreparing => 'Wird eingerichtet…';
@override
String get deviceDictionaryReady =>
'Wörter werden jetzt auf diesem Gerät nachgeschlagen.';
@override
String get deviceDictionaryFailed =>
'Die Wörterbücher konnten nicht heruntergeladen werden. Versuch es in den Einstellungen noch einmal.';
@override
String get settingsDeviceDictionaryTitle => 'Japanisch auf diesem Gerät';
@override
String get settingsDeviceDictionaryAbout =>
'Mit den japanischen Wörterbüchern auf diesem Gerät werden die Zeilen von Videos und Liedern hier in Wörter zerlegt, wie Jisho.org es tut, und ihr Text verlässt es nicht. Ohne sie fragt die App die Instanz, die antwortet und nichts speichert.';
@override
String settingsDeviceDictionaryHeld(String size) {
return 'Auf diesem Gerät: $size';
}
@override
String settingsDeviceDictionaryDownload(String size) {
return 'Herunterladen ($size)';
}
@override
String get settingsDeviceDictionaryRemove => 'Entfernen';
@override
String get settingsDeviceDictionaryFailed =>
'Das Herunterladen ist fehlgeschlagen.';
@override
String jellyfinSignedInAs(String user, String server) {