Flutter ARB · iOS .strings · .xcstrings · Android XML · i18next JSON

One place for every locale
No more file-by-file

Stop adding the same key to five files by hand. StringLane shows every locale side-by-side, fills the gaps with your own AI key, and saves straight to your source files — no cloud, no export step

IDE for localization files · Local-first · Works offline

14-day free trial · No email · No account

Sound familiar?

You already have a system. Here is why it keeps failing you.

Add one string. Now edit it five times.

A new key means opening every locale file and pasting the same key name into each one by hand — hoping you didn't typo it in de.arb or skip ja.arb entirely. The work grows with every language you support.

Comparing locales by hand is archaeology.

Open de.arb, memorize a key, switch to fr.arb, search for it, switch to ja.arb, lose your place, start over. At four locales you're not editing anymore — you're cross-referencing files in your head.

Your build passed. The translation didn't.

The key exists in every file, but the value is still in English. gen_l10n compiles clean, the tests pass, and a German user gets English UI — you find out from a 1-star review, not your toolchain.

One editor that keeps every locale in sync

Add, compare, and fill every language from a single view

en.arb
{
  "@@locale": "en",
  "appTitle": "My Flutter App",
  "@appTitle": {
    "description": "The title of the application"
  },
  "welcomeMessage": "Welcome, {name}!",
  "@welcomeMessage": {
    "description": "Greeting shown on the home screen",
    "placeholders": {
      "name": {
        "type": "String",
        "example": "Alice"
      }
    }
  },
  "itemCount": "{count, plural, one {# item} other {# items}}",
  "@itemCount": {
    "description": "Number of items in the cart",
    "placeholders": {
      "count": {
        "type": "int",
        "example": "3"
      }
    }
  },
  "lastSeen": "Last seen {when}",
  "@lastSeen": {
    "description": "Relative timestamp shown in the activity feed",
    "placeholders": {
      "when": {
        "type": "String",
        "example": "2 hours ago"
      }
    }
  },
  "settingsTitle": "Settings",
  "@settingsTitle": {
    "description": "Settings screen title"
  },
  "saveButton": "Save",
  "@saveButton": {
    "description": "Primary save action button"
  },
  "cancelButton": "Cancel",
  "@cancelButton": {
    "description": "Cancel action button"
  },
  "deleteConfirm": "Are you sure you want to delete "{label}"?",
  "@deleteConfirm": {
    "description": "Confirmation prompt before deleting an item",
    "placeholders": {
      "label": {
        "type": "String",
        "example": "My note"
      }
    }
  },
  "errorGeneric": "Something went wrong. Please try again.",
  "@errorGeneric": {
    "description": "Fallback error message"
  },
  "notificationCount": "{count, plural, zero {No} notifications} one {# notification} other {# notifications}}",
  "@notificationCount": {
    "description": "Notification badge label",
    "placeholders": {
      "count": {
        "type": "int",
        "example": "5"
      }
    }
  },
  "signOut": "Sign out",
  "@signOut": {
    "description": "Sign out button label"
  }
}
de.arb
{
  "@@locale": "de",
  "appTitle": "Meine Flutter-App",
  "@appTitle": {
    "description": "Der Titel der Anwendung"
  },
  "welcomeMessage": "Willkommen, {name}!",
  "itemCount": "{count, plural, one {# Artikel} other {# Artikel}}",
  "lastSeen": "Zuletzt gesehen {when}",
  "settingsTitle": "Einstellungen",
  "saveButton": "Speichern",
  "cancelButton": "Abbrechen",
  "deleteConfirm": "Möchten Sie "{label}" wirklich löschen?",
  "errorGeneric": "",
  "notificationCount": "{count, plural, zero {Keine Benachrichtigungen} one {# Benachrichtigung} other {# Benachrichtigungen}}",
  "signOut": "Abmelden"
}
fr.arb
{
  "@@locale": "fr",
  "appTitle": "Mon application Flutter",
  "welcomeMessage": "Bienvenue, {name} !",
  "itemCount": "{count, plural, one {# article} other {# articles}}",
  "lastSeen": "Vu pour la dernière fois {when}",
  "settingsTitle": "Paramètres",
  "saveButton": "Enregistrer",
  "cancelButton": "Annuler",
  "deleteConfirm": "Voulez-vous vraiment supprimer « {label} » ?",
  "errorGeneric": "Une erreur est survenue. Veuillez réessayer.",
  "notificationCount": "{count, plural, zero {Aucune notification} one {# notification} other {# notifications}}",
  "signOut": "Se déconnecter"
}
uk.arb
{
  "@@locale": "uk",
  "appTitle": "Мій додаток Flutter",
  "cancelButton": "Скасувати",
  "deleteConfirm": "Ви впевнені, що хочете видалити «{label}»?",
  "errorGeneric": "Щось пішло не так. Будь ласка, спробуйте ще раз.",
  "itemCount": "{count, plural, one {# елемент} other {# елементів}}",
  "lastSeen": "Останній візит {when}",
  "notificationCount": "{count, plural, zero {Немає} сповіщень} one {# сповіщення} other {# сповіщень}}",
  "saveButton": "Зберегти",
  "settingsTitle": "Налаштування",
  "signOut": "Вийти",
  "welcomeMessage": "Ласкаво просимо, {name}!"
}
ja.arb
{
  "@@locale": "ja",
  "appTitle": "マイフラッターアプリ",
  "cancelButton": "キャンセル",
  "deleteConfirm": "「{label}」を削除してもよろしいですか?",
  "errorGeneric": "問題が発生しました。もう一度お試しください。",
  "itemCount": "{count, plural, one {# 件} other {# 件}}",
  "lastSeen": "最終確認:{when}",
  "notificationCount": "{count, plural, zero {通知はありません} 通知} one {# 通知} other {# 通知}}",
  "saveButton": "保存",
  "settingsTitle": "設定",
  "signOut": "ログアウト",
  "welcomeMessage": "ようこそ、{name}さん!"
}
en.arb
{
  "@@locale": "en",
  "appTitle": "My Flutter App",
  "@appTitle": {
    "description": "The title of the application"
  },
  "welcomeMessage": "Welcome, {name}!",
  "@welcomeMessage": {
    "description": "Greeting shown on the home screen",
    "placeholders": {
      "name": {
        "type": "String",
        "example": "Alice"
      }
    }
  },
  "itemCount": "{count, plural, one {# item} other {# items}}",
  "@itemCount": {
    "description": "Number of items in the cart",
    "placeholders": {
      "count": {
        "type": "int",
        "example": "3"
      }
    }
  },
  "lastSeen": "Last seen {when}",
  "@lastSeen": {
    "description": "Relative timestamp shown in the activity feed",
    "placeholders": {
      "when": {
        "type": "String",
        "example": "2 hours ago"
      }
    }
  },
  "settingsTitle": "Settings",
  "@settingsTitle": {
    "description": "Settings screen title"
  },
  "saveButton": "Save",
  "@saveButton": {
    "description": "Primary save action button"
  },
  "cancelButton": "Cancel",
  "@cancelButton": {
    "description": "Cancel action button"
  },
  "deleteConfirm": "Are you sure you want to delete "{label}"?",
  "@deleteConfirm": {
    "description": "Confirmation prompt before deleting an item",
    "placeholders": {
      "label": {
        "type": "String",
        "example": "My note"
      }
    }
  },
  "errorGeneric": "Something went wrong. Please try again.",
  "@errorGeneric": {
    "description": "Fallback error message"
  },
  "notificationCount": "{count, plural, zero {No} notifications} one {# notification} other {# notifications}}",
  "@notificationCount": {
    "description": "Notification badge label",
    "placeholders": {
      "count": {
        "type": "int",
        "example": "5"
      }
    }
  },
  "signOut": "Sign out",
  "@signOut": {
    "description": "Sign out button label"
  }
}
de.arb
{
  "@@locale": "de",
  "appTitle": "Meine Flutter-App",
  "@appTitle": {
    "description": "Der Titel der Anwendung"
  },
  "welcomeMessage": "Willkommen, {name}!",
  "itemCount": "{count, plural, one {# Artikel} other {# Artikel}}",
  "lastSeen": "Zuletzt gesehen {when}",
  "settingsTitle": "Einstellungen",
  "saveButton": "Speichern",
  "cancelButton": "Abbrechen",
  "deleteConfirm": "Möchten Sie "{label}" wirklich löschen?",
  "errorGeneric": "",
  "notificationCount": "{count, plural, zero {Keine Benachrichtigungen} one {# Benachrichtigung} other {# Benachrichtigungen}}",
  "signOut": "Abmelden"
}
fr.arb
{
  "@@locale": "fr",
  "appTitle": "Mon application Flutter",
  "welcomeMessage": "Bienvenue, {name} !",
  "itemCount": "{count, plural, one {# article} other {# articles}}",
  "lastSeen": "Vu pour la dernière fois {when}",
  "settingsTitle": "Paramètres",
  "saveButton": "Enregistrer",
  "cancelButton": "Annuler",
  "deleteConfirm": "Voulez-vous vraiment supprimer « {label} » ?",
  "errorGeneric": "Une erreur est survenue. Veuillez réessayer.",
  "notificationCount": "{count, plural, zero {Aucune notification} one {# notification} other {# notifications}}",
  "signOut": "Se déconnecter"
}
uk.arb
{
  "@@locale": "uk",
  "appTitle": "Мій додаток Flutter",
  "cancelButton": "Скасувати",
  "deleteConfirm": "Ви впевнені, що хочете видалити «{label}»?",
  "errorGeneric": "Щось пішло не так. Будь ласка, спробуйте ще раз.",
  "itemCount": "{count, plural, one {# елемент} other {# елементів}}",
  "lastSeen": "Останній візит {when}",
  "notificationCount": "{count, plural, zero {Немає} сповіщень} one {# сповіщення} other {# сповіщень}}",
  "saveButton": "Зберегти",
  "settingsTitle": "Налаштування",
  "signOut": "Вийти",
  "welcomeMessage": "Ласкаво просимо, {name}!"
}
ja.arb
{
  "@@locale": "ja",
  "appTitle": "マイフラッターアプリ",
  "cancelButton": "キャンセル",
  "deleteConfirm": "「{label}」を削除してもよろしいですか?",
  "errorGeneric": "問題が発生しました。もう一度お試しください。",
  "itemCount": "{count, plural, one {# 件} other {# 件}}",
  "lastSeen": "最終確認:{when}",
  "notificationCount": "{count, plural, zero {通知はありません} 通知} one {# 通知} other {# 通知}}",
  "saveButton": "保存",
  "settingsTitle": "設定",
  "signOut": "ログアウト",
  "welcomeMessage": "ようこそ、{name}さん!"
}
en.arb
{
  "@@locale": "en",
  "appTitle": "My Flutter App",
  "@appTitle": {
    "description": "The title of the application"
  },
  "welcomeMessage": "Welcome, {name}!",
  "@welcomeMessage": {
    "description": "Greeting shown on the home screen",
    "placeholders": {
      "name": {
        "type": "String",
        "example": "Alice"
      }
    }
  },
  "itemCount": "{count, plural, one {# item} other {# items}}",
  "@itemCount": {
    "description": "Number of items in the cart",
    "placeholders": {
      "count": {
        "type": "int",
        "example": "3"
      }
    }
  },
  "lastSeen": "Last seen {when}",
  "@lastSeen": {
    "description": "Relative timestamp shown in the activity feed",
    "placeholders": {
      "when": {
        "type": "String",
        "example": "2 hours ago"
      }
    }
  },
  "settingsTitle": "Settings",
  "@settingsTitle": {
    "description": "Settings screen title"
  },
  "saveButton": "Save",
  "@saveButton": {
    "description": "Primary save action button"
  },
  "cancelButton": "Cancel",
  "@cancelButton": {
    "description": "Cancel action button"
  },
  "deleteConfirm": "Are you sure you want to delete "{label}"?",
  "@deleteConfirm": {
    "description": "Confirmation prompt before deleting an item",
    "placeholders": {
      "label": {
        "type": "String",
        "example": "My note"
      }
    }
  },
  "errorGeneric": "Something went wrong. Please try again.",
  "@errorGeneric": {
    "description": "Fallback error message"
  },
  "notificationCount": "{count, plural, zero {No} notifications} one {# notification} other {# notifications}}",
  "@notificationCount": {
    "description": "Notification badge label",
    "placeholders": {
      "count": {
        "type": "int",
        "example": "5"
      }
    }
  },
  "signOut": "Sign out",
  "@signOut": {
    "description": "Sign out button label"
  }
}
de.arb
{
  "@@locale": "de",
  "appTitle": "Meine Flutter-App",
  "@appTitle": {
    "description": "Der Titel der Anwendung"
  },
  "welcomeMessage": "Willkommen, {name}!",
  "itemCount": "{count, plural, one {# Artikel} other {# Artikel}}",
  "lastSeen": "Zuletzt gesehen {when}",
  "settingsTitle": "Einstellungen",
  "saveButton": "Speichern",
  "cancelButton": "Abbrechen",
  "deleteConfirm": "Möchten Sie "{label}" wirklich löschen?",
  "errorGeneric": "",
  "notificationCount": "{count, plural, zero {Keine Benachrichtigungen} one {# Benachrichtigung} other {# Benachrichtigungen}}",
  "signOut": "Abmelden"
}
fr.arb
{
  "@@locale": "fr",
  "appTitle": "Mon application Flutter",
  "welcomeMessage": "Bienvenue, {name} !",
  "itemCount": "{count, plural, one {# article} other {# articles}}",
  "lastSeen": "Vu pour la dernière fois {when}",
  "settingsTitle": "Paramètres",
  "saveButton": "Enregistrer",
  "cancelButton": "Annuler",
  "deleteConfirm": "Voulez-vous vraiment supprimer « {label} » ?",
  "errorGeneric": "Une erreur est survenue. Veuillez réessayer.",
  "notificationCount": "{count, plural, zero {Aucune notification} one {# notification} other {# notifications}}",
  "signOut": "Se déconnecter"
}
uk.arb
{
  "@@locale": "uk",
  "appTitle": "Мій додаток Flutter",
  "cancelButton": "Скасувати",
  "deleteConfirm": "Ви впевнені, що хочете видалити «{label}»?",
  "errorGeneric": "Щось пішло не так. Будь ласка, спробуйте ще раз.",
  "itemCount": "{count, plural, one {# елемент} other {# елементів}}",
  "lastSeen": "Останній візит {when}",
  "notificationCount": "{count, plural, zero {Немає} сповіщень} one {# сповіщення} other {# сповіщень}}",
  "saveButton": "Зберегти",
  "settingsTitle": "Налаштування",
  "signOut": "Вийти",
  "welcomeMessage": "Ласкаво просимо, {name}!"
}
ja.arb
{
  "@@locale": "ja",
  "appTitle": "マイフラッターアプリ",
  "cancelButton": "キャンセル",
  "deleteConfirm": "「{label}」を削除してもよろしいですか?",
  "errorGeneric": "問題が発生しました。もう一度お試しください。",
  "itemCount": "{count, plural, one {# 件} other {# 件}}",
  "lastSeen": "最終確認:{when}",
  "notificationCount": "{count, plural, zero {通知はありません} 通知} one {# 通知} other {# 通知}}",
  "saveButton": "保存",
  "settingsTitle": "設定",
  "signOut": "ログアウト",
  "welcomeMessage": "ようこそ、{name}さん!"
}
en.arb
{
  "@@locale": "en",
  "appTitle": "My Flutter App",
  "@appTitle": {
    "description": "The title of the application"
  },
  "welcomeMessage": "Welcome, {name}!",
  "@welcomeMessage": {
    "description": "Greeting shown on the home screen",
    "placeholders": {
      "name": {
        "type": "String",
        "example": "Alice"
      }
    }
  },
  "itemCount": "{count, plural, one {# item} other {# items}}",
  "@itemCount": {
    "description": "Number of items in the cart",
    "placeholders": {
      "count": {
        "type": "int",
        "example": "3"
      }
    }
  },
  "lastSeen": "Last seen {when}",
  "@lastSeen": {
    "description": "Relative timestamp shown in the activity feed",
    "placeholders": {
      "when": {
        "type": "String",
        "example": "2 hours ago"
      }
    }
  },
  "settingsTitle": "Settings",
  "@settingsTitle": {
    "description": "Settings screen title"
  },
  "saveButton": "Save",
  "@saveButton": {
    "description": "Primary save action button"
  },
  "cancelButton": "Cancel",
  "@cancelButton": {
    "description": "Cancel action button"
  },
  "deleteConfirm": "Are you sure you want to delete "{label}"?",
  "@deleteConfirm": {
    "description": "Confirmation prompt before deleting an item",
    "placeholders": {
      "label": {
        "type": "String",
        "example": "My note"
      }
    }
  },
  "errorGeneric": "Something went wrong. Please try again.",
  "@errorGeneric": {
    "description": "Fallback error message"
  },
  "notificationCount": "{count, plural, zero {No} notifications} one {# notification} other {# notifications}}",
  "@notificationCount": {
    "description": "Notification badge label",
    "placeholders": {
      "count": {
        "type": "int",
        "example": "5"
      }
    }
  },
  "signOut": "Sign out",
  "@signOut": {
    "description": "Sign out button label"
  }
}
de.arb
{
  "@@locale": "de",
  "appTitle": "Meine Flutter-App",
  "@appTitle": {
    "description": "Der Titel der Anwendung"
  },
  "welcomeMessage": "Willkommen, {name}!",
  "itemCount": "{count, plural, one {# Artikel} other {# Artikel}}",
  "lastSeen": "Zuletzt gesehen {when}",
  "settingsTitle": "Einstellungen",
  "saveButton": "Speichern",
  "cancelButton": "Abbrechen",
  "deleteConfirm": "Möchten Sie "{label}" wirklich löschen?",
  "errorGeneric": "",
  "notificationCount": "{count, plural, zero {Keine Benachrichtigungen} one {# Benachrichtigung} other {# Benachrichtigungen}}",
  "signOut": "Abmelden"
}
fr.arb
{
  "@@locale": "fr",
  "appTitle": "Mon application Flutter",
  "welcomeMessage": "Bienvenue, {name} !",
  "itemCount": "{count, plural, one {# article} other {# articles}}",
  "lastSeen": "Vu pour la dernière fois {when}",
  "settingsTitle": "Paramètres",
  "saveButton": "Enregistrer",
  "cancelButton": "Annuler",
  "deleteConfirm": "Voulez-vous vraiment supprimer « {label} » ?",
  "errorGeneric": "Une erreur est survenue. Veuillez réessayer.",
  "notificationCount": "{count, plural, zero {Aucune notification} one {# notification} other {# notifications}}",
  "signOut": "Se déconnecter"
}
uk.arb
{
  "@@locale": "uk",
  "appTitle": "Мій додаток Flutter",
  "cancelButton": "Скасувати",
  "deleteConfirm": "Ви впевнені, що хочете видалити «{label}»?",
  "errorGeneric": "Щось пішло не так. Будь ласка, спробуйте ще раз.",
  "itemCount": "{count, plural, one {# елемент} other {# елементів}}",
  "lastSeen": "Останній візит {when}",
  "notificationCount": "{count, plural, zero {Немає} сповіщень} one {# сповіщення} other {# сповіщень}}",
  "saveButton": "Зберегти",
  "settingsTitle": "Налаштування",
  "signOut": "Вийти",
  "welcomeMessage": "Ласкаво просимо, {name}!"
}
ja.arb
{
  "@@locale": "ja",
  "appTitle": "マイフラッターアプリ",
  "cancelButton": "キャンセル",
  "deleteConfirm": "「{label}」を削除してもよろしいですか?",
  "errorGeneric": "問題が発生しました。もう一度お試しください。",
  "itemCount": "{count, plural, one {# 件} other {# 件}}",
  "lastSeen": "最終確認:{when}",
  "notificationCount": "{count, plural, zero {通知はありません} 通知} one {# 通知} other {# 通知}}",
  "saveButton": "保存",
  "settingsTitle": "設定",
  "signOut": "ログアウト",
  "welcomeMessage": "ようこそ、{name}さん!"
}

Add a key once — every locale, one view

StringLane opens your folder, groups keys by namespace in the sidebar, and renders every locale for the active key side-by-side. Create a key and it lands in all of them at once, ready to fill — no pasting the same key name into five files, no toggling between editor tabs.

MALFORMED

"notificationCount" in de — unclosed brace

MISSING

"errorGeneric" exists in base but missing in de

PARAM

Placeholder mismatch in "notificationCount" for uk

Know every gap before you submit

Gaps are flagged the moment they exist — not after a build fails, not after a 1-star review. You see what's wrong before you touch the build command.

On branch main
Changes not staged for commit:
modified: lib/l10n/en.arb
modified: lib/l10n/de.arb
modified: lib/l10n/uk.arb
[main 4a2f91c] l10n: add missing translations
3 files changed, 24 insertions(+), 2 deletions(-)

Edit, save, commit — nothing else

StringLane writes directly to your ARB, .strings, XML, or JSON files on every keystroke. Your git workflow stays exactly as it is. There is no export step, no sync button, no intermediate format to manage.

Fill all missing translations — with any AI model you already use, cloud or local

Bring your own API key and bulk-translate every missing string across every locale at once. OpenAI, Anthropic, Google Gemini, Groq, Mistral, DeepSeek, xAI — or run fully offline against any OpenAI-compatible local runner (Ollama, LM Studio, Jan, llama.cpp). The Issues Panel's "Fix all with AI" sweep covers ICU errors and placeholder mismatches in the same pass. No per-character credits, no subscription layered on top.

How it works

From open folder to ship-ready in minutes

  • Open Your Project Folder

    Point StringLane at your existing project directory. It finds every ARB, .strings, Android XML, or i18next JSON file automatically — no import dialog, no configuration file, no file picker for each locale.

  • See Every Locale at Once

    Keys live in the sidebar, every locale for the active key fills the detail pane — Grid for short strings, List for long ones. Missing entries highlight immediately, and the Issues Panel (⌘J) lists every validation problem across the project so nothing slips through.

  • Add a Key — It Lands in Every Locale

    Create a key once and StringLane writes it into every locale file at the same time, ready to fill. Rename or delete propagates across all locales too — no find-and-replace across five files, no key that lives in en.arb but goes silently missing from ja.arb.

  • Fill Gaps with AI or Type Directly

    Click any empty cell and type, or sweep every missing cell across every locale via the Command Palette (⌘P) → Translate all missing. Bring your own key for OpenAI, Anthropic, Gemini, Groq, Mistral, DeepSeek, xAI — or run fully local against Ollama / LM Studio / Jan via the OpenAI-compatible Local LLM provider. No credits, no middleman.

  • Changes Save to Your Source Files

    Every edit writes directly back to the original file on disk the moment you leave the cell. No Save button, no Export step — your git diff shows exactly what changed and nothing else.

  • Build and Ship, Nothing Else to Do

    Close StringLane and run your build. The source file is already the right file — gen_l10n, Xcode, and the Android resource compiler find exactly what they expect.

Architecture note: StringLane runs entirely on your machine — no account, no cloud, no server your files pass through. Your locale files stay in your repo, in your exact format. A git diff before and after shows only the lines you changed.

Features

The localization IDE — built for locale files, not bolted onto a generic editor

  • Drop a folder. Done.

    Drag your project folder onto StringLane. It detects Flutter, iOS, Android, or Web from marker files

  • Plurals & CLDR, done right

    Edit any format's native plural shape and surface the exact forms a language needs (one/few/many for Polish, Ukrainian, Arabic). Flip string ↔ plural in one click

  • Metadata, generated

    One click writes @key descriptions, placeholder types, and length limits for every key — the context AI and human translators need to get it right

  • Keyboard-first

    Command Palette (⌘P), Add Key (⌘K), Issues Panel (⌘J), focus search (⌘F), Issues filter (⌘⇧I), shortcuts dialog (?)

Pricing

One price. No subscription. Yours forever.

Free Trial

$0/ 14 days

Full app, all features. No email, no account, works offline.

  • All five formats: ARB, .strings, .xcstrings, XML, JSON
  • Side-by-side locale editor
  • Real-time ICU & placeholder validation
  • AI translation — BYOK, no per-character fees
  • Auto-save directly to source files
  • 14 days · no credit card · works offline
Open Your Project Folder
Early-adopter price

Full License

$49one-time

Full price after launch: $79

One-time purchase. No annual renewal. No seat fee.

  • Everything in Free Trial
  • Lifetime license — pay once, use forever
  • 3 machine activations
  • All future updates within major version
  • Priority email support
  • Secured at early-adopter price ($79 after launch)
Buy Full License — $49

Instant download after purchase

Need more than 3 activations? Contact us and we'll sort it out.

FAQ

Frequently asked questions

Still have questions? Email us at support@stringlane.app

Stop juggling locale files by hand

StringLane adds a key to every locale at once and shows them side-by-side — edits saved straight to your source files, no cloud, no export step. One purchase, no subscription, yours to keep.

Start free 14-day trial

Early-adopter price: $49 one-time. Full price is $79.