Free JLPT practice, in the real format
A study site for Japanese learners living in Japan — 118 timed, automatically marked papers from N5 to N1, every one written for the site, with an interface in twelve languages.
The problem
The JLPT is not a set of loose questions. It is a timed paper with a fixed shape — 問題 groups in a set order, reading passages that several questions share, and listening sections played once. Practice that doesn't look like that paper trains the knowledge but not the sitting.
The site is written for learners who are already living in Japan, many of them from Nepal, Vietnam and China. A study tool that only speaks English or Japanese reaches few of them, so the interface had to be in their languages from the start. And official past papers are not free to republish, so every paper had to be written.
What it does
Each paper opens as one continuous page, like the printed booklet: questions grouped under their 問題 instruction, reading passages pinned beside the questions that use them, one player per listening section, and a question map for moving around. Submitting marks the same page in place and gives an estimated scaled score with a section breakdown.
Every paper carries furigana on a toggle, a meaning for every word in it, and a script for every listening question. All 118 can be sat end to end, sound and all: the listening is read aloud by the reader's own device, so a paper works with the connection off. There is no account and no backend — progress stays in the reader's own browser.
Architecture
There is no server, so the build is the backend. Python tools turn two kinds of
source — item banks of hand-written questions, and open dictionary data — into a
fully static site: more than 1,700 pages across twelve language trees, each tied to
the others with hreflang, plus the JSON the exam player reads. Vercel
serves the result as files, and nothing on a page is fetched from anywhere else.
Every file is written at build time; a page makes no request to anyone but the site itself.
Decisions that shaped it
- Papers are dealt, not typed. Questions live in item banks, and an assembler deals them into papers of the published shape — 67 questions at N5 up to 107 at N1. It shuffles the choices (the first hand-written paper had all 21 answers in position one), refuses to repeat a question anywhere in the library, and records the deal so that adding to a bank never disturbs a paper that already exists.
- A paper is never missing its audio. Every listening question carries its own script, and the device reads it aloud. No recording to host, nothing to lose, and the whole site keeps working offline once it is installed.
- The answer key stays off the server. The banks store the right answer first, on purpose, so they can be checked by eye — which makes every bank an answer key. They are kept out of the deployment entirely, and only the shuffled, built papers are served.
- Twelve languages, without pretending. The interface switches language in place with no reload, and every language has its own URL tree. Where a guide has no translation the build skips that language rather than serving English under a Nepali address, and the level pages stay English-only on purpose — a machine translation would not be the better answer they exist to be.
- Numbers that cannot drift. The counts on the home page — papers per level, questions, words — are generated from the data at build time rather than written by hand.
Outcome
Timed papers, N5 to N1
Questions, auto-marked
Interface languages
Sign-ups or backend
The site is live and free, with nothing to sign up for. Every paper has a glossary — 18,201 different words with their reading, level and meaning — and alongside the papers sit 9,638 vocabulary entries, 2,211 kanji with stroke order and 280 grammar points, levelled from N5 to N1, with 1,753 entries in Nepali.
Stack
Front end
HTML · CSS · vanilla JavaScript · Web Speech · service worker — no framework
Build
Python — static generator, item-bank assembler, JMdict glossary, furigana
Hosting
Vercel · IndexNow
Data
JSON exam files · localStorage for progress