active_keyboard_language 0.0.1
active_keyboard_language: ^0.0.1 copied to clipboard
Detects and streams the active keyboard (IME) language on iOS and Android, with an RTL-aware Directionality helper widget.
active_keyboard_language #
Detects the active keyboard (IME) language on iOS and Android, streams changes
in real time, and provides an RTL-aware Directionality helper widget.

Solves flutter/flutter#25841 ("Add a way to detect keyboard language") — open since December 2018.
Features #
getCurrentLanguage()— BCP-47 tag of the active keyboard language (e.g.en-US,ar,hi)onLanguageChanged— broadcast stream that fires when the user switches keyboard language (globe key)isRtl()— convenience check derived from a language tagKeyboardAwareDirectionality— widget that wraps a child and flipsTextDirectionautomatically- Android (API 21+) and iOS (13+)
- Graceful degradation: returns
null/ an empty stream on unsupported platforms instead of throwing
Usage #
import 'package:active_keyboard_language/active_keyboard_language.dart';
final language = await KeyboardLanguage.getCurrentLanguage(); // e.g. "ar"
KeyboardLanguage.onLanguageChanged.listen((language) {
print('keyboard language changed to $language');
});
KeyboardLanguage.isRtl('ar'); // true
Wrap any widget that should flip direction with the keyboard:
KeyboardAwareDirectionality(
child: TextField(),
)
If the child is a text field, pass its TextEditingController too so the
field clears itself on every language switch (see the Android caveat below
for why that matters):
final controller = TextEditingController();
KeyboardAwareDirectionality(
controller: controller,
child: TextField(controller: controller),
)
API #
| Member | Type | Description |
|---|---|---|
KeyboardLanguage.getCurrentLanguage() |
Future<String?> |
BCP-47 tag of the active keyboard language, or null if undetectable. |
KeyboardLanguage.onLanguageChanged |
Stream<String?> |
Emits the new tag whenever the active keyboard language changes. Broadcast; debounced ~100ms. |
KeyboardLanguage.isRtl(tag) |
bool |
True if tag's primary language subtag is a right-to-left script language. |
KeyboardAwareDirectionality |
Widget |
Wraps child in a Directionality that follows the active keyboard language. |
KeyboardAwareDirectionality.controller |
TextEditingController? |
Optional. If provided, its text is cleared on every language change (not the initial seed) — see the Android caveat below. |
KeyboardAwareDirectionality.onLanguageChanged |
ValueChanged<String?>? |
Optional callback fired with the normalized tag on every change. |
Language coverage #
getCurrentLanguage()/onLanguageChanged pass through whatever tag the OS
reports — there's no closed list, so any keyboard language iOS or Android
ships is supported for detection, including third-party keyboards (Gboard,
SwiftKey, Sogou, etc.) as long as they report a subtype/input mode.
isRtl() does use a fixed list, since RTL-ness isn't derivable from the tag
alone: ar, he, fa, ur, ps, sd, ckb (Sorani Kurdish), dv, yi,
ug (Uyghur). This matches every RTL-script keyboard both platforms actually
ship system-level support for. Plain ku (Kurmanji Kurdish) is deliberately
excluded — its default keyboard is Latin-script and therefore LTR.
Normalization also remaps a handful of legacy Java/Android ISO-639 codes
(iw→he, ji→yi, in→id) that can surface from the deprecated
InputMethodSubtype.locale API path on Android API 21–23, so isRtl() and
tag comparisons stay correct on older devices too.
Platform notes #
- No special permissions are required on either platform.
- Android: detection reflects the IME's currently selected subtype. Gboard's
"multilingual typing" mode reports one subtype while accepting several
languages — the reported tag is whichever subtype is selected, not every
language the keyboard is currently able to type. Some OEM keyboards
(Sogou, iFlytek, etc.) report unusual locale strings; these are normalized
defensively and fall back to
nullrather than crash. - Android caret reset: switching the keyboard's language subtype forces
Android to restart the focused field's input connection, which can reset
the caret to the start of the text. If a field already has mixed-script
content, characters typed after the switch can land in the wrong place —
this is a platform behavior, not something this package's code touches.
Pass a
controllertoKeyboardAwareDirectionality(see Usage) to clear the field on every switch and sidestep it entirely. - iOS:
primaryLanguagecan report the pseudo-languages"emoji"or"dictation"when those keyboards are active — this package passes through the last known real language in that case instead of surfacing the pseudo-language. - iOS initial read before any field is focused: before the first text
field in your app ever gains focus, there is no first responder to read
a language from, so the initial value falls back to
UITextInputMode.activeInputModes.first— the order of your enabled keyboards in Settings, not necessarily the one you last typed with. This self-corrects as soon as a keyboard actually appears (onLanguageChangedfires once a real field is focused, even if iOS doesn't consider the system-wide input mode to have "changed").
Roadmap (v2) #
- Programmatically changing/forcing the keyboard language (flutter/flutter#99606).
- Listing all installed keyboard languages.
- Per-
TextFieldlanguage preference.