Getting started
Quick start
This guide walks through the smallest useful Messagevisor project: initialize, install, define one locale and one message, then build a datafile, and consume it in a JavaScript application.
Prerequisites#
- Node.js 20 or newer
Initialize a project#
$ mkdir my-messagevisor-project && cd my-messagevisor-project$ npx @messagevisor/cli initBy default, init scaffolds the YAML starter project. You can choose another starter:
$ npx messagevisor init --project=json$ npx messagevisor init --project=sets$ npx messagevisor init --project=environmentsThe environments starter sets up a multi-set project with dev, staging, and production ready to use.
If you accidentally run init from a non-empty directory, the CLI prompts for a new child directory name and initializes the project there instead. Pass --overwrite only when you intentionally want to initialize in the current directory and skip conflicting existing files.
Install dependencies#
Once initialized, install the dependencies:
$ npm installDirectory structure#
The project directory structure would appear as follows:
.├── locales/├── messages/├── targets/├── attributes/├── segments/├── tests/└── messagevisor.config.jsLearn more in Projects.
Project configuration#
Project specific configuration is stored in messagevisor.config.js.
Here we are configuring the project to use the ICU module, which allows us to use ICU message syntax in our messages.
const { createICUModule } = require("@messagevisor/module-icu");module.exports = { modules: [createICUModule()],};It's an opt-in module, because some projects may choose to use something much simpler like the interpolation module instead.
Learn more in Configuration and Modules.
Define a locale#
We will start be defining a locale first. They can be a language like en or a regional variant of a language like en-US or en-GB.
description: EnglishFormats#
A locale may also define formats for numbers, dates, time, and more:
description: Englishformats: number: money: style: currency currency: USD currencyDisplay: symbolInheritance#
A locale may inherit translations and formats from another locale, to help reduce duplication and maintenance overhead.
Above we defined the en locale. We can now define a en-US locale that inherits from en:
description: English (United States)inheritTranslationsFrom: eninheritFormatsFrom: enNow that we have two locales defined, we can move on to defining messages.
Define a message#
Messages are the primary translation entities in Messagevisor. They hold base translations, optional metadata, examples, and conditional overrides that react to segments or conditions.
description: Sign in button labeltranslations: en: Sign in # Automatically inherited by en-US below, # because of our locales/en-US.yml definition # en-US: Sign inWe could still define the translation for en-US explicitly, but it would be redundant because it would inherit the same translation from en.
Overrides#
One of the most powerful features of Messagevisor is the ability to conditionally vary translations based on segments or conditions in application runtime.
Attribute#
Before creating an override with direction conditions, we need to define the attribute (or attributes) that it will use:
description: Runtime platformtype: string# list of allowed valuesenum: - web - ios - androidOverride conditions#
Now we can create an override with conditions against that attribute:
description: Sign in button labeltranslations: en: Sign inoverrides: - key: platform-web conditions: - attribute: platform operator: equals value: web translations: en: Sign in from browserAbove, we are defining that the sign in button label should be Sign in for the en locale. However, we are also defining that the sign in button label should be Sign in from browser when the platform is web.
We will learn more about how overrides work using SDKs in later sections.
Namespaces and keys#
Messages can be organized in nested directories, which creates logical namespaces.
In above example, the message definition is in the messages/auth/signin.yml file. The key for this message would be auth.signin.
By default, the namespace character is . (dot). So the key for the message would be auth.signin.
We can change the namespace character in our project's configuration:
module.exports = { namespaceCharacter: "/", // defaults to "."};Segment#
Segments are reusable conditional building blocks that can be referenced by message overrides.
We can define a segment with its own conditions:
description: Web platformconditions: - attribute: platform # referencing attributes/platform.yml operator: equals value: webSegment in override#
If we already had the above segment defined, we could reference it in the message override like this:
description: Sign in button labeloverrides: - key: platform-ios segments: web # referencing segments/web.yml translations: en: Sign in from browserDefine a target#
Targets are the configuration for generating datafiles (which are pure JSON files) which are then consumed by SDKs at runtime.
A simple target definition can look like this:
description: Web application datafileIf no other options are specified, the target will end up generating datafiles against all the available locales in the project including all the messages.
Subset of messages#
It is not uncommon to only want to include a subset of the messages in a target.
To achieve that, we can use the includeMessages and excludeMessages fields:
description: Web application datafileincludeMessages: - auth* # any message key starting with `auth`excludeMessages: - auth.some.unwanted.messageSpecific locales#
If we want our target to only generate datafiles for specific locales, instead of all the locales in the project, we can use the locales property:
description: Web application datafileincludeMessages: - auth*excludeMessages: - auth.some.unwanted.messagelocales: - en - en-USContext#
In our target definitions, we can also specify partially known context upfront, that we know for sure will be used by our intended application runtime.
This helps reducing the size of the datafile by removing impossible override branches ahead of runtime:
description: Web application datafileincludeMessages: - auth*excludeMessages: - auth.some.unwanted.messagelocales: - en - en-UScontext: platform: webLint#
Messagevisor CLI comes with a built-in linter that can be used to validate the project structure and definitions, to catch mistakes early:
$ npx messagevisor lintLearn more in Linting.
Build datafiles#
Datafiles are the runtime artifacts that are consumed by SDKs at runtime. They are generated by the build step:
$ npx messagevisor buildThe build writes generated artifacts such as:
datafiles/├── messagevisor-web-en.json└── messagevisor-web-en-US.jsonLearn more in Building datafiles.
Testing#
Messagevisor CLI also somes with a built-in test runner that can be used to validate the project structure and definitions, to catch mistakes early:
$ npx messagevisor testLearn more in Testing.
Using the SDK#
In your application, install the JavaScript SDK first along with desired modules:
$ npm install --save @messagevisor/sdk @messagevisor/module-icuNow you can use the datafile in your application:
import { createMessagevisor } from "@messagevisor/sdk";import { createICUModule } from "@messagevisor/module-icu";// either fetch it from CDN, or// load it directly from the file systemimport datafile from "./datafiles/messagevisor-web-en.json";const m = createMessagevisor({ datafile, modules: [createICUModule()], context: { platform: "web" },});console.log(m.translate("auth.signin"));// => "Sign in"// passing variable values to the messageconsole.log(m.translate("dashboard.welcome", { name: "Ada" }));// => "Welcome back, Ada"// Assumes original message string is `Welcome back, {name}`Learn more in JavaScript SDK and ICU Module.
Export as CSV#
Often times, a translation workflow requires handing off the translations to a translator (either human or AI), and then bringing the translations back into the project.
This is where exporting as CSV comes in handy:
$ npx messagevisor export \ --locale=en \ --locale=nl-NL \ --target=web \ --output=exports/nl-NL-web.csvRepeating --locale puts both locales in the CSV. Here en gives the translator a source/reference column while nl-NL is the target locale to edit.
Learn more in Exporting CSV guide and CLI documentation.
Import from CSV#
Once the translator has completed the work, we can import the translations back into the project:
$ npx messagevisor import exports/nl-NL-web.csv --locale=nl-NL --applyLearn more in Importing CSV guide and CLI documentation. If your translations already exist as a flat JSON object or URL, see Importing JSON.
Catalog#
Messagevisor also comes with a catalog command that can be used to browse the project visually from your browser:
$ npx messagevisor catalogVisit http://localhost:3000 to browse the catalog.
If port 3000 is already in use, pass a custom port:
$ npx messagevisor catalog --port=3100As you make changes to the project, the catalog will automatically refresh to reflect the changes.
To export the catalog as a static site, you can use its export subcommand:
$ npx messagevisor catalog exportThe generated static site will be available in the catalog/ directory, that you can host anywhere you want.
This is useful when you want to host it internally for your team or organization for quick access.
Learn more in Catalog.
Deployment strategy#
Messagevisor does not have any strong opinions on how to deploy the project. You can either:
- ship the datafiles along with your application(s), or
- host the datafiles on a CDN or object storage, and fetch them at runtime
To make the most of Messagevisor, you are advised to make use of CDNs, so you can serve the datafiles from a global edge network.
Learn more in Deployment.
Further reading#
This was a highly simplified overview of the main concepts and workflows. For more detailed information, you can refer to the following pages:

