WanaKana: Japanese Text Conversion and Input
WanaKana is a JavaScript utility library designed for detecting and transliterating Japanese text between Hiragana, Katakana, Romaji, and handling Kanji. It provides a comprehensive set of functions for checking the type of script (e.g., `isJapanese`, `isKana`, `isRomaji`), converting between them (e.g., `toKana`, `toHiragana`, `toRomaji`), and includes DOM helpers for real-time input conversion (`bind`, `unbind`). The library is currently at version 5.3.1 and maintains an active release cadence, with minor updates and bug fixes occurring every few months. Its key differentiators include robust input method editor (IME) simulation capabilities for HTML text fields, comprehensive handling of various kana and romaji mapping rules, and support for custom mappings. WanaKana ships with TypeScript definitions, making it highly compatible with modern TypeScript-driven web development workflows.
Common errors
-
TypeError: wanakana.toKana is not a function
cause Attempting to call `toKana` on a `wanakana` object that was imported incorrectly, often via `import wanakana from 'wanakana'` instead of `import * as wanakana from 'wanakana'` or named imports.fixUse `import { toKana } from 'wanakana';` for specific functions or `import * as wanakana from 'wanakana';` to import all named exports under a namespace. -
ReferenceError: wanakana is not defined
cause The `wanakana` global object is not available, typically because the UMD bundle was not loaded in a browser environment, or the library was not correctly imported in a module environment.fixFor browser use without a bundler, ensure `<script src="https://unpkg.com/wanakana"></script>` is in your HTML. For module environments, ensure you have `import * as wanakana from 'wanakana';` or appropriate named imports. -
TypeError: Cannot read properties of undefined (reading 'bind')
cause This usually occurs when `wanakana.bind()` is called with an `undefined` or null DOM element, or when `wanakana` itself is not properly imported/defined, leading to `wanakana` being `undefined`.fixVerify that the DOM element you are passing to `bind()` actually exists and is not `null` or `undefined`. Also, confirm that `wanakana` has been correctly imported and is accessible in the current scope.
Warnings
- breaking The `stripOkurigana()` function's options were changed significantly in v4.0.0. The `{ all: Boolean }` option was removed and replaced with `{ leading: Boolean, matchKanji: String }`.
- breaking In v5.2.0, the `々` (iteration mark) character was reclassified. It is now included in `isKanji()` checks and explicitly excluded from Japanese punctuation checks.
- gotcha Starting from v5.0.0, providing `customKanaMapping` or `customRomajiMapping` in conversion options will always replace any existing custom mapping if different. Previously, it would only replace if no custom mapping was already set.
- gotcha In v5.1.0, `bind()` was fixed to prevent binding the same element multiple times, and `unbind()` now removes only the attributes that were specifically added by WanaKana. This might affect applications that relied on `unbind()` leaving certain attributes or allowed multiple `bind()` calls on the same element.
Install
-
npm install wanakana -
yarn add wanakana -
pnpm add wanakana
Imports
- wanakana
import wanakana from 'wanakana';
import * as wanakana from 'wanakana';
- toKana, isRomaji
const { toKana, isRomaji } = require('wanakana');import { toKana, isRomaji } from 'wanakana'; - bind, unbind
wanakana.bind(element); // If wanakana was not imported correctly
import { bind, unbind } from 'wanakana'; - Wanakana (global)
<script src="https://unpkg.com/wanakana"></script> <script>wanakana.toKana('...');</script>
Quickstart
import { toKana, toHiragana, toRomaji, isJapanese, bind, unbind } from 'wanakana';
// Convert Romaji to Hiragana and Katakana
const romajiInput = 'konnichiwa sekai';
const hiragana = toHiragana(romajiInput); // 'こんにちわせかい'
const katakana = toKatakana(romajiInput); // 'コンニチワセカイ'
console.log(`Romaji: "${romajiInput}"`);
console.log(` -> Hiragana: "${hiragana}"`);
console.log(` -> Katakana: "${katakana}"`);
// Check if a string contains Japanese characters
const japaneseText = '日本語を勉強します';
const containsJapanese = isJapanese(japaneseText); // true
console.log(`"${japaneseText}" contains Japanese: ${containsJapanese}`);
// Demonstrating DOM binding (browser environment required)
// This part will only execute if 'document' is defined.
if (typeof document !== 'undefined') {
const inputElement = document.createElement('input');
inputElement.type = 'text';
inputElement.id = 'wanakana-demo-input';
document.body.appendChild(inputElement);
console.log('Appended a demo input element to the document body.');
// Bind wanakana for real-time Romaji to Kana conversion
bind(inputElement, { IMEMode: true });
console.log('WanaKana is bound to the input element. Type romaji to convert to kana.');
// Simulate user input (programmatically)
inputElement.value = 'nihongo';
inputElement.dispatchEvent(new Event('input', { bubbles: true }));
// In a real browser, inputElement.value would now be 'にほんご'
// For console, we'll log what it *should* be:
console.log(`Simulated input 'nihongo'. Expected input value after conversion: 'にほんご'. Current value (may not reflect live conversion in Node): ${inputElement.value}`);
// Clean up
unbind(inputElement);
document.body.removeChild(inputElement);
console.log('WanaKana unbound and input element removed.');
} else {
console.log('Skipping DOM binding example as `document` is not defined (likely a Node.js environment).');
}