Skip to content

v0.7.0

Choose a tag to compare

@github-actions github-actions released this 24 Oct 05:57
· 3 commits to main since this release
ef4c421

Released 0.7.0 across the coordinated @comvi/* release train.

The GitHub Release asset comvi-v0.7.0.tar.gz is the single archive for this release. It contains the packed npm tarballs plus manifest.json and SHA256SUMS.

Comvi i18n 0.7.0 is a CLI release: comvi gets one exit-code scheme for every command, comvi check validates catalogs offline, and comvi translate fills missing values with machine translation. The in-context editor now sends only the languages you changed, the package READMEs are rewritten, and SvelteKit and SolidStart join the examples. Twelve packages ship at one version.

Before you upgrade

  • The breaking changes are confined to @comvi/cli: exit codes, what push validates and how it handles conflicts, and the counts in PushResult. A CI script that tests $? after any comvi command may need the changes in the next section. The runtime packages ship at 0.7.0 with no API change; @comvi/vite-plugin moves its ICU scanner into a shared module, which changes the generated types only for a plural or selectordinal explicit value @comvi/core already rejects (=x, =1e3, =.5, =+1, =Infinity): such a key now reports the ICU issue and gets no parameters, as {price, number} already did.
  • comvi push fails on a locale the project lacks and on a push with nothing in it. Both used to pass. See --skip-unknown-locales and --allow-empty below.
  • comvi push in the default --force-mode ask can now exit 1 with nothing written. When the preview finds no conflict, the commit runs with conflict checking on, so a value a translator saves on the platform between the preview and the commit stops the push; the error says how many values changed and that running the push again resolves it. Before, that value was overwritten.
  • comvi translate needs a new API key scope, mt:use, which comvi.io now offers. In the Comvi app a key's scopes are set when it is created, so create a new key with it.

CLI: one exit-code scheme

Every command now exits with one of five codes, so CI can tell a conflict, an outage and a bad key apart:

Code Meaning
0 Done
1 The command ran and found a problem: a conflict under --force-mode abort, outdated types under typegen --check, errors under comvi check (warnings too with --strict), a value comvi translate could not translate; also a local failure such as an unwritable file
2 The platform was unreachable, timed out, answered 408, 409, 425, 429 or 5xx, or sent an unexpected response: retry
3 The API key was rejected or lacks access, or a plan or credit limit was reached
4 Invalid input

What a script that tests exit codes should know:

  • 1 is narrower. It no longer covers outages (now 2), a rejected key (now 3), a missing .comvirc.json, an existing .comvirc.json under init, --force-mode ask without a terminal when a conflict needs an answer, an unknown command or option, or a schema the emitter refuses (all now 4).
  • typegen --check. A rejected key (401 or 403) now exits 3, not 2, and so does a project that no longer exists. Other 4xx responses, such as a 404 from a wrong apiBaseUrl, exit 4, where 0.6 exited 2. The retryable 408, 409, 425 and 429 still exit 2, as does a platform that could not be reached. A declaration file the check cannot read (for example a directory at that path) exits 4, not 1 as "outdated".
  • comvi push checks local locales first. Before writing anything, it compares the local locales with the locales the project has, as the key may write them. A locale the project lacks exits 4 and names it; pass --skip-unknown-locales to push the rest. Spellings are matched as the platform matches them (pt_br is pt-BR), and two spellings of one locale, or two files for the same locale and namespace, exit 4. A platform that cannot list its locales skips the check with a warning.
  • comvi push with nothing to push exits 4, where it used to exit 0. That covers no files, files without values, and every locale skipped. Pass --allow-empty when that is expected; then no commit is sent.
  • comvi pull --empty-dir deletes only translation files. It removes the files the fileTemplate parses as a catalog, and only for the locales the pull received; a file the template does not match (source code, a README, index.ts) is never removed, so --empty-dir -p src no longer wipes src. Files of locales the key cannot read, or the project no longer has, are left in place. A fileTemplate that puts {languageTag} and {namespace} in one file name cannot tell which locale a file belongs to, so --empty-dir refuses it with exit 4. With the default template any <dir>/<locale>.json reads as a namespace, so run --dry-run first when translationsPath holds other JSON.
  • A locale the key may not read or write. The platform lists to a key only the locales it may read, so pull --locale de with a key restricted from de exits 4 like a locale the project lacks, naming the locales the key may read; before, the pull wrote nothing for it and exited 0. Exit 3 with "Locales not readable with this API key" is kept for the case where the platform lists the locale but sends no data for it. In push, a locale the key may not write is reported with the locales the project lacks and exits 4.
  • A plan or credit limit (LIMIT_EXCEEDED) exits 3 whatever the HTTP status. In 0.6 it exited 1, or 2 under typegen --check.
  • Empty filter values. --locale "" or --ns "", as in --locale "$UNSET_VAR", exits 4 in every command that takes them: pull, push, translate and check. Before, an empty value counted as not given.
  • Running comvi with no command exits 4.
  • An unreadable local translation file. In push, check and the read translate does before its push, it exits 4. A target file translate cannot read while writing is left untouched and the run exits 1. pull warns about it and replaces it.
  • Summary output changed. A script that parses it should know that pull lists the locales and namespaces it wrote, not every project locale, and that push no longer prints Updated or a Progress: line: it reports values new, changed and kept on the platform, see below.
  • Rolled-back commits are retried once. A commit the platform rolled back on a database conflict (409 TRANSACTION_CONFLICT) is sent once more instead of failing.
  • --locale in pull and push matches a locale ignoring case and surrounding whitespace, with _ and - alike.

comvi check: offline catalog validation

comvi check validates the local catalogs against the source locale without an API key, a .comvirc.json, a .env file or the network. It reports keys a translation lacks, keys it has that the source does not (stale), keys whose source value is empty, and translations whose parameter names or select branches differ from the source's, or whose tags differ when the source has tags; plural branches are judged against each locale's own plural rules. It also reports ICU syntax the runtime does not support. --identical also warns when a translation equals its source. Output is text or --format json.

Exit codes follow the scheme: 0 clean, 1 findings (--no-fail turns that into 0, --strict fails on warnings too), 4 invalid input, a catalog or directory it cannot read, an unknown locale or a usage error. It never talks to the platform, so never 2 or 3. A .comvirc.json read by check may use a fileTemplate without {namespace}, such as {languageTag}.json, and may carry sourceLocale and a check section (identical, strict); pull and push still require {namespace}.

comvi translate: machine translation from the CLI

comvi translate machine-translates the values your project is missing on the platform and writes them into your local files. It pushes the local files first (--no-push skips this; --force-mode works as in comvi push), starts machine translation for every key and locale whose value is empty, waits for the jobs, and writes the platform's values where the local files have none, human translations included. The translations are saved on the platform as not reviewed.

  • Local files. It writes only keys that are in your source catalog, and only where the local value is missing: absent or "", and null under --no-push (the push that runs by default rejects a null value). It never overwrites a local value. Each file keeps its keys and shape, nested or flat; the file is rewritten with two-space indentation.
  • Limits. --max-keys (default 1000) caps how many key and locale pairs one run translates; a run over it starts no machine translation and exits 4, though the push before it may already have updated the platform; --max-keys 0 removes the cap. --dry-run prints the count and the credit estimate, over the --ns namespaces when given, and changes nothing.
  • Waiting. --timeout (default 20m) stops the wait. The jobs keep running on the platform, and what is ready is written.
  • Access. The API key needs the mt:use scope ("Machine translation (uses credits)"). Without it, the command exits 3 before it pushes anything.
  • Exit codes. 0 done; 1 some values failed or could not be written; 2 the wait ended with values still missing, a project busy with another translation request, or the platform was unavailable; 3 credits ran out, or the key lacks access; 4 invalid input, over --max-keys, or a platform without this command. After failed jobs or exhausted credits the command still fetches and writes the values that completed; a failed fetch or local write can stop some or all of those writes. --format json prints a summary for scripts; when the push runs and it is not a dry run, it needs a --force-mode other than ask.

Other CLI fixes

  • The push commit gets five minutes, not 30 seconds, so the first push of a large catalog no longer reports a timeout for a push the platform then applies. A commit that does time out says the push may already have been applied and that re-running it is safe. The new COMVI_TIMEOUT_MS sets the read timeout in milliseconds and can only lengthen the commit, never shorten it below five minutes; a value that is not a whole number from 1 to 2147483647 exits 4 before any request.
  • comvi push reports what the platform did: keys created and values new, changed and kept, and a warning about local locales the platform did not import. The Progress: line is gone; the push is a single request. Access-denied errors keep the platform's reason and name the scope the command needs.
  • comvi pull shows what it changes. --dry-run lists each file with its key changes, +2 ~1 −1 for added, changed and removed keys, and names removed keys. Before writing, a pull warns about keys that exist only locally and local files it cannot read, and points to comvi push; the pull still runs and exits 0. A layout where two catalogs would land in the same file is refused with exit 4 before anything is written.
  • comvi typegen --watch reconnects. After a 502, a refused connection or a dropped socket it waits 1, 2, 4 seconds and so on between tries, doubling up to 30; a stream that sends nothing for 45 seconds is replaced; a 401 or 403 stops the watcher with exit 3 instead of leaving it running with no stream; SIGTERM stops it like Ctrl-C.
  • comvi init uses COMVI_API_BASE_URL when --api-url is not given, both to validate the key and in the written config. Before, a staging or self-hosted key was sent to production for validation.
  • Network errors name their cause: fetch failed (connect ECONNREFUSED 127.0.0.1:9) instead of only fetch failed.
  • The programmatic API of @comvi/cli changed too. PushResult.updated now counts changed values and is 0 on a platform without per-value counts; ApiClient takes a commitTimeout and gains fillMissing() and getMtJobStatus(); ConfigLoader.load takes { requireApiKey, optional }. The @comvi/cli section of the changelog below has the details.

In-context editor

  • A save writes only the languages whose value changed. Before, every language of the key was sent back and marked "not reviewed" on the platform, so one German edit also reset the review status of the untouched English and French values. A value typed back to what was stored is not sent either.
  • A save with nothing to write sends no request. Before, an edit typed and then reverted still sent the key's plural flag, which could undo a plural change a teammate had just made. A save the platform accepted also stays saved when the page cannot show the new value at once: the editor reports that the value appears after a reload, and saving again sends nothing.

Docs and examples

  • Package READMEs are rewritten against the source: a short intro per package and claims checked against the code, including the CLI's exit codes and comvi check, the Next.js routing options, the Nuxt request order, locale-detector resolution, and what the in-context editor loads and discloses.
  • SvelteKit and SolidStart examples. examples/sveltekit and examples/solidstart are the server-rendering recipes from the docs as apps: an instance per request on the server, the catalogs handed to the browser as data, and a browser instance that follows the URL on client navigation. / is English and /uk, /de, /ar are the others; Arabic turns the page right-to-left. Both run in the examples end-to-end suite alongside the seven gallery examples.

Requirements

  • Unchanged from 0.6.0: Node 20 or newer for the runtime packages, Node 22 for @comvi/cli and @comvi/vite-plugin. Install the same version of every @comvi/* package.
  • comvi.io already serves what comvi translate and the conflict check behind push --force-mode ask need. An older platform answers comvi translate with exit 4, as a platform without this command.

Documentation: https://comvi.io/docs/i18n

@comvi/core

0.6.0

Minor Changes

  • 1fb2046: Keep flat plain-object catalogs by reference instead of copying them. A catalog passed to messages, addMessages() or returned by a loader is eligible when every leaf is a string and its prototype is either null or exactly Object.prototype — the latter only while Object.prototype itself carries no enumerable key. It is validated with one pass over its enumerable keys and then stored as the object you passed. Everything else (a nested value, a non-string leaf, any other prototype, or a polluted Object.prototype) is still flattened into a fresh null-prototype copy.

    Comvi never writes your catalog object, and getMessages() returns that same object until an addMessages() merges into that locale and namespace: a merge builds a fresh null-prototype object, so identity holds for the first adoption only. Your later edits to it are read by t() without a namespaceLoaded or configChanged event: use addMessages() when bindings must be notified, and pass a copy when you want the instance isolated from later edits.

    A lookup value is a translation only if it is a non-empty string. Members inherited from Object.prototype (constructor, toString, __proto__) therefore never resolve, while an own string property under such a key does.

    Outside the supported catalog shape: non-enumerable own properties, accessor properties, Proxies and symbol keys (a lookup may see what SSR serialization omits). Enumerable keys added to Object.prototype after a catalog was ingested are not guarded against.

  • 1fb2046: # inside plural and selectordinal is now formatted for the message's locale, as ICU MessageFormat defines it: {count, plural, other {# items}} renders 1,234 items in en and 1.234 items in de. Previously # inserted the raw digits. # follows the Intl.NumberFormat defaults, so a fractional count is rounded to three fraction digits (1.23456 renders 1.235). Exact-match selectors (=0, =1) still compare the number itself. A count of negative zero renders 0, without a sign. Use {count} instead of # where the raw digits are wanted.

Patch Changes

  • 1fb2046: Reduce template-cache lookup overhead: compiled templates are now partitioned by a numeric key (message compiler, syntax extensions, plural # context) instead of a string built on every lookup, still bounded by one global 1000-entry FIFO.

    Fix a template-cache collision between message compilers when more than 65535 exist in one process. The overflow warning is removed because compiler ids no longer wrap.

  • 1fb2046: devtools() installs a page-level editor loader the Comvi browser extension uses to load the in-context editor from jsDelivr; new editorVersion option pins the editor. The EditorLoadResult type declares editorVersion, code and host as always present, holding undefined where they do not apply.

  • 1fb2046: devtools({ editorVersion }) fails closed. An explicit value that is not an exact version (SemVer major.minor.patch with no leading zeros, optionally with a prerelease such as 0.6.0-rc.1; build metadata is not accepted) no longer falls back to latest: the editor loader is still installed so the Comvi browser extension can explain the problem, but it requests nothing, and its load() answers the new failure code invalid-editor-version. The extension's popup tells the translator that the pin must be an exact version like 1.2.3, and development builds warn as before. Leaving editorVersion out, or passing "latest", still loads latest.

  • 1fb2046: A {name} placeholder whose parameter is a function no longer prints the function's source code. It now renders as a missing parameter does: the literal {name} by default, with a development warning that says the parameter is a function, or an empty string under missingParam: "drop". This is what a translator hits by typing {link} where the message needs <link>…</link>, both in t() with a tag handler and in <T components={{ link }}>. Tag handlers themselves, and every other parameter value, are unchanged.

  • 1fb2046: In development, the "parameter is a function" warning and the "missing parameter" warning no longer silence each other for the same message and placeholder, and the warning always describes the value that was rendered.

  • 1fb2046: # in a plural branch resolves to that plural's count even after a tag handler inside the branch calls t() and catches what that render throws. Until now the count the failed inner plural had set stayed behind, and the outer # printed it.

  • 1fb2046: icuCompiler no longer reads an argument whose only comma sits inside a nested pair of braces as a parameter. {{,}\t} used to become a parameter named {,}, and {{count, plural, …}} a parameter named after the whole inner plural. Such an argument now fails like any unsupported ICU syntax, as the default compiler already did: E_ICU_SYNTAX at ingestion in development, and in production the braced text renders literally and is reported once through onError.

@comvi/cli

Minor Changes

  • 50f8dae: Breaking: one exit-code scheme for every command. CI can now tell a conflict, an outage and a bad key apart:

    Code Meaning
    0 Done
    1 The command ran and found a problem: a conflict under --force-mode abort, outdated types under typegen --check, errors under comvi check (warnings too with --strict), a value comvi translate could not translate; also a local failure such as an unwritable file
    2 The platform was unreachable, timed out, answered 408, 409, 425, 429 or 5xx, or sent an unexpected response: retry
    3 The API key was rejected or lacks access, or a plan or credit limit was reached
    4 Invalid input

    Migration, for scripts that test exit codes:

    • 1 is narrower. It no longer covers outages (now 2), a rejected key (now 3), a missing .comvirc.json, an existing .comvirc.json under init, --force-mode ask without a terminal when a conflict needs an answer, an unknown command or option, or a schema the emitter refuses (all now 4).
    • typegen --check. A rejected key now exits 3, not 2, and so does a project that no longer exists. Other 4xx responses, such as a wrong apiBaseUrl, exit 4; 408, 409, 425 and 429 still exit 2. 2 covers connection failures, timeouts, retryable HTTP responses and unexpected responses.
    • Other mappings. Running comvi with no command exits 4. A plan or credit limit (LIMIT_EXCEEDED) exits 3 whatever the HTTP status; in 0.6 it exited 1, or 2 under typegen --check. An unreadable local translation file exits 4 in push, check and the read translate does before its push; a target file translate cannot read while writing is left untouched and the run exits 1.
    • comvi push checks local locales first. Before writing anything, it compares local locales with the locales the project has, as the key may write them. A locale the project lacks exits 4 and names it. Pass --skip-unknown-locales to push the rest. Locale spellings are matched as the platform matches them (pt_br is pt-BR), and two spellings of one locale, or two files for the same locale and namespace, exit 4. A platform that cannot list its locales skips the check with a warning.
    • comvi push with nothing to push exits 4 instead of 0. That covers no files, files without values, and every locale skipped. Pass --allow-empty when that is expected; then no commit is sent.
    • comvi pull and locales the key may not read. The platform lists only the locales a key may read, so a requested locale the key may not read exits 4 like one the project lacks, naming the locales the key may read. A locale the platform lists but sends no data for exits 3.
    • Restricted locales. In push, a locale the key's owner is restricted from is reported with the locales the project lacks, and also exits 4.
    • Rolled-back commits are retried once. A commit the platform rolled back on a database conflict (409 TRANSACTION_CONFLICT) is sent once more instead of failing.
    • --locale spellings. --locale in pull and push matches a locale ignoring case and surrounding whitespace, with _ and - alike.
  • 50f8dae: comvi check: offline validation of local catalogs against the source locale (missing, stale, empty source, parameters, plural, select, tags, unsupported ICU, and opt-in identical); text and JSON output. Exit codes follow the CLI's scheme: 0 clean, 1 findings (or a local failure that fits no other code), 4 invalid input (flags, config, a catalog or directory it cannot read, an unknown locale, a usage error); check never talks to the platform, so never 2 or 3. No API key, .comvirc.json, .env or network needed. A .comvirc.json read by check may use a fileTemplate without {namespace} ({languageTag}.json); pull and push still require it.

    TranslationSync now reads a file template without {namespace} as one default-namespace catalog per locale, where it used to find no files: readTranslations returns those catalogs and clearDirectory/previewClear see them.

  • 50f8dae: New command comvi translate. It machine-translates the values your project is missing on the platform and writes them into your local files. The translations are saved on the platform as not reviewed.

    • What it does. It pushes your local files first (--no-push skips this; --force-mode works as in comvi push), starts machine translation for every key and locale whose value is empty, waits for the jobs, and writes the platform's values where your files have none, human translations included.
    • Local files. It writes only keys that are in your source catalog, and only where the local value is missing: absent or "", and null under --no-push (the push that runs by default rejects a null value). It never overwrites a local value. Each file keeps its keys and shape, nested or flat; a changed file is rewritten with two-space indentation.
    • Limits. --max-keys (default 1000) caps how many key and locale pairs one run translates. A run over it starts no machine translation and exits 4, though the push before it may already have updated the platform; --max-keys 0 removes the cap. --dry-run prints the count and the credit estimate, over the --ns namespaces when given, and changes nothing.
    • Waiting. --timeout (default 20m) stops the wait. The jobs keep running on the platform, and what is ready is written.
    • Access. The API key needs the new mt:use scope ("Machine translation (uses credits)"). Without it, the command exits 3 before it pushes anything.
    • Exit codes. 0 done; 1 some values failed or could not be written; 2 the wait ended with values still missing, a project busy with another translation request, or the platform was unavailable; 3 credits ran out, or the key lacks access; 4 invalid input, over --max-keys, or a platform without this command. After failed jobs or exhausted credits the command still fetches and writes the values that completed; a failed fetch or local write can stop some or all of those writes. --format json prints a summary for scripts; when the push runs and it is not a dry run, it needs a --force-mode other than ask.

    ApiClient gains fillMissing() and getMtJobStatus(), and pushTranslations() takes scheduleAutoMt; a platform without the route throws ErrorCodes.API_UNSUPPORTED.

Patch Changes

  • 50f8dae: comvi push --force-mode ask no longer overwrites a value saved on the platform after its preview. When the preview finds no conflict, the push now commits with conflict checking on (fail) instead of override. A value a translator saves between the preview and the commit then stops the push. The error says how many values changed, that nothing was written, and to run the push again. The platform side of this check, which compares under its lock, ships with the matching platform release.

  • 50f8dae: comvi push gives the commit request five minutes instead of 30 seconds, so the first push of a large catalog no longer reports a timeout for a push the platform then applies. A commit that does time out now says the push may already have been applied and that re-running it is safe.

    COMVI_TIMEOUT_MS sets the read timeout in milliseconds and can only lengthen the commit, never shorten it below five minutes. A value that is not a whole number from 1 to 2147483647 exits 4 before any request.

    ApiClient takes a commitTimeout option. A caller that passes only timeout keeps the old behaviour: that value covers the commit too.

  • 50f8dae: comvi pull --empty-dir no longer deletes everything under the translations directory.

    • What it removes. Only files the fileTemplate parses as a catalog, and only for locales the pull actually received. A file the template does not match is never removed: source code, a README, index.ts. So --empty-dir -p src no longer wipes src. Only directories emptied by those removals are removed.
    • Translation-shaped files. With the default template, any <dir>/<locale>.json reads as a namespace, src/fixtures/en.json included. Run --dry-run first when translationsPath holds other JSON.
    • What it leaves. Files of locales your API key cannot read, or that the project no longer has, are left in place; delete those by hand. The directory is no longer created when there is nothing to clear.
    • Ambiguous templates. A fileTemplate with {languageTag} and {namespace} in one file name, such as {languageTag}-{namespace}.json, cannot tell which locale a file belongs to. --empty-dir refuses it with exit 4.

    comvi pull now judges --locale against the locales that came back with data.

    • A locale the project has but the key's owner is restricted from exits 3 with "Locales not readable with this API key". Before, the pull wrote nothing for it and succeeded.
    • The summary lists the locales and namespaces it wrote, not every project locale.

    --locale and --ns given an empty value, as in --locale "$UNSET_VAR", now exit 4 in pull and push. Before, an empty value counted as not given.

  • 50f8dae: comvi pull shows what it changes in each file:

    • --dry-run. Each file it would write is listed with its key changes: (+2 ~1 −1) for added, changed and removed keys, or new, unchanged, nested keys written flat or replaces an unreadable file. Under each file it names up to ten removed keys.
    • Local work it is about to lose. A pull replaces each file with the platform's catalog. Before writing, it warns on stderr about keys that exist only locally, local files it cannot read (bad JSON, a non-string value) and, with --empty-dir, files it deletes because the platform has no catalog for them. It points to comvi push; the pull still runs and exits 0.
  • 50f8dae: comvi push reports what the platform actually did. Before, "Updated" counted the conflicts kept on the platform in keep mode and was 0 after a real overwrite.

    • Summary. It shows keys created and values new, changed and kept on the platform.
    • Locales not imported. It warns about local locales the platform did not import, because the project lacks them or the API key may not write them. On a platform that predates these counts it prints only the number of keys created.
    • Dry run. --dry-run counts values ("New values", "Changed values") instead of calling them keys. Its counts still include values of locales the platform will not import.
    • Progress line. The Progress: line is gone; the push is a single request.

    Access-denied errors keep the platform's reason (a missing scope, a plan limit, read-only billing) and name the scope the command needs: schema:read for typegen, translations:read for pull, translations:write for push. A validation error without a message shows its code and field.

    PushResult gains optional valuesCreated, skippedLocales and detailed. Its updated, and updated in PushProgress, now count changed values; on a platform without per-value counts they are 0 rather than the platform's misnamed figure.

  • 50f8dae: Smaller CLI fixes:

    • init and COMVI_API_BASE_URL. comvi init uses COMVI_API_BASE_URL when --api-url is not given, both to validate the key and in the written config. Before, a staging or self-hosted key was sent to production for validation.
    • Pulling into one file twice. comvi pull refuses (exit 4), before writing anything, a layout where two catalogs land in the same file. That covers en + US-shop and en-US + shop under {languageTag}-{namespace}.json, names that differ only in case (they share a file on macOS and Windows), and a namespace whose directory would be another catalog's file. Before, the second catalog silently replaced the first, or the pull failed halfway.
    • Network errors. They name their cause: fetch failed (connect ECONNREFUSED 127.0.0.1:9) instead of only fetch failed.
    • typegen output. It says it fetches the schema, and prints each step and failure once instead of twice.
    • typegen --check and an unreadable file. The check reports a declaration file it cannot read (for example a directory at that path) as an error the check could not get past, not as outdated (exit 1).
  • 50f8dae: comvi typegen --watch survives a platform deploy and stops loudly when it cannot recover.

    • A lost stream is reopened. After a 502, a refused connection or a dropped socket, the watcher waits 1, 2, 4… up to 30 seconds between tries and says so. Before, any non-200 ended the stream for good while the watcher kept running, or exited 0 when stdin was closed.
    • A silent stream is replaced. One that sends nothing for 45 seconds, not even the platform's 15-second ping, is closed and reopened.
    • A rejected key stops the watcher. A 401 or 403 now exits 3 with the reason, instead of leaving a watcher that runs with no stream.
    • SIGTERM stops the watcher like Ctrl-C (exit 0), for Docker, systemd and CI runners.
  • 50f8dae: ConfigLoader.load accepts { requireApiKey, optional }: with requireApiKey: false it neither requires an API key nor reads COMVI_API_KEY / COMVI_API_BASE_URL, and with optional: true a project without .comvirc.json loads the defaults. .comvirc.json accepts sourceLocale and a check section (identical, strict).

@comvi/next

Patch Changes

  • @comvi/core@0.7.0
  • @comvi/react@0.7.0

@comvi/nuxt

Patch Changes

  • 50f8dae: The package description on npm now says what the module does (type-checked keys, ICU plurals, a <T> component for markup inside translations) instead of naming Nuxt versions.
    • @comvi/core@0.7.0
    • @comvi/vue@0.7.0

@comvi/plugin-fetch-loader

0.6.0

@comvi/plugin-in-context-editor

Patch Changes

  • 50f8dae: Saving in the in-context editor now writes only the languages whose value changed. Before, every language of the key was sent back and marked "not reviewed" on the platform, so one German edit also reset the review status of the untouched English and French values. A value typed back to what was stored, or one a plural or variant switch leaves as it was, is not sent either.
  • 50f8dae: A save in the in-context editor with nothing to write no longer sends a request. Before, an edit typed and then reverted still sent the key's plural flag, which could undo a plural change a teammate had just made on the platform. A save the platform accepted now also stays saved when the page cannot show the new value at once (for example a message the runtime rejects in development): the editor reports that the value appears after a reload, and saving again sends nothing.

@comvi/plugin-locale-detector

0.6.0

@comvi/react

Patch Changes

  • @comvi/core@0.7.0

@comvi/solid

Patch Changes

  • @comvi/core@0.7.0

@comvi/svelte

Patch Changes

  • @comvi/core@0.7.0

@comvi/vite-plugin

Patch Changes

  • 50f8dae: Internal: the ICU scanner that reads parameters out of translation values moved to the workspace-private typegen module, so other tools can share it. Generated types are unchanged for every message @comvi/core accepts. One change for messages core refuses: a plural or selectordinal explicit value outside core's grammar (=x, =1e3, =.5, =+1, =Infinity) now makes the key report the ICU issue and get no parameters, as {price, number} already did, instead of generating parameters for a key core rejects with E_ICU_SYNTAX.

@comvi/vue

Patch Changes

  • @comvi/core@0.7.0