diff --git a/docs/#Project/Pages/Translations.drawio b/docs/#Project/Pages/Translations.drawio new file mode 100644 index 0000000..78684ae --- /dev/null +++ b/docs/#Project/Pages/Translations.drawio @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7fbcd3b23f0c23bb52a72a634a84f7f0b71c707293f0d81991bebc4d93099ca2 +size 306765 diff --git a/public/smartcomponent/svg-layout-designer.ts b/public/smartcomponent/svg-layout-designer.ts index c6ccf8b..66fc222 100644 --- a/public/smartcomponent/svg-layout-designer.ts +++ b/public/smartcomponent/svg-layout-designer.ts @@ -5,6 +5,7 @@ type IHistoryState = SVGLD.IHistoryState; type IEditorState = SVGLD.IEditorState; type IConfiguration = SVGLD.IConfiguration; + type ILanguage = SVGLD.ILanguage; export class SVGLayoutDesigner extends Components.ComponentBase { @@ -210,6 +211,43 @@ const component = this.GetAppComponent(); component.dispatchEvent(new CustomEvent(eventType, { detail: configuration })); } + + /** + * Add a language to the app + * @param option Displayed string of the language + * @param language Language containing an id and a dictionary + * @param callback Callback + */ + public AddLanguage(option: string, language: ILanguage, callback?: () => void) { + const eventType = 'addLanguage'; + this.app.AddEventListener(eventType, callback); + const component = this.GetAppComponent(); + component.dispatchEvent(new CustomEvent(eventType, { detail: { language, option } })); + } + + /** + * Set the language of the app (defaults: ['fr', 'en']) + * @param languageId Language identifier for the language to select + * @param callback Callback + */ + public SetLanguage(languageId: string, callback?: (success: boolean) => void) { + const eventType = 'setLanguage'; + this.app.AddEventListener(eventType, callback); + const component = this.GetAppComponent(); + component.dispatchEvent(new CustomEvent(eventType, { detail: languageId })); + } + + /** + * Set the language of the app (defaults: ['fr', 'en']) + * @param languageId Language identifier for the language to select + * @param callback Callback + */ + public GetLanguages(callback: (languages: Record>) => void) { + const eventType = 'getLanguages'; + this.app.AddEventListener(eventType, callback); + const component = this.GetAppComponent(); + component.dispatchEvent(new CustomEvent(eventType)); + } } diff --git a/public/svgld.d.ts b/public/svgld.d.ts index 49a0de3..cf70054 100644 --- a/public/svgld.d.ts +++ b/public/svgld.d.ts @@ -88,6 +88,7 @@ export interface IAPIConfiguration { + /** Model of available container used in application configuration */ export interface IAvailableContainer { /** type */ @@ -212,7 +213,7 @@ export interface IAvailableContainer { * (optional) * User data that can be used for data storage or custom SVG */ - UserData?: object; + UserData?: IKeyValue[]; } @@ -250,7 +251,6 @@ export interface IConfiguration { export interface IContainerModel { children: string[]; - parent: IContainerModel | null; properties: IContainerProperties; userData: Record; } @@ -260,10 +260,9 @@ export interface IContainerModel { */ export class ContainerModel implements IContainerModel { children: string[]; - parent: IContainerModel | null; properties: IContainerProperties; userData: Record; - constructor(parent: IContainerModel | null, properties: IContainerProperties, children?: string[], userData?: {}); + constructor(properties: IContainerProperties, children?: string[], userData?: {}); } @@ -271,6 +270,7 @@ export class ContainerModel implements IContainerModel { + /** * Properties of a container */ @@ -363,7 +363,7 @@ export interface IContainerProperties { * (optional) * User data that can be used for data storage or custom SVG */ - userData?: object; + userData?: IKeyValue[]; } @@ -428,6 +428,17 @@ export interface IInputGroup { value: string; } +export interface IKeyValue { + Key: string; + Value: string; +} + +export interface ILanguage { + language: string; + dictionary: Record; + languageChange?: (selected: string) => void; +} + export interface IMargin { left?: number; bottom?: number; diff --git a/src/Components/App/App.tsx b/src/Components/App/App.tsx index ef86b3c..66ef475 100644 --- a/src/Components/App/App.tsx +++ b/src/Components/App/App.tsx @@ -1,4 +1,4 @@ -import React, { Dispatch, SetStateAction, useCallback, useEffect, useRef, useState } from 'react'; +import React, { Dispatch, SetStateAction, useCallback, useContext, useEffect, useRef, useState } from 'react'; import { UseCustomEvents } from '../../Events/AppEvents'; import { MainMenu } from '../MainMenu/MainMenu'; import { ContainerModel, IContainerModel } from '../../Interfaces/IContainerModel'; @@ -7,6 +7,7 @@ import { IEditorState } from '../../Interfaces/IEditorState'; import { LoadState } from './Actions/Load'; import { LoadEditor, NewEditor } from './Actions/MenuActions'; import { DEFAULT_CONFIG, DEFAULT_MAINCONTAINER_PROPS } from '../../utils/default'; +import { LanguageContext } from '../LanguageProvider/LanguageProvider'; // App will never have props // eslint-disable-next-line @typescript-eslint/no-empty-interface @@ -44,6 +45,7 @@ function UseHTTPGETStatePreloading( export function App(props: IAppProps): JSX.Element { const [isLoaded, setLoaded] = useState(false); const appRef = useRef(null); + const languageContext = useContext(LanguageContext); const defaultMainContainer = new ContainerModel( DEFAULT_MAINCONTAINER_PROPS @@ -68,6 +70,7 @@ export function App(props: IAppProps): JSX.Element { UseCustomEvents( props.root, appRef, + languageContext, setEditorState, setLoaded ); diff --git a/src/Components/Bar/Bar.tsx b/src/Components/Bar/Bar.tsx index 4c0b5e7..8f28635 100644 --- a/src/Components/Bar/Bar.tsx +++ b/src/Components/Bar/Bar.tsx @@ -14,6 +14,7 @@ import { Cog8ToothIcon as Cog8ToothIconS } from '@heroicons/react/24/solid'; import { BarIcon } from './BarIcon'; +import { Text } from '../Text/Text'; interface IBarProps { isComponentsOpen: boolean @@ -35,7 +36,7 @@ export function Bar(props: IBarProps): JSX.Element {
props.toggleComponents()}> { props.isComponentsOpen @@ -45,7 +46,7 @@ export function Bar(props: IBarProps): JSX.Element { props.toggleSymbols()}> { props.isSymbolsOpen @@ -55,7 +56,7 @@ export function Bar(props: IBarProps): JSX.Element { props.toggleMessages()}> { props.isMessagesOpen @@ -66,7 +67,7 @@ export function Bar(props: IBarProps): JSX.Element {
props.toggleTimeline()}> { props.isHistoryOpen @@ -76,7 +77,7 @@ export function Bar(props: IBarProps): JSX.Element { props.toggleSettings()}> { props.isSettingsOpen diff --git a/src/Components/Components/Components.tsx b/src/Components/Components/Components.tsx index ee4c99a..53a3dd9 100644 --- a/src/Components/Components/Components.tsx +++ b/src/Components/Components/Components.tsx @@ -5,6 +5,7 @@ import { ICategory } from '../../Interfaces/ICategory'; import { IContainerModel } from '../../Interfaces/IContainerModel'; import { TruncateString } from '../../utils/stringtools'; import { Category } from '../Category/Category'; +import { Text } from '../Text/Text'; interface IComponentsProps { selectedContainer: IContainerModel | undefined @@ -24,7 +25,7 @@ interface SidebarCategory { export function Components(props: IComponentsProps): JSX.Element { const [hideDisabled, setHideDisabled] = React.useState(false); - const disabledTitle = hideDisabled ? 'Show disabled components' : 'Hide disabled components'; + const disabledTitle = hideDisabled ? Text({ textId: '@ShowDisabledComponents' }) : Text({ textId: '@HideDisabledComponents' }); const rootElements: Array = []; const categories = new Map(props.categories.map(category => [ diff --git a/src/Components/ContainerProperties/ContainerForm.tsx b/src/Components/ContainerProperties/ContainerForm.tsx index 31718b5..28c893f 100644 --- a/src/Components/ContainerProperties/ContainerForm.tsx +++ b/src/Components/ContainerProperties/ContainerForm.tsx @@ -4,6 +4,7 @@ import { IContainerProperties } from '../../Interfaces/IContainerProperties'; import { ISymbolModel } from '../../Interfaces/ISymbolModel'; import { SHOW_BORROWER_DIMENSIONS, SHOW_CHILDREN_DIMENSIONS, SHOW_SELF_DIMENSIONS } from '../../utils/default'; import { ApplyWidthMargin, ApplyXMargin, RemoveWidthMargin, RemoveXMargin, RestoreX, RestoreY, TransformX, TransformY } from '../../utils/svg'; +import { Text } from '../Text/Text'; import { InputGroup } from '../InputGroup/InputGroup'; import { TextInputGroup } from '../InputGroup/TextInputGroup'; import { Select } from '../Select/Select'; @@ -44,7 +45,7 @@ export function ContainerForm(props: IContainerFormProps): JSX.Element {
@@ -62,14 +63,14 @@ export function ContainerForm(props: IContainerFormProps): JSX.Element {
-
props.onChange('minWidth', Number(value))} />
props.onChange('minHeight', Number(value))} />
props.onChange('left', Number(value), PropertyType.Margin)} /> props.onChange('bottom', Number(value), PropertyType.Margin)} /> props.onChange('top', Number(value), PropertyType.Margin)} />
props.onChange('isFlex', event.target.checked)} /> @@ -321,14 +323,14 @@ export function ContainerForm(props: IContainerFormProps): JSX.Element {