Add localization support for endpoint pages components (#667)

* init localization

* Update defaul to en

* Fix merge issue and import path.

* Set default to en

* Change jsx to tsx

* Update the password max length string.

* Remove languageContext as using the recoil instead.

* Add localization to component endpoints pages

* Revert default to en after testing.

* Update LoginForm.tsx

* Fix translation.

* Make lint happy
This commit is contained in:
Abner Chou 2023-07-22 15:09:45 -04:00 committed by GitHub
parent 4148c6d219
commit b64273957a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 212 additions and 67 deletions

View file

@ -6,6 +6,9 @@ import SelectDropDown from '../../ui/SelectDropDown';
import { cn } from '~/utils/';
import useDebounce from '~/hooks/useDebounce';
import { useUpdateTokenCountMutation } from '@librechat/data-provider';
import { useRecoilValue } from 'recoil';
import store from '~/store';
import { localize } from '~/localization/Translation';
const defaultTextProps =
'rounded-md border border-gray-200 focus:border-slate-400 focus:bg-gray-50 bg-transparent text-sm shadow-[0_0_10px_rgba(0,0,0,0.05)] outline-none placeholder:text-gray-400 focus:outline-none focus:ring-gray-400 focus:ring-opacity-20 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:border-gray-500 dark:bg-gray-700 focus:dark:bg-gray-600 dark:text-gray-50 dark:shadow-[0_0_15px_rgba(0,0,0,0.10)] dark:focus:border-gray-400 dark:focus:outline-none dark:focus:ring-0 dark:focus:ring-gray-400 dark:focus:ring-offset-0';
@ -20,6 +23,7 @@ function Settings(props) {
const setToneStyle = (value) => setOption('toneStyle')(value.toLowerCase());
const debouncedContext = useDebounce(context, 250);
const updateTokenCountMutation = useUpdateTokenCountMutation();
const lang = useRecoilValue(store.lang);
useEffect(() => {
if (!debouncedContext || debouncedContext.trim() === '') {
@ -48,7 +52,7 @@ function Settings(props) {
<div className="col-span-1 flex flex-col items-center justify-start gap-6">
<div className="grid w-full items-center gap-2">
<Label htmlFor="toneStyle-dropdown" className="text-left text-sm font-medium">
Tone Style <small className="opacity-40">(default: creative)</small>
{localize(lang, 'com_endpoint_tone_style')} <small className="opacity-40">({localize(lang, 'com_endpoint_default_creative')})</small>
</Label>
<SelectDropDown
id="toneStyle-dropdown"
@ -66,26 +70,26 @@ function Settings(props) {
</div>
<div className="grid w-full items-center gap-2">
<Label htmlFor="context" className="text-left text-sm font-medium">
Context <small className="opacity-40">(default: blank)</small>
{localize(lang, 'com_endpoint_context')} <small className="opacity-40">({localize(lang, 'com_endpoint_default_blank')})</small>
</Label>
<TextareaAutosize
id="context"
disabled={readonly}
value={context || ''}
onChange={(e) => setContext(e.target.value || null)}
placeholder="Bing can use up to 7k tokens for 'context', which it can reference for the conversation. The specific limit is not known but may run into errors exceeding 7k tokens"
placeholder={localize(lang, 'com_endpoint_bing_context_placeholder')}
className={cn(
defaultTextProps,
'flex max-h-[300px] min-h-[100px] w-full resize-none px-3 py-2',
)}
/>
<small className="mb-5 text-black dark:text-white">{`Token count: ${tokenCount}`}</small>
<small className="mb-5 text-black dark:text-white">{`${localize(lang, 'com_endpoint_token_count')}: ${tokenCount}`}</small>
</div>
</div>
<div className="col-span-1 flex flex-col items-center justify-start gap-6">
<div className="grid w-full items-center gap-2">
<Label htmlFor="jailbreak" className="text-left text-sm font-medium">
Enable Sydney <small className="opacity-40">(default: false)</small>
{localize(lang, 'com_endpoint_bing_enable_sydney')} <small className="opacity-40">({localize(lang, 'com_endpoint_default_false')})</small>
</Label>
<div className="flex h-[40px] w-full items-center space-x-3">
<Checkbox
@ -99,7 +103,7 @@ function Settings(props) {
htmlFor="jailbreak"
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 dark:text-gray-50"
>
Jailbreak <small>To enable Sydney</small>
{localize(lang, 'com_endpoint_bing_jailbreak')} <small>{localize(lang, 'com_endpoint_bing_to_enable_sydney')}</small>
</label>
</div>
</div>
@ -116,9 +120,9 @@ function Settings(props) {
className="text-blue-500 transition-colors duration-200 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-500"
rel="noreferrer"
>
System Message
{localize(lang, 'com_endpoint_system_message')}
</a>{' '}
<small className="opacity-40 dark:text-gray-50">(default: blank)</small>
<small className="opacity-40 dark:text-gray-50">( {localize(lang, 'com_endpoint_default_blank')})</small>
</Label>
<TextareaAutosize
@ -126,7 +130,7 @@ function Settings(props) {
disabled={readonly}
value={systemMessage || ''}
onChange={(e) => setSystemMessage(e.target.value || null)}
placeholder="WARNING: Misuse of this feature can get you BANNED from using Bing! Click on 'System Message' for full instructions and the default message if omitted, which is the 'Sydney' preset that is considered safe."
placeholder={localize(lang, 'com_endpoint_bing_system_message_placeholder')}
className={cn(
defaultTextProps,
'flex max-h-[300px] min-h-[100px] w-full resize-none px-3 py-2 placeholder:text-red-400',

View file

@ -20,10 +20,12 @@ import {
} from '~/components/';
import { cn } from '~/utils/';
import cleanupPreset from '~/utils/cleanupPreset';
import { localize } from '~/localization/Translation';
import store from '~/store';
const EditPresetDialog = ({ open, onOpenChange, preset: _preset, title }) => {
const lang = useRecoilValue(store.lang);
const [preset, setPreset] = useState(_preset);
const setPresets = useSetRecoilState(store.presets);
const [showExamples, setShowExamples] = useState(false);
@ -174,13 +176,13 @@ const EditPresetDialog = ({ open, onOpenChange, preset: _preset, title }) => {
<div className="grid w-full gap-6 sm:grid-cols-2">
<div className="col-span-1 flex flex-col items-start justify-start gap-2">
<Label htmlFor="chatGptLabel" className="text-left text-sm font-medium">
Preset Name
{localize(lang, 'com_endpoint_preset_name')}
</Label>
<Input
id="chatGptLabel"
value={preset?.title || ''}
onChange={(e) => setOption('title')(e.target.value || '')}
placeholder="Set a custom name, in case you can find this preset"
placeholder={localize(lang, 'com_endpoint_set_custom_name')}
className={cn(
defaultTextProps,
'flex h-10 max-h-10 w-full resize-none px-3 py-2 focus:outline-none focus:ring-0 focus:ring-opacity-0 focus:ring-offset-0',
@ -189,7 +191,7 @@ const EditPresetDialog = ({ open, onOpenChange, preset: _preset, title }) => {
</div>
<div className="col-span-1 flex flex-col items-start justify-start gap-2">
<Label htmlFor="endpoint" className="text-left text-sm font-medium">
Endpoint
{localize(lang, 'com_endpoint')}
</Label>
<Dropdown
id="endpoint"
@ -209,7 +211,10 @@ const EditPresetDialog = ({ open, onOpenChange, preset: _preset, title }) => {
onClick={triggerExamples}
>
<MessagesSquared className="mr-1 w-[14px]" />
{(showExamples ? 'Hide' : 'Show') + ' Examples'}
{(showExamples
? localize(lang, 'com_endpoint_hide')
: localize(lang, 'com_endpoint_show')) +
localize(lang, 'com_endpoint_examples')}
</Button>
)}
{preset?.endpoint === 'gptPlugins' && (
@ -220,6 +225,13 @@ const EditPresetDialog = ({ open, onOpenChange, preset: _preset, title }) => {
>
<GPTIcon className="mr-1 mt-[2px] w-[14px]" size={14} />
{`Show ${showAgentSettings ? 'Completion' : 'Agent'} Settings`}
{localize(
lang,
'com_endpoint_show_what_settings',
showAgentSettings
? localize(lang, 'com_endpoint_completion')
: localize(lang, 'com_endpoint_agent'),
)}
</Button>
)}
</div>
@ -261,14 +273,14 @@ const EditPresetDialog = ({ open, onOpenChange, preset: _preset, title }) => {
onClick={submitPreset}
className="dark:hover:gray-400 border-gray-700 bg-green-600 text-white hover:bg-green-700 dark:hover:bg-green-800"
>
Save
{localize(lang, 'com_endpoint_save')}
</DialogClose>
</>
}
leftButtons={
<>
<DialogButton onClick={exportPreset} className="dark:hover:gray-400 border-gray-700">
Export
{localize(lang, 'com_endpoint_export')}
</DialogButton>
</>
}

View file

@ -8,6 +8,7 @@ import { alternateName } from '~/utils';
import Settings from './Settings';
import store from '~/store';
import { localize } from '~/localization/Translation';
// A preset dialog to show readonly preset values.
const EndpointOptionsDialog = ({ open, onOpenChange, preset: _preset, title }) => {
@ -15,6 +16,7 @@ const EndpointOptionsDialog = ({ open, onOpenChange, preset: _preset, title }) =
const [saveAsDialogShow, setSaveAsDialogShow] = useState(false);
const endpointsConfig = useRecoilValue(store.endpointsConfig);
const endpointName = alternateName[preset?.endpoint] ?? 'Endpoint';
const lang = useRecoilValue(store.lang);
const setOption = (param) => (newValue) => {
let update = {};
@ -61,14 +63,14 @@ const EndpointOptionsDialog = ({ open, onOpenChange, preset: _preset, title }) =
onClick={saveAsPreset}
className="dark:hover:gray-400 border-gray-700 bg-green-600 text-white hover:bg-green-700 dark:hover:bg-green-800"
>
Save As Preset
{localize(lang, 'com_endpoint_save_as_preset')}
</DialogButton>
</>
}
leftButtons={
<>
<DialogButton onClick={exportPreset} className="dark:hover:gray-400 border-gray-700">
Export
{localize(lang, 'com_endpoint_export')}
</DialogButton>
</>
}

View file

@ -5,6 +5,10 @@ import CrossIcon from '../svg/CrossIcon';
import { Save } from 'lucide-react';
import { cn } from '~/utils/';
import store from '~/store';
import { useRecoilValue } from 'recoil';
import { localize } from '~/localization/Translation';
function EndpointOptionsPopover({
content,
visible,
@ -12,6 +16,7 @@ function EndpointOptionsPopover({
switchToSimpleMode,
additionalButton = null,
}) {
const lang = useRecoilValue(store.lang);
const cardStyle =
'shadow-md rounded-md min-w-[75px] font-normal bg-white border-black/10 border dark:bg-gray-700 text-black dark:text-white';
@ -37,7 +42,7 @@ function EndpointOptionsPopover({
onClick={saveAsPreset}
>
<Save className="mr-1 w-[14px]" />
Save as preset
{localize(lang, 'com_endpoint_save_as_preset')}
</Button>
{additionalButton && (
<Button

View file

@ -4,11 +4,17 @@ import { Button } from '~/components/ui/Button.tsx';
import { Label } from '~/components/ui/Label.tsx';
import { Plus, Minus } from 'lucide-react';
import { cn } from '~/utils/';
import { useRecoilValue } from 'recoil';
import store from '~/store';
import { localize } from '~/localization/Translation';
const defaultTextProps =
'rounded-md border border-gray-200 focus:border-slate-400 focus:bg-gray-50 bg-transparent text-sm shadow-[0_0_10px_rgba(0,0,0,0.05)] outline-none placeholder:text-gray-400 focus:outline-none focus:ring-gray-400 focus:ring-opacity-20 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:border-gray-500 dark:bg-gray-700 focus:dark:bg-gray-600 dark:text-gray-50 dark:shadow-[0_0_15px_rgba(0,0,0,0.10)] dark:focus:border-gray-400 dark:focus:outline-none dark:focus:ring-0 dark:focus:ring-gray-400 dark:focus:ring-offset-0';
function Examples({ readonly, examples, setExample, addExample, removeExample, edit = false }) {
const maxHeight = edit ? 'max-h-[233px]' : 'max-h-[350px]';
const lang = useRecoilValue(store.lang);
return (
<>
<div className={`${maxHeight} overflow-y-auto`}>
@ -23,7 +29,7 @@ function Examples({ readonly, examples, setExample, addExample, removeExample, e
>
<div className="grid w-full items-center gap-2">
<Label htmlFor={`input-${idx}`} className="text-left text-sm font-medium">
Input <small className="opacity-40">(default: blank)</small>
{localize(lang, 'com_ui_input')} <small className="opacity-40">({localize(lang, 'com_endpoint_default_blank')})</small>
</Label>
<TextareaAutosize
id={`input-${idx}`}
@ -47,7 +53,7 @@ function Examples({ readonly, examples, setExample, addExample, removeExample, e
>
<div className="grid w-full items-center gap-2">
<Label htmlFor={`output-${idx}`} className="text-left text-sm font-medium">
Output <small className="opacity-40">(default: blank)</small>
{localize(lang, 'com_endpoint_output')} <small className="opacity-40">({localize(lang, 'com_endpoint_default_blank')})</small>
</Label>
<TextareaAutosize
id={`output-${idx}`}

View file

@ -1,12 +1,14 @@
import React from 'react';
import { HoverCardPortal, HoverCardContent } from '~/components/ui/HoverCard.tsx';
import { useRecoilValue } from 'recoil';
import store from '~/store';
import { localize } from '~/localization/Translation';
const types = {
temp: 'Higher values = more random, while lower values = more focused and deterministic. We recommend altering this or Top P but not both.',
topp: 'Top-p changes how the model selects tokens for output. Tokens are selected from most K (see topK parameter) probable to least until the sum of their probabilities equals the top-p value.',
topk: 'Top-k changes how the model selects tokens for output. A top-k of 1 means the selected token is the most probable among all tokens in the model\'s vocabulary (also called greedy decoding), while a top-k of 3 means that the next token is selected from among the 3 most probable tokens (using temperature).',
maxoutputtokens:
' Maximum number of tokens that can be generated in the response. Specify a lower value for shorter responses and a higher value for longer responses.',
temp: 'com_endpoint_google_temp',
topp: 'com_endpoint_google_topp',
topk: 'com_endpoint_google_topk',
maxoutputtokens: 'com_endpoint_google_maxoutputtokens',
};
function OptionHover({ type, side }) {
@ -14,6 +16,7 @@ function OptionHover({ type, side }) {
// if (type === 'pres') {
// options.sideOffset = 45;
// }
const lang = useRecoilValue(store.lang);
return (
<HoverCardPortal>
@ -23,7 +26,7 @@ function OptionHover({ type, side }) {
// {...options}
>
<div className="space-y-2">
<p className="text-sm text-gray-600 dark:text-gray-300">{types[type]}</p>
<p className="text-sm text-gray-600 dark:text-gray-300">{localize(lang, types[type])}</p>
</div>
</HoverCardContent>
</HoverCardPortal>

View file

@ -9,6 +9,8 @@ import { InputNumber } from '~/components/ui/InputNumber.tsx';
import OptionHover from './OptionHover';
import { HoverCard, HoverCardTrigger } from '~/components/ui/HoverCard.tsx';
import { cn } from '~/utils/';
import { localize } from '~/localization/Translation';
const defaultTextProps =
'rounded-md border border-gray-200 focus:border-slate-400 focus:bg-gray-50 bg-transparent text-sm shadow-[0_0_10px_rgba(0,0,0,0.05)] outline-none placeholder:text-gray-400 focus:outline-none focus:ring-gray-400 focus:ring-opacity-20 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:border-gray-500 dark:bg-gray-700 focus:dark:bg-gray-600 dark:text-gray-50 dark:shadow-[0_0_15px_rgba(0,0,0,0.10)] dark:focus:border-gray-400 dark:focus:outline-none dark:focus:ring-0 dark:focus:ring-gray-400 dark:focus:ring-offset-0';
@ -30,6 +32,7 @@ function Settings(props) {
setOption,
} = props;
const endpointsConfig = useRecoilValue(store.endpointsConfig);
const lang = useRecoilValue(store.lang);
const setModel = setOption('model');
const setModelLabel = setOption('modelLabel');
@ -64,14 +67,14 @@ function Settings(props) {
<>
<div className="grid w-full items-center gap-2">
<Label htmlFor="modelLabel" className="text-left text-sm font-medium">
Custom Name <small className="opacity-40">(default: blank)</small>
{localize(lang, 'com_endpoint_custom_name')} <small className="opacity-40">({localize(lang, 'com_endpoint_default_blank')})</small>
</Label>
<Input
id="modelLabel"
disabled={readonly}
value={modelLabel || ''}
onChange={(e) => setModelLabel(e.target.value || null)}
placeholder="Set a custom name for PaLM2"
placeholder={localize(lang, 'com_endpoint_google_custom_name_placeholder')}
className={cn(
defaultTextProps,
'flex h-10 max-h-10 w-full resize-none px-3 py-2 focus:outline-none focus:ring-0 focus:ring-opacity-0 focus:ring-offset-0',
@ -80,14 +83,14 @@ function Settings(props) {
</div>
<div className="grid w-full items-center gap-2">
<Label htmlFor="promptPrefix" className="text-left text-sm font-medium">
Prompt Prefix <small className="opacity-40">(default: blank)</small>
{localize(lang, 'com_endpoint_prompt_prefix')} <small className="opacity-40">({localize(lang, 'com_endpoint_default_blank')})</small>
</Label>
<TextareaAutosize
id="promptPrefix"
disabled={readonly}
value={promptPrefix || ''}
onChange={(e) => setPromptPrefix(e.target.value || null)}
placeholder="Set custom instructions or context. Ignored if empty."
placeholder={localize(lang, 'com_endpoint_google_prompt_prefix_placeholder')}
className={cn(
defaultTextProps,
'flex max-h-[300px] min-h-[100px] w-full resize-none px-3 py-2 ',
@ -102,7 +105,7 @@ function Settings(props) {
<HoverCardTrigger className="grid w-full items-center gap-2">
<div className="flex justify-between">
<Label htmlFor="temp-int" className="text-left text-sm font-medium">
Temperature <small className="opacity-40">(default: 0.2)</small>
{localize(lang, 'com_endpoint_temperature')} <small className="opacity-40">({localize(lang, 'com_endpoint_default')}: 0.2)</small>
</Label>
<InputNumber
id="temp-int"
@ -141,7 +144,7 @@ function Settings(props) {
<HoverCardTrigger className="grid w-full items-center gap-2">
<div className="flex justify-between">
<Label htmlFor="top-p-int" className="text-left text-sm font-medium">
Top P <small className="opacity-40">(default: 0.95)</small>
{localize(lang, 'com_endpoint_top_p')} <small className="opacity-40">({localize(lang, 'com_endpoint_default_with_num', 0.95)})</small>
</Label>
<InputNumber
id="top-p-int"
@ -179,7 +182,7 @@ function Settings(props) {
<HoverCardTrigger className="grid w-full items-center gap-2">
<div className="flex justify-between">
<Label htmlFor="top-k-int" className="text-left text-sm font-medium">
Top K <small className="opacity-40">(default: 40)</small>
{localize(lang, 'com_endpoint_top_k')} <small className="opacity-40">({localize(lang, 'com_endpoint_default_with_num', 40)})</small>
</Label>
<InputNumber
id="top-k-int"
@ -218,7 +221,7 @@ function Settings(props) {
<HoverCardTrigger className="grid w-full items-center gap-2">
<div className="flex justify-between">
<Label htmlFor="max-tokens-int" className="text-left text-sm font-medium">
Max Output Tokens <small className="opacity-40">(default: 1024)</small>
{localize(lang, 'com_endpoint_max_output_tokens')} <small className="opacity-40">({localize(lang, 'com_endpoint_default_with_num', 1024)})</small>
</Label>
<InputNumber
id="max-tokens-int"

View file

@ -1,20 +1,25 @@
import React from 'react';
import { HoverCardPortal, HoverCardContent } from '~/components/ui/HoverCard.tsx';
import { useRecoilValue } from 'recoil';
import store from '~/store';
import { localize } from '~/localization/Translation';
const types = {
temp: 'Higher values = more random, while lower values = more focused and deterministic. We recommend altering this or Top P but not both.',
max: 'The max tokens to generate. The total length of input tokens and generated tokens is limited by the model\'s context length.',
topp: 'An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of the tokens with top_p probability mass. So 0.1 means only the tokens comprising the top 10% probability mass are considered. We recommend altering this or temperature but not both.',
freq: 'Number between -2.0 and 2.0. Positive values penalize new tokens based on their existing frequency in the text so far, decreasing the model\'s likelihood to repeat the same line verbatim.',
pres: 'Number between -2.0 and 2.0. Positive values penalize new tokens based on whether they appear in the text so far, increasing the model\'s likelihood to talk about new topics.',
temp: 'com_endpoint_openai_temp',
max: 'com_endpoint_openai_max',
topp: 'com_endpoint_openai_topp',
freq: 'com_endpoint_openai_freq',
pres: 'com_endpoint_openai_pres',
};
function OptionHover({ type, side }) {
const lang = useRecoilValue(store.lang);
return (
<HoverCardPortal>
<HoverCardContent side={side} className="w-80 ">
<div className="space-y-2">
<p className="text-sm text-gray-600 dark:text-gray-300">{types[type]}</p>
<p className="text-sm text-gray-600 dark:text-gray-300">{localize(lang, types[type])}</p>
</div>
</HoverCardContent>
</HoverCardPortal>

View file

@ -8,6 +8,8 @@ import { InputNumber } from '~/components/ui/InputNumber.tsx';
import OptionHover from './OptionHover';
import { HoverCard, HoverCardTrigger } from '~/components/ui/HoverCard.tsx';
import { cn } from '~/utils/';
import { localize } from '~/localization/Translation';
const defaultTextProps =
'rounded-md border border-gray-200 focus:border-slate-400 focus:bg-gray-50 bg-transparent text-sm shadow-[0_0_10px_rgba(0,0,0,0.05)] outline-none placeholder:text-gray-400 focus:outline-none focus:ring-gray-400 focus:ring-opacity-20 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:border-gray-500 dark:bg-gray-700 focus:dark:bg-gray-600 dark:text-gray-50 dark:shadow-[0_0_15px_rgba(0,0,0,0.10)] dark:focus:border-gray-400 dark:focus:outline-none dark:focus:ring-0 dark:focus:ring-gray-400 dark:focus:ring-offset-0';
@ -32,6 +34,7 @@ function Settings(props) {
const isOpenAI = endpoint === 'openAI' || endpoint === 'azureOpenAI';
const endpointsConfig = useRecoilValue(store.endpointsConfig);
const lang = useRecoilValue(store.lang);
const setModel = setOption('model');
const setChatGptLabel = setOption('chatGptLabel');
@ -64,14 +67,14 @@ function Settings(props) {
<>
<div className="grid w-full items-center gap-2">
<Label htmlFor="chatGptLabel" className="text-left text-sm font-medium">
Custom Name <small className="opacity-40">(default: blank)</small>
{localize(lang, 'com_endpoint_custom_name')} <small className="opacity-40">({localize(lang, 'com_endpoint_default_blank')})</small>
</Label>
<Input
id="chatGptLabel"
disabled={readonly}
value={chatGptLabel || ''}
onChange={(e) => setChatGptLabel(e.target.value || null)}
placeholder="Set a custom name for ChatGPT"
placeholder={localize(lang, 'com_endpoint_openai_custom_name_placeholder')}
className={cn(
defaultTextProps,
'flex h-10 max-h-10 w-full resize-none px-3 py-2 focus:outline-none focus:ring-0 focus:ring-opacity-0 focus:ring-offset-0',
@ -80,14 +83,14 @@ function Settings(props) {
</div>
<div className="grid w-full items-center gap-2">
<Label htmlFor="promptPrefix" className="text-left text-sm font-medium">
Prompt Prefix <small className="opacity-40">(default: blank)</small>
{localize(lang, 'com_endpoint_prompt_prefix')} <small className="opacity-40">({localize(lang, 'com_endpoint_default_blank')})</small>
</Label>
<TextareaAutosize
id="promptPrefix"
disabled={readonly}
value={promptPrefix || ''}
onChange={(e) => setPromptPrefix(e.target.value || null)}
placeholder="Set custom instructions to include in System Message. Default: none"
placeholder={localize(lang, 'com_endpoint_openai_prompt_prefix_placeholder')}
className={cn(
defaultTextProps,
'flex max-h-[300px] min-h-[100px] w-full resize-none px-3 py-2 ',
@ -102,8 +105,10 @@ function Settings(props) {
<HoverCardTrigger className="grid w-full items-center gap-2">
<div className="flex justify-between">
<Label htmlFor="temp-int" className="text-left text-sm font-medium">
Temperature{' '}
<small className="opacity-40">(default: {isOpenAI ? '1' : '0'})</small>
{localize(lang, 'com_endpoint_temperature')}{' '}
<small className="opacity-40">
({localize(lang, 'com_endpoint_default_with_num', isOpenAI ? '1' : '0')})
</small>
</Label>
<InputNumber
id="temp-int"
@ -140,7 +145,7 @@ function Settings(props) {
<HoverCardTrigger className="grid w-full items-center gap-2">
<div className="flex justify-between">
<Label htmlFor="top-p-int" className="text-left text-sm font-medium">
Top P <small className="opacity-40">(default: 1)</small>
{localize(lang, 'com_endpoint_top_p')} <small className="opacity-40">({localize(lang, 'com_endpoint_default')}: 1)</small>
</Label>
<InputNumber
id="top-p-int"
@ -178,7 +183,7 @@ function Settings(props) {
<HoverCardTrigger className="grid w-full items-center gap-2">
<div className="flex justify-between">
<Label htmlFor="freq-penalty-int" className="text-left text-sm font-medium">
Frequency Penalty <small className="opacity-40">(default: 0)</small>
{localize(lang, 'com_endpoint_frequency_penalty')} <small className="opacity-40">({localize(lang, 'com_endpoint_default')}: 0)</small>
</Label>
<InputNumber
id="freq-penalty-int"
@ -216,7 +221,7 @@ function Settings(props) {
<HoverCardTrigger className="grid w-full items-center gap-2">
<div className="flex justify-between">
<Label htmlFor="pres-penalty-int" className="text-left text-sm font-medium">
Presence Penalty <small className="opacity-40">(default: 0)</small>
{localize(lang, 'com_endpoint_presence_penalty')} <small className="opacity-40">({localize(lang, 'com_endpoint_default')}: 0)</small>
</Label>
<InputNumber
id="pres-penalty-int"

View file

@ -10,6 +10,8 @@ import {
HoverCardTrigger,
} from '~/components';
import OptionHover from './OptionHover';
import { localize } from '~/localization/Translation';
const defaultTextProps =
'rounded-md border border-gray-200 focus:border-slate-400 focus:bg-gray-50 bg-transparent text-sm shadow-[0_0_10px_rgba(0,0,0,0.05)] outline-none placeholder:text-gray-400 focus:outline-none focus:ring-gray-400 focus:ring-opacity-20 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:border-gray-500 dark:bg-gray-700 focus:dark:bg-gray-600 dark:text-gray-50 dark:shadow-[0_0_15px_rgba(0,0,0,0.10)] dark:focus:border-gray-400 dark:focus:outline-none dark:focus:ring-0 dark:focus:ring-gray-400 dark:focus:ring-offset-0';
@ -21,6 +23,7 @@ import store from '~/store';
function Settings(props) {
const { readonly, agent, skipCompletion, model, temperature, setOption } = props;
const endpoint = 'gptPlugins';
const lang = useRecoilValue(store.lang);
const endpointsConfig = useRecoilValue(store.endpointsConfig);
const setModel = setOption('model');
@ -62,7 +65,7 @@ function Settings(props) {
htmlFor="functions-agent"
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 dark:text-gray-50"
>
<small>Use Functions</small>
<small>{localize(lang, 'com_endpoint_plug_use_functions')}</small>
</label>
<Switch
id="functions-agent"
@ -80,7 +83,7 @@ function Settings(props) {
htmlFor="skip-completion"
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 dark:text-gray-50"
>
<small>Skip Completion</small>
<small>{localize(lang, 'com_endpoint_plug_skip_completion')}</small>
</label>
<Switch
id="skip-completion"
@ -99,7 +102,7 @@ function Settings(props) {
<HoverCardTrigger className="grid w-full items-center gap-2">
<div className="flex justify-between">
<Label htmlFor="temp-int" className="text-left text-sm font-medium">
Temperature <small className="opacity-40">{'(default: 0)'}</small>
{localize(lang, 'com_endpoint_temperature')} <small className="opacity-40">({localize(lang, 'com_endpoint_default')}: 0)</small>
</Label>
<InputNumber
id="temp-int"

View file

@ -11,6 +11,8 @@ import {
HoverCardTrigger,
} from '~/components';
import OptionHover from './OptionHover';
import { localize } from '~/localization/Translation';
const defaultTextProps =
'rounded-md border border-gray-200 focus:border-slate-400 focus:bg-gray-50 bg-transparent text-sm shadow-[0_0_10px_rgba(0,0,0,0.05)] outline-none placeholder:text-gray-400 focus:outline-none focus:ring-gray-400 focus:ring-opacity-20 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:border-gray-500 dark:bg-gray-700 focus:dark:bg-gray-600 dark:text-gray-50 dark:shadow-[0_0_15px_rgba(0,0,0,0.10)] dark:focus:border-gray-400 dark:focus:outline-none dark:focus:ring-0 dark:focus:ring-gray-400 dark:focus:ring-offset-0';
@ -33,6 +35,7 @@ function Settings(props) {
tools,
} = props;
const endpoint = 'gptPlugins';
const lang = useRecoilValue(store.lang);
const endpointsConfig = useRecoilValue(store.endpointsConfig);
const setModel = setOption('model');
@ -67,8 +70,8 @@ function Settings(props) {
<>
<div className="grid w-full items-center gap-2">
<Label htmlFor="chatGptLabel" className="text-left text-sm font-medium">
Custom Name{' '}
<small className="opacity-40">(default: empty | disabled with tools)</small>
{localize(lang, 'com_endpoint_custom_name')}{' '}
<small className="opacity-40">({localize(lang, 'com_endpoint_default_empty')} | {localize(lang, 'com_endpoint_disabled_with_tools')})</small>
</Label>
<Input
id="chatGptLabel"
@ -76,7 +79,9 @@ function Settings(props) {
value={chatGptLabel || ''}
onChange={(e) => setChatGptLabel(e.target.value || null)}
placeholder={
toolsSelected ? 'Disabled with Tools Selected' : 'Set a custom name for ChatGPT.'
toolsSelected
? localize(lang, 'com_endpoint_disabled_with_tools_placeholder')
: localize(lang, 'com_endpoint_plug_set_custom_name_for_gpt_placeholder')
}
className={cn(
defaultTextProps,
@ -86,8 +91,8 @@ function Settings(props) {
</div>
<div className="grid w-full items-center gap-2">
<Label htmlFor="promptPrefix" className="text-left text-sm font-medium">
Prompt Prefix{' '}
<small className="opacity-40">(default: empty | disabled with tools)</small>
{localize(lang, 'com_endpoint_prompt_prefix')}{' '}
<small className="opacity-40">({localize(lang, 'com_endpoint_default_empty')} | {localize(lang, 'com_endpoint_disabled_with_tools')})</small>
</Label>
<TextareaAutosize
id="promptPrefix"
@ -96,8 +101,8 @@ function Settings(props) {
onChange={(e) => setPromptPrefix(e.target.value || null)}
placeholder={
toolsSelected
? 'Disabled with Tools Selected'
: 'Set custom instructions to include in System Message. Default: none'
? localize(lang, 'com_endpoint_disabled_with_tools_placeholder')
: localize(lang, 'com_endpoint_plug_set_custom_instructions_for_gpt_placeholder')
}
className={cn(
defaultTextProps,
@ -149,7 +154,7 @@ function Settings(props) {
<HoverCardTrigger className="grid w-full items-center gap-2">
<div className="flex justify-between">
<Label htmlFor="top-p-int" className="text-left text-sm font-medium">
Top P <small className="opacity-40">(default: 1)</small>
{localize(lang, 'com_endpoint_top_p')} <small className="opacity-40">({localize(lang, 'com_endpoint_default_with_num', 1)})</small>
</Label>
<InputNumber
id="top-p-int"
@ -187,7 +192,7 @@ function Settings(props) {
<HoverCardTrigger className="grid w-full items-center gap-2">
<div className="flex justify-between">
<Label htmlFor="freq-penalty-int" className="text-left text-sm font-medium">
Frequency Penalty <small className="opacity-40">(default: 0)</small>
{localize(lang, 'com_endpoint_frequency_penalty')} <small className="opacity-40">({localize(lang, 'com_endpoint_default_with_num', 0)})</small>
</Label>
<InputNumber
id="freq-penalty-int"
@ -225,7 +230,7 @@ function Settings(props) {
<HoverCardTrigger className="grid w-full items-center gap-2">
<div className="flex justify-between">
<Label htmlFor="pres-penalty-int" className="text-left text-sm font-medium">
Presence Penalty <small className="opacity-40">(default: 0)</small>
{localize(lang, 'com_endpoint_presence_penalty')} <small className="opacity-40">({localize(lang, 'com_endpoint_default_with_num', 0)})</small>
</Label>
<InputNumber
id="pres-penalty-int"

View file

@ -5,11 +5,13 @@ import { cn } from '~/utils/';
import cleanupPreset from '~/utils/cleanupPreset';
import { useCreatePresetMutation } from '@librechat/data-provider';
import store from '~/store';
import { localize } from '~/localization/Translation';
const SaveAsPresetDialog = ({ open, onOpenChange, preset }) => {
const [title, setTitle] = useState(preset?.title || 'My Preset');
const endpointsConfig = useRecoilValue(store.endpointsConfig);
const createPresetMutation = useCreatePresetMutation();
const lang = useRecoilValue(store.lang);
const defaultTextProps =
'rounded-md border border-gray-300 bg-transparent text-sm shadow-[0_0_10px_rgba(0,0,0,0.10)] outline-none placeholder:text-gray-400 focus:outline-none focus:ring-gray-400 focus:ring-opacity-20 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:border-gray-400 dark:bg-gray-700 dark:text-gray-50 dark:shadow-[0_0_15px_rgba(0,0,0,0.10)] dark:focus:border-gray-400 dark:focus:outline-none dark:focus:ring-0 dark:focus:ring-gray-400 dark:focus:ring-offset-0';
@ -37,7 +39,7 @@ const SaveAsPresetDialog = ({ open, onOpenChange, preset }) => {
main={
<div className="grid w-full items-center gap-2">
<Label htmlFor="chatGptLabel" className="text-left text-sm font-medium">
Preset Name
{localize(lang, 'com_endpoint_preset_name')}
</Label>
<Input
id="chatGptLabel"

View file

@ -3,6 +3,21 @@ import Chinese from './languages/Zh';
import Italy from './languages/It';
// === import additional language files here === //
// New method on String allow using "{\d}" placeholder for
// loading value dynamically.
interface String {
format(...replacements: string[]): string;
}
if (!String.prototype.format) {
String.prototype.format = function () {
var args = arguments;
return this.replace(/{(\d+)}/g, function (match, number) {
return typeof args[number] != 'undefined' ? args[number] : match;
});
};
}
// input: language code in string
// returns an object of translated strings in the language
export const getTranslations = (langCode: string) => {
@ -21,7 +36,12 @@ export const getTranslations = (langCode: string) => {
// input: language code in string & phrase key in string
// returns an corresponding phrase value in string
export const localize = (langCode: string, phraseKey: string) => {
export const localize = (langCode: string, phraseKey: string, ...values: string[]) => {
const lang = getTranslations(langCode);
return lang[phraseKey];
if (phraseKey in lang) {
return lang[phraseKey].format(...values);
}
// Fall back logic to cover untranslated phrases
return English[phraseKey].format(...values);
};

View file

@ -78,4 +78,74 @@ export default {
com_auth_to_try_again: 'to try again.',
com_auth_submit_registration: 'Submit registration',
com_auth_welcome_back: 'Welcome back',
com_endpoint_bing_enable_sydney: 'Enable Sydney',
com_endpoint_bing_to_enable_sydney: 'To enable Sydney',
com_endpoint_bing_jailbreak: 'Jailbreak',
com_endpoint_bing_context_placeholder:
'Bing can use up to 7k tokens for \'context\', which it can reference for the conversation. The specific limit is not known but may run into errors exceeding 7k tokens',
com_endpoint_bing_system_message_placeholder:
'WARNING: Misuse of this feature can get you BANNED from using Bing! Click on \'System Message\' for full instructions and the default message if omitted, which is the \'Sydney\' preset that is considered safe.',
com_endpoint_system_message: 'System Message',
com_endpoint_default_blank: 'default: blank',
com_endpoint_default_false: 'default: false',
com_endpoint_default_creative: 'default: creative',
com_endpoint_default_empty: 'default: empty',
com_endpoint_default_with_num: 'default: {0}',
com_endpoint_context: 'Context',
com_endpoint_tone_style: 'Tone Style',
com_endpoint_token_count: 'Token count',
com_endpoint_output: 'Output',
com_endpoint_google_temp:
'Higher values = more random, while lower values = more focused and deterministic. We recommend altering this or Top P but not both.',
com_endpoint_google_topp:
'Top-p changes how the model selects tokens for output. Tokens are selected from most K (see topK parameter) probable to least until the sum of their probabilities equals the top-p value.',
com_endpoint_google_topk:
'Top-k changes how the model selects tokens for output. A top-k of 1 means the selected token is the most probable among all tokens in the model\'s vocabulary (also called greedy decoding), while a top-k of 3 means that the next token is selected from among the 3 most probable tokens (using temperature).',
com_endpoint_google_maxoutputtokens:
' Maximum number of tokens that can be generated in the response. Specify a lower value for shorter responses and a higher value for longer responses.',
com_endpoint_google_custom_name_placeholder: 'Set a custom name for PaLM2',
com_endpoint_google_prompt_prefix_placeholder:
'Set custom instructions or context. Ignored if empty.',
com_endpoint_custom_name: 'Custom Name',
com_endpoint_prompt_prefix: 'Prompt Prefix',
com_endpoint_temperature: 'Temperature',
com_endpoint_default: 'default',
com_endpoint_top_p: 'Top P',
com_endpoint_top_k: 'Top K',
com_endpoint_max_output_tokens: 'Max Output Tokens',
com_endpoint_openai_temp:
'Higher values = more random, while lower values = more focused and deterministic. We recommend altering this or Top P but not both.',
com_endpoint_openai_max:
'The max tokens to generate. The total length of input tokens and generated tokens is limited by the model\'s context length.',
com_endpoint_openai_topp:
'An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of the tokens with top_p probability mass. So 0.1 means only the tokens comprising the top 10% probability mass are considered. We recommend altering this or temperature but not both.',
com_endpoint_openai_freq:
'Number between -2.0 and 2.0. Positive values penalize new tokens based on their existing frequency in the text so far, decreasing the model\'s likelihood to repeat the same line verbatim.',
com_endpoint_openai_pres:
'Number between -2.0 and 2.0. Positive values penalize new tokens based on whether they appear in the text so far, increasing the model\'s likelihood to talk about new topics.',
com_endpoint_openai_custom_name_placeholder: 'Set a custom name for ChatGPT',
com_endpoint_openai_prompt_prefix_placeholder:
'Set custom instructions to include in System Message. Default: none',
com_endpoint_frequency_penalty: 'Frequency Penalty',
com_endpoint_presence_penalty: 'Presence Penalty',
com_endpoint_plug_use_functions: 'Use Functions',
com_endpoint_plug_skip_completion: 'Skip Completion',
com_endpoint_disabled_with_tools: 'disabled with tools',
com_endpoint_disabled_with_tools_placeholder: 'Disabled with Tools Selected',
com_endpoint_plug_set_custom_name_for_gpt_placeholder: 'Set a custom name for ChatGPT.',
com_endpoint_plug_set_custom_instructions_for_gpt_placeholder:
'Set custom instructions to include in System Message. Default: none',
com_endpoint_set_custom_name: 'Set a custom name, in case you can find this preset',
com_endpoint_preset_name: 'Preset Name',
com_endpoint: 'Endpoint',
com_endpoint_hide: 'Hide',
com_endpoint_show: 'Show',
com_endpoint_examples: ' Examples',
com_endpoint_completion: 'Completion',
com_endpoint_agent: 'Agent',
com_endpoint_show_what_settings: 'Show {0} Settings',
com_endpoint_save: 'Save',
com_endpoint_export: 'Export',
com_endpoint_save_as_preset: 'Save As Preset',
com_endpoint_not_implemented: 'Not implemented',
};

View file

@ -36,8 +36,8 @@ export default {
com_auth_sign_up: '注册',
com_auth_sign_in: '登录',
com_auth_google_login: '谷歌登录',
com_auth_github_login: '登录 Github',
com_auth_discord_login: '登录不和谐',
com_auth_github_login: 'Github登录',
com_auth_discord_login: 'Discord登录',
com_auth_email: '电子邮箱',
com_auth_email_required: 'Email is required',
com_auth_email_min_length: 'Email must be at least 6 characters',