Nucleus
OS integration

Correction orthographique

Vérifiez l'orthographe dans les champs de texte Compose via le moteur natif de chaque système — Hunspell sous Linux, NSSpellChecker sous macOS et l'API Windows Spell Checking.

Le module spellcheck vérifie l'orthographe depuis Kotlin en s'appuyant sur le moteur de correction que chaque système d'exploitation embarque déjà. Il expose un wrapper Compose qui ajoute les suggestions au menu contextuel d'un champ de texte, et une API moteur utilisable sans Compose.

Ajouter la dépendance

nucleus-application expose spellcheck en dépendance api : l'intégration Compose est donc déjà dans le classpath de toute application Nucleus.

build.gradle.kts
dependencies {
    implementation("dev.nucleusframework:nucleus.nucleus-application:2.5.0")
}

Déclarez le module explicitement uniquement pour utiliser le moteur sans la couche Compose :

build.gradle.kts
dependencies {
    implementation("dev.nucleusframework:nucleus.spellcheck:2.5.0")
}

Vérifier un champ de texte

Entourez le champ d'un SpellcheckContextMenu. Un clic droit sur un mot mal orthographié liste les suggestions et une entrée « Ajouter au dictionnaire », au-dessus ou en dessous des commandes Couper/Copier/Coller :

import androidx.compose.foundation.text.BasicTextField
import dev.nucleusframework.application.spellcheck.SpellcheckContextMenu

@Composable
fun NoteField(value: String, onValueChange: (String) -> Unit) {
    SpellcheckContextMenu(text = value, onTextChange = onValueChange) {
        BasicTextField(value = value, onValueChange = onValueChange, singleLine = true)
    }
}

Choisir une suggestion remplace le mot cliqué et appelle onTextChange avec le nouveau texte.

Une seconde surcharge cible les champs à état, dont elle gère le texte elle-même :

import androidx.compose.foundation.text.input.rememberTextFieldState
import dev.nucleusframework.application.spellcheck.SpellcheckContextMenu

val state = rememberTextFieldState("helo world")

SpellcheckContextMenu(state = state) {
    TextField(state = state)
}

Choisir la langue de vérification

Sans argument, la session utilise Locale.getDefault(). Passez locale pour vérifier un champ dans une autre langue :

SpellcheckContextMenu(
    text = value,
    onTextChange = onValueChange,
    locale = Locale.FRENCH,
) {
    BasicTextField(value = value, onValueChange = onValueChange)
}

Pour basculer tout le processus, affectez SpellChecker.locale. Charger un dictionnaire touche le disque : préchauffez la session hors du thread principal.

import dev.nucleusframework.spellcheck.SpellChecker
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

LaunchedEffect(locale) {
    SpellChecker.locale = locale
    withContext(Dispatchers.IO) { SpellChecker.ensureSession(locale) }
}

Affecter locale libère la session courante ; l'accès suivant en construit une pour la nouvelle langue. Si vous passez à la fois session et locale au composable, session l'emporte.

Placer les entrées du menu

menuPlacement décide si les suggestions apparaissent au-dessus ou en dessous des commandes d'édition :

import dev.nucleusframework.application.spellcheck.SpellcheckMenuPlacement

SpellcheckContextMenu(
    text = value,
    onTextChange = onValueChange,
    menuPlacement = SpellcheckMenuPlacement.Top,
) {
    BasicTextField(value = value, onValueChange = onValueChange)
}
ValeurOrdre
Bottom (défaut)Couper/Copier/Coller, séparateur, suggestions
TopSuggestions, séparateur, Couper/Copier/Coller

Fonctionnement

Chaque plateforme dispose d'un moteur de correction, atteint via JNI. macOS utilise NSSpellChecker, Windows l'API Spell Checking (ISpellChecker), et Linux charge Hunspell avec dlopen — il n'y a donc aucune dépendance de compilation vers un paquet de distribution.

Une SpellcheckSession détient un dictionnaire chargé pour une locale. SpellChecker conserve une session à l'échelle du processus et la reconstruit quand vous changez locale. Les mots ajoutés via « Ajouter au dictionnaire » sont écrits dans ~/.config/nucleus/spellcheck/<tag>.dic (en respectant XDG_CONFIG_HOME) ; les listes de mots apprises au niveau de l'OS sous macOS et Windows ne sont pas modifiées.

Quand aucun moteur n'est disponible — plateforme non supportée, bibliothèque Hunspell absente ou dictionnaire introuvable — chaque opération devient inopérante au lieu d'échouer : check et addToDictionary renvoient false, suggest renvoie une liste vide et SpellcheckContextMenu affiche son contenu tel quel.

Hunspell est chargé à l'exécution depuis le premier soname qui se résout : libhunspell-1.7.so.0, libhunspell-1.7.so, libhunspell.so.0, libhunspell-1.6.so.0, puis libhunspell.so.

Les dictionnaires sont des paires <tag>.aff + <tag>.dic, cherchées d'abord dans $DICPATH (séparé par des deux-points), puis dans /usr/share/hunspell, /usr/share/myspell/dicts, /usr/share/myspell, /usr/local/share/hunspell et $XDG_DATA_HOME/hunspell (par défaut ~/.local/share/hunspell).

Le tag est résolu en lang_COUNTRY, puis par langue seule, puis via des alias — en essaie en_US, en_GB, en ; fr essaie fr_FR. L'utilisateur final a besoin de la bibliothèque hunspell de sa distribution et d'un paquet de dictionnaire.

NSSpellChecker fournit le moteur et la liste des langues. Aucun fichier de dictionnaire n'est nécessaire, et la locale demandée est confrontée aux langues que macOS déclare disponibles.

L'API Windows Spell Checking (ISpellChecker) fournit le moteur. Aucun fichier de dictionnaire n'est nécessaire ; les langues viennent des modules linguistiques installés.

Référence de l'API

Intégration Compose

Package dev.nucleusframework.application.spellcheck, livré dans nucleus-application.

SymboleDescription
SpellcheckContextMenu(text, onTextChange, session?, locale?, menuPlacement, content)Ajoute les suggestions au menu contextuel du champ dans content.
SpellcheckContextMenu(state, session?, locale?, menuPlacement, content)Idem, pour un champ basé sur TextFieldState.
SpellcheckMenuPlacementTop, Bottom.
NucleusSpellcheckInstaller.menuItems(word, session, onSuggestion, onAddToDictionary, separator?, menuPlacement)Construit les entrées de suggestion à fusionner dans un menu que vous assemblez.
drawMisspellingSquiggles(drawScope, layout, ranges, color)Dessine les soulignements des plages fournies dans un rendu de texte personnalisé.

Moteur

Package dev.nucleusframework.spellcheck, livré dans spellcheck.

SymboleDescription
SpellCheckerSingleton du processus : locale, session, sessionIfReady, isAvailable, ensureSession(), check(), suggest(), addToDictionary(), misspellings().
SpellcheckSession(locale, osName, dictionaryDirectories, userDictionaryFile)Un dictionnaire chargé. AutoCloseable ; expose locale, isAvailable, dictionaryTag, check, suggest, addToDictionary, misspellings.
SpellcheckSession.defaultUserDictionaryFile(locale)Chemin du dictionnaire utilisateur pour une locale.
DictionaryLocator.defaultDirectories() / find(locale, directories)Où les dictionnaires sont cherchés, et la paire correspondant à une locale.
DictionaryFiles(aff, dic, tag)Une paire de dictionnaire résolue.
SpellcheckWord(start, end, word)Un token et sa plage dans le texte.

Utilitaires de texte

FonctionDescription
iterateWords(text)Tous les tokens du texte.
misspellingRanges(text) { isCorrect }Les plages rejetées par le prédicat.
wordAt(text, offset)Le token contenant un offset, ou null.
replaceWord(text, word, replacement)Le texte avec un token remplacé.
buildSpellcheckMenuModel(word, session, range?, maxSuggestions)Les suggestions et le libellé « Ajouter au dictionnaire » localisé.
applySuggestion(text, model, suggestion)Le texte avec la plage du modèle remplacée.

SpellcheckMenuModel.localizedAddToDictionaryLabel(locale) traduit le libellé ; la valeur de repli est DEFAULT_ADD_TO_DICTIONARY_LABEL.

Notes

  • Les tokens sont des lettres Unicode avec apostrophes internes. Les traits d'union coupent les mots ; les tokens purement numériques ou de plus de 64 caractères sont ignorés.
  • SpellChecker.session bloque au premier accès pendant le chargement du dictionnaire. Sur un chemin de frame, utilisez sessionIfReady, ou préchauffez avec ensureSession() depuis un dispatcher d'arrière-plan.
  • Sous Jewel, JewelDecoratedWindow et JewelDecoratedDialog installent ProvideJewelSpellcheckMenu pour que les entrées adoptent le chrome des menus Jewel.

Et ensuite

  • Menus contextuels — le chrome dans lequel les suggestions s'affichent.
  • Native access — comment Nucleus se lie aux bibliothèques natives.
  • Écosystème — les bibliothèques JVM qui couvrent le reste de votre application.