Skip to content
Comvi

Add a locale end to end

View .md

With a Comvi project wired through cdnLoader() as on Connect to Comvi, and access to Languages and Settings on the platform, add a language and ship it to users through the CDN. Your build changes only when the URL rules enumerate locales.

Open Languages and click Add Language. Codes are canonical BCP-47, such as pt-BR or zh-Hant-TW, and the code the platform stores is the code your app configures, uppercase region included. Machine translation fills the column, translation memory fills what the organization has already translated from the same source, and a reviewer moves rows from Needs Review to Translated. See Languages and Machine Translation.

Open Settings → Content Deploy and check that the new language is ticked in the saved selection. The dashboard starts with every locale ticked, so a new one is included unless you narrowed the list before. The next auto-deploy publishes it, or Deploy Now pushes it at once.

Terminal
curl https://cdn.comvi.io/<project-token>/pt-BR.json

The request returns the catalog once the deploy has landed. A 404 means the language is not in the selection or the deploy is still in flight. A partly translated language ships as it is: the CDN publishes exactly the locales you tick. See CDN Deployment.

src/i18n/routing.ts
import { defineRouting } from '@comvi/next/routing';
export const routing = defineRouting({
locales: ['en', 'de', 'pt-BR'],
defaultLocale: 'en',
localePrefix: 'as-needed',
});
nuxt.config.ts
import { defineNuxtConfig } from 'nuxt/config';
export default defineNuxtConfig({
modules: ['@comvi/nuxt'],
comvi: {
defaultLocale: 'en',
locales: [
{ code: 'en', name: 'English', iso: 'en-US' },
{ code: 'pt-BR', name: 'Português (Brasil)', iso: 'pt-BR' },
],
},
});

An i18n instance that fetches locale + '.json' for whatever locale is set needs nothing. React, Vue, Svelte, Solid and vanilla apps add the code wherever their own switcher lists options. An app that composes localeDetector() also adds the code to its supportedLocales: without that option the detector truncates every detected and cached tag to its lowercased base language, so a visitor who picked pt-BR comes back as pt, and pt.json does not exist. Next.js and Nuxt are different: both match the first path segment against their locales list verbatim, so the new code goes into defineRouting (and into createNextI18n, which spreads the same object) or into comvi.locales. Matching is case-sensitive. With pt-BR in the list, /pt-br/… is a different route. On Nuxt the module reads only iso and dir; name is yours, through useRuntimeConfig().public.comvi.localeObjects.

Change Ships via Needs a redeploy
a translation’s wording CDN no
a new key CDN no
a new language already in the routing list CDN no
a new language that must appear in URLs CDN, plus source yes
the default locale, or the prefix strategy source yes

A right-to-left language such as ar or he publishes its catalog but does not set dir on your document. Read the direction from the i18n instance and apply it; on Nuxt the module writes <html lang dir> itself. See Switch the locale.

Content Deploy is a saved selection of locales plus a pipeline that writes one JSON object per locale and namespace to the CDN. Adding a language on Languages adds it to the project; it reaches the CDN only when it is in the selection and a deploy runs. A selection somebody narrowed earlier does not grow on its own: the new language stays unticked until a person ticks it, and the CDN keeps answering 404 for it however complete the translations are. An automatic deploy runs about 5 seconds after the last edit, and at most 1 minute into a continuous stream of edits; Deploy Now skips the wait.

On the app side, cdnLoader() never holds a list of locales. When the i18n instance is set to pt-BR, the loader asks for {cdnUrl}/pt-BR.json for the default namespace and {cdnUrl}/{namespace}/pt-BR.json for every other one, and whatever comes back is the catalog. That is why a plain React or Vue app learns about a new language without a build: the only place the code lists locales is the switcher, and that list is yours. The two frameworks with locale-prefixed URLs are the exception, because their middleware decides from locales whether /pt-BR/about is a locale route or a 404, and nothing at runtime can grow that list.

A deploy publishes the values that pass the Filter by Status setting at that moment. With Translated ticked, a pt-BR key still in review is left out of the file and the i18n instance walks fallbackLocale for it at render time, as it does for a key whose value is empty; with the default empty filter every status ships, drafts included. Finishing the translations later changes the file on the CDN, and the app picks it up on its next load, still with no redeploy.