@fluid-app/fluid-cli-localization
Fluid CLI plugin for selling in another country and in another language. It adds two command groups:
fluid countriesopens a country from Fluid's Country Atlas, converts your prices into its currency, creates its agreements, and checks the result.fluid translationsturns languages on, reports what shoppers would still see untranslated, machine-translates it with Fluid AI, and writes it back.
The country flow hands language work to fluid translations, so each step
has one command.
npm install -g @fluid-app/fluid-cli @fluid-app/fluid-cli-localization
fluid login
# Open a country
fluid countries atlas DE # the atlas: modes, tax, legal, address, payments, languages
fluid countries plan DE --mode otg # preview, changes nothing
fluid countries open DE --mode otg --yes # add the country, seeded from the atlas
fluid countries prices DE # preview converting US prices into EUR
fluid countries prices DE --rate 0.92 --write --yes
fluid countries languages DE # which market languages are off, and the command to turn them on
fluid translations enable de --yes
fluid countries agreements DE --create --yes # the atlas agreements, in every atlas language
fluid countries forms DE # the atlas enrollment fields against the country's forms
fluid countries forms DE --create --yes # the country's enrollment form, as a draft to review
fluid countries status DE # check against the atlas
# Translate
fluid translations missing de # what isn't translated yet, per type
fluid translations auto de --limit 10 # machine-translate 10 per type, print only
fluid translations auto de --limit 25 --write --yes
fluid translations set products 60311 --lang de --yes --set title="Rote-Bete-Mischung"
Every command prints JSON. Failures print a JSON error on stderr and exit
non-zero. Commands that change live configuration, prices or content ask for
confirmation unless you pass --yes.
Walks
Both groups have a walk that asks questions in a terminal instead of
taking flags. Type < to go back, > to skip, ? for the menu, and Ctrl-C
to stop. Each walk saves through the same calls as the commands, and scripts
and agents use the commands instead.
fluid countries walk [iso]opens a country the way Mist does. It asks for the country (searchable) and shows its atlas, then asks the operating mode (each explained in one line), the warehouse, which market languages to turn on, which atlas agreements to create or translate, and whether to keep or change each atlas default: currency, tax, 3-D Secure, payment order and address layout. Then it asks whether to add Fluid's generic defaults and shows a summary to confirm. Nothing is saved before you confirm. It then opens the country, turns on the languages, and creates the agreements. Next it offers the price conversion: it shows the numbers and a sample at the rate you give and saves only on a yes. Finally it hands each market language to the translations walk.fluid translations walk [iso]asks for the language if you don't name one, offering to turn it on. It shows what's missing per type, then lets you machine-translate each type in batches. You go through the proposals one at a time to accept, edit or skip, and each one is saved as you accept it. It covers every type, including theme strings and theme page strings.
fluid countries
| Command | What it does |
|---|---|
atlas <iso> | The atlas for a market, without the agreement legal text. --agreement <localId> prints one agreement in full. |
compliance <iso> | Disclosure pages, cookie rule, tax display and unit pricing from the atlas. |
list | The countries the company sells in. |
plan <iso> --mode <m> | What open would send, with language and agreement status, warehouses and the launch checklist. Read-only. |
open <iso> --mode <m> | Adds the country, seeded from the atlas: currency, mode, tax name, tax-inclusive pricing, tax invoices, 3-D Secure, legal settings, address layout and payment method order. |
update <iso> | Changes only the settings you name on an open country (--set key=value, --warehouse-id, --business-id, --entity-registered, --settlement-currency), e.g. its entity. Nested settings merge into the current ones. |
prices <iso> | Converts each variant's price from another country (--from-country, default US) into this country's currency. A dry run unless --write. |
languages <iso> | The market's major languages and whether each is on, with the fluid translations enable command for the ones that are off. |
agreements <iso> | Atlas agreements matched to the company's by title. --create adds the missing ones; --translate writes the atlas translations onto ones already on the country. |
forms <iso> | The atlas enrollment fields against the country's Post Purchase forms: which are collected, which are missing, and what --create would send. --create makes the country's enrollment form or adds the missing fields to it. |
status <iso> | Compares the country with the atlas, checks that every variant of your active products has a price there and something is on sale and that enrollment asks for the atlas fields, then lists the commands to run and the work left for a person. |
open takes --warehouse-id, --business-id, --entity-registered and
--settlement-currency for what the atlas can't know, and --set key=value
to override a seeded value. It skips Fluid's generic country agreements and
forms (pass --legacy-defaults to keep them), and changes nothing on an open
country unless you pass --reseed, which writes every atlas value over it.
To change a few fields on an open country, use update.
Converting prices
fluid countries prices DE reads every active product (--status for
others) and, for each variant, multiplies its US price by the rate and rounds
it half up to the currency's minor unit (whole units for JPY, KRW and the
other zero-decimal currencies, cents for the rest). It prints the rate, the
rounding, counts, and a sample of before and after prices. Nothing is saved.
- Rate. Pass
--rate: units of the new currency per unit of the source currency. Without it, the preview uses the European Central Bank's daily reference rate.--writealways needs--rate, so the rate saved is the one you reviewed. - Fields.
price,subscription_priceandcompare_priceby default. Addwholesaleandwholesale_subscription_pricewith--fields. A field with no source amount is left alone. - Never free. A variant whose converted price rounds to zero is skipped
(
roundsToZero), and any other field that rounds to zero is left out. - Reruns are safe. A variant that already has a price in the country is
skipped (
alreadyPriced), so a second run never converts a converted price. A price saved in another currency is skipped too (pricedInOtherCurrency).--overwritereplaces both. - On sale. Converted prices keep the variant's current on-sale state in
the country.
--activateputs each converted variant on sale. - Failures. Each variant is saved on its own. A refused save is listed
under
failedwith the API's message, and the rest carry on. - Changes during the run. Each product is read again just before its
variants are saved. A variant that someone priced in the country since the
preview is left alone and listed under
changedSincePreview. - Price editor. When the price editor manages the company's prices,
priceEditoristrue. Each save then goes into the price editor's price lists; one it can't place is listed withrefusedByPriceEditor: true.--overwriteis refused for these companies, so a price someone set in the price editor is never replaced from here.
Setting up the enrollment form
Enrollment checkout shows every active Post Purchase form for the cart's
country after payment, merged into one. fluid countries forms DE reads
those forms and prints, for each atlas enrollment field, the element it maps
to and whether enrollment asks for it (collected, inDraft, missing or
byHand), with plan: what --create would send. Nothing is saved.
| Atlas component | Element type |
|---|---|
LegalName, FullName, Email, PhoneNumber | input, puck_type legal_name, full_name, email, phone_number |
DateOfBirth | input, puck_type date_of_birth, stored sensitive |
ShortTextEntry, LongTextEntry, NumberEntry | short_text_entry, long_text_entry, number_entry |
YesNo, MultipleChoice | yes_no_entry, multiple_choice_entry |
FileUpload, Checkbox | file_upload, checkbox |
SocialSecurityNumber | Not created, nor is a text field labelled as an ID, tax, bank or card number |
- The form.
--createmakesEnrollment - <Country>, a Post Purchase form scoped to the country alone, the same form the admin's country checklist makes. If it exists, as a draft or published, the missing fields are added to it instead.--form <id>adds to another Post Purchase form scoped to the country alone. - Draft first. A new form is a draft, so a person reviews it in the form
builder before enrollment asks for it.
--activatepublishes it (or the existing draft) in the same run. - Only what's missing. A field any active Post Purchase form for the country already collects is not added again. An identity field (name, email, phone, date of birth) matches by type; any other field by type and label.
- Nothing removed. Adding to a form reads it again and sends back each of its components with its element id, so nothing on it is deactivated and no field's sensitivity changes.
- Other countries. A form shared with other countries is read, never changed: a field one country's atlas asks for doesn't belong on another country's enrollment. What it lacks goes on the country's own form.
- Member types. A Post Purchase form reaches everyone who enrolls in the
country, so a field the atlas asks only some member types for (dates of
birth, and most tax questions) is listed under
byHandwith the reason instead. So are multiple choices the atlas gives no choices for. - Data forms must not collect. An SSN, and any field that takes a value
(anything but a yes/no or checkbox) whose label names a national or tax ID number, bank or card details, or a
password (a CPF, a TIN, an IBAN), is never created; it's listed under
byHand. Collect those through your tax or payout provider. - Sensitive fields. A date of birth is stored sensitive, so roles without
the forms view-sensitive permission see its answers masked. Creating one
needs the forms manage-sensitive permission; without it the API refuses the
whole save and the command says so.
--skip-sensitivecreates the rest and lists the ones it left out.
fluid markets ordering and currencies
| Command | What it does |
|---|---|
reorder <market...> | Sets the full market order (ids or names, every market once). The first becomes the fallback. --preview writes nothing; --yes skips the prompt. |
set-fallback <market> | Makes a market the fallback. Refused, with the countries listed, while the fallback prices countries that have no market. --preview writes nothing; --yes. |
currency add <market> <currency> | Adds a currency to a market. Adding one it already has is a no-op. |
currency remove <market> <currency> | Removes a currency from a market. Refused with the counts while it is billed, priced, or the market's last. --yes skips the prompt. |
Every API refusal prints its code and details. Needs the market-config release.
fluid translations
| Command | What it does |
|---|---|
languages | Every language Fluid supports, and whether it's on. |
enable <iso...> / disable <iso> | Turn languages on or off. |
types | The translatable types and their fields. |
missing <iso> | What isn't translated yet, per type. done is true when nothing is. |
show <type> <id> --lang <iso> | One item's default text beside its translation. |
set <type> [id] --lang <iso> --set field=value | Save a translation by hand. --file takes a JSON object for long or HTML values. |
auto <iso> | Machine-translate what's missing with Fluid AI. --write saves it. |
| Type | Fields | Counts as translated when |
|---|---|---|
products | title, introduction, description, feature_text, image_url | the row's languages lists the language |
categories, collections, pages, playlists | title, description, image_url | the same |
posts | title, description, summary, image_url | the same |
media | title, description, image_url, video_url, pdf_url | the same |
enrollment-packs | title, description | the same |
menu-items | title | the title has a value in the language |
theme | every string in locales/<iso>.json | the key has a non-blank value |
theme-sections | a page template's own strings, which override the locale files on that page | the key has a non-blank value in the template's translations |
agreements | title and description, saved together | a read in the language is served in it |
labels | title (product badges you created) | its title in the language differs from the default |
Notes:
autotranslates storefront rows, menu items, agreements and labels from the store's default language, read from the storefront rows (--store-languageonly when it can't be read). Theme strings translate from the--fromlocale,enby default. An item the translator returns only part of is listed underincompleteand not saved;--skip <type>:<id>leaves it out of later runs. Items the API refuses are listed underfailed. Both count towardremaining.- A storefront row with any translation counts as translated, because reads fall back to the default for fields without one.
- A label whose translation is the same word as the default (a brand name)
stays listed; skip it with
--skip labels:<id>. missinglists theme keys whose value is still word for word the source undersameAsSource, to review by eye.- Theme writes publish immediately. A locale file write sends the theme
version it read, so a concurrent edit makes it fail instead of
overwriting;
autolists every key of a refused write underfailed. A theme whose files can't be listed (an invalid member configuration) can be read but not saved, because the write couldn't be guarded. A theme-sections write reads the template again just before saving and merges into it.
Not covered
These have no API that translates them, so they stay in fluid-admin or with a person:
- Promotions (title, description, terms).
- Translations of enrollment form fields and other form labels.
- Fluid's own labels ("New", "Trending"), which Fluid translates.
- Section settings written as literal text rather than as a locale key. Use
the page editor's translate mode, which turns the setting into a key, then
fluid translationscovers it. - Payment provider onboarding and the launch checklist for a country.
The walkthroughs are the "Open a country" and "Add a language" guided setups at https://docs.fluid.app/setup.