Platform-specific copy
The same action has different conventions depending on where it appears. On iOS, the standard call to action for adding an app is "Get it on the App Store." On Android, it is "Get it on Google Play." On web, it is simply "Download the app" or "Install the extension." When these distinctions are handled in application code, every platform carries logic that belongs in the content layer, and changing any variant means coordinating across teams and deployments.
Messagevisor externalizes platform-specific copy in two complementary ways: targets give you platform-specific datafiles with dead branches stripped at build time, and overrides with segment conditions give you runtime switching from a single datafile if that fits your architecture better.
Approach 1: Separate targets per platform#
A target represents a specific output artifact. When you define a target with context: { platform: web }, the builder knows that any override whose condition requires platform: ios or platform: android can never match. Those branches are stripped from the datafile before it is written to disk.
description: Web application datafileincludeMessages: - auth* - nav* - common*locales: - en - en-US - nl-NLcontext: platform: webdescription: iOS application datafileincludeMessages: - auth* - nav* - common* - onboarding*locales: - en - en-US - nl-NLcontext: platform: iosdescription: Android application datafileincludeMessages: - auth* - nav* - common* - onboarding*locales: - en - en-US - nl-NLcontext: platform: androidDefining platform-aware messages#
With the targets defined, write platform-specific variants as overrides on each message:
description: Call to action for installing the apptranslations: en: Install the app nl: Installeer de appoverrides: - key: platform-ios segments: platform-ios translations: en: Download on the App Store nl: Download in de App Store - key: platform-android segments: platform-android translations: en: Get it on Google Play nl: Download via Google Playdescription: iOS platform usersconditions: attribute: platform operator: equals value: iosdescription: Android platform usersconditions: attribute: platform operator: equals value: androidWhen the web target is built, the platform-ios and platform-android overrides are stripped because the target's known context (platform: web) makes them unreachable. The web datafile contains only the base translation. The iOS and Android datafiles each contain only their own variant.
Messages that only exist on certain platforms#
Some messages exist on mobile but not on web. Use includeMessages and excludeMessages on targets to control which messages are in each datafile:
description: Web application datafileincludeMessages: - "*"excludeMessages: - notifications* - push*locales: - en - en-US - nl-NLcontext: platform: webdescription: Mobile application datafileincludeMessages: - "*"locales: - en - en-US - nl-NLcontext: platform: mobilePush notification messages are excluded from the web datafile entirely. Mobile gets the full set.
Approach 2: Runtime platform switching#
When your architecture serves a single datafile to multiple platforms - for example, a universal API layer that serves content to any consumer - you can instead pass the platform as runtime context and let the SDK evaluate the right variant on each request:
import { createMessagevisor } from "@messagevisor/sdk";import datafile from "./datafiles/messagevisor-universal-en-US.json";// Create per-request contextconst m = createMessagevisor({ datafile, locale: "en-US", context: { platform: requestContext.platform, // "web" | "ios" | "android" },});const installLabel = m.translate("common.installApp");In this case the datafile contains all platform branches. The SDK evaluates the segments conditions at runtime to pick the right one. This is simpler to deploy but produces larger datafiles since no branches are stripped at build time.
Build output per platform#
After defining targets, build produces one file per target and locale combination:
$ npx messagevisor build --showSizeOutput:
datafiles/├── messagevisor-web-en-US.json├── messagevisor-web-nl-NL.json├── messagevisor-ios-en-US.json├── messagevisor-ios-nl-NL.json├── messagevisor-android-en-US.json└── messagevisor-android-nl-NL.jsonEach mobile datafile is smaller than a universal bundle and contains exactly the messages that mobile needs.
Testing platform variants#
Write message tests that assert the correct variant per platform:
message: common.installAppassertions: - description: Web default copy locale: en target: web expectedTranslation: Install the app - description: iOS App Store copy locale: en target: ios expectedTranslation: Download on the App Store - description: Android Google Play copy locale: en target: android expectedTranslation: Get it on Google Play - description: Dutch iOS App Store copy locale: nl target: ios expectedTranslation: Download in de App StoreWrite target tests to assert that platform-specific message sets are correct:
target: iosassertions: - description: Onboarding messages are present on iOS expectedToIncludeMessages: - onboarding.step1 - onboarding.step2 - description: iOS install copy resolves correctly locale: en message: common.installApp expectedTranslation: Download on the App StoreFormat differences across platforms#
Platforms can also have different formatting conventions. The iOS human interface guidelines favor different date formats than a desktop web UI. Use target-level format overrides to handle this:
description: iOS application datafilelocales: - en-UScontext: platform: iosformats: en-US: date: long: year: numeric month: short day: numericTarget-level format overrides take precedence over locale-level formats without modifying the locale definition itself.

