Kinnuch bio photo

Email

Github

荏苒之境

Nethaid Mellyn 友站链接

荏苒之境主站

kikomas

Cathamos

Sicusa

Plugins and MCP

← Guide index · 中文 · Settings → Plugins / MCP

Qonlang opens up in a few ways: plugins let other people add things to the app in JavaScript, the built-in Interface translation plugin lets you translate the whole interface into your own language, and MCP lets an LLM client work with your project. All are managed in Settings; plugins and MCP are desktop-only (the web version has neither).

1. Plugins

Installing one

Plugins live in one fixed folder, one folder each:

<plugins folder>/
  my-plugin/
    plugin.json     ← what the plugin is
    index.js        ← the entry point, an ES module

Settings → Plugins → Open plugins folder opens it in your file manager (on Windows usually %APPDATA%\Qonlang\plugins). Drop the folder in, come back and press Reload: the plugin shows up in the list with a tick box you can use to turn it off at any time (everything it registered — panels, commands, import/export, generators — goes away with it).

Plugins run with the same privileges as Qonlang. A plugin can read and write your project and do anything the app itself can. Read the code before installing someone else’s — the same care you’d take with a browser extension.

plugin.json:

Field Meaning
id Unique id (lowercase letters, digits, hyphens); the folder name is used if it’s missing
name The name shown in Settings
version description author Optional, all shown in Settings
main Entry file, index.js by default

index.js can be written either way: default-export an object with activate(qonlang), or just use the global window.qonlang.

export default {
  activate(qonlang) {
    qonlang.ui.toast('plugin loaded')
  },
  deactivate() {
    // called when the plugin is turned off; usually not needed
  }
}

The five extension points

① Inspector panel: adds a block to the inspector on the right. sections limits it to certain modules (leave it out for everywhere); render hands you a DOM element to draw into and re-runs when the context (project, current language, current module, selected entry) changes. Return a function to clean up.

qonlang.ui.addView({
  id: 'stats',
  title: 'Word length',
  sections: ['lexicon'],
  render(el, ctx) {
    const words = ctx.project.lexemes.filter((l) => l.languageId === ctx.languageId)
    el.textContent = `${words.length} entries`
  }
})

② Page: with where: 'page' it becomes a page of its own in the left-hand nav; icon is the single character shown there.

③ Command: registered into the Ctrl+K palette, found by searching its title.

qonlang.commands.register({ id: 'count', title: 'Count entries', run() { … } })

④ Import / export format: appears in the Import and Export menus on the Lexicon page. An import asks the user for a file (filtered by extensions) and hands you the text; an export takes the string you return to the save dialog.

qonlang.io.registerExporter({ id: 'tsv', name: 'Export TSV', extension: '.tsv', run: (ctx) => '…' })
qonlang.io.registerImporter({ id: 'tsv', name: 'Import TSV', extensions: ['.tsv'], run(text, ctx) { … } })

⑤ Paradigm generator: the slot generators in Paradigms gain a Plugin option, and your function produces the form for that cell. You get the project, the entry, the cell’s values and the stem.

qonlang.rules.registerGenerator({ id: 'reverse', name: 'Backwards', run: (ctx) => [...ctx.stem].reverse().join('') })

The API

Call What it does
qonlang.apiVersion Version of this API; it goes up when things are added
qonlang.project The open project (null when none is open)
qonlang.languageId The current language from the top bar
qonlang.edit(fn) Change the project inside the callback; the change lands on the undo stack and marks the project unsaved
qonlang.save() Save the project
qonlang.lexicon.search(query, {languageId, limit}) Find entries with the search syntax from the top bar
qonlang.lexicon.get(id) / .add({lemma, definition}) Read one / add one
qonlang.lexicon.forms(lexeme) Every form this entry’s paradigms produce (computed, not written back)
qonlang.sounds.run(words, {ruleSetName, from, to}) Run a sound-change set and get the form at each stage
qonlang.corpus.analyze(text) / .add(text, {translation}) Analyse a sentence / add one to the corpus
qonlang.ui.toast(msg) .error(msg) .go(section) Notify, report an error, switch module
qonlang.util.newId() Make an id

docs/plugin-example/ in the repository is a complete example using all five extension points; copy it into the plugins folder and it runs.

2. Interface translation (built in)

Qonlang ships with one plugin of its own: Interface translation. It lists every string in the interface so you can translate it into your own language — the result becomes an interface language of its own, alongside the nine that come with the app.

Off by default: go to Settings → Plugins and tick the card marked Built in at the top; an Interface translation page then appears in the navigation bar. Untick it and it disappears again.

Starting a translation

Click New translation and fill in:

Item Description
Language name The name shown in the language menu
Base language Untranslated strings show in this language (a key name is never shown), and it is the default source text while you translate
Written in Latin letters use the app’s own font; my own script needs a font installed in the font library, and the whole interface is then shown in it
Written right to left Like Arabic: only the text runs right to left, the navigation and inspector stay where they are
App name wordmark What replaces the “Qonlang / 千语集” lettering at the top left of the start page and in Settings → About: some text (shown in this translation’s font), or click Use an image… for a picture (under 300 KB). The QL icon on the left stays; leave it empty for the built-in wordmark

All of these can be changed later from the row above the list (name, font, direction and wordmark).

Translating

Categories are on the left (by module — Lexicon, Paradigms, Script… with how many of them are done), and the strings on the right, one per row: the key in grey, the source text below it, and your translation in the box beside it.

  • Source text in: pick the language you would rather translate from.
  • Only untranslated: hide what you have already done.
  • The search box covers keys, source text and translations at once.
  • Placeholders such as {n} and {name} must stay in the translation — a yellow note appears when one goes missing, because the app replaces them with real numbers and names.
  • Translations save as you type; if you are using this language at the moment, the interface changes straight away.
  • Source changed: every translation remembers the source text it was made from. When an update changes a source text, its row is marked Source changed, and hovering the mark shows the old source; tick Only changed source text to see just these. Editing the translation clears the mark; if the translation still holds, click Still fine next to the mark. Strings translated before 0.12.3 have no remembered source and are never marked.

Using it and sharing it

  • Use it: switch to it right away (switch back from the language menu if you would rather).
  • Export: writes a .qonlang-ui.json you can send to somebody else, who imports it with Import.
  • Translations live in your local preferences, not in a project file — export a copy before reinstalling.

3. MCP

MCP (Model Context Protocol) is the common protocol LLM clients use to reach outside tools. Qonlang has an MCP server built in: turn it on and clients such as Claude or Cursor can search your lexicon, run your sound changes, read paradigm derivations, and — once you say yes — change the project.

Turning it on

Settings → MCP → tick Allow LLM access. That will:

  • start a server on 127.0.0.1 (reachable from this computer only), port 7421 by default (use 0 to let the system pick a free one);
  • generate a token — without it every request is 401;
  • show a client configuration snippet you can copy as is.

On the client side it looks like this (Claude Desktop, Claude Code and Cursor all take this HTTP form):

{
  "mcpServers": {
    "qonlang": {
      "type": "http",
      "url": "http://127.0.0.1:7421/mcp",
      "headers": { "Authorization": "Bearer <your token>" }
    }
  }
}

The tools work on whichever project is open — switching projects needs no change to the configuration. Recent calls at the bottom of the settings card shows what the LLM has been doing.

The nine tools

Tool What it does Main arguments
project_info Overview: languages (entry counts, orthographies, scripts, dialects), parts of speech, grammatical dimensions, rule sets and paradigms —
search_lexicon Find entries with the search syntax query, languageId, limit
get_entry Everything about one entry: senses, stems, inflected forms, pronunciation, etymology, relations, tags id or lemma
run_sound_changes Run a rule set and give the form at each stage words, ruleSetId or ruleSetName, fromStage, toStage
gloss_sentence Segment and gloss a sentence (nothing is added to the corpus) text, languageId
derive_forms Derive every slot of the entry’s paradigms, with traces (nothing written back) lexemeId or lemma, paradigmId
add_entry ✎ Create an entry lemma, definition, languageId, pos, tags
update_entry ✎ Change an entry (only the fields you pass) id, lemma, definition, tags, notes
add_sentence ✎ Add a corpus sentence and analyse it text, translation, source

Tools marked ✎ change the project. Languages, rule sets and paradigms are accepted by id, by name or by abbreviation; when one isn’t found the tool lists what the project has.

Writes and safety

  • Writes ask first by default: a dialog names the tool and its arguments, and nothing happens until you confirm. Turn off Ask before writes in Settings if you’d rather not be asked.
  • Every change goes through the normal editing path: it lands on the undo stack (Ctrl+Z takes it back) and the top bar shows the project as unsaved — when to save is still up to you.
  • The server listens on this computer only and always requires the token; New token replaces it at any time (update the client afterwards).
  • Turning the switch off stops the server, and with Qonlang closed there is nothing to connect to.