[Userscript] Japanese Review Prompts

This Userscript replaces the Quiz prompts to be Japanese. You can get it on Greasyfork, copy paste the script below or read about it on my blog.

This script is written from scratch using the Review Question event logic created by @Harald1 in his script WaniKani Katakana For On’yomi
Originally this script was created by @hoovard. I repaired it in 2022 following an update and have rewritten it again to be simple, maintainable and to preserve the WaniKani formatting. Works for Lessons, Extra-Studies and reviews.

Source code
// ==UserScript==
// @name        WaniKani Japanese Review Questions
// @namespace   WK_CustomQuestion
// @description Changes the text of the Review or Lesson Quiz question. Original created by hoovard, with extra thanks going to previous authors Rui Pinheiro (LordGravewish) and Ethan.
// @author    FrostKiwi
// @match     *://www.wanikani.com/subjects/review*
// @match     *://www.wanikani.com/recent-mistakes*
// @match     *://www.wanikani.com/subject-lessons*
// @version     0.5.0
// @license     Do what you want with it (Preferably improve it).
// @grant       none
// ==/UserScript==
// Version 0.5.0 applies to Reviews, Lesson Quizzes and extra studies

(function () {
	const translations = {
		'vocabulary': '単語の',
		'radical': '部首の',
		'kanji': '漢字の',
		'reading': '読み',
		'onyomi': '音読み',
		'kunyomi': '訓読み',
		'meaning': '意味',
		'name': '名'

	let reading_type = null;
	let container = null;
	let categorySpan = null;
	let typeSpan = null;

	/* Predefine the observers to ensure we don't accidentally create more than
	   two in some unknown edge case */
	const observerType = new MutationObserver(() => replaceText(typeSpan));
	const observerCategory = new MutationObserver(() => replaceText(categorySpan));

	function initElements() {
		container = document.querySelector('.quiz-input__question-type-container');
		categorySpan = document.querySelector('.quiz-input__question-category');
		typeSpan = document.querySelector('.quiz-input__question-type');
		observerType.observe(categorySpan, { childList: true });
		observerCategory.observe(typeSpan, { childList: true });

	function replaceText(element) {
		const text = element.innerText.toLowerCase();
		if (translations[text]) {
			element.innerText = translations[text];
			if (reading_type && text == 'reading') {
				element.innerText = translations[reading_type];

	function clearWhitespace() {
		Array.from(container.childNodes).forEach(node => {
			if (node.nodeType === Node.TEXT_NODE && !node.textContent.trim()) {

	const newQuestion = function (e) {
		if (e.detail.subject.type == 'Kanji' && e.detail.questionType == "reading") {
			reading_type = e.detail.subject.primary_reading_type;
		} else {
			reading_type = null;
		if (!container || !categorySpan || !typeSpan) {

	window.addEventListener('willShowNextQuestion', newQuestion);



Does the script recognize when WK is expecting on vs. kun reading? In your example “Kanji Reading” has been translated to “Kanji Chinese Reading”, which is what WK is expecting for 渉. Would it be “漢字の訓読み” if WK was expecting kun reading?

That is correct. It detects Onyomi vs Kunyomi and translates 音読み or 訓読み.
The detection logic for Onyomi was Kunyomi was written by @Harald1 for his script WaniKani Katakana For On’yomi, which I implemented in this script.

1 Like

Very nice. Thanks for confirming.

Not sure whether I should feel proud or mortified that my code is being used here. Probably both :smiley:

Cool script.


I know that feeling…

Right now the userscript doesn’t seem to be working for me and i have no idea why

Edit: It specifically doesn’t work in the Extra Study section

1 Like

Thanks for the report! Indeed the Extra Study URL changed in a recent update. The rest of the script worked as intended.
I updated the script to support the new extra study URL scheme via update 0.5.1

1 Like