Skip to content

Guides

Studio

Your JSON catalogs are the database and git is the history. Studio is a window onto them, which is why it cannot drift from your code: it does not own anything.

What you get

It opens on what needs you. The first screen lists what is waiting, one line each: translations that break your site, messages with nothing in them, machine drafts nobody has read, keys your code calls that no catalog defines, and keys only a translation has. The first three open the table on exactly those messages; the last two have no row to open, so they name their keys instead. Beside that it shows how many of doctor’s checks pass, and the last commits that touched your catalog folder. The commits card needs a git repository; without one it is simply not there.

The search box reads your text, never the key. It looks in every language you have, not only the ones you ticked, and each result says where it matched. Command K opens it, the arrows move, enter takes you to that message in the table.

The first part of a key is its group: nav.home belongs to nav. The rail lists every group with how many messages it holds and how many still need you, and picking one narrows the table. A key with no dot has no group, and Verbaly does not invent one.

The table holds every message in your project, in as many languages as you tick. Each one shows its state: ready, missing, written by a machine and unread, or broken. You fix it in the row itself, and the check runs while you type.

Two commands run from the page. Find new text reads your code and adds what your catalogs do not have. Translate what is missing calls your provider: it shows the count and the languages before anything is spent, what comes back stays a draft until you read it, and a message you save while it runs keeps your text.

Every row has a menu. Copy the key, copy the source text, start editing without leaving the table, see the files that use that message, and see the commit that last changed it.

The commit is read from your catalogs’ history, by comparing what each message said and not the line it sat on. Adding a key rewrites the comma on the line above it, so asking git who touched a line names the wrong commit often enough to matter. When there is no answer the menu says which kind: a message you have not committed yet, one older than the history it read, or a project with no git in it.

Run it

 pnpm add -D @verbaly/studio
npx verbaly-studio

It prints the address it is serving, the project it read and what is in it. The address carries a key, minted fresh on every start, so nothing else on your machine can reach it by guessing the port.

The command

FlagWhat it does
--root <path>Point at another project instead of the folder you are in
--port <n>Start somewhere other than 4747; a busy port climbs to the next free one
--jsonPrint the whole state and exit, no server. This is the panel without the panel: the same object the screen will read, so you can pipe it, diff it and script it

It never edits your source text

Your source text lives in your code, and the key comes from that text. Writing over it here would be undone by your next extract, so Studio refuses it. It also refuses a key your source catalog does not have: accepting one would invent a message no line of your code asks for.

A translation you save runs the same two checks your build runs. A lost {name}, a lost tag or a plural missing its catch-all case is refused, with the reason. Saving is also accepting: once a person writes it, it stops counting as a machine draft.

Your file keeps the order you gave it. A save rewrites the one line it changed, never the whole catalog. A group you ordered by hand stays in that order and a new key lands at its end; a group that was already alphabetical keeps sorting. The diff you review is the edit you made.

The addresses

Every one of them calls the same function the CLI calls, so there is no second implementation to keep in step. Every answer is JSON, errors included.

AddressWhat it gives you
GET /api/stateThe whole project in one answer: your settings, every catalog, where each message is used, the coverage, what verbaly check says, the machine drafts, the triage and anything it could not read
GET /api/healthThe same diagnosis verbaly doctor prints
GET /api/commit/:keyThe commit that last changed that message, or which of the three reasons there is none
PUT /api/message/:locale/:keyWrite one translation and stop counting it as a draft
POST /api/approveAccept machine drafts: a list of keys, or the whole language at once
POST /api/extractRead your code and add what your catalogs do not have. It answers inside the request, because it is local and costs nothing
GET /api/translateThe bill: how many messages and in which languages, without calling your provider. Looking at the cost cannot start the spending, which is why it is its own address
POST /api/translateStart the run and get back a job. One at a time, because two runs over the same catalogs is a race over the same files
GET /api/job/:idHow that run is going, to ask once a second
GET /api/jobThe run in progress, or nothing. A reloaded page has lost the id, and a job you cannot ask about again is a stream with extra steps

The state comes in one piece, not in pages. Even a catalog of a few thousand messages across three languages answers in a fraction of a second on your own machine.

Nothing it reads can take it down

A catalog it cannot read, a drafts file it cannot read, a source file that will not compile, a folder with no catalogs in it: each one is reported by name, and everything else still loads. Studio is what you open to fix those files, so it has to open.

Which machine translations to read first

Adding a language writes hundreds of drafts at once. Reading them one by one is how people end up skipping the review altogether, so Studio ranks them instead of queuing them. Your build already caught the structure; what is left is meaning. These signals do not score a translation, they point at the few worth your eyes.

Tick a single language and the table becomes that language. A bar above it says how many messages it holds, that they are already on your site, and that your build check passes. Three chips split them into everything, worth a look, and nothing odd. Every flagged row carries its reason beside it: which link changed, which number moved. Tick a second language and the comparison table is back, because a reason belongs to a language, not to a row.

SignalWhat it means
divergentA language you already reviewed wrote this same source text two different ways, so the source itself is ambiguous
collisionThe same doubt seen in the result, when no reviewed language can settle it
echoStill word for word the source, while every language with an opinion did translate it
digitsA number the source has came back changed, ignoring the comma or dot a language writes differently
urlA link changed
codeWhat is inside a code span changed

The signals were tuned against real translations, not invented at a desk. Two of them are gone, because everything they flagged turned out to be correct text. What is left is a short list, not a queue.

It writes files, so it defends itself

Any page open in your browser can talk to a server running on your machine, so three defences are on and cannot be turned off.

Requests are capped, and the full path of your project is stripped out of every error before the browser sees it.

↑↓to moveEnterto open
Copied to clipboard