@embeddables/cli 0.7.18 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -154,13 +154,13 @@ export function PageName() {
154
154
  }
155
155
  ```
156
156
 
157
- **OptionSelector buttons pattern**: When writing TSX files with `OptionSelector` components, define the buttons as constants before the JSX, then reference them in the `buttons` prop:
157
+ **OptionSelector buttons pattern**: When writing TSX files with `OptionSelector` components, define the buttons as constants before the JSX, then reference them in the `buttons` prop. Use `OptionSelectorButtonWithLanguages` as the type (imported from `@embeddables/cli/components`) — this type extends `OptionSelectorButton` with an optional `languages` property, so it works for buttons both with and without translations:
158
158
 
159
159
  ```tsx
160
160
  'use client'
161
161
 
162
162
  import { OptionSelector } from '@embeddables/cli/components'
163
- import type { OptionSelectorButton } from '@embeddables/cli/types'
163
+ import type { OptionSelectorButtonWithLanguages as OptionSelectorButton } from '@embeddables/cli/components'
164
164
 
165
165
  const planButtons: OptionSelectorButton[] = [
166
166
  { id: 'button_plan_basic', key: 'basic', text: 'Basic Plan', description: '$9/month' },
@@ -187,6 +187,8 @@ export default function PlanPage() {
187
187
 
188
188
  This pattern improves readability and makes the buttons array easier to maintain compared to defining it inline within the JSX.
189
189
 
190
+ **Important**: Always use `OptionSelectorButtonWithLanguages` (not `OptionSelectorButton` from `@embeddables/cli/types`) when declaring button constants. The alias `as OptionSelectorButton` keeps the code readable while ensuring the type supports the `languages` property for translations. This matches what the CLI generates when reverse-compiling.
191
+
190
192
  ## Styles Structure (CSS)
191
193
 
192
194
  Styles are stored in `Flow.styles` as a map of CSS selectors to style objects. The `FlowStyles` type is defined in `src/types-builder.ts`.
@@ -360,7 +362,7 @@ Note: button icons and checkboxes are before text in the button, unless you set
360
362
  | `ButtonText` | `<div>` | `text` set | |
361
363
  | `ButtonDescription` | `<div>` | `description` set | |
362
364
  | `ButtonIcon` | `<svg>`/`<span>` | `icon` or `emojiIcon` set | If `icon`, must be font-awesome icon name; if `emojiIcon` must be an emoji in text format like 😀 |
363
- | `ButtonIconImage` | `<span>` | `imageUrl` set | Use **`imageUrl`** only (not `imgSrc`). SVG URLs are valid. |
365
+ | `ButtonIconImage` | `<span>` | `imageUrl` set | Use **`imageUrl`** only (not `imgSrc`). SVG URLs are valid. |
364
366
 
365
367
  ### InputBox
366
368
 
@@ -692,6 +694,141 @@ The `config.json` file contains the reduced Embeddable JSON with:
692
694
  1. Update React file: `global-components/{locationKey}.location.tsx`
693
695
  2. Update styles if needed
694
696
 
697
+ ## Multi-Lingual / Translations
698
+
699
+ Embeddables support translating component text into multiple languages. The default language is English (`en`), which uses the standard component properties (e.g. `text`, `label`, `placeholder`). Translations for other languages are stored alongside these properties.
700
+
701
+ ### How Translations are Stored
702
+
703
+ **In JSON** (the underlying format): Translations use flat properties with the pattern `lang--{languageCode}--{attributeKey}`. For example, a Spanish translation of a button's text would be `"lang--es--text": "Enviar"`. The default language (`en`) value is always the base property itself (e.g. `"text": "Submit"`).
704
+
705
+ **In React/TSX** (the local file format): Translations are represented as a `languages` prop — a nested object grouping translations by language code, then by attribute key. The CLI automatically converts between the two formats during compile and reverse-compile.
706
+
707
+ ### Adding Translations to Components
708
+
709
+ Add a `languages` prop to any component in your `.page.tsx` or `.location.tsx` files. The prop is an object where each key is a language code (e.g. `es`, `fr`, `de`, `ja`) and each value is an object mapping attribute keys to translated strings.
710
+
711
+ **Example — PlainText with translations:**
712
+
713
+ ```tsx
714
+ <PlainText
715
+ id="comp_0000000001"
716
+ key="welcome_heading"
717
+ text="Welcome to our platform"
718
+ languages={{
719
+ es: { text: 'Bienvenido a nuestra plataforma' },
720
+ fr: { text: 'Bienvenue sur notre plateforme' },
721
+ }}
722
+ />
723
+ ```
724
+
725
+ **Example — CustomButton with multiple translated attributes:**
726
+
727
+ ```tsx
728
+ <CustomButton
729
+ id="comp_0000000002"
730
+ key="next_button"
731
+ text="Next Page >"
732
+ description="Head to the next step"
733
+ languages={{
734
+ es: {
735
+ text: 'Página siguiente >',
736
+ description: 'Pasar al siguiente paso',
737
+ },
738
+ fr: {
739
+ text: 'Page suivante >',
740
+ description: "Passez à l'étape suivante",
741
+ },
742
+ }}
743
+ />
744
+ ```
745
+
746
+ **Example — InputBox with translated label, placeholder, and validation message:**
747
+
748
+ ```tsx
749
+ <InputBox
750
+ id="comp_0000000003"
751
+ key="email"
752
+ input_type="email"
753
+ label="Email Address"
754
+ placeholder="Enter your email"
755
+ empty_invalid_message="Email is required"
756
+ languages={{
757
+ es: {
758
+ label: 'Correo electrónico',
759
+ placeholder: 'Ingrese su correo',
760
+ empty_invalid_message: 'El correo es requerido',
761
+ },
762
+ fr: {
763
+ label: 'Adresse e-mail',
764
+ placeholder: 'Entrez votre e-mail',
765
+ empty_invalid_message: "L'e-mail est requis",
766
+ },
767
+ }}
768
+ />
769
+ ```
770
+
771
+ ### Adding Translations to OptionSelector Buttons
772
+
773
+ For OptionSelector components, translations are added on each **button** object (not on the component itself). Add a `languages` property inside each button definition. The `OptionSelectorButtonWithLanguages` type (not plain `OptionSelectorButton`) is required here since it includes the `languages` property:
774
+
775
+ ```tsx
776
+ import { OptionSelector } from '@embeddables/cli/components'
777
+
778
+ import type { OptionSelectorButtonWithLanguages as OptionSelectorButton } from '@embeddables/cli/components'
779
+
780
+ const planButtons: OptionSelectorButton[] = [
781
+ {
782
+ id: 'button_plan_basic',
783
+ key: 'basic',
784
+ text: 'Basic Plan',
785
+ languages: {
786
+ es: { text: 'Plan Básico' },
787
+ fr: { text: 'Plan de base' },
788
+ },
789
+ },
790
+ {
791
+ id: 'button_plan_pro',
792
+ key: 'pro',
793
+ text: 'Pro Plan',
794
+ languages: {
795
+ es: { text: 'Plan Profesional' },
796
+ fr: { text: 'Plan Professionnel' },
797
+ },
798
+ },
799
+ ]
800
+
801
+ export default function PlanPage() {
802
+ return <OptionSelector id="comp_0000000004" key="plan_selector" buttons={planButtons} />
803
+ }
804
+ ```
805
+
806
+ ### Translatable Attributes
807
+
808
+ Any text-based attribute on a component can be translated. Common translatable attributes include:
809
+
810
+ | Component Type | Translatable Attributes |
811
+ | ------------------ | ------------------------------------------------------------------ |
812
+ | `PlainText` | `text` |
813
+ | `RichTextMarkdown` | `text` |
814
+ | `CustomButton` | `text`, `description` |
815
+ | `InputBox` | `label`, `placeholder`, `empty_invalid_message` |
816
+ | `OptionSelector` | `label` (on the component); `text`, `description` (on each button) |
817
+ | `MediaImage` | `caption`, `alt_text` |
818
+ | `FileUpload` | `label` |
819
+
820
+ ### Language Codes
821
+
822
+ Use standard ISO 639-1 two-letter language codes: `es` (Spanish), `fr` (French), `de` (German), `pt` (Portuguese), `ja` (Japanese), `zh` (Chinese), `ko` (Korean), `ar` (Arabic), `it` (Italian), `nl` (Dutch), etc.
823
+
824
+ ### Key Rules
825
+
826
+ 1. **Default language is always `en`** — English text goes in the base property (e.g. `text="Submit"`), never in the `languages` prop.
827
+ 2. **Only translate non-default languages** — The `languages` prop should only contain entries for non-English languages.
828
+ 3. **Attribute keys must match** — The keys inside each language object (e.g. `text`, `label`) must match the actual component prop names exactly.
829
+ 4. **The `languages` prop is optional** — Components without translations simply omit it.
830
+ 5. **Translations round-trip cleanly** — The CLI converts `languages` → flat `lang--` properties when compiling to JSON, and flat `lang--` properties → `languages` when reverse-compiling to React. No manual conversion is needed.
831
+
695
832
  ## Important Notes
696
833
 
697
834
  - **IDs**: All components, pages, computed fields, actions, conditions, and buttons inside OptionSelectors have unique `id` properties. These are preserved in config.json and used for internal references, except for component and button ids which should always be written in React. **ID format**: Use a prefix plus 10 digits so generated IDs don't collide with real ones: pages → `page_` + 10 digits (e.g. `page_1234567890`); components → `comp_` + 10 digits; conditions → `cond_` + 10 digits (e.g. `cond_1234567890`); option buttons → `button_` prefix (e.g. `button_plan_basic`). Must be unique across the flow.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@embeddables/cli",
3
- "version": "0.7.18",
3
+ "version": "0.8.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "embeddables": "./bin/embeddables.mjs"
@@ -55,6 +55,7 @@
55
55
  "@supabase/supabase-js": "^2.39.0",
56
56
  "@tailwindcss/postcss": "^4.1.18",
57
57
  "autoprefixer": "^10.4.23",
58
+ "boxen": "^8.0.1",
58
59
  "chokidar": "^3.6.0",
59
60
  "commander": "^12.1.0",
60
61
  "cssjson": "^2.1.3",
@@ -62,6 +63,8 @@
62
63
  "express": "^4.19.2",
63
64
  "fast-glob": "^3.3.2",
64
65
  "http-proxy-middleware": "^3.0.3",
66
+ "log-symbols": "^7.0.1",
67
+ "ora": "^9.3.0",
65
68
  "picocolors": "^1.1.0",
66
69
  "postcss": "^8.5.6",
67
70
  "prompts": "^2.4.2",