emoji_picker_i18n 1.1.0
emoji_picker_i18n: ^1.1.0 copied to clipboard
A multilingual emoji picker for Flutter with localized search in 28 languages. Also handles Korean initial-consonant and Japanese kana search. Powered by Unicode CLDR data.
emoji_picker_i18n #
A multilingual emoji picker for Flutter β localized emoji search in 28 languages at once, powered by Unicode CLDR data via Emojibase, the same data source Apple's and Google's keyboards use. On top of the multilingual search it also adds Korean initial-consonant search and Japanese kana search, the kind you get from those keyboards, now as a Flutter widget.
// Every loaded language is searched at the same time.
search.search('cat'); // π π± πΊ β¦ English
search.search('gato'); // π π± β¦ Spanish
search.search('chat'); // π π± β¦ French
search.search('Katze'); // π π± β¦ German
Why another emoji picker? #
Existing Flutter emoji pickers search in only a handful of Western languages. If your users speak Korean, Thai, Vietnamese, Ukrainian, Hindi, and so on, they can't find emoji in their own language. This package fills that gap:
- 28 languages built in, searchable simultaneously β one picker finds
cat,gato, andchat. - Ranked results β a six-tier ranking (exact > prefix > contains, name before tags) puts the best match first.
- Old-device tofu (β‘) filtering β detects which emoji the device can actually render and hides the rest, using the same "probe a representative emoji" technique as Google's official Android picker, but in pure Dart so it works on iOS, desktop, and web too.
- Extras for Korean and Japanese β initial-consonant and kana search, described below.
Install #
dependencies:
emoji_picker_i18n: ^1.0.1
Usage #
Language data is not bundled automatically β import only the locales you need, so unused languages are tree-shaken out of your app.
import 'package:emoji_picker_i18n/emoji_picker_i18n.dart';
import 'package:emoji_picker_i18n/locales/en.dart';
import 'package:emoji_picker_i18n/locales/es.dart';
// Build the search engine once and reuse it β it builds an index up front.
final search = EmojiSearch(
common: kEmojiCommon,
locales: [kEmojiLocaleEn, kEmojiLocaleEs], // first locale = display language
);
EmojiPickerI18n(
search: search,
onEmojiSelected: (emoji) => print(emoji.char),
);
Korean initial-consonant search #
Korean users expect keyboard-grade search: typing only the initial consonants, or a half-finished word, should still find the emoji. This package does all of it (examples use the Korean word for "cat"):
search.search('κ³ μμ΄'); // π π± β¦ full word
search.search('γ±γ
γ
'); // π π± β¦ initial consonants only
search.search('κ³ γ
'); // π β¦ mixed syllable + consonant
search.search('κ³ μγ
'); // π β¦ half-typed last character
Compound consonants and vowels are decomposed in typing order, and spaces are ignored (κ²μκ³ μμ΄ matches κ²μ κ³ μμ΄).
Japanese kana search #
Japanese IMEs produce hiragana first, but the source data stores keywords in katakana. The engine normalizes between the two with Unicode arithmetic β no dictionary β so all three writings match (examples use the Japanese word for "cat"):
search.search('γγ'); // π± β¦ hiragana
search.search('γγ³'); // π± β¦ katakana
search.search('η«'); // π± β¦ kanji
Filtering emoji the device can't render #
On older phones, newer emoji show up as empty boxes (β‘). The picker detects what the device can actually draw and hides the rest β on by default, nothing to set up:
EmojiPickerI18n(
search: search,
onEmojiSelected: (emoji) => print(emoji.char),
// versionFilter: EmojiVersionFilter.auto(), // the default
)
Detection measures glyph widths (unrenderable emoji come out a telltale width), so it's synchronous β the grid is already filtered on the very first frame. No β‘ ever flashes, no waiting, no loading state. The result is cached for the rest of the app's run.
Other strategies:
versionFilter: EmojiVersionFilter.none() // don't filter β show everything
versionFilter: EmojiVersionFilter.fixed(13.1) // filter by a version you already know
Want to know the outcome (for logging)? Pass onDetectionResult. The library never puts anything on screen itself β messaging is your app's call.
Detection runs the first time a picker opens. To move that small cost to app startup instead, warm it up once:
void main() {
WidgetsFlutterBinding.ensureInitialized();
EmojiPickerI18n.warmUpDetection(mySearch);
runApp(const MyApp());
}
Base emoji stay; only skin-tone variants the device can't draw are dropped (π€ shows, π€π» may not). If widths can't be told apart (some platforms), nothing is filtered β a real emoji is never hidden by mistake. Unsupported flags are the one thing width can't catch; they fall back to their two-letter form rather than a β‘.
EmojiSearch itself never touches Flutter, so it still runs headless (server, CLI, pure Dart tests). Only the detection helpers do, and they live in their own file.
Customizing #
Everything below is optional and has sensible defaults. Colors fall back to your app's ColorScheme (light/dark for free).
EmojiPickerI18n(
search: search,
onEmojiSelected: (emoji) => setState(() => _selected = emoji.char),
// Colors β omit any field to inherit from the app theme
theme: const EmojiPickerTheme(
searchFieldColor: Color(0xFFF7F5F2),
selectedTabColor: Color(0xFFE8DDD3),
),
// Search bar text/icons/placement
searchBarConfig: const EmojiSearchBarConfig(
hintText: 'Search',
noResultsText: 'No results',
),
// Category tab labels β pass the generated constant for your language
categoryBarConfig: const EmojiCategoryBarConfig(
labels: kEmojiGroupNamesEn,
),
// Grid sizing
gridConfig: const EmojiGridConfig(
cellExtent: 44, // columns auto-fit to width
emojiSize: 28,
),
// Long-press skin-tone picker
skinToneConfig: const EmojiSkinToneConfig(
longPressDelay: Duration(milliseconds: 250),
),
// Recently used
recentsConfig: const EmojiRecentsConfig(
label: 'Recently used',
emptyText: 'No emoji used yet',
),
)
Recently used storage #
Recents persist to shared_preferences out of the box. To store them in your own database instead, implement RecentEmojiStorage and pass it via EmojiRecentsConfig(storage: ...).
Search without the UI #
The engine is independent of the widget β use it for your own layout, a chat autocomplete, and so on.
final results = search.search('cat'); // List<Emoji>
for (final e in results) {
print('${e.char} ${e.label} ${e.tags}');
}
Supported languages #
28 languages β every language Emojibase, the upstream data source, currently ships. This list will grow: a future release will source data directly from Unicode CLDR, which carries emoji annotations for far more languages (see the Roadmap).
Import the matching file from package:emoji_picker_i18n/locales/<code>.dart and pass its kEmojiLocale<Code> constant. Each language also ships a kEmojiGroupNames<Code> constant for category labels.
| Language | Code | Language | Code |
|---|---|---|---|
| Bengali | bn |
Korean | ko |
| Danish | da |
Lithuanian | lt |
| German | de |
Malay | ms |
| English | en |
Norwegian BokmΓ₯l | nb |
| English (UK) | en_gb |
Dutch | nl |
| Spanish | es |
Polish | pl |
| Spanish (Mexico) | es_mx |
Portuguese | pt |
| Estonian | et |
Russian | ru |
| Finnish | fi |
Swedish | sv |
| French | fr |
Thai | th |
| Hindi | hi |
Ukrainian | uk |
| Hungarian | hu |
Vietnamese | vi |
| Italian | it |
Chinese (Simplified) | zh |
| Japanese | ja |
Chinese (Traditional) | zh_hant |
Known limitations #
- Emoji size vs. cell size. Flutter's text engine measures line height from the base text font, not the color-emoji font, so a color glyph can be slightly taller than its line box β a platform-level quirk (flutter#119623). The picker compensates with default line-height slack and by not hard-clipping cells, so emoji render fully at the default sizes. If you set an unusually large
emojiSizeagainst a smallcellExtent, some bottom clipping can reappear; give the cell a little more room (cellExtent) or a slightly smalleremojiSize. - Languages are compiled in via import today β there is no runtime locale download yet (it's on the Roadmap).
Roadmap #
- More languages via Unicode CLDR. The current 28 are the full set Emojibase provides. A future release will pull directly from Unicode CLDR's emoji annotations β the same source Emojibase is built on β to expand well beyond 28.
- Runtime locale downloads β fetch and cache languages that aren't compiled in, so apps can offer any language without bundling it.
- Typo-tolerant search β edit-distance matching so a small misspelling still finds the emoji.
License #
MIT