mirror of
https://github.com/IT4Change/ohmyform-ui.git
synced 2025-12-12 17:25:51 +00:00
add german ad english translations
This commit is contained in:
parent
f346ed3900
commit
0698c337f8
@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
### Added
|
||||
|
||||
- `SPA` env variable to have static page with loading spinner before redirect
|
||||
- `de`, `fr`, `es`, `it`, `cn` base folders for translations
|
||||
|
||||
### Changed
|
||||
|
||||
|
||||
@ -35,3 +35,16 @@
|
||||
position: fixed
|
||||
}
|
||||
}
|
||||
|
||||
.admin {
|
||||
.sidemenu {
|
||||
.ant-layout-sider-children {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.language-selector {
|
||||
padding-left: 12px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
import {Button} from 'antd'
|
||||
import {UpOutlined} from '@ant-design/icons/lib'
|
||||
import {Button, Menu, Select} from 'antd'
|
||||
import Link from 'next/link'
|
||||
import {useRouter} from 'next/router'
|
||||
import React from 'react'
|
||||
import {useTranslation} from 'react-i18next'
|
||||
import {languages} from '../../i18n'
|
||||
import {clearAuth, withAuth} from '../with.auth'
|
||||
|
||||
interface Props {
|
||||
@ -13,7 +15,7 @@ interface Props {
|
||||
}
|
||||
|
||||
const AuthFooterInner: React.FC<Props> = props => {
|
||||
const { t } = useTranslation()
|
||||
const { t, i18n } = useTranslation()
|
||||
const router = useRouter()
|
||||
|
||||
const logout = () => {
|
||||
@ -28,6 +30,8 @@ const AuthFooterInner: React.FC<Props> = props => {
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
}}
|
||||
>
|
||||
<Link href={'/admin'}>
|
||||
@ -72,14 +76,24 @@ const AuthFooterInner: React.FC<Props> = props => {
|
||||
</Link>
|
||||
]
|
||||
)}
|
||||
|
||||
<div style={{flex: 1}} />
|
||||
<Select
|
||||
bordered={false}
|
||||
value={i18n.language.replace(/-.*/, '')}
|
||||
onChange={next => i18n.changeLanguage(next)}
|
||||
style={{
|
||||
color: '#FFF',
|
||||
}}
|
||||
suffixIcon={false}
|
||||
>
|
||||
{languages.map(language => <Select.Option value={language} key={language}>{t(`language:${language}`)}</Select.Option> )}
|
||||
</Select>
|
||||
<Button
|
||||
type={'link'}
|
||||
target={'_blank'}
|
||||
ghost
|
||||
href={'https://www.ohmyform.com'}
|
||||
style={{
|
||||
float: 'right',
|
||||
color: '#FFF'
|
||||
}}
|
||||
>
|
||||
|
||||
@ -1,13 +1,16 @@
|
||||
import {Form, Input, Select, Switch, Tabs} from 'antd'
|
||||
import {TabPaneProps} from 'antd/lib/tabs'
|
||||
import React from 'react'
|
||||
import {useTranslation} from 'react-i18next'
|
||||
import {languages} from '../../../i18n'
|
||||
|
||||
export const BaseDataTab: React.FC<TabPaneProps> = props => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<Tabs.TabPane {...props}>
|
||||
<Form.Item
|
||||
label="Is Live"
|
||||
label={t('form:baseData.isLive')}
|
||||
name={['form', 'isLive']}
|
||||
valuePropName={'checked'}
|
||||
>
|
||||
@ -15,12 +18,12 @@ export const BaseDataTab: React.FC<TabPaneProps> = props => {
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label="Title"
|
||||
label={t('form:baseData.title')}
|
||||
name={['form', 'title']}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: 'Please provide a Title',
|
||||
message: t('validation:titleRequired'),
|
||||
},
|
||||
]}
|
||||
>
|
||||
@ -28,22 +31,22 @@ export const BaseDataTab: React.FC<TabPaneProps> = props => {
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label="Language"
|
||||
label={t('form:baseData.language')}
|
||||
name={['form', 'language']}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: 'Please select a Language',
|
||||
message: t('validation:languageRequired'),
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Select>
|
||||
{languages.map(language => <Select.Option value={language} key={language}>{language.toUpperCase()}</Select.Option> )}
|
||||
{languages.map(language => <Select.Option value={language} key={language}>{t(`language:${language}`)}</Select.Option> )}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label="Show Footer"
|
||||
label={t('form:baseData.showFooter')}
|
||||
name={['form', 'showFooter']}
|
||||
valuePropName={'checked'}
|
||||
>
|
||||
|
||||
@ -1,27 +1,30 @@
|
||||
import {Form, Input, Tabs} from 'antd'
|
||||
import {TabPaneProps} from 'antd/lib/tabs'
|
||||
import React from 'react'
|
||||
import {useTranslation} from 'react-i18next'
|
||||
import {InputColor} from '../../input/color'
|
||||
|
||||
export const DesignTab: React.FC<TabPaneProps> = props => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<Tabs.TabPane {...props}>
|
||||
<Form.Item
|
||||
label="Font"
|
||||
label={t('form:design.font')}
|
||||
name={['form', 'design', 'font']}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
|
||||
{[
|
||||
{name: 'backgroundColor', label: 'Background Color'},
|
||||
{name: 'questionColor', label: 'Question Color'},
|
||||
{name: 'answerColor', label: 'Answer Color'},
|
||||
{name: 'buttonColor', label: 'Button Color'},
|
||||
{name: 'buttonActiveColor', label: 'Button Active Color'},
|
||||
{name: 'buttonTextColor', label: 'Button Text Color'},
|
||||
].map(({label, name}) => (
|
||||
<Form.Item key={name} label={label} name={['form', 'design', 'colors', name]}>
|
||||
'backgroundColor',
|
||||
'questionColor',
|
||||
'answerColor',
|
||||
'buttonColor',
|
||||
'buttonActiveColor',
|
||||
'buttonTextColor',
|
||||
].map(name => (
|
||||
<Form.Item key={name} label={t(`form:design.${name}`)} name={['form', 'design', 'colors', name]}>
|
||||
<InputColor />
|
||||
</Form.Item>
|
||||
))}
|
||||
|
||||
@ -2,13 +2,16 @@ import {DeleteOutlined, PlusOutlined} from '@ant-design/icons/lib'
|
||||
import {Button, Card, Form, Input, Switch, Tabs} from 'antd'
|
||||
import {TabPaneProps} from 'antd/lib/tabs'
|
||||
import React from 'react'
|
||||
import {useTranslation} from 'react-i18next'
|
||||
import {InputColor} from '../../input/color'
|
||||
|
||||
export const EndPageTab: React.FC<TabPaneProps> = props => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<Tabs.TabPane {...props}>
|
||||
<Form.Item
|
||||
label={'Show'}
|
||||
label={t('form:endPage.show')}
|
||||
name={['form', 'endPage', 'show']}
|
||||
valuePropName={'checked'}
|
||||
>
|
||||
@ -16,21 +19,21 @@ export const EndPageTab: React.FC<TabPaneProps> = props => {
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label={'Title'}
|
||||
label={t('form:endPage.title')}
|
||||
name={['form', 'endPage', 'title']}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label={'Paragraph'}
|
||||
label={t('form:endPage.paragraph')}
|
||||
name={['form', 'endPage', 'paragraph']}
|
||||
>
|
||||
<Input.TextArea autoSize />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label={'Continue Button Text'}
|
||||
label={t('form:endPage.continueButtonText')}
|
||||
name={['form', 'endPage', 'buttonText']}
|
||||
>
|
||||
<Input />
|
||||
@ -47,7 +50,7 @@ export const EndPageTab: React.FC<TabPaneProps> = props => {
|
||||
wrapperCol={{
|
||||
sm: { offset: index === 0 ? 0 : 6 },
|
||||
}}
|
||||
label={index === 0 ? 'Buttons' : ''}
|
||||
label={index === 0 ? t('form:endPage.buttons') : ''}
|
||||
key={field.key}
|
||||
>
|
||||
<Card
|
||||
@ -56,28 +59,28 @@ export const EndPageTab: React.FC<TabPaneProps> = props => {
|
||||
]}
|
||||
>
|
||||
<Form.Item
|
||||
label={'Url'}
|
||||
label={t('form:endPage.url')}
|
||||
name={[field.key, 'url']}
|
||||
rules={[
|
||||
{type: 'url', message: 'Must be a valid url'}
|
||||
{type: 'url', message: t('validation:invalidUrl')}
|
||||
]}
|
||||
labelCol={{ span: 6 }}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item label={'Action'} name={[field.key, 'action']} labelCol={{ span: 6 }}>
|
||||
<Form.Item label={t('form:endPage.action')} name={[field.key, 'action']} labelCol={{ span: 6 }}>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item label={'Text'} name={[field.key, 'text']} labelCol={{ span: 6 }}>
|
||||
<Form.Item label={t('form:endPage.text')} name={[field.key, 'text']} labelCol={{ span: 6 }}>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item label={'Background Color'} name={[field.key, 'bgColor']} labelCol={{ span: 6 }}>
|
||||
<Form.Item label={t('form:endPage.bgColor')} name={[field.key, 'bgColor']} labelCol={{ span: 6 }}>
|
||||
<InputColor />
|
||||
</Form.Item>
|
||||
<Form.Item label={'Active Color'} name={[field.key, 'activeColor']} labelCol={{ span: 6 }}>
|
||||
<Form.Item label={t('form:endPage.activeColor')} name={[field.key, 'activeColor']} labelCol={{ span: 6 }}>
|
||||
<InputColor />
|
||||
</Form.Item>
|
||||
<Form.Item label={'Color'} name={[field.key, 'color']} labelCol={{ span: 6 }}>
|
||||
<Form.Item label={t('form:endPage.color')} name={[field.key, 'color']} labelCol={{ span: 6 }}>
|
||||
<InputColor />
|
||||
</Form.Item>
|
||||
</Card>
|
||||
@ -96,7 +99,7 @@ export const EndPageTab: React.FC<TabPaneProps> = props => {
|
||||
}}
|
||||
style={{ width: '60%' }}
|
||||
>
|
||||
<PlusOutlined /> Add Button
|
||||
<PlusOutlined /> {t('form:endPage.addButton')}
|
||||
</Button>
|
||||
</Form.Item>
|
||||
</div>
|
||||
|
||||
@ -3,6 +3,7 @@ import {Button, Card, Checkbox, Form, Input, Popconfirm, Tag} from 'antd'
|
||||
import {FormInstance} from 'antd/lib/form'
|
||||
import {FieldData} from 'rc-field-form/lib/interface'
|
||||
import React, {useEffect, useState} from 'react'
|
||||
import {useTranslation} from 'react-i18next'
|
||||
import {AdminFormFieldFragment} from '../../../graphql/fragment/admin.form.fragment'
|
||||
import {adminTypes} from './types'
|
||||
import {TextType} from './types/text.type'
|
||||
@ -17,6 +18,7 @@ interface Props {
|
||||
}
|
||||
|
||||
export const FieldCard: React.FC<Props> = props => {
|
||||
const { t } = useTranslation()
|
||||
const {
|
||||
form,
|
||||
field,
|
||||
@ -54,11 +56,11 @@ export const FieldCard: React.FC<Props> = props => {
|
||||
type={'inner'}
|
||||
extra={(
|
||||
<div>
|
||||
<Tag color={'blue'}>{type}</Tag>
|
||||
<Tag color={'blue'}>{t(`type:${type}.name`)}</Tag>
|
||||
<Popconfirm
|
||||
placement={'left'}
|
||||
title={'Really remove this field? Check that it is not referenced anywhere!'}
|
||||
okText={'Delete Field'}
|
||||
title={t('type:confirmDelete')}
|
||||
okText={t('type:deleteNow')}
|
||||
okButtonProps={{ danger: true }}
|
||||
onConfirm={() => {
|
||||
remove(index)
|
||||
@ -75,7 +77,7 @@ export const FieldCard: React.FC<Props> = props => {
|
||||
>
|
||||
<Form.Item name={[field.name as string, 'type']} noStyle><Input type={'hidden'} /></Form.Item>
|
||||
<Form.Item
|
||||
label={'Title'}
|
||||
label={t('type:title')}
|
||||
name={[field.name as string, 'title']}
|
||||
rules={[
|
||||
{ required: true, message: 'Title is required' }
|
||||
@ -85,18 +87,18 @@ export const FieldCard: React.FC<Props> = props => {
|
||||
<Input onChange={e => setNextTitle(e.target.value)}/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={'Description'}
|
||||
label={t('type:description')}
|
||||
name={[field.name as string, 'description']}
|
||||
labelCol={{ span: 6 }}
|
||||
>
|
||||
<Input.TextArea autoSize />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={'Required'}
|
||||
label={t('type:required')}
|
||||
name={[field.name as string, 'required']}
|
||||
labelCol={{ span: 6 }}
|
||||
valuePropName={'checked'}
|
||||
extra={type === 'hidden' && 'If required, default value must be set to enable users to submit form!'}
|
||||
extra={type === 'hidden' && t('type:requiredInfo')}
|
||||
>
|
||||
<Checkbox />
|
||||
</Form.Item>
|
||||
|
||||
@ -3,6 +3,7 @@ import {Button, Form, Select, Space, Tabs} from 'antd'
|
||||
import {FormInstance} from 'antd/lib/form'
|
||||
import {TabPaneProps} from 'antd/lib/tabs'
|
||||
import React, {useCallback, useState} from 'react'
|
||||
import {useTranslation} from 'react-i18next'
|
||||
import {AdminFormFieldFragment} from '../../../graphql/fragment/admin.form.fragment'
|
||||
import {FieldCard} from './field.card'
|
||||
import {adminTypes} from './types'
|
||||
@ -14,6 +15,7 @@ interface Props extends TabPaneProps {
|
||||
}
|
||||
|
||||
export const FieldsTab: React.FC<Props> = props => {
|
||||
const { t } = useTranslation()
|
||||
const [nextType, setNextType] = useState('textfield')
|
||||
|
||||
const renderType = useCallback((field, index, remove) => {
|
||||
@ -41,7 +43,7 @@ export const FieldsTab: React.FC<Props> = props => {
|
||||
}}
|
||||
>
|
||||
<Select value={nextType} onChange={e => setNextType(e)} style={{ minWidth: 200 }}>
|
||||
{Object.keys(adminTypes).map(type => <Select.Option value={type} key={type}>{type}</Select.Option> )}
|
||||
{Object.keys(adminTypes).map(type => <Select.Option value={type} key={type}>{t(`type:${type}.name`)}</Select.Option> )}
|
||||
</Select>
|
||||
<Button
|
||||
type="dashed"
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
import {InfoCircleOutlined} from '@ant-design/icons/lib'
|
||||
import {Form, Input, Select, Switch, Tabs} from 'antd'
|
||||
import {FormInstance} from 'antd/lib/form'
|
||||
import {TabPaneProps} from 'antd/lib/tabs'
|
||||
import React, {useEffect, useState} from 'react'
|
||||
import {Trans, useTranslation} from 'react-i18next'
|
||||
import {AdminFormFieldFragment} from '../../../graphql/fragment/admin.form.fragment'
|
||||
|
||||
interface Props extends TabPaneProps {
|
||||
@ -10,6 +12,7 @@ interface Props extends TabPaneProps {
|
||||
}
|
||||
|
||||
export const RespondentNotificationsTab: React.FC<Props> = props => {
|
||||
const { t } = useTranslation()
|
||||
const [enabled, setEnabled] = useState<boolean>()
|
||||
|
||||
useEffect(() => {
|
||||
@ -40,7 +43,7 @@ export const RespondentNotificationsTab: React.FC<Props> = props => {
|
||||
return (
|
||||
<Tabs.TabPane {...props}>
|
||||
<Form.Item
|
||||
label={'Enabled'}
|
||||
label={t('form:respondentNotifications.enabled')}
|
||||
name={['form', 'respondentNotifications', 'enabled']}
|
||||
valuePropName={'checked'}
|
||||
>
|
||||
@ -48,12 +51,12 @@ export const RespondentNotificationsTab: React.FC<Props> = props => {
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label={'Subject'}
|
||||
label={t('form:respondentNotifications.subject')}
|
||||
name={['form', 'respondentNotifications', 'subject']}
|
||||
rules={[
|
||||
{
|
||||
required: enabled,
|
||||
message: 'Please provide a Subject',
|
||||
message: t('validation:subjectRequired'),
|
||||
},
|
||||
]}
|
||||
>
|
||||
@ -61,26 +64,40 @@ export const RespondentNotificationsTab: React.FC<Props> = props => {
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label={'HTML Template'}
|
||||
label={t('form:respondentNotifications.htmlTemplate')}
|
||||
name={['form', 'respondentNotifications', 'htmlTemplate']}
|
||||
rules={[
|
||||
{
|
||||
required: enabled,
|
||||
message: 'Please provide a Template',
|
||||
message: t('validation:templateRequired'),
|
||||
},
|
||||
]}
|
||||
extra={(
|
||||
<div>
|
||||
<Trans>form:respondentNotifications.htmlTemplateInfo</Trans>
|
||||
<a
|
||||
href={'https://mjml.io/try-it-live'}
|
||||
target={'_blank'}
|
||||
style={{
|
||||
marginLeft: 16,
|
||||
}}
|
||||
>
|
||||
<InfoCircleOutlined />
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
>
|
||||
<Input.TextArea autoSize />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label={'Email Field'}
|
||||
label={t('form:respondentNotifications.toField')}
|
||||
name={['form', 'respondentNotifications', 'toField']}
|
||||
extra={'Field with Email for receipt'}
|
||||
extra={t('form:respondentNotifications.toFieldInfo')}
|
||||
rules={[
|
||||
{
|
||||
required: enabled,
|
||||
message: 'Please provide a Email Field',
|
||||
message: t('validation:emailFieldRequired'),
|
||||
},
|
||||
]}
|
||||
>
|
||||
@ -96,9 +113,9 @@ export const RespondentNotificationsTab: React.FC<Props> = props => {
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label={'Sender Email'}
|
||||
label={t('form:respondentNotifications.fromEmail')}
|
||||
name={['form', 'respondentNotifications', 'fromEmail']}
|
||||
extra={'Make sure your mailserver can send from this email'}
|
||||
extra={t('form:respondentNotifications.fromEmailInfo')}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
import {InfoCircleOutlined} from '@ant-design/icons/lib'
|
||||
import {Form, Input, Select, Switch, Tabs} from 'antd'
|
||||
import {FormInstance} from 'antd/lib/form'
|
||||
import {TabPaneProps} from 'antd/lib/tabs'
|
||||
import React, {useEffect, useState} from 'react'
|
||||
import {Trans, useTranslation} from 'react-i18next'
|
||||
import {AdminFormFieldFragment} from '../../../graphql/fragment/admin.form.fragment'
|
||||
|
||||
interface Props extends TabPaneProps {
|
||||
@ -10,6 +12,7 @@ interface Props extends TabPaneProps {
|
||||
}
|
||||
|
||||
export const SelfNotificationsTab: React.FC<Props> = props => {
|
||||
const { t } = useTranslation()
|
||||
const [enabled, setEnabled] = useState<boolean>()
|
||||
|
||||
useEffect(() => {
|
||||
@ -38,7 +41,7 @@ export const SelfNotificationsTab: React.FC<Props> = props => {
|
||||
return (
|
||||
<Tabs.TabPane {...props}>
|
||||
<Form.Item
|
||||
label={'Enabled'}
|
||||
label={t('form:selfNotifications.enabled')}
|
||||
name={['form', 'selfNotifications', 'enabled']}
|
||||
valuePropName={'checked'}
|
||||
>
|
||||
@ -46,12 +49,12 @@ export const SelfNotificationsTab: React.FC<Props> = props => {
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label={'Subject'}
|
||||
label={t('form:selfNotifications.subject')}
|
||||
name={['form', 'selfNotifications', 'subject']}
|
||||
rules={[
|
||||
{
|
||||
required: enabled,
|
||||
message: 'Please provide a Subject',
|
||||
message: t('validation:subjectRequired'),
|
||||
},
|
||||
]}
|
||||
>
|
||||
@ -59,23 +62,36 @@ export const SelfNotificationsTab: React.FC<Props> = props => {
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label={'HTML Template'}
|
||||
label={t('form:selfNotifications.htmlTemplate')}
|
||||
name={['form', 'selfNotifications', 'htmlTemplate']}
|
||||
rules={[
|
||||
{
|
||||
required: enabled,
|
||||
message: 'Please provide a Template',
|
||||
message: t('validation:templateRequired'),
|
||||
},
|
||||
]}
|
||||
extra={'You can also use <a href="https://mjml.io/try-it-live">MJML</a> to create your email templates'}
|
||||
extra={(
|
||||
<div>
|
||||
<Trans>form:selfNotifications.htmlTemplateInfo</Trans>
|
||||
<a
|
||||
href={'https://mjml.io/try-it-live'}
|
||||
target={'_blank'}
|
||||
style={{
|
||||
marginLeft: 16,
|
||||
}}
|
||||
>
|
||||
<InfoCircleOutlined />
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
>
|
||||
<Input.TextArea autoSize />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label={'Email Field'}
|
||||
label={t('form:selfNotifications.fromField')}
|
||||
name={['form', 'selfNotifications', 'fromField']}
|
||||
extra={'Field with Email, will set the Reply-To header'}
|
||||
extra={t('form:selfNotifications.fromFieldInfo')}
|
||||
>
|
||||
<Select>
|
||||
{Object.keys(groups).map(key => (
|
||||
@ -89,9 +105,9 @@ export const SelfNotificationsTab: React.FC<Props> = props => {
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label={'Your Email'}
|
||||
label={t('form:selfNotifications.toEmail')}
|
||||
name={['form', 'selfNotifications', 'toEmail']}
|
||||
extra={'If not set will send to the admin of the form'}
|
||||
extra={t('form:selfNotifications.toEmailInfo')}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
|
||||
@ -2,13 +2,16 @@ import {DeleteOutlined, PlusOutlined} from '@ant-design/icons/lib'
|
||||
import {Button, Card, Form, Input, Switch, Tabs} from 'antd'
|
||||
import {TabPaneProps} from 'antd/lib/tabs'
|
||||
import React from 'react'
|
||||
import {useTranslation} from 'react-i18next'
|
||||
import {InputColor} from '../../input/color'
|
||||
|
||||
export const StartPageTab: React.FC<TabPaneProps> = props => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<Tabs.TabPane {...props}>
|
||||
<Form.Item
|
||||
label={'Show'}
|
||||
label={t('form:startPage.show')}
|
||||
name={['form', 'startPage', 'show']}
|
||||
valuePropName={'checked'}
|
||||
>
|
||||
@ -16,21 +19,21 @@ export const StartPageTab: React.FC<TabPaneProps> = props => {
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label={'Title'}
|
||||
label={t('form:startPage.title')}
|
||||
name={['form', 'startPage', 'title']}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label={'Paragraph'}
|
||||
label={t('form:startPage.paragraph')}
|
||||
name={['form', 'startPage', 'paragraph']}
|
||||
>
|
||||
<Input.TextArea autoSize />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label={'Continue Button Text'}
|
||||
label={t('form:startPage.continueButtonText')}
|
||||
name={['form', 'startPage', 'buttonText']}
|
||||
>
|
||||
<Input />
|
||||
@ -47,7 +50,7 @@ export const StartPageTab: React.FC<TabPaneProps> = props => {
|
||||
wrapperCol={{
|
||||
sm: { offset: index === 0 ? 0 : 6 },
|
||||
}}
|
||||
label={index === 0 ? 'Buttons' : ''}
|
||||
label={index === 0 ? t('form:startPage.buttons') : ''}
|
||||
key={field.key}
|
||||
>
|
||||
<Card
|
||||
@ -56,28 +59,28 @@ export const StartPageTab: React.FC<TabPaneProps> = props => {
|
||||
]}
|
||||
>
|
||||
<Form.Item
|
||||
label={'Url'}
|
||||
label={t('form:startPage.url')}
|
||||
name={[field.key, 'url']}
|
||||
rules={[
|
||||
{type: 'url', message: 'Must be a valid url'}
|
||||
{type: 'url', message: t('validation:invalidUrl')}
|
||||
]}
|
||||
labelCol={{ span: 6 }}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item label={'Action'} name={[field.key, 'action']} labelCol={{ span: 6 }}>
|
||||
<Form.Item label={t('form:startPage.action')} name={[field.key, 'action']} labelCol={{ span: 6 }}>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item label={'Text'} name={[field.key, 'text']} labelCol={{ span: 6 }}>
|
||||
<Form.Item label={t('form:startPage.text')} name={[field.key, 'text']} labelCol={{ span: 6 }}>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item label={'Background Color'} name={[field.key, 'bgColor']} labelCol={{ span: 6 }}>
|
||||
<Form.Item label={t('form:startPage.bgColor')} name={[field.key, 'bgColor']} labelCol={{ span: 6 }}>
|
||||
<InputColor />
|
||||
</Form.Item>
|
||||
<Form.Item label={'Active Color'} name={[field.key, 'activeColor']} labelCol={{ span: 6 }}>
|
||||
<Form.Item label={t('form:startPage.activeColor')} name={[field.key, 'activeColor']} labelCol={{ span: 6 }}>
|
||||
<InputColor />
|
||||
</Form.Item>
|
||||
<Form.Item label={'Color'} name={[field.key, 'color']} labelCol={{ span: 6 }}>
|
||||
<Form.Item label={t('form:startPage.color')} name={[field.key, 'color']} labelCol={{ span: 6 }}>
|
||||
<InputColor />
|
||||
</Form.Item>
|
||||
</Card>
|
||||
@ -96,7 +99,7 @@ export const StartPageTab: React.FC<TabPaneProps> = props => {
|
||||
}}
|
||||
style={{ width: '60%' }}
|
||||
>
|
||||
<PlusOutlined /> Add Button
|
||||
<PlusOutlined /> {t('form:startPage.addButton')}
|
||||
</Button>
|
||||
</Form.Item>
|
||||
</div>
|
||||
|
||||
@ -29,7 +29,7 @@ export const RadioType: React.FC<AdminFieldTypeProps> = props => {
|
||||
sm: { offset: index === 0 ? 0 : 6 },
|
||||
}}
|
||||
labelCol={{ span: 6 }}
|
||||
label={index === 0 ? 'Options' : ''}
|
||||
label={index === 0 ? t('type:radio:options') : ''}
|
||||
key={field.key}
|
||||
>
|
||||
<Row gutter={16}>
|
||||
@ -39,7 +39,7 @@ export const RadioType: React.FC<AdminFieldTypeProps> = props => {
|
||||
name={[field.name, 'title']}
|
||||
style={{marginBottom: 0}}
|
||||
>
|
||||
<Input placeholder={'Title'} />
|
||||
<Input placeholder={t('type:radio:titlePlaceholder')} />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col span={8}>
|
||||
@ -48,15 +48,15 @@ export const RadioType: React.FC<AdminFieldTypeProps> = props => {
|
||||
name={[field.name, 'value']}
|
||||
style={{marginBottom: 0}}
|
||||
rules={[
|
||||
{ required: true, message: 'Please provide a value' }
|
||||
{ required: true, message: t('validation:valueRequired') }
|
||||
]}
|
||||
>
|
||||
<Input placeholder={'Value'} />
|
||||
<Input placeholder={t('type:radio:valuePlaceholder')} />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col span={4}>
|
||||
<Button danger onClick={() => remove(index)}>
|
||||
Remove
|
||||
{t('type:radio:removeOption')}
|
||||
</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
@ -72,7 +72,9 @@ export const RadioType: React.FC<AdminFieldTypeProps> = props => {
|
||||
<Button
|
||||
type={'dashed'}
|
||||
onClick={() => add()}
|
||||
>Add Option</Button>
|
||||
>
|
||||
{t('type:radio:addOption')}
|
||||
</Button>
|
||||
</Form.Item>
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -13,7 +13,7 @@ export const RatingType: React.FC<AdminFieldTypeProps> = props => {
|
||||
label={t('type:rating:default')}
|
||||
name={[props.field.name, 'value']}
|
||||
labelCol={{ span: 6 }}
|
||||
extra={'Click again to remove default value'}
|
||||
extra={t('type:rating.clearNote')}
|
||||
>
|
||||
<Rate
|
||||
allowHalf
|
||||
|
||||
@ -8,7 +8,7 @@ export const TextType: React.FC<AdminFieldTypeProps> = props => {
|
||||
|
||||
return (
|
||||
<Form.Item
|
||||
label={t('type:text:default')}
|
||||
label={t('type:textfield:default')}
|
||||
name={[props.field.name, 'value']}
|
||||
labelCol={{ span: 6 }}
|
||||
>
|
||||
|
||||
@ -1,9 +1,11 @@
|
||||
import {CaretDownOutlined, UserOutlined} from '@ant-design/icons'
|
||||
import {MenuFoldOutlined, MenuUnfoldOutlined} from '@ant-design/icons/lib'
|
||||
import {Dropdown, Layout, Menu, PageHeader, Spin, Tag} from 'antd'
|
||||
import {Dropdown, Layout, Menu, PageHeader, Select, Spin, Tag} from 'antd'
|
||||
import Link from 'next/link'
|
||||
import {useRouter} from 'next/router'
|
||||
import React, {FunctionComponent} from 'react'
|
||||
import {useTranslation} from 'react-i18next'
|
||||
import {languages} from '../i18n'
|
||||
import {sideMenu, SideMenuElement} from './sidemenu'
|
||||
import {useWindowSize} from './use.window.size'
|
||||
import {clearAuth} from './with.auth'
|
||||
@ -32,6 +34,7 @@ interface Props {
|
||||
}
|
||||
|
||||
const Structure: FunctionComponent<Props> = (props) => {
|
||||
const { t, i18n } = useTranslation()
|
||||
const size = useWindowSize()
|
||||
const [userMenu, setUserMenu] = React.useState(false)
|
||||
const [open, setOpen] = React.useState<string[]>()
|
||||
@ -120,7 +123,7 @@ const Structure: FunctionComponent<Props> = (props) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<Layout style={{ height: '100vh' }}>
|
||||
<Layout style={{ height: '100vh' }} className={'admin'}>
|
||||
<Header
|
||||
style={{
|
||||
paddingLeft: 0,
|
||||
@ -177,9 +180,11 @@ const Structure: FunctionComponent<Props> = (props) => {
|
||||
maxHeight: '100%',
|
||||
overflow: 'auto',
|
||||
}}
|
||||
className={'sidemenu'}
|
||||
>
|
||||
<Menu
|
||||
mode="inline"
|
||||
style={{ flex: 1 }}
|
||||
defaultSelectedKeys={['1']}
|
||||
selectedKeys={selected}
|
||||
onSelect={(s): void => setSelected(s.keyPath)}
|
||||
@ -192,11 +197,19 @@ const Structure: FunctionComponent<Props> = (props) => {
|
||||
mode="inline"
|
||||
selectable={false}
|
||||
>
|
||||
<Menu.Item
|
||||
style={{
|
||||
marginTop: 40,
|
||||
}}
|
||||
>
|
||||
<Menu.Item className={'language-selector'}>
|
||||
<Select
|
||||
bordered={false}
|
||||
value={i18n.language.replace(/-.*/, '')}
|
||||
onChange={next => i18n.changeLanguage(next)}
|
||||
style={{
|
||||
width: '100%',
|
||||
}}
|
||||
>
|
||||
{languages.map(language => <Select.Option value={language} key={language}>{t(`language:${language}`)}</Select.Option> )}
|
||||
</Select>
|
||||
</Menu.Item>
|
||||
<Menu.Item>
|
||||
Version: <Tag color="gold">{process.env.version}</Tag>
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
|
||||
2
i18n.ts
2
i18n.ts
@ -14,5 +14,7 @@ i18n
|
||||
defaultNS: 'common',
|
||||
react: {
|
||||
useSuspense: process.browser,
|
||||
transSupportBasicHtmlNodes: true,
|
||||
transKeepBasicHtmlNodesFor: ['br', 'strong', 'i', 'em', 'u'],
|
||||
}
|
||||
})
|
||||
|
||||
8
locales/de/admin.ts
Normal file
8
locales/de/admin.ts
Normal file
@ -0,0 +1,8 @@
|
||||
export const admin = {
|
||||
home: 'Home',
|
||||
users: 'Benutzer',
|
||||
forms: 'Formulare',
|
||||
submissions: 'Eingaben',
|
||||
profile: 'Profil',
|
||||
username: 'Benutzername',
|
||||
}
|
||||
7
locales/de/common.ts
Normal file
7
locales/de/common.ts
Normal file
@ -0,0 +1,7 @@
|
||||
export const common = {
|
||||
logout: 'Abmelden',
|
||||
login: "Anmelden",
|
||||
register: "Benutzer erstellen",
|
||||
recover: 'Passwort vergessen',
|
||||
admin: "Administration",
|
||||
}
|
||||
97
locales/de/form.ts
Normal file
97
locales/de/form.ts
Normal file
@ -0,0 +1,97 @@
|
||||
export const form = {
|
||||
building: 'Formular wird aufgebaut',
|
||||
submitted: 'Vielen dank für ihre Eingaben!',
|
||||
restart: 'Formular neu starten',
|
||||
loading: 'Formular wird geladen',
|
||||
mange: 'Formular "{{title}}" bearbeiten',
|
||||
new: 'Neues Formular',
|
||||
created: 'Formular Erstellt',
|
||||
creationError: 'Formular konnte nicht erstellt werden',
|
||||
create: 'Neues Formular erstellen',
|
||||
createNow: 'Jetzt Anlegen',
|
||||
baseDataTab: 'Basis Daten',
|
||||
selfNotificationsTab: 'Benachrichtigungen für Verwalter',
|
||||
respondentNotificationsTab: 'Benarichtigungen für Nutzer',
|
||||
updated: 'Formular aktualisiert',
|
||||
updateError: 'Formular konnte nicht aktualisiert werden',
|
||||
updateNow: 'Speichern',
|
||||
designTab: 'Design',
|
||||
startPageTab: 'Eröffnungs Seite',
|
||||
endPageTab: 'Abschluss Seite',
|
||||
confirmDelete: 'Wollen sie dieses Formular mit allen Eintragungen löschen?',
|
||||
deleted: 'Formular gelöscht',
|
||||
deleteError: 'Formular konnte nicht gelöscht werden',
|
||||
deleteNow: 'Jetzt löschen!',
|
||||
row: {
|
||||
isLive: 'Öffentlich',
|
||||
title: 'Titel',
|
||||
admin: 'Verwalter',
|
||||
language: 'Sprache',
|
||||
created: 'Erstellt',
|
||||
lastModified: 'Letzte Änderung',
|
||||
menu: ''
|
||||
},
|
||||
baseData: {
|
||||
isLive: 'Öffentlich',
|
||||
title: 'Titel',
|
||||
language: 'Sprache',
|
||||
showFooter: 'Fußzeile anzeigen',
|
||||
},
|
||||
design: {
|
||||
font: 'Schriftart',
|
||||
backgroundColor: 'Hintergrund Farbe',
|
||||
questionColor: 'Fragen Farbe',
|
||||
answerColor: 'Antworten Farbe',
|
||||
buttonColor: 'Aktions Farbe',
|
||||
buttonActiveColor: 'Aktive Aktion Farbe',
|
||||
buttonTextColor: 'Aktion Schrift Farbe',
|
||||
},
|
||||
endPage: {
|
||||
show: 'Anzeigen',
|
||||
continueButtonText: 'Weiter Text',
|
||||
paragraph: 'Paragraf',
|
||||
title: 'Titel',
|
||||
buttons: 'Aktionen',
|
||||
url: 'Url',
|
||||
text: 'Text',
|
||||
action: 'Aktion',
|
||||
bgColor: 'Hintergrund Farbe',
|
||||
activeColor: 'Aktive Farbe',
|
||||
color: 'Text Farbe',
|
||||
addButton: 'Aktion hinzufügen',
|
||||
},
|
||||
startPage: {
|
||||
show: 'Anzeigen',
|
||||
continueButtonText: 'Weiter Text',
|
||||
paragraph: 'Paragraf',
|
||||
title: 'Titel',
|
||||
buttons: 'Aktionen',
|
||||
url: 'Url',
|
||||
text: 'Text',
|
||||
action: 'Aktion',
|
||||
bgColor: 'Hintergrund Farbe',
|
||||
activeColor: 'Aktive Farbe',
|
||||
color: 'Text Farbe',
|
||||
addButton: 'Aktion hinzufügen',
|
||||
},
|
||||
respondentNotifications: {
|
||||
enabled: 'Aktiv',
|
||||
subject: 'Betreff',
|
||||
htmlTemplate: 'HTML Template',
|
||||
htmlTemplateInfo: 'Sie können auch <u>MJML</u> verwenden um das Template zu gestalten',
|
||||
toField: 'Empfänger E-Mail',
|
||||
toFieldInfo: 'Formular E-Mail Feld für Benachrichtigung',
|
||||
fromEmail: 'Absender E-Mail',
|
||||
fromEmailInfo: 'Der E-Mail Server muss den versand von dieser E-Mail zulassen',
|
||||
},
|
||||
selfNotifications: {
|
||||
enabled: 'Aktiv',
|
||||
subject: 'Betreff',
|
||||
htmlTemplate: 'HTML Template',
|
||||
htmlTemplateInfo: 'Sie können auch <u>MJML</u> verwenden um das Template zu gestalten',
|
||||
toEmail: 'Empfänger E-Mail',
|
||||
toEmailInfo: 'Als Standard wird die E-Mail des Verwalters verwendet',
|
||||
fromField: 'Absender E-Mail',
|
||||
fromFieldInfo: 'Formular E-Mail Feld für Benachrichtigung, wird as Reply-To gesetzt',
|
||||
},
|
||||
}
|
||||
@ -1 +1,27 @@
|
||||
export const de = {}
|
||||
import {admin} from './admin'
|
||||
import {common} from './common'
|
||||
import {form} from './form'
|
||||
import language from './language'
|
||||
import {login} from './login'
|
||||
import {profile} from './profile'
|
||||
import {register} from './register'
|
||||
import {statistic} from './statistic'
|
||||
import {submission} from './submission'
|
||||
import {type} from './type'
|
||||
import {user} from './user'
|
||||
import {validation} from './validation'
|
||||
|
||||
export const de = {
|
||||
admin,
|
||||
common,
|
||||
form,
|
||||
language,
|
||||
login,
|
||||
profile,
|
||||
register,
|
||||
statistic,
|
||||
submission,
|
||||
type,
|
||||
user,
|
||||
validation,
|
||||
}
|
||||
|
||||
8
locales/de/language.ts
Normal file
8
locales/de/language.ts
Normal file
@ -0,0 +1,8 @@
|
||||
export default {
|
||||
en: 'English',
|
||||
de: 'Deutsch',
|
||||
cn: '繁體中文',
|
||||
es: 'Español',
|
||||
fr: 'Français',
|
||||
it: 'Italiano',
|
||||
}
|
||||
7
locales/de/login.ts
Normal file
7
locales/de/login.ts
Normal file
@ -0,0 +1,7 @@
|
||||
export const login = {
|
||||
welcomeBack: 'Willkomen zurück!',
|
||||
invalidLoginCredentials: 'Benutzername oder Passwort ist falsch',
|
||||
usernamePlaceholder: 'Benutzername',
|
||||
passwordPlaceholder: 'Passwort',
|
||||
loginNow: 'Jetzt Anmelden',
|
||||
}
|
||||
10
locales/de/profile.ts
Normal file
10
locales/de/profile.ts
Normal file
@ -0,0 +1,10 @@
|
||||
export const profile = {
|
||||
updated: 'Profil Aktualisieren',
|
||||
updateError: 'Profil konnte nicht aktualisiert werden',
|
||||
updateNow: 'Speichern',
|
||||
language: 'Sprache',
|
||||
email: 'E-Mail',
|
||||
username: 'Benutzername',
|
||||
firstName: 'Vorname',
|
||||
lastName: 'Nachname',
|
||||
}
|
||||
6
locales/de/register.ts
Normal file
6
locales/de/register.ts
Normal file
@ -0,0 +1,6 @@
|
||||
export const register = {
|
||||
welcome: 'Willkommen, bitte bestätige noch deine E-Mail',
|
||||
credentialsAlreadyInUse: 'Deine Daten werden bereits verwendet!',
|
||||
registerNow: 'Jetzt Registrieren',
|
||||
gotoLogin: 'Sie haben schon einen Account? Weiter zur Anmeldung',
|
||||
}
|
||||
5
locales/de/statistic.ts
Normal file
5
locales/de/statistic.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export const statistic = {
|
||||
'total-forms': 'Anzahl der Formulare',
|
||||
'total-users': 'Anzahl der Benutzer',
|
||||
'total-submissions': 'Anzahl der Eingaben',
|
||||
}
|
||||
16
locales/de/submission.ts
Normal file
16
locales/de/submission.ts
Normal file
@ -0,0 +1,16 @@
|
||||
export const submission = {
|
||||
progress: 'Fortschritt',
|
||||
created: 'Erstellt',
|
||||
lastModified: 'Letzte Änderung',
|
||||
submission: 'Eingabe',
|
||||
add: 'Neue Eingabe starten',
|
||||
edit: 'Formular bearbeiten',
|
||||
field: 'Feld',
|
||||
value: 'Wert',
|
||||
country: 'Land',
|
||||
city: 'Stadt',
|
||||
device: {
|
||||
type: 'Geräte Typ',
|
||||
name: 'Geräte Name',
|
||||
}
|
||||
}
|
||||
65
locales/de/type.ts
Normal file
65
locales/de/type.ts
Normal file
@ -0,0 +1,65 @@
|
||||
export const type = {
|
||||
deleteNow: 'Feld löschen',
|
||||
confirmDelete: 'Wollen sie das Feld wirklich löschen? Bitte beachten sie das es keine Referenzen auf das Feld gibt!',
|
||||
title: 'Titel',
|
||||
description: 'Beschreibung',
|
||||
required: 'Pflichtfeld',
|
||||
requiredInfo: 'Falls verpflichtend sollte ein Standard Wert gesetzt sein damit Nutzer fortfahren können!',
|
||||
date: {
|
||||
name: 'Datum',
|
||||
default: 'Standard Dateum',
|
||||
min: 'Ältest mögliche Datum',
|
||||
max: 'Neuest mögliche Datum',
|
||||
},
|
||||
dropdown: {
|
||||
name: 'Auswahl Liste',
|
||||
default: 'Standard Wert',
|
||||
options: 'Auswahl',
|
||||
titlePlaceholder: 'Titel',
|
||||
valuePlaceholder: 'Wert',
|
||||
removeOption: 'Entfernen',
|
||||
addOption: 'Auswahl hinzufügen',
|
||||
},
|
||||
email: {
|
||||
name: 'E-Mail',
|
||||
default: 'Standard E-Mail',
|
||||
},
|
||||
hidden: {
|
||||
name: 'Versteckt',
|
||||
default: 'Standard Wert',
|
||||
},
|
||||
link: {
|
||||
name: 'URL',
|
||||
default: 'Standard Url',
|
||||
},
|
||||
number: {
|
||||
name: 'Zahl',
|
||||
default: 'Standard Zahl',
|
||||
},
|
||||
radio: {
|
||||
name: 'Knopf Auswahl Liste',
|
||||
default: 'Standard Wert',
|
||||
options: 'Auswahl',
|
||||
titlePlaceholder: 'Titel',
|
||||
valuePlaceholder: 'Wert',
|
||||
removeOption: 'Entfernen',
|
||||
addOption: 'Auswahl hinzufügen',
|
||||
},
|
||||
rating: {
|
||||
name: 'Bewertung',
|
||||
default: 'Standard Bewertung',
|
||||
clearNote: 'Erneut klicken um Auswahl aufzuheben'
|
||||
},
|
||||
textfield: {
|
||||
name: 'Einzeiliger Text',
|
||||
default: 'Standard Wert',
|
||||
},
|
||||
textarea: {
|
||||
name: 'Mehrzeiliger Text',
|
||||
default: 'Standard Wert',
|
||||
},
|
||||
yes_no: {
|
||||
name: 'Ja / Nein',
|
||||
default: 'Standard Wert',
|
||||
},
|
||||
}
|
||||
18
locales/de/user.ts
Normal file
18
locales/de/user.ts
Normal file
@ -0,0 +1,18 @@
|
||||
export const user = {
|
||||
confirmDelete: 'Wollen sie diesen Benutzer wirklich löschen?',
|
||||
deleted: 'Benutzer gelöscht',
|
||||
deleteError: 'Benutzer konnte nicht gelöscht werden',
|
||||
deleteNow: 'Jetzt löschen!',
|
||||
loading: 'Benutzer wird geladen',
|
||||
mange: 'Benutzer "{{email}}" bearbeiten',
|
||||
row: {
|
||||
roles: 'Rolle',
|
||||
email: 'E-Mail',
|
||||
created: 'Erstellt',
|
||||
menu: ''
|
||||
},
|
||||
updated: 'Benutzer aktualisiert updated',
|
||||
updateError: 'Konnte Benutzer nicht aktualisieren',
|
||||
updateNow: 'Speichern',
|
||||
baseData: 'Basis Daten',
|
||||
}
|
||||
15
locales/de/validation.ts
Normal file
15
locales/de/validation.ts
Normal file
@ -0,0 +1,15 @@
|
||||
export const validation = {
|
||||
invalidEmail: 'ungültige E-Mail!',
|
||||
mandatoryFieldsMissing: 'Nicht alle Pflichfelder befüllt',
|
||||
usernameRequired: 'Bitte einen Benutzernamen angeben',
|
||||
emailRequired: 'Bitte eine E-Mail angeben',
|
||||
emailFieldRequired: 'Bitte ein E-Mail Feld auswählen',
|
||||
languageRequired: 'Bitte eine Sprache angeben',
|
||||
valueRequired: 'Bitte einen Wert angeben',
|
||||
invalidUrl: 'ungültige Url',
|
||||
titleRequired: 'Bitte einen Titel angeben',
|
||||
templateRequired: 'Bitte ein Template angeben',
|
||||
subjectRequired: 'Bitte einen Betreff angeben',
|
||||
passwordRequired: 'Bitte ein Passwort angeben',
|
||||
passwordMinLength: 'Passwort muss mindestens 5 Zeichen haben!',
|
||||
}
|
||||
@ -9,13 +9,15 @@ export const form = {
|
||||
creationError: 'Could not create form',
|
||||
create: 'Create new form',
|
||||
createNow: 'Save',
|
||||
baseData: 'Base Data',
|
||||
baseDataTab: 'Base Data',
|
||||
selfNotificationsTab: 'Self Notifications',
|
||||
respondentNotificationsTab: 'Respondent Notifications',
|
||||
updated: 'Form updated',
|
||||
updateError: 'Could not update form',
|
||||
updateNow: 'Save',
|
||||
design: 'Design',
|
||||
startPage: 'Start Page',
|
||||
endPage: 'End Page',
|
||||
designTab: 'Design',
|
||||
startPageTab: 'Start Page',
|
||||
endPageTab: 'End Page',
|
||||
confirmDelete: 'Are you sure delete this form with all submissions?',
|
||||
deleted: 'Form deleted',
|
||||
deleteError: 'could not delete form',
|
||||
@ -28,5 +30,68 @@ export const form = {
|
||||
created: 'Created',
|
||||
lastModified: 'Last Modified',
|
||||
menu: ''
|
||||
}
|
||||
},
|
||||
baseData: {
|
||||
isLive: 'Is Live',
|
||||
title: 'Title',
|
||||
language: 'Language',
|
||||
showFooter: 'Show Footer',
|
||||
},
|
||||
design: {
|
||||
font: 'Font',
|
||||
backgroundColor: 'Background Color',
|
||||
questionColor: 'Question Color',
|
||||
answerColor: 'Answer Color',
|
||||
buttonColor: 'Button Color',
|
||||
buttonActiveColor: 'Button Active Color',
|
||||
buttonTextColor: 'Button Text Color',
|
||||
},
|
||||
endPage: {
|
||||
show: 'Show',
|
||||
continueButtonText: 'Continue Button Text',
|
||||
paragraph: 'Paragraph',
|
||||
title: 'Title',
|
||||
buttons: 'Buttons',
|
||||
url: 'Url',
|
||||
text: 'Text',
|
||||
action: 'Action',
|
||||
bgColor: 'Background Color',
|
||||
activeColor: 'Active Color',
|
||||
color: 'Color',
|
||||
removeButton: 'Add Button',
|
||||
},
|
||||
startPage: {
|
||||
show: 'Show',
|
||||
continueButtonText: 'Continue Button Text',
|
||||
paragraph: 'Paragraph',
|
||||
title: 'Title',
|
||||
buttons: 'Buttons',
|
||||
url: 'Url',
|
||||
text: 'Text',
|
||||
action: 'Action',
|
||||
bgColor: 'Background Color',
|
||||
activeColor: 'Active Color',
|
||||
color: 'Color',
|
||||
addButton: 'Add Button',
|
||||
},
|
||||
respondentNotifications: {
|
||||
enabled: 'Enabled',
|
||||
subject: 'Subject',
|
||||
htmlTemplate: 'HTML Template',
|
||||
htmlTemplateInfo: 'You can also use <u>MJML</u> to create your email templates',
|
||||
toField: 'Email Field',
|
||||
toFieldInfo: 'Field with Email for receipt',
|
||||
fromEmail: 'Sender Email',
|
||||
fromEmailInfo: 'Make sure your mailserver can send from this email',
|
||||
},
|
||||
selfNotifications: {
|
||||
enabled: 'Enabled',
|
||||
subject: 'Subject',
|
||||
htmlTemplate: 'HTML Template',
|
||||
htmlTemplateInfo: 'You can also use <strong>MJML</strong> to create your email templates',
|
||||
toEmail: 'Your Email',
|
||||
toEmailInfo: 'If not set will send to the admin of the form',
|
||||
fromField: 'Sender Email',
|
||||
fromFieldInfo: 'Field with Email, will set the Reply-To header',
|
||||
},
|
||||
}
|
||||
|
||||
@ -1,11 +1,13 @@
|
||||
import {admin} from './admin'
|
||||
import {common} from './common'
|
||||
import {form} from './form'
|
||||
import language from './language'
|
||||
import {login} from './login'
|
||||
import {profile} from './profile'
|
||||
import {register} from './register'
|
||||
import {statistic} from './statistic'
|
||||
import {submission} from './submission'
|
||||
import {type} from './type'
|
||||
import {user} from './user'
|
||||
import {validation} from './validation'
|
||||
|
||||
@ -13,11 +15,13 @@ export const en = {
|
||||
admin,
|
||||
common,
|
||||
form,
|
||||
language,
|
||||
login,
|
||||
profile,
|
||||
register,
|
||||
statistic,
|
||||
submission,
|
||||
type,
|
||||
user,
|
||||
validation,
|
||||
}
|
||||
|
||||
8
locales/en/language.ts
Normal file
8
locales/en/language.ts
Normal file
@ -0,0 +1,8 @@
|
||||
export default {
|
||||
en: 'English',
|
||||
de: 'Deutsch',
|
||||
cn: '繁體中文',
|
||||
es: 'Español',
|
||||
fr: 'Français',
|
||||
it: 'Italiano',
|
||||
}
|
||||
@ -1,9 +1,7 @@
|
||||
export const login = {
|
||||
'welcome-back': 'Welcome back!',
|
||||
'invalid-login-credentials': 'username / password are invalid',
|
||||
'username-required': 'Please input your username!',
|
||||
'username-placeholder': 'Username',
|
||||
'password-required': 'Please input your password!',
|
||||
'password-placeholder': 'Password',
|
||||
'login-now': 'Login Now',
|
||||
welcomeBack: 'Welcome back!',
|
||||
invalidLoginCredentials: 'username / password are invalid',
|
||||
usernamePlaceholder: 'Username',
|
||||
passwordPlaceholder: 'Password',
|
||||
loginNow: 'Login Now',
|
||||
}
|
||||
|
||||
@ -1,8 +1,6 @@
|
||||
export const register = {
|
||||
welcome: 'Welcome, please also confirm your email',
|
||||
'credentials-already-in-use': 'Some data already in use!',
|
||||
'password-min-length': 'Must be longer than or equal to 5 characters!',
|
||||
'email-required': 'Please input your email!',
|
||||
'register-now': 'Register Now',
|
||||
'goto-login': 'Have an account? Go to login',
|
||||
'credentialsAlreadyInUse': 'Some data already in use!',
|
||||
'registerNow': 'Register Now',
|
||||
'gotoLogin': 'Have an account? Go to login',
|
||||
}
|
||||
|
||||
@ -1,10 +1,18 @@
|
||||
export const type = {
|
||||
deleteNow: 'Delete Field',
|
||||
confirmDelete: 'Really remove this field? Check that it is not referenced anywhere!',
|
||||
title: 'Title',
|
||||
description: 'Description',
|
||||
required: 'Required',
|
||||
requiredInfo: 'If required, default value must be set to enable users to submit form!',
|
||||
date: {
|
||||
name: 'Date',
|
||||
default: 'Default Date',
|
||||
min: 'Min Date',
|
||||
max: 'Max Date',
|
||||
},
|
||||
dropdown: {
|
||||
name: 'Dropdown',
|
||||
default: 'Default Value',
|
||||
options: 'Options',
|
||||
titlePlaceholder: 'Title',
|
||||
@ -13,30 +21,45 @@ export const type = {
|
||||
addOption: 'Add Option',
|
||||
},
|
||||
email: {
|
||||
name: 'Email',
|
||||
default: 'Default Email',
|
||||
},
|
||||
hidden: {
|
||||
name: 'Hidden',
|
||||
default: 'Default Value',
|
||||
},
|
||||
link: {
|
||||
name: 'URL',
|
||||
default: 'Default Link',
|
||||
},
|
||||
number: {
|
||||
name: 'Number',
|
||||
default: 'Default Number',
|
||||
},
|
||||
radio: {
|
||||
name: 'Radio Switch',
|
||||
default: 'Default Value',
|
||||
options: 'Options',
|
||||
titlePlaceholder: 'Title',
|
||||
valuePlaceholder: 'Value',
|
||||
removeOption: 'Remove',
|
||||
addOption: 'Add Option',
|
||||
},
|
||||
rating: {
|
||||
name: 'Rating',
|
||||
default: 'Default Value',
|
||||
clearNote: 'Click again to remove the default value'
|
||||
},
|
||||
text: {
|
||||
textfield: {
|
||||
name: 'Text Line',
|
||||
default: 'Default Value',
|
||||
},
|
||||
textarea: {
|
||||
name: 'Text Area',
|
||||
default: 'Default Value',
|
||||
},
|
||||
yes_no: {
|
||||
name: 'Yes / No',
|
||||
default: 'Default Value',
|
||||
},
|
||||
}
|
||||
|
||||
@ -11,8 +11,8 @@ export const user = {
|
||||
created: 'Created',
|
||||
menu: ''
|
||||
},
|
||||
updated: 'Form updated',
|
||||
updateError: 'Could not update form',
|
||||
updated: 'User updated',
|
||||
updateError: 'Could not update user',
|
||||
updateNow: 'Save',
|
||||
baseData: 'Base Data',
|
||||
}
|
||||
|
||||
@ -3,7 +3,13 @@ export const validation = {
|
||||
mandatoryFieldsMissing: 'Mandatory fields missing',
|
||||
usernameRequired: 'Please provide a Username',
|
||||
emailRequired: 'Please provide an Email',
|
||||
emailFieldRequired: 'Please select an Email Field',
|
||||
languageRequired: 'Please select a Language',
|
||||
valueRequired: 'Please provide a Value',
|
||||
invalidUrl: 'Must be a valid URL',
|
||||
titleRequired: 'Please provide a title',
|
||||
templateRequired: 'Please provide a template',
|
||||
subjectRequired: 'Please provide a subject',
|
||||
passwordRequired: 'Please input your password!',
|
||||
passwordMinLength: 'Must be longer than or equal to 5 characters!',
|
||||
}
|
||||
|
||||
@ -153,27 +153,27 @@ const Index: NextPage = () => {
|
||||
<Tabs>
|
||||
<FieldsTab
|
||||
key={'fields'}
|
||||
tab={'Fields'}
|
||||
tab={t('form:fieldsTab')}
|
||||
fields={fields}
|
||||
onChangeFields={setFields}
|
||||
form={form}
|
||||
/>
|
||||
<BaseDataTab key={'base_data'} tab={t('form:baseData')} />
|
||||
<DesignTab key={'design'} tab={'form:design'} />
|
||||
<BaseDataTab key={'base_data'} tab={t('form:baseDataTab')} />
|
||||
<DesignTab key={'design'} tab={t('form:designTab')} />
|
||||
<SelfNotificationsTab
|
||||
key={'self_notifications'}
|
||||
tab={'Self Notifications'}
|
||||
tab={t('form:selfNotificationsTab')}
|
||||
fields={fields}
|
||||
form={form}
|
||||
/>
|
||||
<RespondentNotificationsTab
|
||||
key={'respondent_notifications'}
|
||||
tab={'Respondent Notifications'}
|
||||
tab={t('form:respondentNotificationsTab')}
|
||||
fields={fields}
|
||||
form={form}
|
||||
/>
|
||||
<StartPageTab key={'start_page'} tab={t('form:startPage')} />
|
||||
<EndPageTab key={'end_page'} tab={t('form:endPage')} />
|
||||
<StartPageTab key={'start_page'} tab={t('form:startPageTab')} />
|
||||
<EndPageTab key={'end_page'} tab={t('form:endPageTab')} />
|
||||
</Tabs>
|
||||
</Form>
|
||||
</Structure>
|
||||
|
||||
@ -79,7 +79,7 @@ const Create: NextPage = () => {
|
||||
<Form.Item noStyle name={['form', 'id']}><Input type={'hidden'} /></Form.Item>
|
||||
|
||||
<Tabs>
|
||||
<BaseDataTab key={'base_data'} tab={t('form:baseData')} />
|
||||
<BaseDataTab key={'base_data'} tab={t('form:baseDataTab')} />
|
||||
</Tabs>
|
||||
</Form>
|
||||
</Structure>
|
||||
|
||||
@ -89,6 +89,7 @@ const Index: NextPage = () => {
|
||||
{
|
||||
title: t('form:row.language'),
|
||||
dataIndex: 'language',
|
||||
render: lang => t(`language:${lang}`)
|
||||
},
|
||||
{
|
||||
title: t('form:row.created'),
|
||||
|
||||
@ -129,7 +129,7 @@ const Profile: NextPage = () => {
|
||||
]}
|
||||
>
|
||||
<Select>
|
||||
{languages.map(language => <Select.Option value={language} key={language}>{language.toUpperCase()}</Select.Option> )}
|
||||
{languages.map(language => <Select.Option value={language} key={language}>{t(`language:${language}`)}</Select.Option> )}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
|
||||
|
||||
@ -7,7 +7,7 @@ import {LoadingPage} from 'components/loading.page'
|
||||
import {FORM_QUERY, FormQueryData, FormQueryVariables} from 'graphql/query/form.query'
|
||||
import {NextPage} from 'next'
|
||||
import {useRouter} from 'next/router'
|
||||
import React, {useState} from 'react'
|
||||
import React, {useEffect, useState} from 'react'
|
||||
import {useTranslation} from 'react-i18next'
|
||||
import Swiper from 'react-id-swiper'
|
||||
import {ReactIdSwiperProps} from 'react-id-swiper/lib/types'
|
||||
@ -19,7 +19,7 @@ interface Props {
|
||||
}
|
||||
|
||||
const Index: NextPage<Props> = () => {
|
||||
const { t } = useTranslation()
|
||||
const { t, i18n } = useTranslation()
|
||||
const router = useRouter()
|
||||
const id = router.query.id as string
|
||||
const [swiper, setSwiper] = useState<OriginalSwiper.default>(null)
|
||||
@ -31,6 +31,17 @@ const Index: NextPage<Props> = () => {
|
||||
}
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
// check form language to switch to!
|
||||
if (!data) {
|
||||
return
|
||||
}
|
||||
|
||||
if (i18n.language !== data.form.language) {
|
||||
i18n.changeLanguage(data.form.language)
|
||||
}
|
||||
}, [data])
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<LoadingPage message={t('form:build')} />
|
||||
|
||||
@ -30,11 +30,11 @@ const Index: NextPage = () => {
|
||||
result.data.tokens.refresh
|
||||
)
|
||||
|
||||
message.success(t('login:welcome-back'))
|
||||
message.success(t('login:welcomeBack'))
|
||||
|
||||
router.push('/admin')
|
||||
} catch (e) {
|
||||
message.error(t('login:invalid-login-credentials'))
|
||||
message.error(t('login:invalidLoginCredentials'))
|
||||
}
|
||||
|
||||
setLoading(false)
|
||||
@ -71,21 +71,21 @@ const Index: NextPage = () => {
|
||||
|
||||
<Form.Item
|
||||
name="username"
|
||||
rules={[{ required: true, message: t('login:username-required') }]}
|
||||
rules={[{ required: true, message: t('validation:usernameRequired') }]}
|
||||
>
|
||||
<Input
|
||||
size="large"
|
||||
placeholder={t('login:username-placeholder')}
|
||||
placeholder={t('login:usernamePlaceholder')}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="password"
|
||||
rules={[{ required: true, message: t('login:password-required') }]}
|
||||
rules={[{ required: true, message: t('validation:passwordRequired') }]}
|
||||
>
|
||||
<Input.Password
|
||||
size="large"
|
||||
placeholder={t('login:password-placeholder')}
|
||||
placeholder={t('login:passwordPlaceholder')}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
@ -96,7 +96,7 @@ const Index: NextPage = () => {
|
||||
htmlType="submit"
|
||||
block
|
||||
>
|
||||
{t('login:login-now')}
|
||||
{t('login:loginNow')}
|
||||
</Button>
|
||||
</Form.Item>
|
||||
|
||||
|
||||
@ -38,7 +38,7 @@ const Register: NextPage = () => {
|
||||
|
||||
router.push('/')
|
||||
} catch (e) {
|
||||
message.error(t('register:credentials-already-in-use'))
|
||||
message.error(t('register:credentialsAlreadyInUse'))
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
@ -74,18 +74,18 @@ const Register: NextPage = () => {
|
||||
|
||||
<Form.Item
|
||||
name="username"
|
||||
rules={[{ required: true, message: t('login:username-required') }]}
|
||||
rules={[{ required: true, message: t('validation:usernameRequired') }]}
|
||||
>
|
||||
<Input
|
||||
size="large"
|
||||
placeholder={t('login:username-placeholder')}
|
||||
placeholder={t('login:usernamePlaceholder')}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="email"
|
||||
rules={[
|
||||
{ required: true, message: t('register:email-required') },
|
||||
{ required: true, message: t('validation:emailRequired') },
|
||||
{ type: 'email', message: t('validation:invalidEmail') }
|
||||
]}
|
||||
>
|
||||
@ -98,13 +98,13 @@ const Register: NextPage = () => {
|
||||
<Form.Item
|
||||
name="password"
|
||||
rules={[
|
||||
{ required: true, message: t('login:password-required') },
|
||||
{ min: 5, message: t('register:password-min-length') },
|
||||
{ required: true, message: t('validation:passwordRequired') },
|
||||
{ min: 5, message: t('validation:passwordMinLength') },
|
||||
]}
|
||||
>
|
||||
<Input.Password
|
||||
size="large"
|
||||
placeholder={t('login:password-placeholder')}
|
||||
placeholder={t('login:passwordPlaceholder')}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
@ -115,7 +115,7 @@ const Register: NextPage = () => {
|
||||
htmlType="submit"
|
||||
block
|
||||
>
|
||||
{t('register:register-now')}
|
||||
{t('register:registerNow')}
|
||||
</Button>
|
||||
</Form.Item>
|
||||
|
||||
@ -131,7 +131,7 @@ const Register: NextPage = () => {
|
||||
type={'link'}
|
||||
ghost
|
||||
>
|
||||
{t('register:goto-login')}
|
||||
{t('register:gotoLogin')}
|
||||
</Button>
|
||||
</Link>
|
||||
</Button.Group>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user