Skip to content

Commit

Permalink
🌐 Add theme tab translation keys (#1119)
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**
- Implemented internationalization across various components, enabling
dynamic language translation for UI elements.

- **Enhancements**
	- Improved accessibility with translated `aria-label` attributes.
	- Enhanced user interface with translated button texts and labels.

- **Refactor**
	- Streamlined translation handling with the `useTranslate` hook.

- **Bug Fixes**
	- Corrected tooltip label for better clarity.

- **Style**
	- Updated visual elements to reflect changes in language settings.
<!-- 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 f26eafd commit 5fbbe9d
Show file tree
Hide file tree
Showing 23 changed files with 186 additions and 62 deletions.
8 changes: 5 additions & 3 deletions apps/builder/src/components/ColorPicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
ButtonProps,
Box,
} from '@chakra-ui/react'
import { useTranslate } from '@tolgee/react'
import React, { ChangeEvent, useState } from 'react'
import tinyColor from 'tinycolor2'

Expand All @@ -37,6 +38,7 @@ type Props = {
}

export const ColorPicker = ({ value, defaultValue, onColorChange }: Props) => {
const { t } = useTranslate()
const [color, setColor] = useState(defaultValue ?? '')
const displayedValue = value ?? color

Expand All @@ -54,7 +56,7 @@ export const ColorPicker = ({ value, defaultValue, onColorChange }: Props) => {
<Popover variant="picker" placement="right" isLazy>
<PopoverTrigger>
<Button
aria-label={'Pick a color'}
aria-label={t('colorPicker.pickColor.ariaLabel')}
height="22px"
width="22px"
padding={0}
Expand Down Expand Up @@ -98,7 +100,7 @@ export const ColorPicker = ({ value, defaultValue, onColorChange }: Props) => {
borderRadius={3}
marginTop={3}
placeholder="#2a9d8f"
aria-label="Color value"
aria-label={t('colorPicker.colorValue.ariaLabel')}
size="sm"
value={displayedValue}
onChange={handleColorChange}
Expand All @@ -108,7 +110,7 @@ export const ColorPicker = ({ value, defaultValue, onColorChange }: Props) => {
color={displayedValue}
onColorChange={handleColorChange}
>
Advanced picker
{t('colorPicker.advancedColors')}
</NativeColorPicker>
</PopoverBody>
</PopoverContent>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export const EditableTypebotName = ({
}

return (
<Tooltip label={t('editor.editableTypebotName.tooltip.rename.label')}>
<Tooltip label={t('rename')}>
<Editable
value={currentName}
onChange={setCurrentName}
Expand Down
4 changes: 3 additions & 1 deletion apps/builder/src/features/theme/components/MyTemplates.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { ThemeTemplate } from '@typebot.io/schemas'
import { areThemesEqual } from '../helpers/areThemesEqual'
import { SaveThemeModal } from './SaveThemeModal'
import { ThemeTemplateCard } from './ThemeTemplateCard'
import { useTranslate } from '@tolgee/react'

type Props = {
selectedTemplateId: string | undefined
Expand All @@ -21,6 +22,7 @@ export const MyTemplates = ({
workspaceId,
onTemplateSelect,
}: Props) => {
const { t } = useTranslate()
const { isOpen, onOpen, onClose } = useDisclosure()
const { data } = trpc.theme.listThemeTemplates.useQuery({
workspaceId,
Expand All @@ -41,7 +43,7 @@ export const MyTemplates = ({
{(!selectedTemplate ||
!areThemesEqual(selectedTemplate?.theme, currentTheme)) && (
<Button leftIcon={<SaveIcon />} onClick={onOpen} colorScheme="blue">
Save current theme
{t('theme.sideMenu.template.myTemplates.saveTheme')}
</Button>
)}
<SaveThemeModal
Expand Down
16 changes: 11 additions & 5 deletions apps/builder/src/features/theme/components/SaveThemeModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
ModalOverlay,
} from '@chakra-ui/react'
import { createId } from '@paralleldrive/cuid2'
import { useTranslate } from '@tolgee/react'
import { ThemeTemplate } from '@typebot.io/schemas'
import { FormEvent, useRef, useState } from 'react'

Expand All @@ -31,6 +32,7 @@ export const SaveThemeModal = ({
selectedTemplate,
theme,
}: Props) => {
const { t } = useTranslate()
const { showToast } = useToast()
const [isSaving, setIsSaving] = useState(false)
const inputRef = useRef<HTMLInputElement>(null)
Expand Down Expand Up @@ -80,27 +82,31 @@ export const SaveThemeModal = ({
<Modal isOpen={isOpen} onClose={onClose} initialFocusRef={inputRef}>
<ModalOverlay />
<ModalContent as="form" onSubmit={updateExistingTemplate}>
<ModalHeader>Save theme</ModalHeader>
<ModalHeader>
{t('theme.sideMenu.template.myTemplates.saveTheme.title')}
</ModalHeader>
<ModalCloseButton />
<ModalBody>
<TextInput
ref={inputRef}
label="Name:"
label={t('theme.sideMenu.template.myTemplates.saveTheme.name')}
defaultValue={selectedTemplate?.name}
withVariableButton={false}
placeholder="My template"
placeholder={t(
'theme.sideMenu.template.myTemplates.saveTheme.myTemplate'
)}
isRequired
/>
</ModalBody>

<ModalFooter as={HStack}>
{selectedTemplate?.id && (
<Button isLoading={isSaving} onClick={saveNewTemplate}>
Save as new template
{t('theme.sideMenu.template.myTemplates.saveTheme.saveAsNew')}
</Button>
)}
<Button type="submit" colorScheme="blue" isLoading={isSaving}>
{selectedTemplate?.id ? 'Update' : 'Save'}
{selectedTemplate?.id ? t('update') : t('save')}
</Button>
</ModalFooter>
</ModalContent>
Expand Down
13 changes: 8 additions & 5 deletions apps/builder/src/features/theme/components/ThemeSideMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,11 @@ import { ChatThemeSettings } from './chat/ChatThemeSettings'
import { GeneralSettings } from './general/GeneralSettings'
import { ThemeTemplates } from './ThemeTemplates'
import { defaultSettings } from '@typebot.io/schemas/features/typebot/settings/constants'
import { useTranslate } from '@tolgee/react'

export const ThemeSideMenu = () => {
const { t } = useTranslate()

const { typebot, updateTypebot, currentUserMode } = useTypebot()

const updateChatTheme = (chat: ChatTheme) =>
Expand Down Expand Up @@ -67,15 +70,15 @@ export const ThemeSideMenu = () => {
position="relative"
>
<Heading fontSize="xl" textAlign="center">
Customize the theme
{t('theme.sideMenu.title')}
</Heading>
<Accordion allowMultiple>
{currentUserMode === 'write' && (
<AccordionItem>
<AccordionButton py={6}>
<HStack flex="1" pl={2}>
<TableIcon />
<Heading fontSize="lg">Templates</Heading>
<Heading fontSize="lg">{t('theme.sideMenu.template')}</Heading>
</HStack>
<AccordionIcon />
</AccordionButton>
Expand All @@ -97,7 +100,7 @@ export const ThemeSideMenu = () => {
<AccordionButton py={6}>
<HStack flex="1" pl={2}>
<DropletIcon />
<Heading fontSize="lg">Global</Heading>
<Heading fontSize="lg">{t('theme.sideMenu.global')}</Heading>
</HStack>
<AccordionIcon />
</AccordionButton>
Expand All @@ -119,7 +122,7 @@ export const ThemeSideMenu = () => {
<AccordionButton py={6}>
<HStack flex="1" pl={2}>
<ChatIcon />
<Heading fontSize="lg">Chat</Heading>
<Heading fontSize="lg">{t('theme.sideMenu.chat')}</Heading>
</HStack>
<AccordionIcon />
</AccordionButton>
Expand All @@ -138,7 +141,7 @@ export const ThemeSideMenu = () => {
<AccordionButton py={6}>
<HStack flex="1" pl={2}>
<CodeIcon />
<Heading fontSize="lg">Custom CSS</Heading>
<Heading fontSize="lg">{t('theme.sideMenu.customCSS')}</Heading>
</HStack>
<AccordionIcon />
</AccordionButton>
Expand Down
13 changes: 9 additions & 4 deletions apps/builder/src/features/theme/components/ThemeTemplateCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
BackgroundType,
defaultTheme,
} from '@typebot.io/schemas/features/typebot/theme/constants'
import { useTranslate } from '@tolgee/react'

export const ThemeTemplateCard = ({
workspaceId,
Expand All @@ -38,6 +39,7 @@ export const ThemeTemplateCard = ({
onClick: () => void
onDeleteSuccess?: () => void
}) => {
const { t } = useTranslate()
const borderWidth = useColorModeValue(undefined, '1px')
const [isDeleting, setIsDeleting] = useState(false)

Expand Down Expand Up @@ -160,23 +162,25 @@ export const ThemeTemplateCard = ({
<MenuButton
as={IconButton}
icon={<MoreHorizontalIcon />}
aria-label="Open template menu"
aria-label={t(
'theme.sideMenu.template.myTemplates.menu.ariaLabel'
)}
variant="ghost"
size="xs"
onClick={(e) => e.stopPropagation()}
/>
<MenuList onClick={(e) => e.stopPropagation()}>
{isSelected && (
<MenuItem icon={<EditIcon />} onClick={onRenameClick}>
Rename
{t('rename')}
</MenuItem>
)}
<MenuItem
icon={<TrashIcon />}
color="red.500"
onClick={deleteThemeTemplate}
>
Delete
{t('delete')}
</MenuItem>
</MenuList>
</Menu>
Expand Down Expand Up @@ -208,11 +212,12 @@ const AvatarPreview = ({
}: {
avatar: NonNullable<Theme['chat']>['hostAvatar']
}) => {
const { t } = useTranslate()
if (avatar?.isEnabled) return null
return avatar?.url ? (
<Image
src={avatar.url}
alt="Avatar preview in theme template card"
alt={t('theme.sideMenu.template.gallery.avatarPreview.alt')}
boxSize="12px"
rounded="full"
/>
Expand Down
7 changes: 5 additions & 2 deletions apps/builder/src/features/theme/components/ThemeTemplates.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { ThemeTemplate } from '@typebot.io/schemas'
import { useState } from 'react'
import { MyTemplates } from './MyTemplates'
import { TemplatesGallery } from './TemplatesGallery'
import { useTranslate } from '@tolgee/react'

type Tab = 'my-templates' | 'gallery'

Expand All @@ -21,6 +22,8 @@ export const ThemeTemplates = ({
currentTheme,
onTemplateSelect,
}: Props) => {
const { t } = useTranslate()

const [selectedTab, setSelectedTab] = useState<Tab>('my-templates')

return (
Expand All @@ -32,15 +35,15 @@ export const ThemeTemplates = ({
colorScheme={selectedTab === 'my-templates' ? 'blue' : 'gray'}
onClick={() => setSelectedTab('my-templates')}
>
My templates
{t('theme.sideMenu.template.myTemplates')}
</Button>
<Button
flex="1"
variant="outline"
colorScheme={selectedTab === 'gallery' ? 'blue' : 'gray'}
onClick={() => setSelectedTab('gallery')}
>
Gallery
{t('theme.sideMenu.template.gallery')}
</Button>
</HStack>
<ThemeTemplatesBody
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@ import { Stack, Flex, Text } from '@chakra-ui/react'
import { Theme } from '@typebot.io/schemas'
import React from 'react'
import { ColorPicker } from '../../../../components/ColorPicker'
import { useTranslate } from '@tolgee/react'

type Props = {
buttons: NonNullable<Theme['chat']>['buttons']
onButtonsChange: (buttons: NonNullable<Theme['chat']>['buttons']) => void
}

export const ButtonsTheme = ({ buttons, onButtonsChange }: Props) => {
const { t } = useTranslate()

const handleBackgroundChange = (backgroundColor: string) =>
onButtonsChange({ ...buttons, backgroundColor })
const handleTextChange = (color: string) =>
Expand All @@ -17,14 +20,14 @@ export const ButtonsTheme = ({ buttons, onButtonsChange }: Props) => {
return (
<Stack data-testid="buttons-theme">
<Flex justify="space-between" align="center">
<Text>Background:</Text>
<Text>{t('theme.sideMenu.chat.theme.background')}</Text>
<ColorPicker
value={buttons?.backgroundColor}
onColorChange={handleBackgroundChange}
/>
</Flex>
<Flex justify="space-between" align="center">
<Text>Text:</Text>
<Text>{t('theme.sideMenu.chat.theme.text')}</Text>
<ColorPicker value={buttons?.color} onColorChange={handleTextChange} />
</Flex>
</Stack>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { GuestBubbles } from './GuestBubbles'
import { HostBubbles } from './HostBubbles'
import { InputsTheme } from './InputsTheme'
import { defaultTheme } from '@typebot.io/schemas/features/typebot/theme/constants'
import { useTranslate } from '@tolgee/react'

type Props = {
workspaceId: string
Expand All @@ -27,6 +28,8 @@ export const ChatThemeSettings = ({
chatTheme,
onChatThemeChange,
}: Props) => {
const { t } = useTranslate()

const updateHostBubbles = (
hostBubbles: NonNullable<Theme['chat']>['hostBubbles']
) => onChatThemeChange({ ...chatTheme, hostBubbles })
Expand Down Expand Up @@ -55,7 +58,7 @@ export const ChatThemeSettings = ({
typebotId,
fileName: 'hostAvatar',
}}
title="Bot avatar"
title={t('theme.sideMenu.chat.botAvatar')}
avatarProps={chatTheme?.hostAvatar}
isDefaultCheck
onAvatarChange={updateHostAvatar}
Expand All @@ -66,38 +69,40 @@ export const ChatThemeSettings = ({
typebotId,
fileName: 'guestAvatar',
}}
title="User avatar"
title={t('theme.sideMenu.chat.userAvatar')}
avatarProps={chatTheme?.guestAvatar}
onAvatarChange={updateGuestAvatar}
/>
<Stack borderWidth={1} rounded="md" p="4" spacing={4}>
<Heading fontSize="lg">Bot bubbles</Heading>
<Heading fontSize="lg">{t('theme.sideMenu.chat.botBubbles')}</Heading>
<HostBubbles
hostBubbles={chatTheme?.hostBubbles}
onHostBubblesChange={updateHostBubbles}
/>
</Stack>

<Stack borderWidth={1} rounded="md" p="4" spacing={4}>
<Heading fontSize="lg">User bubbles</Heading>
<Heading fontSize="lg">{t('theme.sideMenu.chat.userBubbles')}</Heading>
<GuestBubbles
guestBubbles={chatTheme?.guestBubbles}
onGuestBubblesChange={updateGuestBubbles}
/>
</Stack>
<Stack borderWidth={1} rounded="md" p="4" spacing={4}>
<Heading fontSize="lg">Buttons</Heading>
<Heading fontSize="lg">{t('theme.sideMenu.chat.buttons')}</Heading>
<ButtonsTheme
buttons={chatTheme?.buttons}
onButtonsChange={updateButtons}
/>
</Stack>
<Stack borderWidth={1} rounded="md" p="4" spacing={4}>
<Heading fontSize="lg">Inputs</Heading>
<Heading fontSize="lg">{t('theme.sideMenu.chat.inputs')}</Heading>
<InputsTheme inputs={chatTheme?.inputs} onInputsChange={updateInputs} />
</Stack>
<Stack borderWidth={1} rounded="md" p="4" spacing={4}>
<Heading fontSize="lg">Corners roundness</Heading>
<Heading fontSize="lg">
{t('theme.sideMenu.chat.cornersRoundness')}
</Heading>
<RadioButtons
options={[
{
Expand Down
Loading

1 comment on commit 5fbbe9d

@vercel
Copy link

@vercel vercel bot commented on 5fbbe9d 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-git-main-typebot-io.vercel.app
app.typebot.io
builder-v2-typebot-io.vercel.app

Please sign in to comment.