diff --git a/docs/notes/1.2.0.md b/docs/notes/1.2.0.md new file mode 100644 index 0000000000..125bc2733b --- /dev/null +++ b/docs/notes/1.2.0.md @@ -0,0 +1,60 @@ +--- +id: 1.2.0 +title: 1.2.0 +--- + + +#### 05/01/2025 + +import ComingSoon from '@site/src/components/ComingSoon' + + + +## Qodly Studio + +

What's new

+ +- [Qodly Looker Studio Connector](../qodlyLookerStudio/qodlyLookerStudioConnector): Added integration between Qodly applications and Google Looker Studio, enabling users to create interactive dashboards, track real-time business metrics, and generate custom reports using Qodly data. + +- [Saved Condition Go To Button](../studio/pageLoaders/states/conditionalState.md#saved-condition-integration): When a saved condition is integrated into a state, a **Go to** button now appears next to its name. Clicking it opens the full saved condition in edit mode—so you can quickly review or update it without leaving the schema view. + +- [Interval Range Validation for Text Input](../studio/pageLoaders/components/textinput.md#intervals-for-date-input): For text inputs using the **interval type `Range`**, if the **start date is later than the end date**, an error message will be shown and the dates will be temporarily disabled until corrected. + +- [Matrix Selection Behavior Options](../studio/pageLoaders/components/matrix.md#properties-customization): You can now control how the **Matrix** behaves after a data update (like reloading or filtering). + +- [Debugger Sidebar](../studio/debugging.md#debugger-sidebar): A new sidebar in the code editor lets you monitor, group, enable/disable, delete, and jump to breakpoints across your entire app. It also shows a [Variables panel](../studio/debugging.md#variables-panel) during debug sessions, so you can view local variables, current line variables, and method arguments—all in one place. + +- [Localization (i18n)](../studio/localization.md): Launched built-in Localization support, allowing you to create multilingual applications visually—without coding. You can define supported locales, manage translation keys and literals, preview translations directly in the Studio, and allow users to switch languages at runtime using the [UserLanguage](../studio/pageLoaders/qodlySources.md#qodlysource-userlanguage) shared source. + +- [Built-in Shared Qodly Namespace](../studio/pageLoaders/qodlySources.md#built-in-shared-qodly-namespace): Introduced a built-in Qodly namespace available across all application pages. It provides ready-to-use qodlysources for shared data handling, including a [Location shared qodlysource](../studio/pageLoaders/qodlySources.md#qodlysource-location) that simplifies working with URL segments, query parameters, and anchors. As well as, a [UserLanguage shared qodlysource](../studio/pageLoaders/qodlySources.md#qodlysource-userlanguage) that allows runtime management of user-selected languages and lists supported locales dynamically; and a [Title shared qodlysource](../studio/pageLoaders/qodlySources.md#qodlysource-title) that enables setting the browser tab title dynamically at runtime. + +- [Connection Status Handling in Renderer](../studio/rendering.md#connection-status-handling): The Renderer now displays connection status messages when the network is lost or restored during rendering. A red banner appears when disconnected, and a green banner confirms when the connection is restored. + +

Improvements

+ +- **Renamed properties in the [intervals datasource](../studio/pageLoaders/components/textinput.md#params-object-properties)** of the text input component for consistency: + + - `toDay` is now `today` + - `startingfrom` is now `startingFrom` + - `untilto` is now `until` + +- **Include Option and Interval Card Toggle**: Added visual controls to improve interval management. The [Include checkbox](../studio/pageLoaders/components/textinput.md#include-checkbox-within-the-card) lets users include or exclude specific date ranges, while the [card toggle](../studio/pageLoaders/components/textinput.md#card-toggle-top-right) allows enabling or disabling intervals without losing their configuration. + +- [HTTP Handlers UI Redesign](../studio/httpHandlers.md): Updated the UI to provide a clearer and more intuitive layout, making it easier to configure and manage request handlers. + +- [Roles and Privileges UI – Button Label Update](../studio/roles/permissionsOverview.md#clean-non-existing-resources): In the Roles and Privileges interface, the **Clear** button was renamed to **Clean** for clarity. This button appears when a resource (like an attribute) is no longer available, and lets users remove outdated permissions. + +- [Initial Value Editing in Qodly Source](../studio/pageLoaders/qodlySources.md#editing-a-qodly-source): For qodlysources with editable properties, initial values now include a **Maximize** button for fields of type `object` or `array`. Clicking the maximize icon opens a popup editor, which can also be expanded to fill the contextual panel, making it easier to edit complex or long values. + +- [Date Picker Navigation in Text Input](../studio/pageLoaders/components/textinput.md#embedded-input): Users can now navigate to the next/previous month and next/previous year directly within the date picker for a smoother selection experience. + + +## Qodly Server + +

What's New

+ +- + +

Improvements

+ +- \ No newline at end of file diff --git a/docs/studio/img/addLocalLocalization.png b/docs/studio/img/addLocalLocalization.png new file mode 100644 index 0000000000..0544557441 Binary files /dev/null and b/docs/studio/img/addLocalLocalization.png differ diff --git a/docs/studio/img/addLocalLocalization2.png b/docs/studio/img/addLocalLocalization2.png new file mode 100644 index 0000000000..25e2a038bb Binary files /dev/null and b/docs/studio/img/addLocalLocalization2.png differ diff --git a/docs/studio/img/availableLocales.png b/docs/studio/img/availableLocales.png new file mode 100644 index 0000000000..320f976e3c Binary files /dev/null and b/docs/studio/img/availableLocales.png differ diff --git a/docs/studio/img/deleteKey.png b/docs/studio/img/deleteKey.png new file mode 100644 index 0000000000..f12f8fd9ec Binary files /dev/null and b/docs/studio/img/deleteKey.png differ diff --git a/docs/studio/img/deleteLocaleButton.png b/docs/studio/img/deleteLocaleButton.png new file mode 100644 index 0000000000..87edfd0392 Binary files /dev/null and b/docs/studio/img/deleteLocaleButton.png differ diff --git a/docs/studio/img/editKey.png b/docs/studio/img/editKey.png new file mode 100644 index 0000000000..b040d01005 Binary files /dev/null and b/docs/studio/img/editKey.png differ diff --git a/docs/studio/img/editLocaleButton.png b/docs/studio/img/editLocaleButton.png new file mode 100644 index 0000000000..eea70e1876 Binary files /dev/null and b/docs/studio/img/editLocaleButton.png differ diff --git a/docs/studio/img/explorerLocalization.png b/docs/studio/img/explorerLocalization.png new file mode 100644 index 0000000000..78052a9d9d Binary files /dev/null and b/docs/studio/img/explorerLocalization.png differ diff --git a/docs/studio/img/exportLitralsButton.png b/docs/studio/img/exportLitralsButton.png new file mode 100644 index 0000000000..290c6b59fc Binary files /dev/null and b/docs/studio/img/exportLitralsButton.png differ diff --git a/docs/studio/img/exportLitralsButton2.png b/docs/studio/img/exportLitralsButton2.png new file mode 100644 index 0000000000..314b96a2f0 Binary files /dev/null and b/docs/studio/img/exportLitralsButton2.png differ diff --git a/docs/studio/img/exportLitralsCheckbox.png b/docs/studio/img/exportLitralsCheckbox.png new file mode 100644 index 0000000000..b7bc198bea Binary files /dev/null and b/docs/studio/img/exportLitralsCheckbox.png differ diff --git a/docs/studio/img/exportLitralsCheckboxAll.png b/docs/studio/img/exportLitralsCheckboxAll.png new file mode 100644 index 0000000000..19b85ad0cb Binary files /dev/null and b/docs/studio/img/exportLitralsCheckboxAll.png differ diff --git a/docs/studio/img/exportLitralsModal.png b/docs/studio/img/exportLitralsModal.png new file mode 100644 index 0000000000..a3887551ca Binary files /dev/null and b/docs/studio/img/exportLitralsModal.png differ diff --git a/docs/studio/img/importLitralsButton.png b/docs/studio/img/importLitralsButton.png new file mode 100644 index 0000000000..02f572f865 Binary files /dev/null and b/docs/studio/img/importLitralsButton.png differ diff --git a/docs/studio/img/importLitralsModal.png b/docs/studio/img/importLitralsModal.png new file mode 100644 index 0000000000..e466130b0d Binary files /dev/null and b/docs/studio/img/importLitralsModal.png differ diff --git a/docs/studio/img/localizationPageKeyLocale.png b/docs/studio/img/localizationPageKeyLocale.png new file mode 100644 index 0000000000..7663d390ed Binary files /dev/null and b/docs/studio/img/localizationPageKeyLocale.png differ diff --git a/docs/studio/img/localizationPageKeyLocale2.png b/docs/studio/img/localizationPageKeyLocale2.png new file mode 100644 index 0000000000..b348f9993b Binary files /dev/null and b/docs/studio/img/localizationPageKeyLocale2.png differ diff --git a/docs/studio/img/localizationResult1.png b/docs/studio/img/localizationResult1.png new file mode 100644 index 0000000000..531d075741 Binary files /dev/null and b/docs/studio/img/localizationResult1.png differ diff --git a/docs/studio/img/localizationResult2.png b/docs/studio/img/localizationResult2.png new file mode 100644 index 0000000000..56d2a8ea4c Binary files /dev/null and b/docs/studio/img/localizationResult2.png differ diff --git a/docs/studio/img/manualEditLocal1.png b/docs/studio/img/manualEditLocal1.png new file mode 100644 index 0000000000..12fbb6b2b2 Binary files /dev/null and b/docs/studio/img/manualEditLocal1.png differ diff --git a/docs/studio/img/manualEditLocal2.png b/docs/studio/img/manualEditLocal2.png new file mode 100644 index 0000000000..a0f1ee6b40 Binary files /dev/null and b/docs/studio/img/manualEditLocal2.png differ diff --git a/docs/studio/img/multipleSupportedLocales.png b/docs/studio/img/multipleSupportedLocales.png new file mode 100644 index 0000000000..c184b2cd1c Binary files /dev/null and b/docs/studio/img/multipleSupportedLocales.png differ diff --git a/docs/studio/img/noLocalLocalization.png b/docs/studio/img/noLocalLocalization.png new file mode 100644 index 0000000000..100d4338f5 Binary files /dev/null and b/docs/studio/img/noLocalLocalization.png differ diff --git a/docs/studio/img/pageDefaultNoLocale.png b/docs/studio/img/pageDefaultNoLocale.png new file mode 100644 index 0000000000..e7d0c1e37e Binary files /dev/null and b/docs/studio/img/pageDefaultNoLocale.png differ diff --git a/docs/studio/img/pageLocalizationButton.png b/docs/studio/img/pageLocalizationButton.png new file mode 100644 index 0000000000..ff4eb2ddb7 Binary files /dev/null and b/docs/studio/img/pageLocalizationButton.png differ diff --git a/docs/studio/img/primaryLocale.png b/docs/studio/img/primaryLocale.png new file mode 100644 index 0000000000..8bf4ec7b59 Binary files /dev/null and b/docs/studio/img/primaryLocale.png differ diff --git a/docs/studio/img/revokeI18nKey.png b/docs/studio/img/revokeI18nKey.png new file mode 100644 index 0000000000..bd431e3e0e Binary files /dev/null and b/docs/studio/img/revokeI18nKey.png differ diff --git a/docs/studio/img/revokeI18nKeyButton.png b/docs/studio/img/revokeI18nKeyButton.png new file mode 100644 index 0000000000..5cf55a26b2 Binary files /dev/null and b/docs/studio/img/revokeI18nKeyButton.png differ diff --git a/docs/studio/img/studioLocaleValue1.png b/docs/studio/img/studioLocaleValue1.png new file mode 100644 index 0000000000..15959015ea Binary files /dev/null and b/docs/studio/img/studioLocaleValue1.png differ diff --git a/docs/studio/img/studioLocaleValue2.png b/docs/studio/img/studioLocaleValue2.png new file mode 100644 index 0000000000..1f690b0def Binary files /dev/null and b/docs/studio/img/studioLocaleValue2.png differ diff --git a/docs/studio/img/styleboxLanguageSwitching.png b/docs/studio/img/styleboxLanguageSwitching.png new file mode 100644 index 0000000000..d9598bcf93 Binary files /dev/null and b/docs/studio/img/styleboxLanguageSwitching.png differ diff --git a/docs/studio/img/styleboxLanguageSwitching2.png b/docs/studio/img/styleboxLanguageSwitching2.png new file mode 100644 index 0000000000..7707442473 Binary files /dev/null and b/docs/studio/img/styleboxLanguageSwitching2.png differ diff --git a/docs/studio/img/textTranslationKey.png b/docs/studio/img/textTranslationKey.png new file mode 100644 index 0000000000..99d8c9a27c Binary files /dev/null and b/docs/studio/img/textTranslationKey.png differ diff --git a/docs/studio/img/tooltipI18n.png b/docs/studio/img/tooltipI18n.png new file mode 100644 index 0000000000..fec829c9c2 Binary files /dev/null and b/docs/studio/img/tooltipI18n.png differ diff --git a/docs/studio/img/tooltipI18nModal.png b/docs/studio/img/tooltipI18nModal.png new file mode 100644 index 0000000000..ff421dc98d Binary files /dev/null and b/docs/studio/img/tooltipI18nModal.png differ diff --git a/docs/studio/img/tooltipI18nModalCreateKey.png b/docs/studio/img/tooltipI18nModalCreateKey.png new file mode 100644 index 0000000000..c0cdf97625 Binary files /dev/null and b/docs/studio/img/tooltipI18nModalCreateKey.png differ diff --git a/docs/studio/img/tooltipI18nModalSearchForKeys.png b/docs/studio/img/tooltipI18nModalSearchForKeys.png new file mode 100644 index 0000000000..9de5913589 Binary files /dev/null and b/docs/studio/img/tooltipI18nModalSearchForKeys.png differ diff --git a/docs/studio/localization.md b/docs/studio/localization.md new file mode 100644 index 0000000000..80943a7a1b --- /dev/null +++ b/docs/studio/localization.md @@ -0,0 +1,542 @@ +--- +id: localization +title: Localization (i18n) +--- + +import Column from '@site/src/components/Column' + +## Overview + +The Localization (i18n) in Qodly provides built-in support for creating multilingual applications without requiring any manual coding. +It enables developers to manage languages, create translation keys, configure dynamic translations for page elements, and allow end-users to switch languages at runtime. + +Localization in Qodly is designed to integrate seamlessly into the visual development workflow. Developers can define locales, manage literals (translated text values), and bind language-switching mechanisms using qodlysources, without needing to manipulate data structures manually. + +:::info Feature Capabilities +- Define supported application locales. +- Set a primary (default) locale for fallback. +- Create and manage translation keys linked to UI components. +- Edit literals per locale directly within the Webform Editor. +- Enable runtime language switching through the UserLanguage shared source. +- Export and import literals using CSV or JSON for external translation processes. +::: + +## Key Concepts + +| Term | Definition | +|---------------------------------|---------------------------------------------------------------| +| Locale | A specific language or regional variation used for translations. | +| Primary Locale | The fallback language displayed when no user selection or supported browser language is available. | +| Literal | A piece of user-facing text that can have translations across multiple locales. | +| Key | A unique reference identifier linking a literal to its translations. | +| UserLanguage | A built-in shared source containing the currently selected locale and the list of supported locales. | + + +## Localization Setup + +### Accessing the Localization Page + + + + The **Localization** page provides a centralized interface for managing application languages and translation keys. + + It is accessible through the **Explorer** view within Qodly Studio. + + From this page, developers can create supported locales, define primary locales, manage literals, and configure translations without modifying application logic. + + + + + + + +### Creating Locales + +A **locale** represents a specific language or regional variant that the application supports. Adding locales allows the application to adapt its content to different audiences. + +To add supported languages: + + + + 1. Navigate to the Localization page. + + 2. Click **Add new Locale** to open the locale selection dropdown. + + + + + + + + + 3. Choose the desired language from the list. + + 4. Validate the selection to add the locale. + + + + + + + + + + Developers can define multiple supported locales by clicking on the "+" button . + + + + + + + +### Setting the Primary Locale + +One of the locales must be set as the **Primary Locale**, which acts as the default language whenever no user preference or browser match is available. + + + +Setting a Primary Locale ensures consistent fallback behavior across user sessions and browsers. + + +### Previewing Locales in the Studio + +By default, no locale is selected when opening a page in the Studio. + + + +Developers can manually switch between configured locales during development to preview how translations appear across languages. + + + + + This is achieved by: + - Clicking the **Localization** button in the [Header panel](./pageLoaders/pageLoaderOverview.md#header-panel) of the page. + + - Selecting any of the available locales to simulate the translated application view. + + + + + + +This preview is strictly for **design-time visualization** within the canvas and does not affect runtime user sessions or language selection persistence. + + +## Translating Content + +A **literal** is any visible text in the application interface (e.g., labels, button texts, titles). By default, each literal exists independently for each locale page. + +### Manual Translation + +Developers can manually modify the literal text **directly** in each locale's version without creating a translation key. + + + + + + + + + + +:::info +This method is simple for small applications but becomes harder to maintain as the number of locales grows. +::: + +### Creating Translation Keys + +For better scalability, **literals can be assigned to translation keys**. A **translation key** links a text element to a centralized reference, allowing it to be easily managed and translated across all supported locales. + +Assigning a translation key enables centralized updates, reduces duplication, and ensures consistency when a literal is reused across different pages or components. + +To create a translation key: + + + + 1. Double-click the text within the text component you want to translate. + + + + + +2. From the tooltip, click on the **i18n** button . + + + 3. A modal will appear showing the current text value. + + + + + + + + 4. In the **Search for keys** field, type the desired key name (for example, `marketingText_Key`). + + + + + + + + 5. The system will suggest creating the key. + + 6. Click **Create** to link your text to the new key. + + + + + + +Once created: + +- The translation key will be automatically associated with the text. + + + :::tip + The key will appear under all locales. + ::: + +- Different values can be assigned for the same key depending on the active locale. + +### Translation Key Scenarios + +Here’s how key assignment works when localizing content: + +1. **Assigning a Key in the Base State (No Locale Selected)**: When no specific locale is selected (you’re in the base state), clicking the purple i18n button adds the key to all locales. + +2. **Assigning a Key While a Locale is Selected**: If a locale is selected when you click the i18n button, the key is still added to all locales, including the base state. + +3. **Manually Editing Labels per Locale (No Key Used)**: Instead of using keys, you can manually update the Label field for each locale. + - Select a locale and directly type the desired label. + - This is quick and flexible but may become harder to manage at scale. + - Use the approach that best matches the complexity and reuse patterns of your UI labels. + + +### Removing a Key from a Literal + +If needed, you can remove a translation key association from a text component: + + + + - Click again on the **i18n** button from the component’s tooltip. + + - In the key field, click the **remove key** ("-") button next to the assigned key. + + + + + + +This action will unlink the text from the translation key, allowing it to behave as a standard independent literal again. + +:::warning +Removing a key from a literal in a specific locale will only affect that locale. The key remains available and associated in other locales where it has already been used. +::: + +### Configuring Key Values Per Locale + +Translation keys maintain a **single unique identifier** across all locales. However, the **value** associated with the key is locale-specific, allowing developers to configure different translations for each supported language. + +To configure key values: + +- Navigate to the Localization page. +- Select the desired locale. +- Locate the relevant translation key. +- Edit the literal value for that locale. +- Confirm the changes. + + + + +By switching between locales inside the Studio and previewing the pages, developers can immediately see how each configured translation appears for different languages. + + + + + + + + + + + +:::info Important Behavior for Key Creation + +When creating locales for the first time, **no keys exist initially**. + +- The first key must be created while translating elements directly on the page using the i18n buttton. +- Once at least one key has been created through a component (e.g., a text field, button label), the Localization page becomes fully enabled for direct key management. +- After the first key is created, you can create additional translation keys directly from the Localization page, even without selecting elements on the page. + +This ensures that key management is progressively unlocked as localization is set up. +::: + +### Add i18n for Other Specific Components + +For components other than the Text component, adding i18n translation keys is done directly through the Properties panel in Qodly Studio. + +For example, to localize the label of a Button component: + +1. Select the component in your page. +2. Go to the Properties tab in the right-hand panel. +3. Locate the Label/Title field. +4. You have three options: + - Assign a key to all locales: Click the purple i18n button next to the label field without selecting a locale. This adds the key for all supported locales. + - Assign a key to a specific locale: First select the target locale from the locale switcher, then click the i18n button. This will assign the key only for that selected locale. + - Manually edit label value: You can also manually change the value of the label per locale without using a translation key. + + +## Managing Locales + +### Editing a Locale + +To edit an existing locale: + +- Navigate to the **Localization** page from the Explorer. +- Locate the locale you want to modify in the list. +- Click on the **Edit** button next to the locale name. +- A language selector dropdown will appear. +- Choose a new language to replace the current one. + +### Removing a Locale + +To completely remove a locale: + +- Navigate to the **Localization** page from the Explorer. +- Find the locale you wish to remove. +- Click on the **Delete** button next to the locale name. + +Removing a locale will: + +- Delete all translation keys associated with that locale. +- Automatically update the `UserLanguage.supported` array, removing the deleted language from the runtime switching options. + + +## Managing Keys + +### Editing a Translation Key + +To edit the value of a translation key for a specific locale: + +1. Go to the Localization page in Qodly Studio. +2. Select the desired locale. +3. Locate the key you wish to update from the list. +4. Click the edit icon or directly click into the value field. +5. Modify the value and click the ✔ button to confirm your changes or ✖ to cancel. + + + +### Deleting a Translation Key + +To delete a translation key entirely from the Localization page: + +1. Open the Localization page. +2. Navigate to the locale where the key is visible. +3. Locate the key in the list and click the delete icon. + + + +Deleting a key will: + +- Remove the key itself. +- Remove all translations associated with it across all locales. +- Unlink any components or literals that were referencing the deleted key. + +Use this option only when the key is no longer needed in the application. + + +## Runtime Language Switching + +To enable dynamic, user-driven language switching at runtime, the application must be configured to bind to the [UserLanguage shared Qodly source](./pageLoaders/qodlySources.md#qodlysource-userlanguage). + +Runtime switching involves the following configuration steps: + + + + 1. Bind the `UserLanguage.supported` to the listbox qodly source. + + 2. Bind the `UserLanguage.selected` to the *Selected Element** of the listbox. + + + + + + +This binding enables users to pick a language dynamically from a dropdown list during runtime. + +When the application is rendered: + + + + - The select box allows the user to switch between available languages. + + + + + + +- Upon selecting a language, the value of `UserLanguage.selected` is updated. + +- The application automatically refreshes the displayed text to match the translations configured for the selected locale. + + + + + + + + + + +:::info +If no UserLanguage binding is configured, language switching will not function in preview or renderer modes, even if locales exist. +::: + +## Localization Feature Behavior + +Localization in Qodly follows a **layered priority model** to determine which language is displayed to the end user at any given moment. + +The priority order for language resolution is: + +1. **User-selected language**: If the user manually selects a language during their session (for example, using a language switcher dropdown), the application will immediately display the selected language and store it in the session. + +2. **Session-stored language**: On subsequent visits, if a session language has been previously stored, the application will automatically reuse this stored language preference without requiring user interaction. + +3. **Browser language detection**: If no session language is set (e.g., on a user's very first login), the application will attempt to detect the user's browser language. + - If the browser language matches one of the supported locales configured in the Localization page, it will be used automatically. + +4. **Primary locale fallback**: If neither a session language nor a matching browser language is available, the application will fall back to displaying the **Primary locale** defined in the Localization settings. + +:::info Behavior for Missing Translations + +If a literal does not have a translation value for the active locale, the original text value (literal) will be displayed as-is. + +This ensures that the application remains functional even if translations are incomplete. + +::: + +## Exporting and Importing Translations + +Qodly makes it easy to manage translations externally by allowing you to **export** and **import** translation files. You can export your application's literals to a CSV or JSON file, translate them externally, and then re-import them back into your application. + +### Export First, then Import + +Before you can import translations into Qodly, you must first export your application's literals. This ensures that the file structure matches the expected internal format. + +You cannot create a valid translation file from scratch or use a file exported from another app. The import process requires a file that was originally exported from your own Qodly app. + +Once exported, you can edit the file using a spreadsheet editor (for CSV) or a code/text editor (for JSON), then re-import it into your app. + +### Exporting Literals + +The **Export** button is initially disabled by default. + +To enable the Export button: + +1. You must select at least one locale from the Localization panel. + +2. You can either: + + - Manually check the box for one or more locales. + + - Or check the **Select All** checkbox to select all available locales at once. + + + Once at least one locale is selected, the **Export** button becomes active . + +3. Click **Export** to open the export configuration modal. + + + + Inside the Export modal: + - Select your preferred export format: + - **CSV**: Suitable for spreadsheet editing or basic translation workflows. + - **JSON**: Suitable for structured editing and external system integration. + - After selecting the format, click **Export**. + + + + + + +A file will be generated and downloaded in the chosen format containing all literals for the selected locales. + +### Importing Literals + +To import translated literals: + - Click the **Import** button located next to the Export options. + + + - A file selector will open. + + - Upload a valid `.csv` or `.json` file matching the export format. + + - Once a file is selected, click **Import** to update your application's literals. + + + + + + +### Supported File Formats + +Qodly supports two export/import formats: JSON and CSV. Each format has its own structure and is suitable for different use cases. + +#### JSON Format + +The JSON format is structured for developers and tools that prefer a nested, key-based structure. + +| Field | Description | +|-------|-------------| +| `webforms.i18n` | Maps component IDs to their translation data. Each ID represents a UI element. | +| `resolverName` | The type of component (e.g., Label, Text, SelectBox). | +| `props` | An array of translated properties, each with: `__dataPath`, `__default`, and one or more language translations. | +| `i18n` | Contains all custom translation keys created by the developer. Each key includes a `default` value and language-specific values. | + +**Example:** +```json +{ + "webforms": { + "i18n": { + "1DVbAUpEoU": { + "resolverName": "Label", + "props": [ + { + "__dataPath": "text", + "__default": "Label", + "en": "Label", + "es": "Label" + } + ] + }, + ... + } + }, + "i18n": { + "marketingText_Key": { + "default": "marketing Style Text", + "en": "Qodly Studio is a modern, low-code development environment...", + "fr": "Qodly Studio est un environnement de développement..." + } + } +} +``` + +#### CSV Format + +The CSV format is ideal for translation teams working in spreadsheet editors. + +| Column | Description | +|--------|-------------| +| `keys` | Path to the literal or translation key. E.g., `webforms.i18n.Z7Gc1JzZ16.doc` or `i18n.marketingText_Key.en`. | +| `resolverName` | Type of the UI component (`Label`, `Text`, etc.). | +| `__t` | The default fallback value shown when a translation is missing. | +| `en`, `es`, `fr`, etc. | Columns for each language code, containing the translated values. | +| `key_default` | The value tied to a custom translation key when applicable. | + +**Example:** +``` +keys,resolverName,__t,en,es,key_default,zh,ja,it,de,fr +webforms.i18n.1DVbAUpEoU.text,Label,"Label","Label","Label" +i18n.marketingText_Key.en,,,,,Qodly Studio is a modern, low-code development environment... +``` diff --git a/docs/studio/pageLoaders/components/fileupload.md b/docs/studio/pageLoaders/components/fileupload.md index ffc5627446..83ccc4b32b 100644 --- a/docs/studio/pageLoaders/components/fileupload.md +++ b/docs/studio/pageLoaders/components/fileupload.md @@ -118,6 +118,16 @@ The qodlysource for the **File Upload** component can take the form of either a Alternatively, you can establish the connection by dragging and dropping the qodlysource onto the File Upload component. ::: +## Example: Sending the File and File Name + +To send both a file and its name to the database, the File Upload component must be bound to a Picture field (e.g., imageEntity.Content) within an entity. However, to capture the file name along with the file itself, you must also reference the entity in the action that handles the file upload. + +For example, in the "Send" button of your form, you can use a function with two parameters: + +uploadImage(imageEntity, imageEntity.Content) + +To implement this, your function should retrieve the picture from imageEntity.Content and the file name from the object (e.g., OB Get($oImage; "path")), then save both to a new entity instance. + ## Showcase Here's a glimpse of how the **File Upload** component will look and behave in action: diff --git a/docs/studio/pageLoaders/components/img/inputType_date.png b/docs/studio/pageLoaders/components/img/inputType_date.png index a1d068474f..ad11d30c56 100644 Binary files a/docs/studio/pageLoaders/components/img/inputType_date.png and b/docs/studio/pageLoaders/components/img/inputType_date.png differ diff --git a/docs/studio/pageLoaders/components/matrix.md b/docs/studio/pageLoaders/components/matrix.md index 333abfc6d6..ebc7886875 100644 --- a/docs/studio/pageLoaders/components/matrix.md +++ b/docs/studio/pageLoaders/components/matrix.md @@ -53,7 +53,7 @@ Enhance the **Matrix** component to align with your application's requirements u diff --git a/docs/studio/pageLoaders/components/selectbox.md b/docs/studio/pageLoaders/components/selectbox.md index 8a721f0d8b..3173fee139 100644 --- a/docs/studio/pageLoaders/components/selectbox.md +++ b/docs/studio/pageLoaders/components/selectbox.md @@ -208,6 +208,9 @@ The Select Box component supports various CSS classes, enabling customization of | `.fd-selectbox__container > div:hover` | Components within choices | Styles individual components inside each choice when hovered. | | `.FdVirtualList` | The select box options list | Applies styles to the list of choices in the select box. | | `.fd-selectbox__menu` | The select box menu | Styles the entire select box menu, including the search area. | +| `.fd-selectbox__search ` | The select box search bar wrapper | Styles the overall container for the search bar. | +| `.fd-selectbox__search__icon ` | The select box search icon | Styles the icon used for searching. | +| `.fd-selectbox__search__input ` | The select box search input field | Styles the text input where users type search terms. | ### Custom styling examples The following examples demonstrate how to customize the Select Box component's appearance. @@ -219,7 +222,7 @@ This example styles the Select Box default view (Header), using a silver backgro
         {`
-self.fd-selectbox {
+self .fd-selectbox {
 border-radius: 10px;
 background-color: #E0E0E0; 
 box-shadow: -4px 4px 10px rgba(220, 220, 220, 0.4), -2px 2px 10px rgba(192, 192, 192, 0.3);
@@ -262,7 +265,7 @@ In this example each choice within the select box is customized with rounded cor
 	
 		
 			{`
-self.fd-selectbox {
+self .fd-selectbox {
 border-radius: 10px;
 background-color: #E0E0E0; 
 box-shadow: -4px 4px 10px rgba(220, 220, 220, 0.4), -2px 2px 10px rgba(192, 192, 192, 0.3);
@@ -290,7 +293,7 @@ In this example, the virtual list of the Select Box is customized by applying a
 	
 		
 			{`
-self.fd-selectbox {
+self .fd-selectbox {
 border-radius: 10px;
 background-color: #E0E0E0; 
 box-shadow: -4px 4px 10px rgba(220, 220, 220, 0.4), -2px 2px 10px rgba(192, 192, 192, 0.3);
@@ -316,7 +319,7 @@ This example customizes the Select Box menu by applying a light gray background,
 	
 		
 			{`
-self.fd-selectbox__menu {
+self .fd-selectbox__menu {
 	color:rgb(152, 92, 8);
 	background-color: #E0E0E0; 
 	font-family: cursive;
@@ -334,6 +337,24 @@ self.fd-selectbox__menu {
 For smooth application of CSS Classes, both `.fd-selectbox` and `.fd-selectbox__menu` should be attached to `self` **without an extra space** unlike other classNames.
 :::
 
+#### Example 6: Custom Search Bar Styling
+This example shows how to apply a dark theme to the search bar using the available CSS classes:
+
+```css
+self {
+	.fd-selectbox__search {
+		background-color: black;
+		color: white;
+	}
+	.fd-selectbox__search__input {
+		background-color: transparent;
+	}
+	.fd-selectbox__search__icon {
+		color: white;
+	}
+}
+```
+
 ## Showcase
 
 Here's a glimpse of how the **Select Box** component will look and behave in action:
diff --git a/docs/studio/pageLoaders/components/textinput.md b/docs/studio/pageLoaders/components/textinput.md
index dc8148c053..6c5a70b074 100644
--- a/docs/studio/pageLoaders/components/textinput.md
+++ b/docs/studio/pageLoaders/components/textinput.md
@@ -146,7 +146,7 @@ Within the **Text Input** component, an embedded **Input** allows for further cu
                 :::
                 
                         
-                                
  • date: Limits input to date values with a date picker.
  • +
  • date: Limits input to date values with a date picker. Users can navigate to the next or previous month, as well as jump to the next or previous year directly within the date picker.
  • @@ -199,6 +199,7 @@ Within the **Text Input** component, an embedded **Input** allows for further cu | `include` | `Boolean` | Defines whether the interval should include (`true`) or exclude (`false`) dates. | | `type` | `String` | Specifies the interval type. Possible values: **startingFrom, until, range, days**. | | `params` | `Object` | Contains details about the interval, such as specific dates or recurring patterns. | + | `active` | `Boolean` | Whether the interval is active. Defaults to true. If false, the interval is ignored. This behaves exactly like the Card Toggle in the UI, which enables or disables the interval block without removing your settings. |
    #### **`params` Object Properties** | **Interval Type** | **Parameters** | **Example JSON Format** | diff --git a/docs/studio/pageLoaders/img/QodlysourceUserLanguage.png b/docs/studio/pageLoaders/img/QodlysourceUserLanguage.png new file mode 100644 index 0000000000..267ed26321 Binary files /dev/null and b/docs/studio/pageLoaders/img/QodlysourceUserLanguage.png differ diff --git a/docs/studio/pageLoaders/img/headerPanel.png b/docs/studio/pageLoaders/img/headerPanel.png index 2f5787ae24..76f6aca5e1 100644 Binary files a/docs/studio/pageLoaders/img/headerPanel.png and b/docs/studio/pageLoaders/img/headerPanel.png differ diff --git a/docs/studio/pageLoaders/img/maximizeQodlySourceEditor.png b/docs/studio/pageLoaders/img/maximizeQodlySourceEditor.png new file mode 100644 index 0000000000..b00edb6cc4 Binary files /dev/null and b/docs/studio/pageLoaders/img/maximizeQodlySourceEditor.png differ diff --git a/docs/studio/pageLoaders/img/pageLocalizationButton.png b/docs/studio/pageLoaders/img/pageLocalizationButton.png new file mode 100644 index 0000000000..fdced0b2c4 Binary files /dev/null and b/docs/studio/pageLoaders/img/pageLocalizationButton.png differ diff --git a/docs/studio/pageLoaders/img/popupEditor.png b/docs/studio/pageLoaders/img/popupEditor.png new file mode 100644 index 0000000000..a962a97182 Binary files /dev/null and b/docs/studio/pageLoaders/img/popupEditor.png differ diff --git a/docs/studio/pageLoaders/img/popupEditor2.png b/docs/studio/pageLoaders/img/popupEditor2.png new file mode 100644 index 0000000000..4b4f278508 Binary files /dev/null and b/docs/studio/pageLoaders/img/popupEditor2.png differ diff --git a/docs/studio/pageLoaders/pageLoaderOverview.md b/docs/studio/pageLoaders/pageLoaderOverview.md index bb7e418914..a9ad5a12b5 100644 --- a/docs/studio/pageLoaders/pageLoaderOverview.md +++ b/docs/studio/pageLoaders/pageLoaderOverview.md @@ -86,6 +86,14 @@ The Page Editor enhances your application by providing a versatile toolkit for i
    +### Localization (i18n) + +The Localization button Localization Icon in the header panel lets you preview your application in the different locales you created from the Localization page. + +:::info +For further details, refer to the [Localization (i18n)](../localization.md) section. +::: + ### Dialogs The Dialog button Dialog Icon in the header panel provides access to a list of Dialogs. Each Dialog is designed as a popup overlay, aimed at enhancing user engagement by displaying additional content within the existing Page. diff --git a/docs/studio/pageLoaders/qodlySources.md b/docs/studio/pageLoaders/qodlySources.md index 7708949a04..29e6df6bbd 100644 --- a/docs/studio/pageLoaders/qodlySources.md +++ b/docs/studio/pageLoaders/qodlySources.md @@ -76,13 +76,13 @@ The `Qodly` namespace . +Within the **Qodly** namespace, you'll find the predefined qodlysource named **Location** . The Location qodlysource is specifically designed to facilitate handling URL-related data, making it simple to interact with different URL segments. @@ -114,7 +114,90 @@ The Location qodlysource is specifically designed to facilitate handling URL-rel ``` :::info Restrictions: -The **Location** datasource is shared across your entire application and **cannot be edited or deleted**. This ensures uniform behavior and prevents accidental modifications. +The **Location** qodlysource is shared across your entire application and **cannot be edited or deleted**. This ensures uniform behavior and prevents accidental modifications. +::: + +### Qodlysource: UserLanguage + +Within the **Qodly** namespace, you'll find the predefined qodlysource named **UserLanguage** . + +The UserLanguage qodlysource is specifically designed to manage multilingual behavior within your application by storing the currently selected language and the list of available supported languages. + +It provides a seamless way to bind user-selected languages at runtime without requiring manual coding or session handling. + +#### Key Attributes of UserLanguage: + +- **selected** *(Object)*: Stores the currently active locale chosen by the user. This object contains information about the selected language. + + **Structure:** + ```javascript + { + isocode: "en", + locale: "anglais", + native: "English" + } + ``` + + Each locale entry include: + - `isocode`: Standard two-letter language code (e.g., "en" for English). + - `locale`: Display name for the language. + - `native`: Native name for the language (as spoken in that locale). + + **Example:** + ```javascript + UserLanguage.selected // → { isocode: "fr", locale: "français", native: "Français" } + ``` + +- **supported** (Array): Lists all the available supported locales that the user has created in the **Localization page**. Each entry in the array represents one locale and must follow the same structure as the `selected` object. + + **Structure:** + ```javascript + [ + { + isocode: "en", + locale: "anglais", + native: "English" + }, + { + isocode: "de", + locale: "allemand", + native: "Deutsch" + } + ] + ``` + + **Example:** + ```javascript + UserLanguage.supported // → [ + // { isocode: "en", locale: "anglais", native: "English" }, + // { isocode: "es", locale: "espagnol", native: "Español" } + // ] + ``` + +:::info Restrictions: +The **UserLanguage** qodlysource is shared across your entire application and **cannot be deleted or edited manually**. + +To modify the list of supported languages (adding or removing locales), you must update the configuration from the [Localization page](../localization.md#accessing-the-localization-page). +Changes made in the Localization page will automatically be reflected in the `UserLanguage.supported` array. +::: + +### Qodlysource: Title + +Within the Qodly namespace, you'll find the predefined qodlysource named Title. + +The Title qodlysource is specifically designed to control the browser tab title dynamically. By default, the browser tab title is derived from the name of the current Page. When the Qodly.Title qodlysource is defined, it overrides this behavior and sets the tab title based on its value. + +#### Key Behavior of Title: + +- **Override tab title**: When a value is set in Qodly.Title, it becomes the browser tab title, replacing the default Page-based title. + +- **Fallback behavior**: If Qodly.Title is not defined, the default behavior remains in place, and the tab title is derived from the Page name. + + +:::info Restrictions: +The **Title** qodlysource is shared across your entire application and **cannot be deleted or edited manually**. + +It is of type String and its value is editable at runtime to allow dynamic updates to the tab title. ::: @@ -274,6 +357,24 @@ For Entity Selection or Entity types, make sure to also configure additional set
    + + + If the value is long or complex, a Maximize button appears (only for object and array types), opening a popup editor to give you more editing space. + + + + + + + + + The popup itself can also be maximized to cover the full contextual panel for better visibility. + + + + + + ### Renaming a Qodly Source You can easily rename a qodlysource from the contextual panel. In doing so, Qodly Studio will automatically update references to the renamed qodlysource: diff --git a/docs/studio/rendering.md b/docs/studio/rendering.md index 714a59be83..8447793f61 100644 --- a/docs/studio/rendering.md +++ b/docs/studio/rendering.md @@ -179,4 +179,27 @@ Understanding the lifecycle of a page is crucial for diagnosing and fixing rende - **Loading JSON of Sub Pages**: In some cases, additional sub pages need to be loaded dynamically based on user interactions or specific conditions. This involves fetching and loading JSON files for sub pages, allowing for the dynamic expansion of content. - - **Restarting Initialization for Sub Pages**: Once the JSON of sub pages is loaded, the initialization process restarts from **initializing local Qodly sources** for these sub pages. This ensures that each sub page has access to the necessary data and components, repeating the initialization steps to prepare the sub page for display. \ No newline at end of file + - **Restarting Initialization for Sub Pages**: Once the JSON of sub pages is loaded, the initialization process restarts from **initializing local Qodly sources** for these sub pages. This ensures that each sub page has access to the necessary data and components, repeating the initialization steps to prepare the sub page for display. + +## Connection Status Handling + +The Qodly Renderer displays system messages when the client loses or regains network connectivity during rendering. + +These messages appear as colored banners at the top of the page and provide immediate feedback without interrupting the current page state. + +#### When the connection is lost: + +* A red banner is displayed at the top of the rendered page. +* The message shown is: + **Connection lost** +* The banner remains visible until: + + * The connection is restored, or + * The user manually closes it using the close button located in the top-right corner of the banner. + +#### When the connection is re-established: + +* A green banner is displayed with the message: + **Connection restored** +* This message automatically disappears after a few seconds. +* No user action is required to dismiss it. \ No newline at end of file diff --git a/docs/studio/roles/example-of-configuration.md b/docs/studio/roles/example-of-configuration.md index b119c57aea..8e3612d5a7 100644 --- a/docs/studio/roles/example-of-configuration.md +++ b/docs/studio/roles/example-of-configuration.md @@ -101,10 +101,17 @@ Only the *Doctor* role can view the patient's confidential data (gathered in a * -2. Assign it to the *Doctor* role (see [roles](#roles) below). This will exclude all other roles). ​ +2. Assign it to the *Doctor* role (see [roles](#roles) below). This will exclude all other roles. ​ +:::info Why are all other roles excluded? + +Once a resource is associated with a privilege, that privilege is required to access the resource, which blocks roles that do not have that privilege. It's like putting a lock on a door: you need to have the key to open it. In this case, we created the *viewConfidentialInfo* privilege and associated it to the `Patients.confidentialInfo` attribute, so it automatically impacts roles that do not have this privilege (i.e., Secretary). +Usually, when reading entities, if a privilege is missing to read certain attributes, they are excluded (filtered) from the query response. + +::: + ### Roles Here are the corresponding role definitions. diff --git a/docs/studio/roles/img/example-viewsecretinfo.png b/docs/studio/roles/img/example-viewsecretinfo.png index 387027079e..9eecd28761 100644 Binary files a/docs/studio/roles/img/example-viewsecretinfo.png and b/docs/studio/roles/img/example-viewsecretinfo.png differ diff --git a/sidebars.js b/sidebars.js index aeae91a5c5..67c83f58ae 100644 --- a/sidebars.js +++ b/sidebars.js @@ -183,6 +183,11 @@ const sidebars = { id: 'studio/httpHandlers', label: "HTTP Handlers" }, + { + type: 'doc', + id: 'studio/localization', + label: "Localization (i18n)" + }, { type: 'doc', id: 'studio/settings', @@ -534,13 +539,13 @@ const sidebars = { }, 'qodlyLookerStudio/qodlyLookerStudioConnector', { - type: "link", - label: "Third-party Authentication", - href: "https://github.com/4d/4D-NetKit/tree/20R8#oauth2provider" + type: 'link', + label: 'OAuth 2.0', + href: 'https://github.com/4d/4D-NetKit/tree/20R8#oauth2provider' }, { type: 'category', - label: 'Email Integration', + label: 'Email', items: [ { type: 'link', diff --git a/versioned_docs/version-1.1.0/studio/roles/example-of-configuration.md b/versioned_docs/version-1.1.0/studio/roles/example-of-configuration.md index b119c57aea..8e3612d5a7 100644 --- a/versioned_docs/version-1.1.0/studio/roles/example-of-configuration.md +++ b/versioned_docs/version-1.1.0/studio/roles/example-of-configuration.md @@ -101,10 +101,17 @@ Only the *Doctor* role can view the patient's confidential data (gathered in a * -2. Assign it to the *Doctor* role (see [roles](#roles) below). This will exclude all other roles). ​ +2. Assign it to the *Doctor* role (see [roles](#roles) below). This will exclude all other roles. ​ +:::info Why are all other roles excluded? + +Once a resource is associated with a privilege, that privilege is required to access the resource, which blocks roles that do not have that privilege. It's like putting a lock on a door: you need to have the key to open it. In this case, we created the *viewConfidentialInfo* privilege and associated it to the `Patients.confidentialInfo` attribute, so it automatically impacts roles that do not have this privilege (i.e., Secretary). +Usually, when reading entities, if a privilege is missing to read certain attributes, they are excluded (filtered) from the query response. + +::: + ### Roles Here are the corresponding role definitions. diff --git a/versioned_docs/version-1.1.0/studio/roles/img/example-viewsecretinfo.png b/versioned_docs/version-1.1.0/studio/roles/img/example-viewsecretinfo.png index 387027079e..9eecd28761 100644 Binary files a/versioned_docs/version-1.1.0/studio/roles/img/example-viewsecretinfo.png and b/versioned_docs/version-1.1.0/studio/roles/img/example-viewsecretinfo.png differ