🔄 chore: Enforce 18next Language Keys (#5803)

* chore: enforcing language keys to adhere to the new standard.

* chore: enforcing i18n forbids to write plain text in JSX markup

* chore: enforcing i18n forbids to write plain text in JSX markup

* fix: ci with checkbox for unused keys :)

* refactor: removed all the unused `i18n` keys
This commit is contained in:
Ruben Talstra 2025-02-12 21:48:13 +01:00 committed by GitHub
parent 2a506df443
commit 7f48030452
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
33 changed files with 200 additions and 219 deletions

View file

@ -1,4 +1,4 @@
/* eslint-disable react-hooks/rules-of-hooks */
import { ArrowUpDown, Database } from 'lucide-react';
import { FileSources, FileContext } from 'librechat-data-provider';
import type { ColumnDef } from '@tanstack/react-table';
@ -7,10 +7,10 @@ import { Button, Checkbox, OpenAIMinimalIcon, AzureMinimalIcon } from '~/compone
import ImagePreview from '~/components/Chat/Input/Files/ImagePreview';
import FilePreview from '~/components/Chat/Input/Files/FilePreview';
import { SortFilterHeader } from './SortFilterHeader';
import { useLocalize, useMediaQuery } from '~/hooks';
import { TranslationKeys, useLocalize, useMediaQuery } from '~/hooks';
import { formatDate, getFileType } from '~/utils';
const contextMap = {
const contextMap: Record<any, TranslationKeys> = {
[FileContext.avatar]: 'com_ui_avatar',
[FileContext.unknown]: 'com_ui_unknown',
[FileContext.assistants]: 'com_ui_assistants',
@ -127,8 +127,8 @@ export const columns: ColumnDef<TFile>[] = [
),
}}
valueMap={{
[FileSources.azure]: 'Azure',
[FileSources.openai]: 'OpenAI',
[FileSources.azure]: 'com_ui_azure',
[FileSources.openai]: 'com_ui_openai',
[FileSources.local]: 'com_ui_host',
}}
/>
@ -182,7 +182,7 @@ export const columns: ColumnDef<TFile>[] = [
const localize = useLocalize();
return (
<div className="flex flex-wrap items-center gap-2">
{localize(contextMap[context ?? FileContext.unknown] ?? 'com_ui_unknown')}
{localize(contextMap[context ?? FileContext.unknown])}
</div>
);
},
@ -212,4 +212,4 @@ export const columns: ColumnDef<TFile>[] = [
return `${value}${suffix}`;
},
},
];
];

View file

@ -16,7 +16,7 @@ interface SortFilterHeaderProps<TData, TValue> extends React.HTMLAttributes<HTML
title: string;
column: Column<TData, TValue>;
filters?: Record<string, string[] | number[]>;
valueMap?: Record<string, string>;
valueMap?: Record<any, TranslationKeys>;
}
export function SortFilterHeader<TData, TValue>({
@ -82,7 +82,7 @@ export function SortFilterHeader<TData, TValue>({
const translationKey = valueMap?.[value ?? ''];
const filterValue =
translationKey != null && translationKey.length
? localize(translationKey as TranslationKeys)
? localize(translationKey)
: String(value);
if (!filterValue) {
return null;

View file

@ -6,7 +6,7 @@ import type { MentionOption, ConvoGenerator } from '~/common';
import useSelectMention from '~/hooks/Input/useSelectMention';
import { useAssistantsMapContext } from '~/Providers';
import useMentions from '~/hooks/Input/useMentions';
import { useLocalize, useCombobox } from '~/hooks';
import { useLocalize, useCombobox, TranslationKeys } from '~/hooks';
import { removeCharIfLast } from '~/utils';
import MentionItem from './MentionItem';
@ -24,7 +24,7 @@ export default function Mention({
newConversation: ConvoGenerator;
textAreaRef: React.MutableRefObject<HTMLTextAreaElement | null>;
commandChar?: string;
placeholder?: string;
placeholder?: TranslationKeys;
includeAssistants?: boolean;
}) {
const localize = useLocalize();
@ -162,7 +162,7 @@ export default function Mention({
<div className="popover border-token-border-light rounded-2xl border bg-white p-2 shadow-lg dark:bg-gray-700">
<input
// The user expects focus to transition to the input field when the popover is opened
// eslint-disable-next-line jsx-a11y/no-autofocus
autoFocus
ref={inputRef}
placeholder={localize(placeholder)}

View file

@ -1,4 +1,4 @@
import { useState, useRef } from 'react';
import React, { useState, useRef } from 'react';
import { useRecoilState } from 'recoil';
import { GitFork, InfoIcon } from 'lucide-react';
import * as Popover from '@radix-ui/react-popover';
@ -21,9 +21,9 @@ import store from '~/store';
interface PopoverButtonProps {
children: React.ReactNode;
setting: string;
onClick: (setting: string) => void;
setActiveSetting: React.Dispatch<React.SetStateAction<string>>;
setting: ForkOptions;
onClick: (setting: ForkOptions) => void;
setActiveSetting: React.Dispatch<React.SetStateAction<TranslationKeys>>;
sideOffset?: number;
timeoutRef: React.MutableRefObject<NodeJS.Timeout | null>;
hoverInfo?: React.ReactNode | string;
@ -31,11 +31,11 @@ interface PopoverButtonProps {
hoverDescription?: React.ReactNode | string;
}
const optionLabels = {
const optionLabels: Record<ForkOptions, TranslationKeys> = {
[ForkOptions.DIRECT_PATH]: 'com_ui_fork_visible',
[ForkOptions.INCLUDE_BRANCHES]: 'com_ui_fork_branches',
[ForkOptions.TARGET_LEVEL]: 'com_ui_fork_all_target',
default: 'com_ui_fork_from_message',
[ForkOptions.DEFAULT]: 'com_ui_fork_from_message',
};
const PopoverButton: React.FC<PopoverButtonProps> = ({
@ -65,10 +65,10 @@ const PopoverButton: React.FC<PopoverButtonProps> = ({
clearTimeout(timeoutRef.current);
}
timeoutRef.current = setTimeout(() => {
setActiveSetting(optionLabels.default);
setActiveSetting(optionLabels[ForkOptions.DEFAULT]);
}, 175);
}}
className="mx-1 max-w-14 flex-1 rounded-lg border-2 bg-white text-gray-700 transition duration-300 ease-in-out hover:bg-gray-200 hover:text-gray-900 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-400 dark:hover:bg-gray-600 dark:hover:text-gray-100 "
className="mx-1 max-w-14 flex-1 rounded-lg border-2 bg-white text-gray-700 transition duration-300 ease-in-out hover:bg-gray-200 hover:text-gray-900 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-400 dark:hover:bg-gray-600 dark:hover:text-gray-100"
type="button"
>
{children}
@ -77,18 +77,12 @@ const PopoverButton: React.FC<PopoverButtonProps> = ({
(hoverTitle != null && hoverTitle !== '') ||
(hoverDescription != null && hoverDescription !== '')) && (
<HoverCardPortal>
<HoverCardContent
side="right"
className="z-[999] w-80 dark:bg-gray-700"
sideOffset={sideOffset}
>
<HoverCardContent side="right" className="z-[999] w-80 dark:bg-gray-700" sideOffset={sideOffset}>
<div className="space-y-2">
<p className="flex flex-col gap-2 text-sm text-gray-600 dark:text-gray-300">
{hoverInfo != null && hoverInfo !== '' && hoverInfo}
{hoverTitle != null && hoverTitle !== '' && (
<span className="flex flex-wrap gap-1 font-bold">{hoverTitle}</span>
)}
{hoverDescription != null && hoverDescription !== '' && hoverDescription}
{hoverInfo && hoverInfo}
{hoverTitle && <span className="flex flex-wrap gap-1 font-bold">{hoverTitle}</span>}
{hoverDescription && hoverDescription}
</p>
</div>
</HoverCardContent>
@ -201,7 +195,7 @@ export default function Fork({
align="center"
>
<div className="flex h-6 w-full items-center justify-center text-sm dark:text-gray-200">
{localize(activeSetting as TranslationKeys)}
{localize(activeSetting )}
<HoverCard openDelay={50}>
<HoverCardTrigger asChild>
<InfoIcon className="ml-auto flex h-4 w-4 gap-2 text-gray-500 dark:text-white/50" />
@ -235,7 +229,7 @@ export default function Fork({
hoverTitle={
<>
<GitCommit className="h-5 w-5 rotate-90" />
{localize(optionLabels[ForkOptions.DIRECT_PATH] as TranslationKeys)}
{localize(optionLabels[ForkOptions.DIRECT_PATH])}
</>
}
hoverDescription={localize('com_ui_fork_info_visible')}
@ -253,7 +247,7 @@ export default function Fork({
hoverTitle={
<>
<GitBranchPlus className="h-4 w-4 rotate-180" />
{localize(optionLabels[ForkOptions.INCLUDE_BRANCHES] as TranslationKeys)}
{localize(optionLabels[ForkOptions.INCLUDE_BRANCHES])}
</>
}
hoverDescription={localize('com_ui_fork_info_branches')}
@ -272,7 +266,7 @@ export default function Fork({
<>
<ListTree className="h-5 w-5" />
{`${localize(
optionLabels[ForkOptions.TARGET_LEVEL] as TranslationKeys,
optionLabels[ForkOptions.TARGET_LEVEL],
)} (${localize('com_endpoint_default')})`}
</>
}

View file

@ -1,4 +1,4 @@
import { useState, useRef } from 'react';
import React, { useState, useRef } from 'react';
import * as Tabs from '@radix-ui/react-tabs';
import { MessageSquare, Command } from 'lucide-react';
import { SettingsTabValues } from 'librechat-data-provider';
@ -6,7 +6,7 @@ import type { TDialogProps } from '~/common';
import { Dialog, DialogPanel, DialogTitle, Transition, TransitionChild } from '@headlessui/react';
import { GearIcon, DataIcon, SpeechIcon, UserIcon, ExperimentIcon } from '~/components/svg';
import { General, Chat, Speech, Beta, Commands, Data, Account } from './SettingsTabs';
import { useMediaQuery, useLocalize } from '~/hooks';
import { useMediaQuery, useLocalize, TranslationKeys } from '~/hooks';
import { cn } from '~/utils';
export default function Settings({ open, onOpenChange }: TDialogProps) {
@ -47,6 +47,44 @@ export default function Settings({ open, onOpenChange }: TDialogProps) {
}
};
const settingsTabs: { value: SettingsTabValues; icon: React.JSX.Element; label: TranslationKeys }[] = [
{
value: SettingsTabValues.GENERAL,
icon: <GearIcon />,
label: 'com_nav_setting_general',
},
{
value: SettingsTabValues.CHAT,
icon: <MessageSquare className="icon-sm" />,
label: 'com_nav_setting_chat',
},
{
value: SettingsTabValues.BETA,
icon: <ExperimentIcon />,
label: 'com_nav_setting_beta',
},
{
value: SettingsTabValues.COMMANDS,
icon: <Command className="icon-sm" />,
label: 'com_nav_commands',
},
{
value: SettingsTabValues.SPEECH,
icon: <SpeechIcon className="icon-sm" />,
label: 'com_nav_setting_speech',
},
{
value: SettingsTabValues.DATA,
icon: <DataIcon />,
label: 'com_nav_setting_data',
},
{
value: SettingsTabValues.ACCOUNT,
icon: <UserIcon />,
label: 'com_nav_setting_account',
},
];
const handleTabChange = (value: string) => {
setActiveTab(value as SettingsTabValues);
};
@ -126,43 +164,7 @@ export default function Settings({ open, onOpenChange }: TDialogProps) {
)}
onKeyDown={handleKeyDown}
>
{[
{
value: SettingsTabValues.GENERAL,
icon: <GearIcon />,
label: 'com_nav_setting_general',
},
{
value: SettingsTabValues.CHAT,
icon: <MessageSquare className="icon-sm" />,
label: 'com_nav_setting_chat',
},
{
value: SettingsTabValues.BETA,
icon: <ExperimentIcon />,
label: 'com_nav_setting_beta',
},
{
value: SettingsTabValues.COMMANDS,
icon: <Command className="icon-sm" />,
label: 'com_nav_commands',
},
{
value: SettingsTabValues.SPEECH,
icon: <SpeechIcon className="icon-sm" />,
label: 'com_nav_setting_speech',
},
{
value: SettingsTabValues.DATA,
icon: <DataIcon />,
label: 'com_nav_setting_data',
},
{
value: SettingsTabValues.ACCOUNT,
icon: <UserIcon />,
label: 'com_nav_setting_account',
},
].map(({ value, icon, label }) => (
{settingsTabs.map(({ value, icon, label }) => (
<Tabs.Trigger
key={value}
className={cn(

View file

@ -14,6 +14,7 @@ import { useDeleteUserMutation } from '~/data-provider';
import { useAuthContext } from '~/hooks/AuthContext';
import { useLocalize } from '~/hooks';
import { cn } from '~/utils';
import { LocalizeFunction } from '~/common';
const DeleteAccount = ({ disabled = false }: { title?: string; disabled?: boolean }) => {
const localize = useLocalize();
@ -103,7 +104,7 @@ const renderDeleteButton = (
handleDeleteUser: () => void,
isDeleting: boolean,
isLocked: boolean,
localize: (key: string) => string,
localize: LocalizeFunction,
) => (
<button
className={cn(

View file

@ -18,7 +18,6 @@ export default function PlusCommandSwitch() {
id="plusCommand"
checked={plusCommand}
onCheckedChange={handleCheckedChange}
f
className="ml-4"
data-testid="plusCommand"
/>

View file

@ -18,7 +18,6 @@ export default function SlashCommandSwitch() {
id="slashCommand"
checked={slashCommand}
onCheckedChange={handleCheckedChange}
f
data-testid="slashCommand"
/>
</div>

View file

@ -34,7 +34,7 @@ export default function ActionsAuth({ disableOAuth }: { disableOAuth?: boolean }
</div>
<div className="border-token-border-medium flex rounded-lg border text-sm hover:cursor-pointer">
<div className="h-9 grow px-3 py-2">
{localize(`com_ui_${type}` as TranslationKeys)}
{localize(getAuthLocalizationKey(type))}
</div>
<div className="bg-token-border-medium w-px"></div>
<button type="button" color="neutral" className="flex items-center gap-2 px-3">
@ -269,6 +269,18 @@ const ApiKey = () => {
);
};
/** Returns the appropriate localization key for authentication type */
function getAuthLocalizationKey(type: AuthTypeEnum): TranslationKeys {
switch (type) {
case AuthTypeEnum.ServiceHttp:
return 'com_ui_api_key';
case AuthTypeEnum.OAuth:
return 'com_ui_oauth';
default:
return 'com_ui_none';
}
}
const OAuth = () => {
const localize = useLocalize();
const { register, watch, setValue } = useFormContext();

View file

@ -2,7 +2,7 @@ import { useMemo, useState } from 'react';
import { OptionTypes } from 'librechat-data-provider';
import type { DynamicSettingProps } from 'librechat-data-provider';
import { Label, Checkbox, HoverCard, HoverCardTrigger } from '~/components/ui';
import { useLocalize, useParameterEffects } from '~/hooks';
import { TranslationKeys, useLocalize, useParameterEffects } from '~/hooks';
import { useChatContext } from '~/Providers';
import OptionHover from './OptionHover';
import { ESide } from '~/common';
@ -66,7 +66,7 @@ function DynamicCheckbox({
htmlFor={`${settingKey}-dynamic-checkbox`}
className="text-left text-sm font-medium"
>
{labelCode ? localize(label) ?? label : label || settingKey}{' '}
{labelCode ? localize(label as TranslationKeys) ?? label : label || settingKey}{' '}
{showDefault && (
<small className="opacity-40">
({localize('com_endpoint_default')}:{' '}
@ -85,7 +85,7 @@ function DynamicCheckbox({
</HoverCardTrigger>
{description && (
<OptionHover
description={descriptionCode ? localize(description) ?? description : description}
description={descriptionCode ? localize(description as TranslationKeys) ?? description : description}
side={ESide.Left}
/>
)}

View file

@ -3,7 +3,7 @@ import { OptionTypes } from 'librechat-data-provider';
import type { DynamicSettingProps } from 'librechat-data-provider';
import { Label, HoverCard, HoverCardTrigger } from '~/components/ui';
import ControlCombobox from '~/components/ui/ControlCombobox';
import { useLocalize, useParameterEffects } from '~/hooks';
import { TranslationKeys, useLocalize, useParameterEffects } from '~/hooks';
import { useChatContext } from '~/Providers';
import OptionHover from './OptionHover';
import { ESide } from '~/common';
@ -93,7 +93,7 @@ function DynamicCombobox({
htmlFor={`${settingKey}-dynamic-combobox`}
className="text-left text-sm font-medium"
>
{labelCode ? localize(label) ?? label : label || settingKey}
{labelCode ? localize(label as TranslationKeys) ?? label : label || settingKey}
{showDefault && (
<small className="opacity-40">
({localize('com_endpoint_default')}: {defaultValue})
@ -105,10 +105,10 @@ function DynamicCombobox({
<ControlCombobox
displayValue={selectedValue}
selectPlaceholder={
selectPlaceholderCode === true ? localize(selectPlaceholder) : selectPlaceholder
selectPlaceholderCode === true ? localize(selectPlaceholder as TranslationKeys) : selectPlaceholder
}
searchPlaceholder={
searchPlaceholderCode === true ? localize(searchPlaceholder) : searchPlaceholder
searchPlaceholderCode === true ? localize(searchPlaceholder as TranslationKeys) : searchPlaceholder
}
isCollapsed={isCollapsed}
ariaLabel={settingKey}
@ -120,7 +120,7 @@ function DynamicCombobox({
</HoverCardTrigger>
{description && (
<OptionHover
description={descriptionCode ? localize(description) ?? description : description}
description={descriptionCode ? localize(description as TranslationKeys) ?? description : description}
side={ESide.Left}
/>
)}

View file

@ -2,7 +2,7 @@ import { useMemo, useState } from 'react';
import { OptionTypes } from 'librechat-data-provider';
import type { DynamicSettingProps } from 'librechat-data-provider';
import { Label, HoverCard, HoverCardTrigger, SelectDropDown } from '~/components/ui';
import { useLocalize, useParameterEffects } from '~/hooks';
import { TranslationKeys, useLocalize, useParameterEffects } from '~/hooks';
import { useChatContext } from '~/Providers';
import OptionHover from './OptionHover';
import { ESide } from '~/common';
@ -78,7 +78,7 @@ function DynamicDropdown({
htmlFor={`${settingKey}-dynamic-dropdown`}
className="text-left text-sm font-medium"
>
{labelCode ? localize(label) ?? label : label || settingKey}
{labelCode ? localize(label as TranslationKeys) ?? label : label || settingKey}
{showDefault && (
<small className="opacity-40">
({localize('com_endpoint_default')}: {defaultValue})
@ -96,12 +96,12 @@ function DynamicDropdown({
availableValues={options}
containerClassName="w-full"
id={`${settingKey}-dynamic-dropdown`}
placeholder={placeholderCode ? localize(placeholder) ?? placeholder : placeholder}
placeholder={placeholderCode ? localize(placeholder as TranslationKeys) ?? placeholder : placeholder}
/>
</HoverCardTrigger>
{description && (
<OptionHover
description={descriptionCode ? localize(description) ?? description : description}
description={descriptionCode ? localize(description as TranslationKeys) ?? description : description}
side={ESide.Left}
/>
)}

View file

@ -1,6 +1,6 @@
import { OptionTypes } from 'librechat-data-provider';
import type { DynamicSettingProps } from 'librechat-data-provider';
import { useLocalize, useDebouncedInput, useParameterEffects } from '~/hooks';
import { useLocalize, useDebouncedInput, useParameterEffects, TranslationKeys } from '~/hooks';
import { Label, Input, HoverCard, HoverCardTrigger } from '~/components/ui';
import { useChatContext } from '~/Providers';
import OptionHover from './OptionHover';
@ -73,7 +73,7 @@ function DynamicInput({
htmlFor={`${settingKey}-dynamic-input`}
className="text-left text-sm font-medium"
>
{labelCode ? localize(label) || label : label || settingKey}{' '}
{labelCode ? localize(label as TranslationKeys) || label : label || settingKey}{' '}
{showDefault && (
<small className="opacity-40">
(
@ -90,7 +90,7 @@ function DynamicInput({
disabled={readonly}
value={inputValue ?? ''}
onChange={handleInputChange}
placeholder={placeholderCode ? localize(placeholder) || placeholder : placeholder}
placeholder={placeholderCode ? localize(placeholder as TranslationKeys) || placeholder : placeholder}
className={cn(
'flex h-10 max-h-10 w-full resize-none border-none bg-surface-secondary px-3 py-2',
)}
@ -98,7 +98,7 @@ function DynamicInput({
</HoverCardTrigger>
{description && (
<OptionHover
description={descriptionCode ? localize(description) || description : description}
description={descriptionCode ? localize(description as TranslationKeys) || description : description}
side={ESide.Left}
/>
)}

View file

@ -2,7 +2,7 @@ import { useMemo, useCallback } from 'react';
import { OptionTypes } from 'librechat-data-provider';
import type { DynamicSettingProps } from 'librechat-data-provider';
import { Label, Slider, HoverCard, Input, InputNumber, HoverCardTrigger } from '~/components/ui';
import { useLocalize, useDebouncedInput, useParameterEffects } from '~/hooks';
import { useLocalize, useDebouncedInput, useParameterEffects, TranslationKeys } from '~/hooks';
import { cn, defaultTextProps, optionText } from '~/utils';
import { ESide, defaultDebouncedDelay } from '~/common';
import { useChatContext } from '~/Providers';
@ -117,7 +117,7 @@ function DynamicSlider({
htmlFor={`${settingKey}-dynamic-setting`}
className="text-left text-sm font-medium"
>
{labelCode ? localize(label) ?? label : label || settingKey}{' '}
{labelCode ? localize(label as TranslationKeys) ?? label : label || settingKey}{' '}
{showDefault && (
<small className="opacity-40">
({localize('com_endpoint_default')}: {defaultValue})
@ -176,7 +176,7 @@ function DynamicSlider({
</HoverCardTrigger>
{description && (
<OptionHover
description={descriptionCode ? localize(description) ?? description : description}
description={descriptionCode ? localize(description as TranslationKeys) ?? description : description}
side={ESide.Left}
/>
)}

View file

@ -2,7 +2,7 @@ import { useState, useMemo } from 'react';
import { OptionTypes } from 'librechat-data-provider';
import type { DynamicSettingProps } from 'librechat-data-provider';
import { Label, Switch, HoverCard, HoverCardTrigger } from '~/components/ui';
import { useLocalize, useParameterEffects } from '~/hooks';
import { TranslationKeys, useLocalize, useParameterEffects } from '~/hooks';
import { useChatContext } from '~/Providers';
import OptionHover from './OptionHover';
import { ESide } from '~/common';
@ -65,7 +65,7 @@ function DynamicSwitch({
htmlFor={`${settingKey}-dynamic-switch`}
className="text-left text-sm font-medium"
>
{labelCode ? localize(label) ?? label : label || settingKey}{' '}
{labelCode ? localize(label as TranslationKeys) ?? label : label || settingKey}{' '}
{showDefault && (
<small className="opacity-40">
({localize('com_endpoint_default')}:{' '}
@ -84,7 +84,7 @@ function DynamicSwitch({
</HoverCardTrigger>
{description && (
<OptionHover
description={descriptionCode ? localize(description) ?? description : description}
description={descriptionCode ? localize(description as TranslationKeys) ?? description : description}
side={ESide.Left}
/>
)}

View file

@ -1,7 +1,7 @@
import { OptionTypes } from 'librechat-data-provider';
import type { DynamicSettingProps } from 'librechat-data-provider';
import { Label, TextareaAutosize, HoverCard, HoverCardTrigger } from '~/components/ui';
import { useLocalize, useDebouncedInput, useParameterEffects } from '~/hooks';
import { useLocalize, useDebouncedInput, useParameterEffects, TranslationKeys } from '~/hooks';
import { cn, defaultTextProps } from '~/utils';
import { useChatContext } from '~/Providers';
import OptionHover from './OptionHover';
@ -58,7 +58,7 @@ function DynamicTextarea({
htmlFor={`${settingKey}-dynamic-textarea`}
className="text-left text-sm font-medium"
>
{labelCode ? localize(label) ?? label : label || settingKey}{' '}
{labelCode ? localize(label as TranslationKeys) ?? label : label || settingKey}{' '}
{showDefault && (
<small className="opacity-40">
(
@ -75,7 +75,7 @@ function DynamicTextarea({
disabled={readonly}
value={inputValue ?? ''}
onChange={setInputValue}
placeholder={placeholderCode ? localize(placeholder) ?? placeholder : placeholder}
placeholder={placeholderCode ? localize(placeholder as TranslationKeys) ?? placeholder : placeholder}
className={cn(
// TODO: configurable max height
'flex max-h-[138px] min-h-[100px] w-full resize-none rounded-lg bg-surface-secondary px-3 py-2 focus:outline-none',
@ -84,7 +84,7 @@ function DynamicTextarea({
</HoverCardTrigger>
{description && (
<OptionHover
description={descriptionCode ? localize(description) ?? description : description}
description={descriptionCode ? localize(description as TranslationKeys) ?? description : description}
side={ESide.Left}
/>
)}

View file

@ -1,6 +1,6 @@
import React from 'react';
import { HoverCardPortal, HoverCardContent } from '~/components/ui';
import { useLocalize } from '~/hooks';
import { TranslationKeys, useLocalize } from '~/hooks';
import { ESide } from '~/common';
type TOptionHoverProps = {
@ -24,7 +24,7 @@ function OptionHover({
if (disabled) {
return null;
}
const text = langCode ? localize(description) : description;
const text = langCode ? localize(description as TranslationKeys) : description;
return (
<HoverCardPortal>
<HoverCardContent side={side} className={`z-[999] w-80 ${className}`} sideOffset={sideOffset}>

View file

@ -27,6 +27,7 @@ import {
import { TrashIcon, Spinner } from '~/components/svg';
import { useLocalize, useMediaQuery } from '~/hooks';
import { cn } from '~/utils';
import { LocalizeFunction } from '~/common';
type TableColumn<TData, TValue> = ColumnDef<TData, TValue> & {
meta?: {
@ -177,7 +178,7 @@ const DeleteButton = memo(
isDeleting: boolean;
disabled: boolean;
isSmallScreen: boolean;
localize: (key: string) => string;
localize:LocalizeFunction;
}) => {
if (!onDelete) {
return null;

View file

@ -1,5 +1,5 @@
import React, { useState, useCallback, useRef, useEffect } from 'react';
import { useLocalize } from '~/hooks';
import { TranslationKeys, useLocalize } from '~/hooks';
import { Minus, Plus } from 'lucide-react';
interface ModelParametersProps {
@ -33,7 +33,7 @@ const ModelParameters: React.FC<ModelParametersProps> = ({
const rangeRef = useRef<HTMLInputElement>(null);
const id = `model-parameter-${ariaLabel.toLowerCase().replace(/\s+/g, '-')}`;
const displayLabel = label.startsWith('com_') ? localize(label) : label;
const displayLabel = label.startsWith('com_') ? localize(label as TranslationKeys) : label;
const getDecimalPlaces = (num: number) => {
const match = ('' + num).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/);