native_spell_checker 0.4.2
native_spell_checker: ^0.4.2 copied to clipboard
Native OS spell checking for Flutter — zero bundled dictionaries, uses the built-in system checker on Windows, Linux, and Android.
Changelog #
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
0.4.2 #
Changed #
- Removed the pub.dev badge images from
README.mdandREADME_FR.md— they kept regenerating stale pub stats and cluttered the top of the docs. No content lost. - Added analyzer
excludeentries for the generated platform folders (android/,ios/,web/,windows/,macos/,linux/) in bothanalysis_options.yamlandexample/analysis_options.yaml, so the linter no longer analyzes the generated native scaffolding. - Aligned the example app's Android build tooling to a mutually
compatible set: Gradle 9.6.1 → 9.3.1, Android Gradle Plugin 9.3.1 →
9.1.0, Kotlin 2.3.10 → 2.4.0; dropped the now-unneeded
android.sync.suppressAgpWarningsflag inexample/android/gradle.properties.
No API or behavior change for consumers.
0.4.1 #
Changed #
- Shortened
pubspec.yamldescriptionto comply with pub.dev's 60–180 character limit (was ~230 characters, which penalized the package score). No API or behavior change.
0.4.0 #
Added #
NativeSpellChecker.contextMenuBuilder— static method that builds a context menu with spelling suggestions inserted above the standard Cut/Copy/Paste/Select All buttons. Clicking a suggestion replaces the misspelled word and repositions the caret.NativeSpellCheckService.findSuggestionSpanAt(String text, int offset)— synchronous lookup into the last spell-check result cache. Returns theSuggestionSpancoveringoffset, ornullwhen the cache is stale (text changed since the lastfetchSpellCheckSuggestionscall). Designed for use inside acontextMenuBuilder, which must be synchronous.SpellCheckTextField— drop-inTextFieldreplacement that pre-wires spell checking, context menu suggestions, and right-click cursor positioning. On desktop (Windows, Linux), aListenerintercepts the secondary button (right-click), moves the caret to the text position under the cursor viaRenderEditable.getPositionForPoint, then lets Flutter open the context menu — so suggestions appear for the right-clicked word without requiring a prior left-click selection. On Android, behaves as a plainTextField(the OS handles everything natively).SpellCheckTextFormField— drop-inTextFormFieldreplacement with the same spell-check and right-click wiring asSpellCheckTextField, plus form-specific params (validator,onFieldSubmitted,onSaved,initialValue,autovalidateMode).SpellCheckTextMixin— shared logic used by both widgets, so the desktop right-click caret placement and spell-check wiring live in one place.NativeSpellChecker.defaultMisspelledTextStyle— public constant so consumers can reuse the plugin's default red wavy underline style.- Both
SpellCheckTextFieldandSpellCheckTextFormFieldacceptmisspelledTextStyleandmisspelledSelectionColorparams to customize the spell-check visual style.
Changed #
NativeSpellCheckService.fetchSpellCheckSuggestionsis nowasyncand caches the last result (_lastText/_lastSpans) sofindSuggestionSpanAtcan serve the context menu synchronously without triggering a new OS spell check.- Repository flattened to a single-package layout: the plugin now lives at
the repository root instead of under
packages/native_spell_checker/. The Dart pub workspace was removed (no longer needed with a single package), therepositoryURL simplified, a.pubignoreexcludes repo-only tooling (_script/,githooks/) from the published archive, anddocs/was renamed todoc/to follow the Pub layout convention. No API or behavior change for consumers.
0.3.0 #
Added #
NativeSpellChecker.resolvedLanguageTag({Locale? locale})— returns the language tag of the dictionary the OS spell checker will actually use for the given locale (or the platform default locale whenlocaleisnull), after applying the same fallback chain used during spell checking.- Windows: BCP-47 tag (e.g.
fr-FR,en-US), resolved viaISpellCheckerFactory.isSupportedon a workerIsolate(MTA, same rationale as spell checking — COM must not touch the STA UI thread). - Linux: Hunspell dictionary name (e.g.
fr_FR,en_US) of the first.aff/.dicpair found in/usr/share/hunspell/. Returnsnullif no dictionary is installed for the locale family. - Android: always
null— Flutter'sDefaultSpellCheckServiceowns spell checking; usePlatform.localeNamefor the system locale.
- Windows: BCP-47 tag (e.g.
- Internal
NativeSpellCheckBackendinterface soNativeSpellCheckServicecan delegate to platform methods (such asresolvedLanguageTag) without anis/cast per platform. - Example app now displays a "Native language" line sourcing
NativeSpellChecker.resolvedLanguageTag()on desktop (andPlatform.localeNameon Android). - Live tests for
resolvedLanguageTagon Windows: cross-consistency withfetchSpellCheckSuggestions(same_resolveLanguageTagcode path), fallback for unsupported locales, stability across isolates, and concurrent interleaving with spell checking.
Fixed #
- Example: platform detection was broken. The previous implementation relied
on
service.toString().contains('Windows'|'Linux'), but the defaulttoString()returnsInstance of 'NativeSpellCheckService'(no override), so the UI always showed "Unknown platform" on Windows and Linux. The example now usesdart:io'sPlatform.isWindows/Platform.isLinux/Platform.isAndroidand displays the resolved native language tag. - Example:
example/test/widget_test.dartwas an unmodified Flutter template referencing a non-existentMyAppclass (compilation failure). Replaced with a real widget test exercising the platform-backend label and the resolved native language (escaped fromFakeAsyncviatester.runAsyncso the Windows COMIsolate.runcan complete during the test).
Changed #
WindowsSpellCheckServiceandLinuxSpellCheckServicenowextends NativeSpellCheckBackendinstead ofSpellCheckService(no observable API change; they still satisfySpellCheckService).WindowsSpellCheckService._resolveLanguageTagnow acceptsLocale?: anulllocale skips the requested-locale step and resolves straight to the system default (GetUserDefaultLocaleName), i.e. the language the spell checker would select on its own.LinuxSpellCheckService._ensureDictionaryrefactored to share_resolveDictionaryTagwithresolvedLanguageTag, so the reported tag and the actually-loaded dictionary are guaranteed to agree.
0.2.0 #
Fixed #
- Windows spell check now actually works. The COM call was previously
silently failing: the UI thread is initialized as STA by the Flutter
Windows runner, but the plugin called
CoInitializeEx(COINIT_MULTITHREADED), causingRPC_E_CHANGED_MODE(0x80010106) to be thrown and swallowed (return null). No suggestions, no underlines, no crash — just silence. - Tolerate
RPC_E_CHANGED_MODEwhen the thread is already initialized with a different apartment. WinRTISpellChecker2objects are agile and work in either STA or MTA, so the existing apartment wins. - Eliminate UI jank on Windows. A single
comprehensiveCheckcall takes ~200 ms — previously executed synchronously on the UI thread (12x the 60 fps frame budget), causing visible stutter at every keystroke. The whole COM work is now delegated to a workerIsolateviaIsolate.run, leaving the UI thread free. - Memoize
NativeSpellCheckService.instance(lazy singleton). Previously, a brand-newWindowsSpellCheckServicewas constructed on everyserviceaccess, re-initializing COM and re-creating the spell checker on each call. configuration()now provides a defaultmisspelledTextStyle(red wavy underline, matching Material'smaterialMisspelledTextStyle) when none is provided. Required byEditableTextin debug mode (assert spellCheckConfiguration.misspelledTextStyle != null) and would crash in release mode on the first spell-check result otherwise. Safe for non-Material consumers too.
Changed #
- Surface COM exceptions via
debugPrintbefore returningnull. Failures are no longer silent — they appear in the console and Flutter DevTools. - Refactor
WindowsSpellCheckServiceinternals tostaticmethods so the COM-bound computation can cross theIsolateboundary without capturingthis. The per-Isolate COM init flag is now a static field.
0.1.0 #
- Initial release.
- Windows support via WinRT
ISpellChecker2(COM FFI throughwin32package). - Linux support via
libhunspell-1.7system library (dart:ffi). - Android defers to Flutter's built-in
DefaultSpellCheckService. - Zero bundled dictionaries — uses OS-installed spell checkers.