Skip to content

Commit

Permalink
🌐 Add translation keys for input blocks (#1114)
Browse files Browse the repository at this point in the history
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Integrated localization support across various components using the
`useTranslate` hook for dynamic translations.

- **Enhancements**
- Replaced hardcoded text with localized strings to support multiple
languages in the user interface.

- **User Interface**
- Updated labels, placeholders, tooltips, and button texts to utilize
translated content for a multilingual experience.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Baptiste Arnaud <baptiste.arnaud95@gmail.com>
  • Loading branch information
gabrielgpavao and baptisteArno authored Dec 29, 2023
1 parent 5fbbe9d commit 53b702e
Show file tree
Hide file tree
Showing 37 changed files with 550 additions and 152 deletions.
4 changes: 3 additions & 1 deletion apps/builder/src/components/SetVariableLabel.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useColorModeValue, HStack, Tag, Text } from '@chakra-ui/react'
import { useTranslate } from '@tolgee/react'
import { Variable } from '@typebot.io/schemas'

export const SetVariableLabel = ({
Expand All @@ -8,6 +9,7 @@ export const SetVariableLabel = ({
variableId: string
variables?: Variable[]
}) => {
const { t } = useTranslate()
const textColor = useColorModeValue('gray.600', 'gray.400')
const variableName = variables?.find(
(variable) => variable.id === variableId
Expand All @@ -17,7 +19,7 @@ export const SetVariableLabel = ({
return (
<HStack fontStyle="italic" spacing={1}>
<Text fontSize="sm" color={textColor}>
Set
{t('variables.set')}
</Text>
<Tag bg="orange.400" color="white" size="sm">
{variableName}
Expand Down
12 changes: 7 additions & 5 deletions apps/builder/src/components/inputs/VariableSearchInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import { byId, isDefined, isNotDefined } from '@typebot.io/lib'
import { useOutsideClick } from '@/hooks/useOutsideClick'
import { useParentModal } from '@/features/graph/providers/ParentModalProvider'
import { MoreInfoTooltip } from '../MoreInfoTooltip'
import { useTranslate } from '@tolgee/react'

type Props = {
initialVariableId: string | undefined
Expand Down Expand Up @@ -78,6 +79,7 @@ export const VariableSearchInput = ({
const createVariableItemRef = useRef<HTMLButtonElement | null>(null)
const itemsRef = useRef<(HTMLButtonElement | null)[]>([])
const { ref: parentModalRef } = useParentModal()
const { t } = useTranslate()

useOutsideClick({
ref: dropdownRef,
Expand Down Expand Up @@ -137,7 +139,7 @@ export const VariableSearchInput = ({
const handleRenameVariableClick =
(variable: Variable) => (e: React.MouseEvent) => {
e.stopPropagation()
const name = prompt('Rename variable', variable.name)
const name = prompt(t('variables.rename'), variable.name)
if (!name) return
updateVariable(variable.id, { name })
setFilteredItems(
Expand Down Expand Up @@ -221,7 +223,7 @@ export const VariableSearchInput = ({
onChange={onInputChange}
onFocus={openDropdown}
onKeyDown={handleKeyUp}
placeholder={placeholder ?? 'Select a variable'}
placeholder={placeholder ?? t('variables.select')}
autoComplete="off"
{...inputProps}
/>
Expand Down Expand Up @@ -255,7 +257,7 @@ export const VariableSearchInput = ({
: 'transparent'
}
>
Create
{t('create')}
<Tag colorScheme="orange" ml="1">
<Text noOfLines={0} display="block">
{inputValue}
Expand Down Expand Up @@ -296,13 +298,13 @@ export const VariableSearchInput = ({
<HStack>
<IconButton
icon={<EditIcon />}
aria-label="Rename variable"
aria-label={t('variables.rename')}
size="xs"
onClick={handleRenameVariableClick(item)}
/>
<IconButton
icon={<TrashIcon />}
aria-label="Remove variable"
aria-label={t('variables.remove')}
size="xs"
onClick={handleDeleteVariableClick(item)}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Stack, Tag, Text, Wrap } from '@chakra-ui/react'
import { useTypebot } from '@/features/editor/providers/TypebotProvider'
import { SetVariableLabel } from '@/components/SetVariableLabel'
import { ItemNodesList } from '@/features/graph/components/nodes/item/ItemNodesList'
import { useTranslate } from '@tolgee/react'

type Props = {
block: ChoiceInputBlock
Expand All @@ -12,6 +13,7 @@ type Props = {

export const ButtonsBlockNode = ({ block, indices }: Props) => {
const { typebot } = useTypebot()
const { t } = useTranslate()
const dynamicVariableName = typebot?.variables.find(
(variable) => variable.id === block.options?.dynamicVariableId
)?.name
Expand All @@ -20,11 +22,11 @@ export const ButtonsBlockNode = ({ block, indices }: Props) => {
<Stack w="full">
{block.options?.dynamicVariableId ? (
<Wrap spacing={1}>
<Text>Display</Text>
<Text>{t('blocks.inputs.button.variables.display.label')}</Text>
<Tag bg="orange.400" color="white">
{dynamicVariableName}
</Tag>
<Text>buttons</Text>
<Text>{t('blocks.inputs.button.variables.buttons.label')}</Text>
</Wrap>
) : (
<ItemNodesList block={block} indices={indices} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ import { ChoiceInputBlock, Variable } from '@typebot.io/schemas'
import React from 'react'
import { SwitchWithRelatedSettings } from '@/components/SwitchWithRelatedSettings'
import { defaultChoiceInputOptions } from '@typebot.io/schemas/features/blocks/inputs/choice/constants'
import { useTranslate } from '@tolgee/react'

type Props = {
options?: ChoiceInputBlock['options']
onOptionsChange: (options: ChoiceInputBlock['options']) => void
}

export const ButtonsBlockSettings = ({ options, onOptionsChange }: Props) => {
const { t } = useTranslate()
const updateIsMultiple = (isMultipleChoice: boolean) =>
onOptionsChange({ ...options, isMultipleChoice })
const updateIsSearchable = (isSearchable: boolean) =>
Expand All @@ -29,43 +31,42 @@ export const ButtonsBlockSettings = ({ options, onOptionsChange }: Props) => {
return (
<Stack spacing={4}>
<SwitchWithRelatedSettings
label="Multiple choice?"
label={t('blocks.inputs.settings.multipleChoice.label')}
initialValue={
options?.isMultipleChoice ??
defaultChoiceInputOptions.isMultipleChoice
}
onCheckChange={updateIsMultiple}
>
<TextInput
label="Submit button label:"
label={t('blocks.inputs.settings.submitButton.label')}
defaultValue={
options?.buttonLabel ?? defaultChoiceInputOptions.buttonLabel
options?.buttonLabel ?? t('blocks.inputs.settings.buttonText.label')
}
onChange={updateButtonLabel}
/>
</SwitchWithRelatedSettings>
<SwitchWithRelatedSettings
label="Is searchable?"
label={t('blocks.inputs.settings.isSearchable.label')}
initialValue={
options?.isSearchable ?? defaultChoiceInputOptions.isSearchable
}
onCheckChange={updateIsSearchable}
>
<TextInput
label="Input placeholder:"
label={t('blocks.inputs.settings.input.placeholder.label')}
defaultValue={
options?.searchInputPlaceholder ??
defaultChoiceInputOptions.searchInputPlaceholder
t('blocks.inputs.settings.input.filterOptions.label')
}
onChange={updateSearchInputPlaceholder}
/>
</SwitchWithRelatedSettings>
<FormControl>
<FormLabel>
Dynamic data:{' '}
{t('blocks.inputs.button.settings.dynamicData.label')}{' '}
<MoreInfoTooltip>
If defined, buttons will be dynamically displayed based on what the
variable contains.
{t('blocks.inputs.button.settings.dynamicData.infoText.label')}
</MoreInfoTooltip>
</FormLabel>
<VariableSearchInput
Expand All @@ -75,7 +76,7 @@ export const ButtonsBlockSettings = ({ options, onOptionsChange }: Props) => {
</FormControl>
<Stack>
<FormLabel mb="0" htmlFor="variable">
Save answer in a variable:
{t('blocks.inputs.settings.saveAnswer.label')}
</FormLabel>
<VariableSearchInput
initialVariableId={options?.variableId}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import React, { useRef, useState } from 'react'
import { isNotDefined } from '@typebot.io/lib'
import { useGraph } from '@/features/graph/providers/GraphProvider'
import { ButtonsItemSettings } from './ButtonsItemSettings'
import { useTranslate } from '@tolgee/react'

type Props = {
item: ButtonItem
Expand All @@ -29,9 +30,12 @@ type Props = {
}

export const ButtonsItemNode = ({ item, indices, isMouseOver }: Props) => {
const { t } = useTranslate()
const { deleteItem, updateItem, createItem } = useTypebot()
const { openedItemId, setOpenedItemId } = useGraph()
const [itemValue, setItemValue] = useState(item.content ?? 'Click to edit')
const [itemValue, setItemValue] = useState(
item.content ?? t('blocks.inputs.button.clickToEdit.label')
)
const editableRef = useRef<HTMLDivElement | null>(null)
const ref = useRef<HTMLDivElement | null>(null)
const arrowColor = useColorModeValue('white', 'gray.800')
Expand All @@ -47,8 +51,16 @@ export const ButtonsItemNode = ({ item, indices, isMouseOver }: Props) => {
}

const handleKeyPress = (e: React.KeyboardEvent<HTMLDivElement>) => {
if (e.key === 'Escape' && itemValue === 'Click to edit') deleteItem(indices)
if (e.key === 'Enter' && itemValue !== '' && itemValue !== 'Click to edit')
if (
e.key === 'Escape' &&
itemValue === t('blocks.inputs.button.clickToEdit.label')
)
deleteItem(indices)
if (
e.key === 'Enter' &&
itemValue !== '' &&
itemValue !== t('blocks.inputs.button.clickToEdit.label')
)
handlePlusClick()
}

Expand Down Expand Up @@ -82,7 +94,11 @@ export const ButtonsItemNode = ({ item, indices, isMouseOver }: Props) => {
>
<EditablePreview
w="full"
color={item.content !== 'Click to edit' ? 'inherit' : 'gray.500'}
color={
item.content !== t('blocks.inputs.button.clickToEdit.label')
? 'inherit'
: 'gray.500'
}
cursor="pointer"
/>
<EditableInput onMouseDownCapture={(e) => e.stopPropagation()} />
Expand All @@ -101,7 +117,7 @@ export const ButtonsItemNode = ({ item, indices, isMouseOver }: Props) => {
>
<Flex bgColor={useColorModeValue('white', 'gray.800')} rounded="md">
<IconButton
aria-label="Open settings"
aria-label={t('blocks.inputs.button.openSettings.ariaLabel')}
icon={<SettingsIcon />}
variant="ghost"
size="sm"
Expand All @@ -121,7 +137,7 @@ export const ButtonsItemNode = ({ item, indices, isMouseOver }: Props) => {
unmountOnExit
>
<IconButton
aria-label="Add item"
aria-label={t('blocks.inputs.button.addItem.ariaLabel')}
icon={<PlusIcon />}
size="xs"
shadow="md"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@ import { SwitchWithRelatedSettings } from '@/components/SwitchWithRelatedSetting
import { ConditionForm } from '@/features/blocks/logic/condition/components/ConditionForm'
import { ButtonItem, Condition } from '@typebot.io/schemas'
import { LogicalOperator } from '@typebot.io/schemas/features/blocks/logic/condition/constants'
import { useTranslate } from '@tolgee/react'

type Props = {
item: ButtonItem
onSettingsChange: (updates: Omit<ButtonItem, 'content'>) => void
}

export const ButtonsItemSettings = ({ item, onSettingsChange }: Props) => {
const { t } = useTranslate()

const updateIsDisplayConditionEnabled = (isEnabled: boolean) =>
onSettingsChange({
...item,
Expand All @@ -32,8 +35,10 @@ export const ButtonsItemSettings = ({ item, onSettingsChange }: Props) => {
return (
<Stack spacing={4}>
<SwitchWithRelatedSettings
label="Display condition"
moreInfoContent="Only display this item if a condition is met."
label={t('blocks.inputs.settings.displayCondition.label')}
moreInfoContent={t(
'blocks.inputs.button.buttonSettings.displayCondition.infoText.label'
)}
initialValue={item.displayCondition?.isEnabled ?? false}
onCheckChange={updateIsDisplayConditionEnabled}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ import { FormLabel, Stack } from '@chakra-ui/react'
import { DateInputBlock, Variable } from '@typebot.io/schemas'
import React from 'react'
import { defaultDateInputOptions } from '@typebot.io/schemas/features/blocks/inputs/date/constants'
import { useTranslate } from '@tolgee/react'

type Props = {
options: DateInputBlock['options']
onOptionsChange: (options: DateInputBlock['options']) => void
}

export const DateInputSettings = ({ options, onOptionsChange }: Props) => {
const { t } = useTranslate()
const updateFromLabel = (from: string) =>
onOptionsChange({ ...options, labels: { ...options?.labels, from } })
const updateToLabel = (to: string) =>
Expand Down Expand Up @@ -41,64 +43,69 @@ export const DateInputSettings = ({ options, onOptionsChange }: Props) => {
return (
<Stack spacing={4}>
<SwitchWithRelatedSettings
label="Is range?"
label={t('blocks.inputs.date.settings.isRange.label')}
initialValue={options?.isRange ?? defaultDateInputOptions.isRange}
onCheckChange={updateIsRange}
>
<TextInput
label="From label:"
label={t('blocks.inputs.date.settings.from.label')}
defaultValue={
options?.labels?.from ?? defaultDateInputOptions.labels.from
}
onChange={updateFromLabel}
/>
<TextInput
label="To label:"
label={t('blocks.inputs.date.settings.to.label')}
defaultValue={
options?.labels?.to ?? defaultDateInputOptions.labels.to
options?.labels?.to ??
t('blocks.inputs.date.settings.toInputValue.label')
}
onChange={updateToLabel}
/>
</SwitchWithRelatedSettings>
<SwitchWithLabel
label="With time?"
label={t('blocks.inputs.date.settings.withTime.label')}
initialValue={options?.hasTime ?? defaultDateInputOptions.hasTime}
onCheckChange={updateHasTime}
/>
<TextInput
label="Button label:"
label={t('blocks.inputs.settings.button.label')}
defaultValue={
options?.labels?.button ?? defaultDateInputOptions.labels.button
}
onChange={updateButtonLabel}
/>
<TextInput
label="Min:"
label={t('blocks.inputs.settings.min.label')}
defaultValue={options?.min}
placeholder={options?.hasTime ? 'YYYY-MM-DDTHH:mm' : 'YYYY-MM-DD'}
onChange={updateMin}
/>
<TextInput
label="Max:"
label={t('blocks.inputs.settings.max.label')}
defaultValue={options?.max}
placeholder={options?.hasTime ? 'YYYY-MM-DDTHH:mm' : 'YYYY-MM-DD'}
onChange={updateMax}
/>
<TextInput
label="Format:"
label={t('blocks.inputs.date.settings.format.label')}
defaultValue={
options?.format ??
(options?.hasTime
? defaultDateInputOptions.formatWithTime
: defaultDateInputOptions.format)
}
moreInfoTooltip="i.e dd/MM/yyyy, MM/dd/yy, yyyy-MM-dd"
moreInfoTooltip={`
${t(
'blocks.inputs.date.settings.format.example.label'
)} dd/MM/yyyy, MM/dd/yy, yyyy-MM-dd
`}
placeholder={options?.hasTime ? 'dd/MM/yyyy HH:mm' : 'dd/MM/yyyy'}
onChange={updateFormat}
/>
<Stack>
<FormLabel mb="0" htmlFor="variable">
Save answer in a variable:
{t('blocks.inputs.settings.saveAnswer.label')}
</FormLabel>
<VariableSearchInput
initialVariableId={options?.variableId}
Expand Down
Loading

1 comment on commit 53b702e

@vercel
Copy link

@vercel vercel bot commented on 53b702e Dec 29, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

builder-v2 – ./apps/builder

builder-v2-typebot-io.vercel.app
builder-v2-git-main-typebot-io.vercel.app
app.typebot.io

Please sign in to comment.